private static double CoulombF_Integrate(int L, double eta, double rho) { // start at the series limit double rho0 = 4.0 + 2.0 * Math.Sqrt(L); if (Math.Abs(rho0 * eta) > 8.0 + 4.0 * L) { rho0 = (8.0 + 4.0 * L) / Math.Abs(eta); } double F, FP; CoulombF_Series(L, eta, rho0, out F, out FP); // TODO: switch so we integrate w/o the C factor, then apply it afterward if ((F == 0.0) && (FP == 0.0)) { return(0.0); } // integrate out to rho BulrischStoerStoermerStepper s = new BulrischStoerStoermerStepper(); s.RightHandSide = delegate(double x, double U) { return((L * (L + 1) / x / x + 2.0 * eta / x - 1.0) * U); }; s.X = rho0; s.Y = F; s.YPrime = FP; s.DeltaX = 0.25; s.Accuracy = 2.5E-13; s.Integrate(rho); // return the result return(s.Y); }
/// <summary> /// Computes the irregular Coulomb wave function. /// </summary> /// <param name="L">The angular momentum number, which must be non-negative.</param> /// <param name="eta">The charge parameter, which can be postive or negative.</param> /// <param name="rho">The radial distance parameter, which must be non-negative.</param> /// <returns>The value of G<sub>L</sub>(η,ρ).</returns> /// <remarks> /// <para>For information on the Coulomb wave functions, see the remarks on <see cref="CoulombF" />.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="L"/> or <paramref name="rho"/> is negative.</exception> /// <seealso cref="CoulombF"/> /// <seealso href="http://en.wikipedia.org/wiki/Coulomb_wave_function" /> /// <seealso href="http://mathworld.wolfram.com/CoulombWaveFunction.html" /> public static double CoulombG(int L, double eta, double rho) { if (L < 0) throw new ArgumentOutOfRangeException("L"); if (rho < 0) throw new ArgumentOutOfRangeException("rho"); if ((rho < 4.0) && Math.Abs(rho * eta) < 8.0) { // for small enough rho, use the power series for L=0, then recurse upward to desired L double F, FP, G, GP; Coulomb_Zero_Series(eta, rho, out F, out FP, out G, out GP); Coulomb_Recurse_Upward(0, L, eta, rho, ref G, ref GP); return (G); } else if (rho > 32.0 + (L * L + eta * eta) / 2.0) { // for large enough rho, use the asymptotic series double F, G; Coulomb_Asymptotic(L, eta, rho, out F, out G); return (G); } else { // transition region if (rho >= CoulombTurningPoint(L, eta)) { // beyond the turning point, use Steed's method SolutionPair result = Coulomb_Steed(L, eta, rho); return (result.SecondSolutionValue); } else { // we will start at L=0 (which has a smaller turning point radius) and recurse up to the desired L // this is okay because G increasees with increasing L double G, GP; if (rho < 2.0 * eta) { // if inside the turning point even for L=0, start at the turning point and integrate in // this is okay becaue G increases with decraseing rho // use Steed's method at the turning point // for large enough eta, we could use the turning point expansion at L=0, but it contributes // a lot of code for little overall performance increase so we have chosen not to SolutionPair result; //if (eta > 12.0) { // result = Coulomb_Zero_Turning_Expansion(eta); //} else { result = Coulomb_Steed(0, eta, 2.0 * eta); //} G = result.SecondSolutionValue; GP = result.SecondSolutionDerivative; BulrischStoerStoermerStepper s = new BulrischStoerStoermerStepper(); s.RightHandSide = delegate(double x, double U) { return ((2.0 * eta / x - 1.0) * U); }; s.X = 2.0 * eta; s.Y = G; s.YPrime = GP; s.DeltaX = 0.25; s.Accuracy = 2.5E-13; s.Integrate(rho); G = s.Y; GP = s.YPrime; } else { // if beyond the turning point for L=0, just use Steeds method SolutionPair result = Coulomb_Steed(0, eta, rho); G = result.SecondSolutionValue; GP = result.SecondSolutionDerivative; } // recurse up to desired L Coulomb_Recurse_Upward(0, L, eta, rho, ref G, ref GP); return (G); } } }
private static double CoulombF_Integrate(int L, double eta, double rho) { // start at the series limit double rho0 = 4.0 + 2.0 * Math.Sqrt(L); if (Math.Abs(rho0 * eta) > 8.0 + 4.0 * L) rho0 = (8.0 + 4.0 * L) / Math.Abs(eta); double F, FP; CoulombF_Series(L, eta, rho0, out F, out FP); // TODO: switch so we integrate w/o the C factor, then apply it afterward if ((F == 0.0) && (FP == 0.0)) return (0.0); // integrate out to rho BulrischStoerStoermerStepper s = new BulrischStoerStoermerStepper(); s.RightHandSide = delegate(double x, double U) { return ((L * (L + 1) / x / x + 2.0 * eta / x - 1.0) * U); }; s.X = rho0; s.Y = F; s.YPrime = FP; s.DeltaX = 0.25; s.Accuracy = 2.5E-13; s.Integrate(rho); // return the result return (s.Y); }
/// <summary> /// Computes the irregular Coulomb wave function. /// </summary> /// <param name="L">The angular momentum number, which must be non-negative.</param> /// <param name="eta">The charge parameter, which can be postive or negative.</param> /// <param name="rho">The radial distance parameter, which must be non-negative.</param> /// <returns>The value of G<sub>L</sub>(η,ρ).</returns> /// <remarks> /// <para>For information on the Coulomb wave functions, see the remarks on <see cref="CoulombF" />.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="L"/> or <paramref name="rho"/> is negative.</exception> /// <seealso cref="CoulombF"/> /// <seealso href="http://en.wikipedia.org/wiki/Coulomb_wave_function" /> /// <seealso href="http://mathworld.wolfram.com/CoulombWaveFunction.html" /> public static double CoulombG(int L, double eta, double rho) { if (L < 0) { throw new ArgumentOutOfRangeException("L"); } if (rho < 0) { throw new ArgumentOutOfRangeException("rho"); } if ((rho < 4.0) && Math.Abs(rho * eta) < 8.0) { // for small enough rho, use the power series for L=0, then recurse upward to desired L double F, FP, G, GP; Coulomb_Zero_Series(eta, rho, out F, out FP, out G, out GP); Coulomb_Recurse_Upward(0, L, eta, rho, ref G, ref GP); return(G); } else if (rho > 32.0 + (L * L + eta * eta) / 2.0) { // for large enough rho, use the asymptotic series double F, G; Coulomb_Asymptotic(L, eta, rho, out F, out G); return(G); } else { // transition region if (rho >= CoulombTurningPoint(L, eta)) { // beyond the turning point, use Steed's method SolutionPair result = Coulomb_Steed(L, eta, rho); return(result.SecondSolutionValue); } else { // we will start at L=0 (which has a smaller turning point radius) and recurse up to the desired L // this is okay because G increasees with increasing L double G, GP; if (rho < 2.0 * eta) { // if inside the turning point even for L=0, start at the turning point and integrate in // this is okay becaue G increases with decraseing rho // use Steed's method at the turning point // for large enough eta, we could use the turning point expansion at L=0, but it contributes // a lot of code for little overall performance increase so we have chosen not to SolutionPair result; //if (eta > 12.0) { // result = Coulomb_Zero_Turning_Expansion(eta); //} else { result = Coulomb_Steed(0, eta, 2.0 * eta); //} G = result.SecondSolutionValue; GP = result.SecondSolutionDerivative; BulrischStoerStoermerStepper s = new BulrischStoerStoermerStepper(); s.RightHandSide = delegate(double x, double U) { return((2.0 * eta / x - 1.0) * U); }; s.X = 2.0 * eta; s.Y = G; s.YPrime = GP; s.DeltaX = 0.25; s.Accuracy = 2.5E-13; s.Integrate(rho); G = s.Y; GP = s.YPrime; } else { // if beyond the turning point for L=0, just use Steeds method SolutionPair result = Coulomb_Steed(0, eta, rho); G = result.SecondSolutionValue; GP = result.SecondSolutionDerivative; } // recurse up to desired L Coulomb_Recurse_Upward(0, L, eta, rho, ref G, ref GP); return(G); } } }