Example #1
0
        // ( 3/2  J2  J3 )
        // ( M1   M2  M3 )
        private static double ThreeJ_ThreeHalvesJ(SpinState s1, SpinState s2, SpinState s3)
        {
            Debug.Assert(s1.TwoJ == 3);

            if (s1.TwoM < 0)
            {
                // m1 is negative; invert the m's
                double r = ThreeJ_ThreeHalvesJ(s1.Invert(), s2.Invert(), s3.Invert());
                // fix sign!
                return(r);
            }
            else if (s1.TwoM == 1)
            {
                // m1 = 1/2
                if (s3.TwoJ == (s2.TwoJ + 1))
                {
                    // j3 = j2 + 1/2
                    double r = (s2.JMinusM - s2.TwoM) * Math.Sqrt(1.0 * (s2.JPlusM + 1) / s2.TwoJ / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3));
                    if (s2.JMinusM % 2 != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
                else
                {
                    // j3 = j2 + 3/2
                    double r = Math.Sqrt(3.0 * (s2.JPlusM + 1) * (s2.JPlusM + 2) * (s2.JMinusM + 1) / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3) / (s2.TwoJ + 4));
                    if (s2.JMinusM % 2 != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
            }
            else
            {
                // m1 = 3/2
                if (s3.TwoJ == (s2.TwoJ + 1))
                {
                    // j3 = j2 + 1/2
                    double r = -Math.Sqrt(3.0 * (s2.JPlusM + 1) * (s2.JPlusM + 2) * (s2.JMinusM) / s2.TwoJ / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3));
                    if (s2.JMinusM % 2 != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
                else
                {
                    // j3 = j2 + 3/2
                    double r = -Math.Sqrt(1.0 * (s2.JPlusM + 1) * (s2.JPlusM + 2) * (s2.JPlusM + 3) / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3) / (s2.TwoJ + 4));
                    if (s2.JMinusM % 2 != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
            }
        }
Example #2
0
        // ( 1/2  J2   J+1/2 )
        // ( M1   M2  -M1-M2 )
        private static double ThreeJ_HalfJ(SpinState s1, SpinState s2)
        {
            Debug.Assert(s1.TwoJ == 1);

            if (s1.TwoM < 0)
            {
                // m1 = -1/2
                // invert to turn into m1 = +1/2 case
                double r = ThreeJ_HalfJ(s1.Invert(), s2.Invert());
                if (s2.TwoJ % 2 == 0)
                {
                    r = -r;
                }
                return(r);
            }
            else
            {
                // m1 = +1/2
                double r = -Math.Sqrt((s2.JPlusM + 1.0) / (s2.TwoJ + 1.0) / (s2.TwoJ + 2.0));
                if (s2.JMinusM % 2 != 0)
                {
                    r = -r;
                }
                return(r);
            }
        }
Example #3
0
        // ( J1  J2  J3 )
        // ( 0   0   0  )
        private static double ThreeJ_ZeroM_Int(SpinState s1, SpinState s2, SpinState s3)
        {
            Debug.Assert(s1.TwoM == 0);
            Debug.Assert(s2.TwoM == 0);
            Debug.Assert(s3.TwoM == 0);

            // this method depends on the ordering j1 <= j2 <= j3
            Debug.Assert(s1.TwoJ <= s2.TwoJ);
            Debug.Assert(s2.TwoJ <= s3.TwoJ);

            int j = (s1.TwoJ + s2.TwoJ + s3.TwoJ) / 2;

            if (j % 2 != 0)
            {
                return(0.0);
            }
            else
            {
                // use the method formula derived in

                int A = j - s1.TwoJ;
                int B = j - s2.TwoJ;
                int C = j - s3.TwoJ;

                // note that A >= B >= C, because of the ordering of js; therefore we eliminate factors involving C, which are largest
                // note also that A, B, and C are even, because j is even and we subtract even numbers from j to get them

                int hA = A / 2;
                int hB = B / 2;
                int hC = C / 2;

                // calculate first factor
                double f   = 1.0 / (j + 1);
                int    fp1 = B / 2;
                int    fp2 = A / 2;
                int    fq1 = A;
                int    fq2 = A + B / 2;
                for (int i = 1; i <= hB; i++)
                {
                    f = f * (hB + i) * (hA + i) * (hA + i) / (A + i) / (A + hB + i) / i;
                }
                f = Math.Sqrt(f);

                // calculate second factor
                double g = 1.0;
                for (int i = 1; i <= hC; i++)
                {
                    g = g * (hC + i) * (hA + hB + i) * (hA + hB + i) / (A + B + i) / (A + B + hC + i) / i;
                }
                g = Math.Sqrt(g);

                if ((j / 2) % 2 != 0)
                {
                    f = -f;
                }

                return(f * g);
            }
        }
Example #4
0
        // ( 0  J   J )
        // ( 0  M  -M )
        private static double ThreeJ_ZeroJ(SpinState s)
        {
            double r = 1.0 / Math.Sqrt(s.TwoJ + 1);

            if (s.JMinusM % 2 != 0)
            {
                r = -r;
            }
            return(r);
        }
Example #5
0
        // ( J1 J2 M1 M2 | J M ) =
        // (-1)^{J1-J2+M} * Sqrt(2J+1) *
        // ( J1  J2   J )
        // ( M1  M1  -M )

        /// <summary>
        /// Computes a Clebsch-Gordon coefficient.
        /// </summary>
        /// <param name="s1">The first spin state.</param>
        /// <param name="s2">The second spin state.</param>
        /// <param name="s">The total spin state.</param>
        /// <returns>The Clebsch-Gordon coefficient measuring the contribution of the given first and
        /// second spin states to the given total spin state.</returns>
        public static double ClebschGodron(SpinState s1, SpinState s2, SpinState s)
        {
            double f = Math.Sqrt(s.TwoJ + 1);

            if (s1.JPlusM % 2 != 0)
            {
                f = -f;
            }
            if (s2.JMinusM % 2 != 0)
            {
                f = -f;
            }
            return(f * ThreeJ(s1, s2, s.Invert()));
        }
Example #6
0
        // ( 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);
        }
Example #7
0
        /// <summary>
        /// Enumerates all spin states that may be obtained by combining two spin states.
        /// </summary>
        /// <param name="s1">The first spin state.</param>
        /// <param name="s2">The second spin state.</param>
        /// <returns>A list of spin states which may  be obtained.</returns>
        public static SpinState[] Combine(SpinState s1, SpinState s2)
        {
            int tj_max = s1.TwoJ + s2.TwoJ;
            int tj_min = Math.Abs(s1.TwoJ - s2.TwoJ);
            int tm     = s1.TwoM + s2.TwoM;

            if (Math.Abs(tm) > tj_min)
            {
                tj_min = Math.Abs(tm);
            }

            SpinState[] states = new SpinState[(tj_max - tj_min) / 2 + 1];
            for (int i = 0; i < states.Length; i++)
            {
                states[i] = new SpinState((tj_min + 2 * i) / 2.0, tm / 2.0);
            }

            return(states);
        }
Example #8
0
        private static double ThreeJ_ZeroHalfM(SpinState s1, SpinState s2, SpinState s3)
        {
            Debug.Assert(s1.TwoM == 0);
            Debug.Assert(Math.Abs(s2.TwoM) == 0);

            int j = (s1.TwoJ + s2.TwoJ + s3.TwoJ) / 2;

            // if m2 < 0 invert and re-call

            if (j % 2 == 0)
            {
                double f = -Math.Sqrt(1.0 * (s1.TwoJ - s2.TwoJ + s3.TwoJ + 2) * (s1.TwoJ + s2.TwoJ - s3.TwoJ) / (s2.TwoJ + 1) / (s3.TwoJ + 1)) / 2.0;
                double g = ThreeJ_ZeroM(new SpinState(s1.TwoJ / 2.0, 0.0), new SpinState((s2.TwoJ - 1) / 2.0, 0.0), new SpinState((s3.TwoJ + 1) / 2.0, 0.0));
                return(f * g);
            }
            else
            {
                double f = Math.Sqrt(1.0 * (j + 2) / (s2.TwoJ + 1) / (s3.TwoJ + 1)) / 2.0;
                throw new NotImplementedException();
            }
        }
Example #9
0
        // ( 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);
                }
            }
        }
Example #10
0
 public void SpinStateInvalid1()
 {
     // spin state indices are smaller than spin indices
     SpinState s = new SpinState(1.0, -2.0);
 }
Example #11
0
        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);
        }
Example #12
0
 public void SpinStateInvalid2()
 {
     // spin states indices match the parity of spin indices
     SpinState s = new SpinState(1.0, 0.5);
 }
Example #13
0
        public void SixJThreeJRelation()
        {
            SixJSymbol[] symbols = GenerateRandomSixJSymbols(50.0, 5);
            foreach (SixJSymbol symbol in symbols) {

                Spin a = symbol.J1;
                Spin b = symbol.J2;
                Spin c = symbol.J3;
                Spin d = symbol.J4;
                Spin e = symbol.J5;
                Spin f = symbol.J6;

                SpinState[] ams = GenerateRandomSpinStates(a, 2);
                SpinState[] bms = GenerateRandomSpinStates(b, 2);
                foreach (SpinState am in ams) {
                    foreach (SpinState bm in bms) {

                        if (Math.Abs(am.M + bm.M) > c.J) continue;
                        SpinState cm = new SpinState(c, -(am.M + bm.M));

                        double g1 = SpinMath.ThreeJ(am, bm, cm);
                        double g2 = SpinMath.SixJ(a, b, c, d, e, f);
                        double p = g1 * g2;

                        double q = 0.0;
                        List<double> ts = new List<double>();
                        SpinState[] dms = d.States();
                        foreach (SpinState dm in dms) {

                            if (Math.Abs(dm.M + cm.M) > e.J) continue;
                            SpinState em = new SpinState(e, dm.M + cm.M);
                            SpinState mem = new SpinState(e, -em.M);
                            double f1 = SpinMath.ThreeJ(dm, mem, cm);

                            if (Math.Abs(em.M + am.M) > f.J) continue;
                            SpinState fm = new SpinState(f, em.M + am.M);
                            SpinState mfm = new SpinState(f, -fm.M);
                            double f2 = SpinMath.ThreeJ(em, mfm, am);

                            SpinState mdm = new SpinState(d, -dm.M);
                            double f3 = SpinMath.ThreeJ(fm, mdm, bm);

                            double t = f1 * f2 * f3;

                            int s = (int) Math.Round(dm.J + dm.M + em.J + em.M + fm.J + fm.M);
                            if (s % 2 != 0) t = -t;

                            q += t;
                            ts.Add(t);

                        }

                        Console.WriteLine("{0} v. {1}", p, q);
                        //Assert.IsTrue(TestUtilities.IsNearlyEqual(p, q));
                        Assert.IsTrue(TestUtilities.IsSumNearlyEqual(ts, p));
                    }
                }

            }
        }
Example #14
0
        // equality

        private static bool Equals(SpinState s1, SpinState s2)
        {
            return((s1.spin == s2.spin) && (s1.twoM == s2.twoM));
        }
Example #15
0
 // equality
 private static bool Equals(SpinState s1, SpinState s2)
 {
     return ((s1.spin == s2.spin) && (s1.twoM == s2.twoM));
 }
Example #16
0
        private static SpinState[] GenerateRandomSpinStates(Spin j, int n)
        {
            int tj = (int) (2.0 * j.J);

            SpinState[] result = new SpinState[n];
            Random rng = new Random(1);
            for (int i = 0; i < n; i++) {

                int tm = -tj + 2 * rng.Next(tj + 1);
                result[i] = new SpinState(j, tm / 2.0);

            }

            return (result);
        }
Example #17
0
        public void ThreeJRacahSymmetry()
        {
            foreach (ThreeJSymbol symbol in GenerateRandomThreeJSymbols(50.0, 10)) {

                // compute the 3j symbol
                SpinState s1 = symbol.Column1;
                SpinState s2 = symbol.Column2;
                SpinState s3 = symbol.Column3;
                double C = SpinMath.ThreeJ(s1, s2, s3);

                // form other 3j symbols related by Racah symmetry

                double k1, k2, k3, n1, n2, n3;
                SpinState t1, t2, t3;

                // rows 1->2->3

                k1 = (s2.J + s2.M + s3.J + s3.M) / 2.0;
                k2 = (s1.J + s1.M + s3.J + s3.M) / 2.0;
                k3 = (s1.J + s1.M + s2.J + s2.M) / 2.0;
                n1 = s1.J - s1.M - k1;
                n2 = s2.J - s2.M - k2;
                n3 = s3.J - s3.M - k3;

                t1 = new SpinState(k1, n1);
                t2 = new SpinState(k2, n2);
                t3 = new SpinState(k3, n3);
                double CC = SpinMath.ThreeJ(t1, t2, t3);

                Assert.IsTrue(TestUtilities.IsNearlyEqual(C, CC));

                // transpose rows and columns

                /*
                k1 = s1.J;
                k2 = (s2.J + s3.J + s1.M) / 2.0;
                k3 = (s2.J + s3.J - s1.M) / 2.0;
                n1 = s2.J - s3.J;
                n2 = s3.J - s3.M - k2;
                n3 = s3.J + s3.M - k2;

                t1 = new SpinState(k1, n1);
                t2 = new SpinState(k2, n2);
                t3 = new SpinState(k3, n3);
                double CT = SpinMath.ThreeJ(t1, t2, t3);

                Assert.IsTrue(TestUtilities.IsNearlyEqual(C, CT));
                */

            }
        }
Example #18
0
 public void SpinStateInvalid3()
 {
     // spin state values are integer or half-integer
     SpinState s = new SpinState(3.0, 0.75);
 }
Example #19
0
        // method described by Shulten & Gordon in J. Math. Phys. 16 (1975) 1961
        // uses the recurrsion
        //  j3 A_(j3+1) ( j1 j2 j3+1 ) + B_j3 ( j1 j2 j3 ) + (j3+1) A_j3 ( j1 j2 j3-1 )
        //              ( m1 m2  m3  )        ( m1 m2 m3 )               ( m1 m2  m3  )
        // plus the normalization condition
        // \sum_j3 (2 j3 + 1) ( j1 j2 j3 )^2 = 1
        //                    ( m1 m2 m3 )

        // we recurse on j3 because, for j1 <= j2 <= j3, the typical number of recursion steps
        // will be 2 * j1, the lowest of the three possible spins to recurse on

        private static double ThreeJ_ShultenGordon_RecurseJ(SpinState s1, SpinState s2, SpinState s3)
        {
            // find the range of j
            int tj_min = Math.Abs(s1.TwoJ - s2.TwoJ);

            if (tj_min < Math.Abs(s3.TwoM))
            {
                tj_min = Math.Abs(s3.TwoM);
            }
            int tj_max = s1.TwoJ + s2.TwoJ;

            // find the midpoint of the range
            int tj_mid = (tj_min + tj_max) / 2;

            if ((tj_mid % 2) != (tj_max % 2))
            {
                tj_mid++;
            }

            // variables to store recurrence coefficients and (unscaled) 3j values
            double ap, a0, b0;
            double cm, c0, cp;
            int    tj;

            // a variable to store the sought value
            double c = 0.0;

            // iterate in from the right
            double NR = 0.0;

            cp = 0.0;
            ap = 0.0;
            c0 = 0.5 / tj_max;
            if (((s1.TwoJ - s2.TwoJ - s3.TwoM) / 2) % 2 != 0)
            {
                c0 = -c0;                                               // sign convention
            }
            tj = tj_max;
            while (true)
            {
                // keep track of the normalization constant
                NR += (tj + 1) * c0 * c0;

                // remember the (unscaled) value of the desired 3j symbol
                if (tj == s3.TwoJ)
                {
                    c = c0;
                }

                // check whether we have reached the center
                if (tj <= tj_mid)
                {
                    if (Math.Abs(c0) <= Math.Pow(2.0, -40.0) * Math.Abs(cp))
                    {
                        // if the middle value is zero, the left and right values cannot be matached
                        // (acutally, the numbers will be two random tiny numbers, and their ratio will
                        // be a random number of order one); in this case, go down one more step
                        tj_mid -= 2;
                    }
                    else
                    {
                        break;
                    }
                }

                // compute required coefficients
                b0 = ShultenGodron_B(s1.TwoJ, s2.TwoJ, tj, s1.TwoM, s2.TwoM, s3.TwoM);
                a0 = ShultenGordon_A(s1.TwoJ, s2.TwoJ, tj, s3.TwoM);

                // use recursion to compute the tj-2 symbol
                cm = (-b0 * c0 - (tj / 2.0) * ap * cp) / ((tj + 2) / 2.0) / a0;

                // prepare for the next cycle
                cp  = c0;
                c0  = cm;
                ap  = a0;
                tj -= 2;
            }

            // remember the (unscaled) middle value
            double c1 = c0;

            // iterate in from the left
            double NL = 0.0;

            cm = 0.0;
            a0 = 0.0;
            c0 = 0.5 / tj_max;
            tj = tj_min;

            // j_min = 0 iff j1 = j2 and m3 = 0
            // in this case for j3=0, b0 = 0 and all three coefficients vanish, so the recursion is indeterminate
            // in this case we do the first recursion step "by hand" using relationships

            if (tj == 0)
            {
                NL += c0 * c0;
                cm  = c0;
                c0  = s1.TwoM / Math.Sqrt(s1.TwoJ * (s1.TwoJ + 2)) * cm;
                a0  = ShultenGordon_A(s1.TwoJ, s2.TwoJ, 2, 0);
                tj  = 2;
            }

            while (true)
            {
                // check whether we have reached the center
                if (tj >= tj_mid)
                {
                    break;
                }

                // notice that we terminate before checking whether we are at the desired value,
                // or adding to the normalization constant; this is different from the previous loop
                // we do this so that the middle element does not double contribute to the normalization
                // and because if the middle element is desired, it has already been stored from the previous loop

                // remember the desired (unscaled) value
                if (tj == s3.TwoJ)
                {
                    c = c0;
                }

                // add current value to normalization
                NL += (tj + 1) * c0 * c0;

                // check for end
                if (tj >= tj_max)
                {
                    break;
                }

                // compute required coeficients
                b0 = ShultenGodron_B(s1.TwoJ, s2.TwoJ, tj, s1.TwoM, s2.TwoM, s3.TwoM);
                ap = ShultenGordon_A(s1.TwoJ, s2.TwoJ, tj + 2, s3.TwoM);

                // use recursion relation to compute tj+2
                cp = (-b0 * c0 - ((tj + 2) / 2.0) * a0 * cm) / (tj / 2.0) / ap;

                // prepare for next iteration
                cm  = c0;
                c0  = cp;
                a0  = ap;
                tj += 2;
            }

            // match in the middle
            double r = c0 / c1;

            NL = NL / (r * r);
            if (s3.TwoJ < tj_mid)
            {
                c = c / r;
            }

            // normalize
            double N = NL + NR;

            c = c / Math.Sqrt(N);

            return(c);
        }
Example #20
0
        // ( 1   J2  J3 )
        // ( M1  M2  M3 )
        private static double ThreeJ_OneJ(SpinState s1, SpinState s2, SpinState s3)
        {
            Debug.Assert(s1.TwoJ == 2);

            if (s1.TwoM < 0)
            {
                // m1 = -1
                double r = ThreeJ_OneJ(s1.Invert(), s2.Invert(), s3.Invert());
                if ((s1.TwoJ + s2.TwoJ + s3.TwoJ) / 2 % 2 != 0)
                {
                    r = -r;
                }
                return(r);
            }
            else if (s1.TwoM == 0)
            {
                // m1 = 0
                if (s3.TwoJ == s2.TwoJ)
                {
                    // j3 = j2
                    double r = s2.TwoM / Math.Sqrt(s2.TwoJ * (s2.TwoJ + 1) * (s2.TwoJ + 2));
                    if ((s2.JMinusM % 2) != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
                else
                {
                    // j3 = j2 + 1
                    double r = -Math.Sqrt(2.0 * (s2.JPlusM + 1) * (s2.JMinusM + 1) / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3));
                    if ((s2.JMinusM % 2) != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
            }
            else
            {
                // m1 = 1
                if (s3.TwoJ == s2.TwoJ)
                {
                    // j3 = j2
                    double r = Math.Sqrt(2.0 * s2.JMinusM * (s2.JPlusM + 1) / s2.TwoJ / (s2.TwoJ + 1) / (s2.TwoJ + 2));
                    if ((s2.JMinusM % 2) != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
                else
                {
                    // j3 = j2 + 1
                    double r = Math.Sqrt(1.0 * (s2.JPlusM + 1) * (s2.JPlusM + 2) / (s2.TwoJ + 1) / (s2.TwoJ + 2) / (s2.TwoJ + 3));
                    if ((s2.JMinusM % 2) != 0)
                    {
                        r = -r;
                    }
                    return(r);
                }
            }
        }
Example #21
0
        /// <summary>
        /// Computes a 3j symbol.
        /// </summary>
        /// <param name="s1">The first column spin state.</param>
        /// <param name="s2">The second column spin state.</param>
        /// <param name="s3">The third column spin state.</param>
        /// <returns>The 3j symbol.</returns>
        public static double ThreeJ(SpinState s1, SpinState s2, SpinState s3)
        {
            // require that Js satisfy triangle inequality
            if (s3.TwoJ < Math.Abs(s1.TwoJ - s2.TwoJ))
            {
                return(0.0);
            }
            if (s3.TwoJ > (s1.TwoJ + s2.TwoJ))
            {
                return(0.0);
            }

            // require that the parity of the spins agree
            // for example, spin-1 and spin-2 cannot combine to spin 3/2, even though 1 < 3/2 < 3
            if ((s1.TwoJ + s2.TwoJ + s3.TwoJ) % 2 != 0)
            {
                return(0.0);
            }

            // require that Ms add to zero
            if ((s1.TwoM + s2.TwoM + s3.TwoM) != 0)
            {
                return(0.0);
            }

            // determine permutation factor for row switching or inverting
            int P;

            if (((s1.TwoJ + s2.TwoJ + s3.TwoJ) / 2) % 2 == 0)
            {
                P = 1;
            }
            else
            {
                P = -1;
            }

            // shuffle so J1 <= J2 <= J3
            // keeping track of the sign induced by the permutation
            int s = 1;

            if (s1.TwoJ > s3.TwoJ)
            {
                Swap(ref s1, ref s3);
                s = s * P;
            }
            if (s1.TwoJ > s2.TwoJ)
            {
                Swap(ref s1, ref s2);
                s = s * P;
            }
            if (s2.TwoJ > s3.TwoJ)
            {
                Swap(ref s2, ref s3);
                s = s * P;
            }

            // now we can test for special cases,
            // knowing where the Js will fall in each case

            if (s1.TwoJ == 0)
            {
                // J1 = 0
                return(s * ThreeJ_ZeroJ(s2));
            }
            else if (s1.TwoJ == 1)
            {
                // J1 = 1/2
                return(s * ThreeJ_HalfJ(s1, s2));
            }
            else if (s1.TwoJ == 2)
            {
                // J1 = 1
                return(s * ThreeJ_OneJ(s1, s2, s3));
            }
            else
            {
                // arbitrary Js
                if ((s1.TwoM == 0) && (s2.TwoM == 0) && (s3.TwoM == 0))
                {
                    // special case of all M's zero
                    return(s * ThreeJ_ZeroM_Int(s1, s2, s3));
                }
                else
                {
                    // general case
                    return(s * ThreeJ_ShultenGordon_RecurseJ(s1, s2, s3));
                }
            }

            // other possible special cases include:
            // J1 = 3/2, J1 = 2
            // Ms = 1/2 -1/2 0, 1/2 1/2 1, 1 -1 0 and permutations
            // maximum coupling J3 = J1 + J2, minimum coupling J3 = |J1 - J2|
        }
Example #22
0
        // generates only spinors of the same parity as j_min
        private static SpinState[] GenerateRandomSpinStates(double j_min, double j_max, int n)
        {
            int tj_min = (int) Math.Truncate(2.0 * j_min);
            int tj_max = (int) Math.Truncate(2.0 * j_max);

            SpinState[] states = new SpinState[n];
            Random rng = new Random(1);
            for (int i = 0; i < n; i++) {
                int tj = tj_min + 2 * rng.Next((tj_max - tj_min) / 2);
                int tm = -tj + 2 * rng.Next(tj);
                states[i] = new SpinState(tj / 2.0, tm / 2.0);
            }

            return (states);
        }