// asymptotic region private static void Coulomb_Asymptotic(double L, double eta, double rho, out double F, out double G) { // compute phase // reducing the eta = 0 and eta != 0 parts seperately preserves accuracy for large rho and small eta double t0 = Reduce(rho, -L / 4.0); double t1 = Reduce(AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho), 0.0); double t = t0 + t1; double s = Math.Sin(t); double c = Math.Cos(t); // determine the weights of sin and cos double f0 = 1.0; double g0 = 0.0; double f = f0; double g = g0; for (int k = 0; true; k++) { // compute the next contributions to f and g double q = 2 * (k + 1) * rho; double a = (2 * k + 1) * eta / q; double b = ((L * (L + 1) - k * (k + 1)) + eta * eta) / q; double f1 = a * f0 - b * g0; double g1 = a * g0 + b * f0; // add them double f_old = f; f += f1; double g_old = g; g += g1; if ((f == f_old) && (g == g_old)) { break; } // check for non-convergence if (k > Global.SeriesMax) { throw new NonconvergenceException(); } // prepare for the next iteration f0 = f1; g0 = g1; } F = g * c + f * s; G = f * c - g * s; }
// asymptotic region private static SolutionPair Coulomb_Asymptotic(double L, double eta, double rho) { // Abromowitz & Stegun 14.5 describes this asymptotic expansion /* * double F, G; * Coulomb_Asymptotic(L, eta, rho, out F, out G); * return (new SolutionPair(F, 0.0, G, 0.0)); */ /* * // Old reduction algorithm * double t0 = Reduce(rho, -L / 4.0); * double t1 = Reduce(AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho), 0.0); * double t = t0 + t1; * double s = Math.Sin(t); * double c = Math.Cos(t); */ /* * // New reduction algorithm * double t = AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho) + rho; * double s = MoreMath.Sin(t); * double c = MoreMath.Cos(t); * * int r = -((int) L) % 4; * if (r < 0) r += 4; * * switch (r) { * case 0: * // no change * break; * case 1: * Global.Swap(ref s, ref c); * c = -c; * break; * case 2: * s = -s; * c = -c; * break; * case 3: * Global.Swap(ref s, ref c); * s = -s; * break; * default: * throw new InvalidOperationException(); * }; */ long t00; double t01; RangeReduction.ReduceByPiHalves(rho, out t00, out t01); long t10; double t11; RangeReduction.ReduceByPiHalves(AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho), out t10, out t11); long t20; double t1; RangeReduction.ReduceByOnes(t01 + t11, out t20, out t1); long t0 = t00 + t10 + t20 - (long)L; double s = RangeReduction.Sin(t0, t1); double c = RangeReduction.Cos(t0, t1); /* * long tt0; double tt1; * RangeReduction.ReduceByPiHalves(rho - eta * Math.Log(2.0 * rho) + AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im, out tt0, out tt1); * * tt0 -= (long) L; * * double s = RangeReduction.Sin(tt0, tt1); * double c = RangeReduction.Cos(tt0, tt1); */ /* * // compute phase * // reducing the eta = 0 and eta != 0 parts seperately preserves accuracy for large rho and small eta * double t0 = Reduce(rho, -L / 4.0); * double t1 = Reduce(AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho), 0.0); * double t = t0 + t1; * double s = Math.Sin(t); * double c = Math.Cos(t); */ // determine the weights of sin and cos double f0 = 1.0; double g0 = 0.0; double fp0 = 0.0; double gp0 = 1.0 - eta / rho; double f = f0; double g = g0; double fp = fp0; double gp = gp0; for (int k = 0; k < Global.SeriesMax; k++) { // Remember the old values for comparison double f_old = f; double g_old = g; double fp_old = fp; double gp_old = gp; // Compute the next corrections double q = 2 * (k + 1) * rho; double a = (2 * k + 1) * eta / q; double b = ((L * (L + 1) - k * (k + 1)) + eta * eta) / q; double f1 = a * f0 - b * g0; double g1 = a * g0 + b * f0; double fp1 = a * fp0 - b * gp0 - f1 / rho; double gp1 = a * gp0 + b * fp0 - g1 / rho; // Apply them f += f1; g += g1; fp += fp1; gp += gp1; // Test for convergence if ((f == f_old) && (g == g_old) && (fp == fp_old)) { return(new SolutionPair( g * c + f * s, gp * c + fp * s, f * c - g * s, fp * c - gp * s) ); } // Prepare for the next iteration f0 = f1; g0 = g1; fp0 = fp1; gp0 = gp1; } throw new NonconvergenceException(); }
// asymptotic region private static SolutionPair Coulomb_Asymptotic(double L, double eta, double rho) { // Abromowitz & Stegun 14.5 describes this asymptotic expansion RangeReduction.ReduceByPiHalves(rho, out long t00, out double t01); RangeReduction.ReduceByPiHalves(AdvancedComplexMath.LogGamma(new Complex(L + 1.0, eta)).Im - eta * Math.Log(2.0 * rho), out long t10, out double t11); RangeReduction.ReduceByOnes(t01 + t11, out long t20, out double t1); long t0 = t00 + t10 + t20 - (long)L; double s = RangeReduction.Sin(t0, t1); double c = RangeReduction.Cos(t0, t1); // determine the weights of sin and cos double f0 = 1.0; double g0 = 0.0; double fp0 = 0.0; double gp0 = 1.0 - eta / rho; double f = f0; double g = g0; double fp = fp0; double gp = gp0; for (int k = 0; k < Global.SeriesMax; k++) { // Remember the old values for comparison double f_old = f; double g_old = g; double fp_old = fp; //double gp_old = gp; // Compute the next corrections double q = 2 * (k + 1) * rho; double a = (2 * k + 1) * eta / q; double b = ((L * (L + 1) - k * (k + 1)) + eta * eta) / q; double f1 = a * f0 - b * g0; double g1 = a * g0 + b * f0; double fp1 = a * fp0 - b * gp0 - f1 / rho; double gp1 = a * gp0 + b * fp0 - g1 / rho; // Apply them f += f1; g += g1; fp += fp1; gp += gp1; // Test for convergence if ((f == f_old) && (g == g_old) && (fp == fp_old)) { return(new SolutionPair( g * c + f * s, gp * c + fp * s, f * c - g * s, fp * c - gp * s) ); } // Prepare for the next iteration f0 = f1; g0 = g1; fp0 = fp1; gp0 = gp1; } throw new NonconvergenceException(); }