Esempio n. 1
0
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))
Esempio n. 2
0
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))