Ejemplo n.º 1
0
        // Elliptic integrals (complete and incomplete) of the second kind
        // Carlson, Numerische Mathematik, vol 33, 1 (1979)


        /// <summary>
        /// Returns the incomplete elliptic integral of the second kind E(φ, k)
        /// <para>E(φ, k) =  ∫ sqrt(1-k^2*sin^2(θ)) dθ, θ={0,φ}</para>
        /// </summary>
        /// <param name="k">The modulus. Requires |k| ≤ 1</param>
        /// <param name="phi">The amplitude</param>
        public static double EllintE(double k, double phi)
        {
            if ((!(k >= -1 && k <= 1)) || (double.IsNaN(phi)))
            {
                Policies.ReportDomainError("EllintE(k: {0}, phi: {1}): Requires |k| <= 1; phi not NaN", k, phi);
                return(double.NaN);
            }
            if (double.IsInfinity(phi))
            {
                return(phi);
            }

            if (Math.Abs(phi) > Trig.PiReductionLimit)
            {
                Policies.ReportNotImplementedError("EllintE(k: {0}, phi: {1}): |phi| > {2} not implemented", k, phi, Trig.PiReductionLimit);
                return(double.NaN);
            }

            // special values
            if (k == 0)
            {
                return(phi);
            }
            if (phi == 0)
            {
                return(0);
            }
            if (phi == Math.PI / 2)
            {
                return(Math2.EllintE(k));
            }

            // Carlson's algorithm works only for |phi| <= π/2,
            // use the integrand's periodicity to normalize phi
            // E(k, phi + π*mult) = E(k, phi) + 2*mult*E(k)

            double result = 0;
            double rphi   = Math.Abs(phi);

            if (rphi > Math.PI / 2)
            {
                // Normalize periodicity so that |rphi| <= π/2
                var(angleMultiple, angleRemainder) = Trig.RangeReducePI(rphi);
                double mult = 2 * angleMultiple;
                rphi = angleRemainder;
                if (mult != 0)
                {
                    result += mult * EllintE(k);
                }
            }

            if (k == 1)
            {
                result += Math.Sin(rphi);
            }
            else
            {
                double k2   = k * k;
                double sinp = Math.Sin(rphi);
                double cosp = Math.Cos(rphi);
                double x    = cosp * cosp;
                double t    = k2 * sinp * sinp;
                double y    = (t < 0.875) ? 1 - t : (1 - k2) + k2 * x;
                double z    = 1;

                result += sinp * (Math2.EllintRF(x, y, z) - t * Math2.EllintRD(x, y, z) / 3);
            }

            return((phi < 0) ? -result : result);
        }
Ejemplo n.º 2
0
        // Elliptic integrals (complete and incomplete) of the third kind
        // Carlson, Numerische Mathematik, vol 33, 1 (1979)

        public static double Imp(double k, double n, double nc)
        {
            // Note arg nc = 1-n, possibly without cancellation errors

            Debug.Assert(k >= -1 && k <= 1, "Requires |k| <= 1: k = " + k);

            // special values
            // See: http://dlmf.nist.gov/19.6.E3

            if (n == 0)
            {
                if (k == 0)
                {
                    return(Math.PI / 2);
                }
                return(Math2.EllintK(k));
            }

            // special values
            // See: http://functions.wolfram.com/EllipticIntegrals/EllipticPi/03/01/01/

            if (k == 0)
            {
                return((Math.PI / 2) / Math.Sqrt(nc));
            }

            if (k == 1)
            {
                return(double.NegativeInfinity / Math.Sign(n - 1));
            }

            if (n < 0)
            {
                // when the magnitude of n gets very large, N below becomes ~= 1, so
                // there can be some error, so use the series at n=Infinity
                // http://functions.wolfram.com/EllipticIntegrals/EllipticPi/06/01/05/
                if (n < -1 / DoubleLimits.MachineEpsilon)
                {
                    return((Math.PI / 2) / Math.Sqrt(-n) + (Math2.EllintE(k) - Math2.EllintK(k)) / n);
                }

                // A&S 17.7.17:
                // shift to k^2 < N < 1

                double k2 = k * k;
                double N  = (k2 - n) / nc;
                double Nc = (1 - k2) / nc; // Nc = 1-N

                double result = k2 / (k2 - n) * Math2.EllintK(k);
                result -= (n / nc) * ((1 - k2) / (k2 - n)) * _EllintPi.Imp(k, N, Nc);
                return(result);
            }

            double x = 0;
            double y = 1 - k * k;
            double z = 1;
            double p = nc;

            double value = Math2.EllintK(k) + n * Math2.EllintRJ(x, y, z, p) / 3;

            return(value);
        }