Ejemplo n.º 1
0
        // series for L=0 for both F and G
        // this has the same convergence properties as the L != 0 series for F above

        private static void Coulomb_Zero_Series(double eta, double rho, out double F, out double FP, out double G, out double GP)
        {
            if (rho == 0.0)
            {
                double C = CoulombFactorZero(eta);
                F  = 0.0;
                FP = C;
                G  = 1.0 / C;
                GP = Double.NegativeInfinity;
                return;
            }

            double eta_rho = eta * rho;
            double rho_2   = rho * rho;

            double u0 = 0.0;
            double u1 = rho;
            double u  = u0 + u1;
            double up = u1;

            double v0 = 1.0;
            double v1 = 0.0;
            double v  = v0 + v1;

            for (int n = 2; n <= Global.SeriesMax; n++)
            {
                double u2 = (2.0 * eta_rho * u1 - rho_2 * u0) / (n * (n - 1));
                double v2 = (2.0 * eta_rho * v1 - rho_2 * v0 - 2.0 * eta * (2 * n - 1) * u2) / (n * (n - 1));

                double u_old = u;
                u  += u2;
                up += n * u2;

                double v_old = v;
                v += v2;

                if ((u == u_old) && (v == v_old))
                {
                    double C = CoulombFactorZero(eta);
                    F = C * u;

                    FP = C * up / rho;

                    double r = AdvancedComplexMath.Psi(new Complex(1.0, eta)).Re + 2.0 * AdvancedMath.EulerGamma - 1.0;
                    G = (v + 2.0 * eta * u * (Math.Log(2.0 * rho) + r)) / C;

                    GP = (FP * G - 1.0) / F;

                    return;
                }

                u0 = u1; u1 = u2; v0 = v1; v1 = v2;
            }

            throw new NonconvergenceException();
        }
Ejemplo n.º 2
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;
        }
        /// <summary>
        /// Computes the Riemann zeta function for complex values.
        /// </summary>
        /// <param name="z">The argument.</param>
        /// <returns>The value of &#x3B6;(z).</returns>
        /// <remarks>
        /// <para>As the imaginary part of the argument increases, the computation of the zeta function becomes slower and more difficult.
        /// The computation time is approximately proprotional to the imaginary part of z. The result also slowly looses accuracy for arguments with
        /// very large imaginary parts; for arguments with z.Im of order 10^d, approximately the last d digits of the result are suspect.</para>
        /// <para>The image below shows the complex &#x393; function near the origin using domain coloring. You can see the first non-trivial
        /// zeros at (1/2, &#177;14.13...) as well as the trivial zeros along the negative real axis.</para>
        /// <img src="../images/ComplexRiemannZetaPlot.png" />
        /// </remarks>
        public static Complex RiemannZeta(Complex z)
        {
            // Use conjugation and reflection symmetry to move to the first quadrant.
            if (z.Im < 0.0)
            {
                return(RiemannZeta(z.Conjugate).Conjugate);
            }
            if (z.Re < 0.0)
            {
                Complex zp = Complex.One - z;
                return(2.0 * ComplexMath.Pow(Global.TwoPI, -zp) * ComplexMath.Cos(Global.HalfPI * zp) * AdvancedComplexMath.Gamma(zp) * RiemannZeta(zp));
            }

            // Close to pole, use Laurent series.
            Complex zm1 = z - Complex.One;

            if (ComplexMath.Abs(zm1) < 0.50)
            {
                return(RiemannZeta_LaurentSeries(zm1));
            }

            // Fall back to Euler-Maclaurin summation.
            int n = RiemannZeta_EulerMaclaurin_N(z.Re, z.Im);

            return(RiemannZeta_EulerMaclaurin(z, n));
        }
        // 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();
        }
Ejemplo n.º 5
0
        // 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();
        }