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

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

            // See: http://dlmf.nist.gov/19.6#iv
            if (phi == 0)
            {
                return(0);
            }
            if (phi == Math.PI / 2)
            {
                return(Math2.EllintPi(k, n));
            }

            if (n == 0)
            {
                if (k == 0)
                {
                    return(phi);
                }
                return(Math2.EllintF(k, phi));
            }


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


            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) && (nc > 0))
                {
                    result = mult * _EllintPi.Imp(k, n, nc);
                }
            }


            if (k == 0)
            {
                double ncr;

                // A&S 17.7.20:
                if (n < 1)
                {
                    if (nc == 1)
                    {
                        return(phi);
                    }
                    ncr     = Math.Sqrt(nc);
                    result += Math.Atan(ncr * Math.Tan(rphi)) / ncr;
                }
                else if (n == 1)
                {
                    result += Math.Tan(rphi);
                }
                else
                {
                    // n > 1:
                    ncr     = Math.Sqrt(-nc);
                    result += Math2.Atanh(ncr * Math.Tan(rphi)) / ncr;
                }

                return((phi < 0) ? -result : result);
            }


            double sphi = Math.Sin(Math.Abs(phi));

            if (n > 1 / (sphi * sphi))
            {
                // Complex result is a domain error:
                Policies.ReportDomainError("EllintPi(k: {0}, nu: {1}, phi: {2}): Complex results not supported. Requires n > 1 / sin^2(phi)", k, n, phi);
                return(double.NaN);
            }


            // Special cases first:

            if (n < 0)
            {
                //
                // If we don't shift to 0 <= n <= 1 we get
                // cancellation errors later on.  Use
                // A&S 17.7.15/16 to shift to n > 0:
                //
                double k2 = k * k;
                double N  = (k2 - n) / nc;
                double Nc = (1 - k2) / nc; // Nc = 1-N = (1-k^2)/nc

                // check to see if a rounding error occurred
                //  k^2 <= N <= 1
                if (N < k2)
                {
#if EXTRA_DEBUG
                    Debug.WriteLine("Rounding error: EllintPi(k: {0} , nu: {1} , phi: {2})", k, n, phi);
#endif
                    N  = k2;
                    Nc = 1 - N;
                }

                double p2    = Math.Sqrt(-n * N);
                double delta = Math.Sqrt(1 - k2 * sphi * sphi);


                // Reduce A&S 17.7.15/16
                // Mathematica eqns below
                // N is protected in Mathematica, so use V
                // V = (k2 - n)/(1 - n)
                // Assuming[(k2 >= 0 && k2 <= 1) && n < 0,  FullSimplify[Sqrt[(1 - V)*(1 - k2/V)]/Sqrt[((1 - n)*(1 - k2/n))]]]
                // Result: ((-1 + k2) n)/((-1 + n) (-k2 + n))

                // Assuming[(k2 >= 0 && k2 <= 1) && n < 0,  FullSimplify[k2/(Sqrt[-n*(k2 - n)/(1 - n)]*Sqrt[(1 - n)*(1 - k2/n)])]]
                // Result: k2/(k2 - n)

                // Assuming[(k2 >= 0 && k2 <= 1) && n < 0,  FullSimplify[Sqrt[1/((1 - n)*(1 - k2/n))]]]
                // Result: Sqrt[n/((k2 - n) (-1 + n))]

                double nResult = -(n / nc) * ((1 - k2) / (k2 - n)) * _EllintPi.Imp(k, N, Nc, rphi);
                nResult += k2 / (k2 - n) * Math2.EllintF(k, rphi);
                nResult += Math.Sqrt((n / nc) / (n - k2)) * Math.Atan((p2 / (2 * delta)) * Math.Sin(2 * rphi));

                result += nResult;

                return((phi < 0) ? -result : result);
            }


            double sinp = Math.Sin(rphi);
            double cosp = Math.Cos(rphi);
            double x    = cosp * cosp;
            double t    = sinp * sinp;
            double y    = 1 - k * k * t;
            double z    = 1;
            double p    = (n * t < 0.5) ? 1 - n * t : x + nc * t;

            result += sinp * (Math2.EllintRF(x, y, z) + n * t * Math2.EllintRJ(x, y, z, p) / 3);

            return((phi < 0) ? -result : result);
        }