// ( J1 J2 J1+J2 ) // ( M1 M2 -(M1+M2) ) private static double ThreeJ_MaxJ(SpinState j1, SpinState j2) { double r = AdvancedIntegerMath.LogFactorial(j1.TwoJ) + AdvancedIntegerMath.LogFactorial(j2.TwoJ) + AdvancedIntegerMath.LogFactorial(j1.JPlusM + j2.JPlusM) + AdvancedIntegerMath.LogFactorial(j1.JMinusM + j2.JMinusM) - AdvancedIntegerMath.LogFactorial(j1.TwoJ + j2.TwoJ + 1) - AdvancedIntegerMath.LogFactorial(j1.JPlusM) - AdvancedIntegerMath.LogFactorial(j1.JMinusM) - AdvancedIntegerMath.LogFactorial(j2.JPlusM) - AdvancedIntegerMath.LogFactorial(j2.JMinusM); r = Math.Exp(r / 2.0); return(r); }
// Legendre polynomials normalized for their use in the spherical harmonics /// <summary> /// Computes the value of an associated Legendre polynomial. /// </summary> /// <param name="l">The order, which must be non-negative.</param> /// <param name="m">The associated order, which must lie between -l and l inclusive.</param> /// <param name="x">The argument, which must lie on the closed interval between -1 and +1.</param> /// <returns>The value of P<sub>l,m</sub>(x).</returns> /// <remarks> /// <para>Associated Legendre polynomials appear in the definition of the <see cref="AdvancedMath.SphericalHarmonic"/> functions.</para> /// <para>For values of l and m over about 150, values of this polynomial can exceed the capacity of double-wide floating point numbers.</para> /// </remarks> /// <seealso href="http://en.wikipedia.org/wiki/Associated_Legendre_polynomials"/> public static double LegendreP(int l, int m, double x) { if (l < 0) { throw new ArgumentOutOfRangeException(nameof(l)); } //if (l < 0) { // return (LegendreP(-l + 1, m, x)); //} if (Math.Abs(m) > l) { throw new ArgumentOutOfRangeException(nameof(m)); } double f; if (l < 10) { // for low enough orders, we can can get the factorial quickly from a table look-up and without danger of overflow f = Math.Sqrt(AdvancedIntegerMath.Factorial(l + m) / AdvancedIntegerMath.Factorial(l - m)); } else { // for higher orders, we must move into log space to avoid overflow f = Math.Exp((AdvancedIntegerMath.LogFactorial(l + m) - AdvancedIntegerMath.LogFactorial(l - m)) / 2.0); } if (m < 0) { m = -m; if (m % 2 != 0) { f = -f; } } if (Math.Abs(x) > 1.0) { throw new ArgumentOutOfRangeException(nameof(x)); } return(f * LegendrePe(l, m, x)); }
// ( J1 J2 J3 ) // ( 0 0 0 ) private static double ThreeJ_ZeroM(SpinState s1, SpinState s2, SpinState s3) { Debug.Assert(s1.TwoM == 0); Debug.Assert(s2.TwoM == 0); Debug.Assert(s3.TwoM == 0); int j = (s1.TwoJ + s2.TwoJ + s3.TwoJ) / 2; if (j % 2 != 0) { // zero by symmetry return(0.0); } else { double f = -AdvancedIntegerMath.LogFactorial(j + 1) + AdvancedIntegerMath.LogFactorial(j - s1.TwoJ) + AdvancedIntegerMath.LogFactorial(j - s2.TwoJ) + AdvancedIntegerMath.LogFactorial(j - s3.TwoJ); f = Math.Exp(f / 2.0); int k = j / 2; double g = AdvancedIntegerMath.LogFactorial(k) - AdvancedIntegerMath.LogFactorial(k - s1.TwoJ / 2) - AdvancedIntegerMath.LogFactorial(k - s2.TwoJ / 2) - AdvancedIntegerMath.LogFactorial(k - s3.TwoJ / 2); g = Math.Exp(g); if (k % 2 != 0) { return(-f * g); } else { return(f * g); } } }
private static double ThreeJ_Any(SpinState j1, SpinState j2, SpinState j3) { // compute prefactor double f1 = 0.0 + AdvancedIntegerMath.LogFactorial((j1.TwoJ + j2.TwoJ - j3.TwoJ) / 2) + AdvancedIntegerMath.LogFactorial((j1.TwoJ - j2.TwoJ + j3.TwoJ) / 2) + AdvancedIntegerMath.LogFactorial((-j1.TwoJ + j2.TwoJ + j3.TwoJ) / 2) - AdvancedIntegerMath.LogFactorial((j1.TwoJ + j2.TwoJ + j3.TwoJ) / 2 + 1); double f2 = 0.0 + AdvancedIntegerMath.LogFactorial(j1.JPlusM) + AdvancedIntegerMath.LogFactorial(j1.JMinusM) + AdvancedIntegerMath.LogFactorial(j2.JPlusM) + AdvancedIntegerMath.LogFactorial(j2.JMinusM) + AdvancedIntegerMath.LogFactorial(j3.JPlusM) + AdvancedIntegerMath.LogFactorial(j3.JMinusM); double f = Math.Exp((f1 + f2) / 2.0); if ((j1.JPlusM - j2.JMinusM) % 2 != 0) { f = -f; } Console.WriteLine("f={0}", f); // determine maximum and minimum values of k in sum int kmin = 0; int k23 = j2.JPlusM - j3.JMinusM; if (kmin < k23) { kmin = k23; } int k13 = j1.JMinusM - j3.JPlusM; if (kmin < k13) { kmin = k13; } int k123 = (j1.TwoJ + j2.TwoJ - j3.TwoJ) / 2; int kmax = k123; int k1 = j1.JMinusM; if (k1 < kmax) { kmax = k1; } int k2 = j2.JPlusM; if (k2 < kmax) { kmax = k2; } Console.WriteLine("{0} <= k <= {1}", kmin, kmax); Debug.Assert(kmin <= kmax); // compute the sum double g = 0.0; for (int k = kmin; k <= kmax; k++) { double gt = AdvancedIntegerMath.LogFactorial(k) + AdvancedIntegerMath.LogFactorial(k123 - k) + AdvancedIntegerMath.LogFactorial(k1 - k) + AdvancedIntegerMath.LogFactorial(k2 - k) + AdvancedIntegerMath.LogFactorial(k - k13) + AdvancedIntegerMath.LogFactorial(k - k23); gt = Math.Exp(-gt); if (k % 2 != 0) { gt = -gt; } g += gt; } Console.WriteLine("g={0}", g); return(f * g); }