def Wigner3j(j1, j2, j3, m1, m2, m3): r""" Evaluates Wigner 3-j symbol Args: j1,j2,j3,m1,m2,m3 (float): parameters of :math:`\begin{pmatrix}j_1 & j_2 & j_2 \\ m_1 & m_2 & m_3\end{pmatrix}` """ # use precalculated values if wignerPrecal and ((j2 < 2.1) and abs(m2) < 2.1 and (j1 < wignerPrecalJmax)): # we shoud have precalculated value if ((abs(j1 - j2) - 0.1 < j3) and (j3 < j1 + j2 + 0.1) and abs(m1 + m2 + m3) < 0.1): # return precalculated value return wignerPrecal3j[int(roundPy2(2 * j1)), int(roundPy2(2 * (wignerPrecalJmax + m1))), int(roundPy2(2. * j2)), int(roundPy2(m2 + j2)), int(roundPy2(2 - j3 + j1))] else: # that value is 0 return 0 if (j1 > 40 or j2 > 40 or j3 > 40 or m1 > 40 or m2 > 40 or m3 > 40): # usual implementation of coefficient calculation that uses factorials # would fail (overflow). Use instead something slower verion from Sympy return float( sympyEvaluate(Wigner3j_sympy(j1, j2, j3, m1, m2, m3).doit())) # print "unknown %.1f %.1f %.1f %.1f %.1f %.1f " % (j1,j2,j3,m1,m2,m3) # ====================================================================== # Wigner3j.m by David Terr, Raytheon, 6-17-04 # # Compute the Wigner 3j symbol using the Racah formula [1]. # # Usage: # from wigner import Wigner3j # wigner = Wigner3j(j1,j2,j3,m1,m2,m3) # # / j1 j2 j3 \ # | | # \ m1 m2 m3 / # # Reference: Wigner 3j-Symbol entry of Eric Weinstein's Mathworld: # http://mathworld.wolfram.com/Wigner3j-Symbol.html # ====================================================================== # Error checking if ((2 * j1 != floor(2 * j1)) | (2 * j2 != floor(2 * j2)) | (2 * j3 != floor(2 * j3)) | (2 * m1 != floor(2 * m1)) | (2 * m2 != floor(2 * m2)) | (2 * m3 != floor(2 * m3))): raise ValueError('All arguments must be integers or half-integers.') # Additional check if the sum of the second row equals zero if (m1 + m2 + m3 != 0): #print('3j-Symbol unphysical') return 0 if (j1 - m1 != floor(j1 - m1)): raise ValueError('2*j1 and 2*m1 must have the same parity') if (j2 - m2 != floor(j2 - m2)): raise ValueError('2*j2 and 2*m2 must have the same parity') if (j3 - m3 != floor(j3 - m3)): raise ValueError('2*j3 and 2*m3 must have the same parity') if (j3 > j1 + j2) | (j3 < abs(j1 - j2)): raise ValueError('j3 is out of bounds.') if abs(m1) > j1: raise ValueError('m1 is out of bounds.') if abs(m2) > j2: raise ValueError('m2 is out of bounds.') if abs(m3) > j3: raise ValueError('m3 is out of bounds.') t1 = j2 - m1 - j3 t2 = j1 + m2 - j3 t3 = j1 + j2 - j3 t4 = j1 - m1 t5 = j2 + m2 tmin = max(0, max(t1, t2)) tmax = min(t3, min(t4, t5)) tvec = arange(tmin, tmax + 1, 1) wigner = 0 for t in tvec: wigner += (-1)**t / (factorial(t) * factorial(t - t1) * factorial(t - t2) * factorial(t3 - t) * factorial(t4 - t) * factorial(t5 - t)) return wigner * (-1)**(j1 - j2 - m3) * sqrt( factorial(j1 + j2 - j3) * factorial(j1 - j2 + j3) * factorial(-j1 + j2 + j3) / factorial(j1 + j2 + j3 + 1) * factorial(j1 + m1) * factorial(j1 - m1) * factorial(j2 + m2) * factorial(j2 - m2) * factorial(j3 + m3) * factorial(j3 - m3))
def Wigner6j(j1, j2, j3, J1, J2, J3): r""" Evaluates Wigner 6-j symbol Args: j1,j2,j3,J1,J2,J3 (float): parameters of :math:`\left\{ \begin{matrix}j_1 & j_2 & j_3\ \\ J_1 & J_2 & J_3\end{matrix}\right\}` """ # ====================================================================== # Calculating the Wigner6j-Symbols using the Racah-Formula # Author: Ulrich Krohn # Date: 13th November 2009 # # Based upon Wigner3j.m from David Terr, Raytheon # Reference: http://mathworld.wolfram.com/Wigner6j-Symbol.html # # Usage: # from wigner import Wigner6j # WignerReturn = Wigner6j(j1,j2,j3,J1,J2,J3) # # / j1 j2 j3 \ # < > # \ J1 J2 J3 / # # ====================================================================== # Check that the js and Js are only integer or half integer if ((2 * j1 != roundPy2(2 * j1)) | (2 * j2 != roundPy2(2 * j2)) | (2 * j3 != roundPy2(2 * j3)) | (2 * J1 != roundPy2(2 * J1)) | (2 * J2 != roundPy2(2 * J2)) | (2 * J3 != roundPy2(2 * J3))): raise ValueError('All arguments must be integers or half-integers.') return -1 # Check if the 4 triads ( (j1 j2 j3), (j1 J2 J3), (J1 j2 J3), (J1 J2 j3) ) # satisfy the triangular inequalities if ((abs(j1 - j2) > j3) | (j1 + j2 < j3) | (abs(j1 - J2) > J3) | (j1 + J2 < J3) | (abs(J1 - j2) > J3) | (J1 + j2 < J3) | (abs(J1 - J2) > j3) | (J1 + J2 < j3)): raise ValueError('6j-Symbol is not triangular!') # Check if the sum of the elements of each traid is an integer if ((2 * (j1 + j2 + j3) != roundPy2(2 * (j1 + j2 + j3))) | (2 * (j1 + J2 + J3) != roundPy2(2 * (j1 + J2 + J3))) | (2 * (J1 + j2 + J3) != roundPy2(2 * (J1 + j2 + J3))) | (2 * (J1 + J2 + j3) != roundPy2(2 * (J1 + J2 + j3)))): raise ValueError('6j-Symbol is not triangular!') # if possible, use precalculated values global wignerPrecal if wignerPrecal and ( (roundPy2(2 * j2) >= -0.1) and (roundPy2(2 * j2) <= 2.1) and (J2 == 1 or J2 == 2) and (j1 <= wignerPrecalJmax) and (J3 <= wignerPrecalJmax) and (abs(roundPy2(j1) - j1) < 0.1) and (abs(roundPy2(J3) - J3) < 0.1) and abs(j1 - J3) < 2.1): # we have precalculated value return wignerPrecal6j[j1, 2 + j1 - J3, int(roundPy2(2 + 2 * (j3 - j1))), int(roundPy2(2 + 2 * (J1 - J3))), J2 - 1, int(roundPy2(2 * j2))] ##print("not in database %1.f %1.f %1.f %1.f %1.f %1.f" % (j1,j2,j3,J1,J2,J3)) if (j1 > 50 or j2 > 50 or j3 > 50 or J1 > 50 or J2 > 50 or J3 > 50): # usual implementation of coefficient calculation that uses factorials # would fail (overflow). Use instead something slower verion from Sympy return float( sympyEvaluate(Wigner6j_sympy(j1, j2, j3, J1, J2, J3).doit())) # Arguments for the factorials t1 = j1 + j2 + j3 t2 = j1 + J2 + J3 t3 = J1 + j2 + J3 t4 = J1 + J2 + j3 t5 = j1 + j2 + J1 + J2 t6 = j2 + j3 + J2 + J3 t7 = j1 + j3 + J1 + J3 # Finding summation borders tmin = max(0, max(t1, max(t2, max(t3, t4)))) tmax = min(t5, min(t6, t7)) tvec = arange(tmin, tmax + 1, 1) # Calculation the sum part of the 6j-Symbol WignerReturn = 0 for t in tvec: WignerReturn += (-1)**t * factorial(t + 1) / ( factorial(t - t1) * factorial(t - t2) * factorial(t - t3) * factorial(t - t4) * factorial(t5 - t) * factorial(t6 - t) * factorial(t7 - t)) # Calculation of the 6j-Symbol return WignerReturn * sqrt(TriaCoeff(j1, j2, j3) * TriaCoeff(j1, J2, J3) \ * TriaCoeff(J1, j2, J3) * TriaCoeff(J1, J2, j3))