Exemple #1
0
        // 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();
        }