/// <summary> /// Instantiates a new SpinState with the given spin and magnetic quantum number. /// </summary> /// <param name="s">The spin.</param> /// <param name="m">The magnetic quantum number.</param> public SpinState(Spin s, double m) { spin = s; // 2M must be an integer double tm = 2.0 * m; double tmt = Math.Floor(tm); if (tmt != tm) { throw new ArgumentOutOfRangeException("m"); } int tmti = (int)tmt; twoM = (int)tmt; // -J <= M <= J if (Math.Abs(tmti) > s.TwoJ) { throw new ArgumentOutOfRangeException("m"); } // half-integer J requires half-integer M; integer J requires integer M if ((s.TwoJ % 2) != Math.Abs(twoM % 2)) { throw new ArgumentOutOfRangeException("m"); } }
// j1 j2 j3 // j2 j1 0 private static double SixJ_Zero(Spin j1, Spin j2, Spin j3) { double f = 1.0 / Math.Sqrt((j1.TwoJ + 1) * (j2.TwoJ + 1)); if ((j1.TwoJ + j2.TwoJ + j3.TwoJ) / 2 % 2 != 0) { f = -f; } return(f); }
// SixJ /// <summary> /// Computes the value of the 6j symbol for the six given spins. /// </summary> /// <param name="j1">Upper left spin.</param> /// <param name="j2">Upper middle spin.</param> /// <param name="j3">Upper right spin.</param> /// <param name="j4">Lower left spin.</param> /// <param name="j5">Lower middle spin.</param> /// <param name="j6">Lower right spin.</param> /// <returns>The value of {{j1,j2,j3},{j4,j5,j6}}.</returns> public static double SixJ(Spin j1, Spin j2, Spin j3, Spin j4, Spin j5, Spin j6) { // check for required triangle relations bool t = (Triangle(j1, j2, j3) && Triangle(j1, j5, j6) && Triangle(j4, j2, j6) && Triangle(j4, j5, j3)); if (!t) { return(0.0); } // move the smallest entry to the lower-right corner // move lowest entry in first column to bottom if (j1.TwoJ < j4.TwoJ) { Swap(ref j1, ref j4); Swap(ref j2, ref j5); } // move lowest entry in second column to bottom if (j2.TwoJ < j5.TwoJ) { Swap(ref j2, ref j5); Swap(ref j3, ref j6); } // move lowest of first two entries in lower row to right if (j4.TwoJ < j5.TwoJ) { Swap(ref j1, ref j2); Swap(ref j4, ref j5); } // move lowest entry in third column to bottom if (j3.TwoJ < j6.TwoJ) { Swap(ref j3, ref j6); Swap(ref j1, ref j4); } // move lowest of last two entries in lower row to right if (j5.TwoJ < j6.TwoJ) { Swap(ref j2, ref j3); Swap(ref j5, ref j6); } if (j6.TwoJ == 0) { // special case for 0 entry return(SixJ_Zero(j1, j2, j3)); } else if (j6.TwoJ == 1) { // special case for 1/2 entry return(SixJ_OneHalf(j1, j2, j3, j4, j5)); } else { // general case return(SixJ_ShultenGorton_Recurse(j1.TwoJ, j2.TwoJ, j3.TwoJ, j4.TwoJ, j5.TwoJ, j6.TwoJ)); } }
private static bool Triangle(Spin a, Spin b, Spin c) { // check integer relationships int s = (a.TwoJ + b.TwoJ + c.TwoJ); if (s % 2 != 0) { return(false); } // check triangle inequality return((Math.Abs(a.TwoJ - b.TwoJ) <= c.TwoJ) && (c.TwoJ <= (a.TwoJ + b.TwoJ))); }
/// <summary> /// Enumerates all the spins that can be obtained by combining two spins. /// </summary> /// <param name="j1">The first spin.</param> /// <param name="j2">The second spin.</param> /// <returns>A list of spins which may be obtained.</returns> public static Spin[] Combine(Spin j1, Spin j2) { int tj_min = Math.Abs(j1.TwoJ - j2.TwoJ); int tj_max = j1.TwoJ + j2.TwoJ; Spin[] spins = new Spin[(tj_max - tj_min) / 2 + 1]; for (int i = 0; i < spins.Length; i++) { spins[i] = new Spin((tj_min + 2 * i) / 2.0); } return(spins); }
// j1 j2 j3 // j4 j5 1/2 private static double SixJ_OneHalf(Spin j1, Spin j2, Spin j3, Spin j4, Spin j5) { Debug.Assert(Math.Abs(j1.TwoJ - j5.TwoJ) == 1); Debug.Assert(Math.Abs(j2.TwoJ - j4.TwoJ) == 1); // make j5 = j1-1/2, reducing the number of formulae required if (j5.TwoJ > j1.TwoJ) { Swap(ref j1, ref j5); Swap(ref j2, ref j4); } double f; if (j4.TwoJ < j2.TwoJ) { // a b c // b-1/2 a-1/2 1/2 f = (j1.TwoJ + j2.TwoJ - j3.TwoJ) * (j1.TwoJ + j2.TwoJ + j3.TwoJ + 2) / 4.0 / (j1.TwoJ * (j1.TwoJ + 1)) / (j2.TwoJ * (j2.TwoJ + 1)); } else { // a b c // b+1/2 a-1/2 1/2 f = (j1.TwoJ - j2.TwoJ + j3.TwoJ) * (j2.TwoJ + j3.TwoJ - j1.TwoJ + 2) / 4.0 / (j1.TwoJ * (j1.TwoJ + 1)) / ((j2.TwoJ + 1) * (j2.TwoJ + 2)); } f = Math.Sqrt(f); if ((j1.TwoJ + j2.TwoJ + j3.TwoJ) % 4 != 0) { f = -f; } return(f); /* * // ensure that J1, J2 are integer-spins; J3, J4 are half-spins * if (j1.TwoJ % 2 != 0) { Swap(ref j1, ref j4); Swap(ref j2, ref j5); } * * // apply relation to 3j symbols * // re-write to call directly into specialized 3j routines * if ((j1.TwoJ + j2.TwoJ + j3.TwoJ) % 4 == 0) { * double p = ThreeJ(new SpinState(j4, 0.5), new SpinState(j5, -0.5), new SpinState(j3, 0.0)); * double q = ThreeJ(new SpinState(j1, 0.0), new SpinState(j2, 0.0), new SpinState(j3, 0.0)); * double r = Math.Sqrt((j1.TwoJ + 1) * (j2.TwoJ + 1)); * return (- p / q / r); * } else { * return (0.0); * } */ }