995 lines
31 KiB
Python
995 lines
31 KiB
Python
# -*- coding: utf-8 -*-
|
||
r"""
|
||
Wigner, Clebsch-Gordan, Racah, and Gaunt coefficients
|
||
|
||
Collection of functions for calculating Wigner 3j, 6j, 9j,
|
||
Clebsch-Gordan, Racah as well as Gaunt coefficients exactly, all
|
||
evaluating to a rational number times the square root of a rational
|
||
number [Rasch03]_.
|
||
|
||
Please see the description of the individual functions for further
|
||
details and examples.
|
||
|
||
References
|
||
==========
|
||
|
||
.. [Regge58] 'Symmetry Properties of Clebsch-Gordan Coefficients',
|
||
T. Regge, Nuovo Cimento, Volume 10, pp. 544 (1958)
|
||
.. [Regge59] 'Symmetry Properties of Racah Coefficients',
|
||
T. Regge, Nuovo Cimento, Volume 11, pp. 116 (1959)
|
||
.. [Edmonds74] A. R. Edmonds. Angular momentum in quantum mechanics.
|
||
Investigations in physics, 4.; Investigations in physics, no. 4.
|
||
Princeton, N.J., Princeton University Press, 1957.
|
||
.. [Rasch03] J. Rasch and A. C. H. Yu, 'Efficient Storage Scheme for
|
||
Pre-calculated Wigner 3j, 6j and Gaunt Coefficients', SIAM
|
||
J. Sci. Comput. Volume 25, Issue 4, pp. 1416-1428 (2003)
|
||
.. [Liberatodebrito82] 'FORTRAN program for the integral of three
|
||
spherical harmonics', A. Liberato de Brito,
|
||
Comput. Phys. Commun., Volume 25, pp. 81-85 (1982)
|
||
|
||
Credits and Copyright
|
||
=====================
|
||
|
||
This code was taken from Sage with the permission of all authors:
|
||
|
||
https://groups.google.com/forum/#!topic/sage-devel/M4NZdu-7O38
|
||
|
||
Authors
|
||
=======
|
||
|
||
- Jens Rasch (2009-03-24): initial version for Sage
|
||
|
||
- Jens Rasch (2009-05-31): updated to sage-4.0
|
||
|
||
- Oscar Gerardo Lazo Arjona (2017-06-18): added Wigner D matrices
|
||
|
||
Copyright (C) 2008 Jens Rasch <jyr2000@gmail.com>
|
||
|
||
"""
|
||
from sympy import (Integer, pi, sqrt, sympify, Dummy, S, Sum, Ynm, zeros,
|
||
Function, sin, cos, exp, I, factorial, binomial,
|
||
Add, ImmutableMatrix)
|
||
|
||
# This list of precomputed factorials is needed to massively
|
||
# accelerate future calculations of the various coefficients
|
||
_Factlist = [1]
|
||
|
||
|
||
def _calc_factlist(nn):
|
||
r"""
|
||
Function calculates a list of precomputed factorials in order to
|
||
massively accelerate future calculations of the various
|
||
coefficients.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
nn : integer
|
||
Highest factorial to be computed.
|
||
|
||
Returns
|
||
=======
|
||
|
||
list of integers :
|
||
The list of precomputed factorials.
|
||
|
||
Examples
|
||
========
|
||
|
||
Calculate list of factorials::
|
||
|
||
sage: from sage.functions.wigner import _calc_factlist
|
||
sage: _calc_factlist(10)
|
||
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
|
||
"""
|
||
if nn >= len(_Factlist):
|
||
for ii in range(len(_Factlist), int(nn + 1)):
|
||
_Factlist.append(_Factlist[ii - 1] * ii)
|
||
return _Factlist[:int(nn) + 1]
|
||
|
||
|
||
def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3):
|
||
r"""
|
||
Calculate the Wigner 3j symbol `\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3)`.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
j_1, j_2, j_3, m_1, m_2, m_3 :
|
||
Integer or half integer.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy.physics.wigner import wigner_3j
|
||
>>> wigner_3j(2, 6, 4, 0, 0, 0)
|
||
sqrt(715)/143
|
||
>>> wigner_3j(2, 6, 4, 0, 0, 1)
|
||
0
|
||
|
||
It is an error to have arguments that are not integer or half
|
||
integer values::
|
||
|
||
sage: wigner_3j(2.1, 6, 4, 0, 0, 0)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: j values must be integer or half integer
|
||
sage: wigner_3j(2, 6, 4, 1, 0, -1.1)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: m values must be integer or half integer
|
||
|
||
Notes
|
||
=====
|
||
|
||
The Wigner 3j symbol obeys the following symmetry rules:
|
||
|
||
- invariant under any permutation of the columns (with the
|
||
exception of a sign change where `J:=j_1+j_2+j_3`):
|
||
|
||
.. math::
|
||
|
||
\begin{aligned}
|
||
\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3)
|
||
&=\operatorname{Wigner3j}(j_3,j_1,j_2,m_3,m_1,m_2) \\
|
||
&=\operatorname{Wigner3j}(j_2,j_3,j_1,m_2,m_3,m_1) \\
|
||
&=(-1)^J \operatorname{Wigner3j}(j_3,j_2,j_1,m_3,m_2,m_1) \\
|
||
&=(-1)^J \operatorname{Wigner3j}(j_1,j_3,j_2,m_1,m_3,m_2) \\
|
||
&=(-1)^J \operatorname{Wigner3j}(j_2,j_1,j_3,m_2,m_1,m_3)
|
||
\end{aligned}
|
||
|
||
- invariant under space inflection, i.e.
|
||
|
||
.. math::
|
||
|
||
\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3)
|
||
=(-1)^J \operatorname{Wigner3j}(j_1,j_2,j_3,-m_1,-m_2,-m_3)
|
||
|
||
- symmetric with respect to the 72 additional symmetries based on
|
||
the work by [Regge58]_
|
||
|
||
- zero for `j_1`, `j_2`, `j_3` not fulfilling triangle relation
|
||
|
||
- zero for `m_1 + m_2 + m_3 \neq 0`
|
||
|
||
- zero for violating any one of the conditions
|
||
`j_1 \ge |m_1|`, `j_2 \ge |m_2|`, `j_3 \ge |m_3|`
|
||
|
||
Algorithm
|
||
=========
|
||
|
||
This function uses the algorithm of [Edmonds74]_ to calculate the
|
||
value of the 3j symbol exactly. Note that the formula contains
|
||
alternating sums over large factorials and is therefore unsuitable
|
||
for finite precision arithmetic and only useful for a computer
|
||
algebra system [Rasch03]_.
|
||
|
||
Authors
|
||
=======
|
||
|
||
- Jens Rasch (2009-03-24): initial version
|
||
"""
|
||
if int(j_1 * 2) != j_1 * 2 or int(j_2 * 2) != j_2 * 2 or \
|
||
int(j_3 * 2) != j_3 * 2:
|
||
raise ValueError("j values must be integer or half integer")
|
||
if int(m_1 * 2) != m_1 * 2 or int(m_2 * 2) != m_2 * 2 or \
|
||
int(m_3 * 2) != m_3 * 2:
|
||
raise ValueError("m values must be integer or half integer")
|
||
if m_1 + m_2 + m_3 != 0:
|
||
return 0
|
||
prefid = Integer((-1) ** int(j_1 - j_2 - m_3))
|
||
m_3 = -m_3
|
||
a1 = j_1 + j_2 - j_3
|
||
if a1 < 0:
|
||
return 0
|
||
a2 = j_1 - j_2 + j_3
|
||
if a2 < 0:
|
||
return 0
|
||
a3 = -j_1 + j_2 + j_3
|
||
if a3 < 0:
|
||
return 0
|
||
if (abs(m_1) > j_1) or (abs(m_2) > j_2) or (abs(m_3) > j_3):
|
||
return 0
|
||
|
||
maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2),
|
||
j_3 + abs(m_3))
|
||
_calc_factlist(int(maxfact))
|
||
|
||
argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] *
|
||
_Factlist[int(j_1 - j_2 + j_3)] *
|
||
_Factlist[int(-j_1 + j_2 + j_3)] *
|
||
_Factlist[int(j_1 - m_1)] *
|
||
_Factlist[int(j_1 + m_1)] *
|
||
_Factlist[int(j_2 - m_2)] *
|
||
_Factlist[int(j_2 + m_2)] *
|
||
_Factlist[int(j_3 - m_3)] *
|
||
_Factlist[int(j_3 + m_3)]) / \
|
||
_Factlist[int(j_1 + j_2 + j_3 + 1)]
|
||
|
||
ressqrt = sqrt(argsqrt)
|
||
if ressqrt.is_complex or ressqrt.is_infinite:
|
||
ressqrt = ressqrt.as_real_imag()[0]
|
||
|
||
imin = max(-j_3 + j_1 + m_2, -j_3 + j_2 - m_1, 0)
|
||
imax = min(j_2 + m_2, j_1 - m_1, j_1 + j_2 - j_3)
|
||
sumres = 0
|
||
for ii in range(int(imin), int(imax) + 1):
|
||
den = _Factlist[ii] * \
|
||
_Factlist[int(ii + j_3 - j_1 - m_2)] * \
|
||
_Factlist[int(j_2 + m_2 - ii)] * \
|
||
_Factlist[int(j_1 - ii - m_1)] * \
|
||
_Factlist[int(ii + j_3 - j_2 + m_1)] * \
|
||
_Factlist[int(j_1 + j_2 - j_3 - ii)]
|
||
sumres = sumres + Integer((-1) ** ii) / den
|
||
|
||
res = ressqrt * sumres * prefid
|
||
return res
|
||
|
||
|
||
def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3):
|
||
r"""
|
||
Calculates the Clebsch-Gordan coefficient.
|
||
`\left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle`.
|
||
|
||
The reference for this function is [Edmonds74]_.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
j_1, j_2, j_3, m_1, m_2, m_3 :
|
||
Integer or half integer.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy import S
|
||
>>> from sympy.physics.wigner import clebsch_gordan
|
||
>>> clebsch_gordan(S(3)/2, S(1)/2, 2, S(3)/2, S(1)/2, 2)
|
||
1
|
||
>>> clebsch_gordan(S(3)/2, S(1)/2, 1, S(3)/2, -S(1)/2, 1)
|
||
sqrt(3)/2
|
||
>>> clebsch_gordan(S(3)/2, S(1)/2, 1, -S(1)/2, S(1)/2, 0)
|
||
-sqrt(2)/2
|
||
|
||
Notes
|
||
=====
|
||
|
||
The Clebsch-Gordan coefficient will be evaluated via its relation
|
||
to Wigner 3j symbols:
|
||
|
||
.. math::
|
||
|
||
\left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle
|
||
=(-1)^{j_1-j_2+m_3} \sqrt{2j_3+1}
|
||
\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,-m_3)
|
||
|
||
See also the documentation on Wigner 3j symbols which exhibit much
|
||
higher symmetry relations than the Clebsch-Gordan coefficient.
|
||
|
||
Authors
|
||
=======
|
||
|
||
- Jens Rasch (2009-03-24): initial version
|
||
"""
|
||
res = (-1) ** sympify(j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * \
|
||
wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3)
|
||
return res
|
||
|
||
|
||
def _big_delta_coeff(aa, bb, cc, prec=None):
|
||
r"""
|
||
Calculates the Delta coefficient of the 3 angular momenta for
|
||
Racah symbols. Also checks that the differences are of integer
|
||
value.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
aa :
|
||
First angular momentum, integer or half integer.
|
||
bb :
|
||
Second angular momentum, integer or half integer.
|
||
cc :
|
||
Third angular momentum, integer or half integer.
|
||
prec :
|
||
Precision of the ``sqrt()`` calculation.
|
||
|
||
Returns
|
||
=======
|
||
|
||
double : Value of the Delta coefficient.
|
||
|
||
Examples
|
||
========
|
||
|
||
sage: from sage.functions.wigner import _big_delta_coeff
|
||
sage: _big_delta_coeff(1,1,1)
|
||
1/2*sqrt(1/6)
|
||
"""
|
||
|
||
if int(aa + bb - cc) != (aa + bb - cc):
|
||
raise ValueError("j values must be integer or half integer and fulfill the triangle relation")
|
||
if int(aa + cc - bb) != (aa + cc - bb):
|
||
raise ValueError("j values must be integer or half integer and fulfill the triangle relation")
|
||
if int(bb + cc - aa) != (bb + cc - aa):
|
||
raise ValueError("j values must be integer or half integer and fulfill the triangle relation")
|
||
if (aa + bb - cc) < 0:
|
||
return 0
|
||
if (aa + cc - bb) < 0:
|
||
return 0
|
||
if (bb + cc - aa) < 0:
|
||
return 0
|
||
|
||
maxfact = max(aa + bb - cc, aa + cc - bb, bb + cc - aa, aa + bb + cc + 1)
|
||
_calc_factlist(maxfact)
|
||
|
||
argsqrt = Integer(_Factlist[int(aa + bb - cc)] *
|
||
_Factlist[int(aa + cc - bb)] *
|
||
_Factlist[int(bb + cc - aa)]) / \
|
||
Integer(_Factlist[int(aa + bb + cc + 1)])
|
||
|
||
ressqrt = sqrt(argsqrt)
|
||
if prec:
|
||
ressqrt = ressqrt.evalf(prec).as_real_imag()[0]
|
||
return ressqrt
|
||
|
||
|
||
def racah(aa, bb, cc, dd, ee, ff, prec=None):
|
||
r"""
|
||
Calculate the Racah symbol `W(a,b,c,d;e,f)`.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
a, ..., f :
|
||
Integer or half integer.
|
||
prec :
|
||
Precision, default: ``None``. Providing a precision can
|
||
drastically speed up the calculation.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number
|
||
(if ``prec=None``), or real number if a precision is given.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy.physics.wigner import racah
|
||
>>> racah(3,3,3,3,3,3)
|
||
-1/14
|
||
|
||
Notes
|
||
=====
|
||
|
||
The Racah symbol is related to the Wigner 6j symbol:
|
||
|
||
.. math::
|
||
|
||
\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)
|
||
=(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6)
|
||
|
||
Please see the 6j symbol for its much richer symmetries and for
|
||
additional properties.
|
||
|
||
Algorithm
|
||
=========
|
||
|
||
This function uses the algorithm of [Edmonds74]_ to calculate the
|
||
value of the 6j symbol exactly. Note that the formula contains
|
||
alternating sums over large factorials and is therefore unsuitable
|
||
for finite precision arithmetic and only useful for a computer
|
||
algebra system [Rasch03]_.
|
||
|
||
Authors
|
||
=======
|
||
|
||
- Jens Rasch (2009-03-24): initial version
|
||
"""
|
||
prefac = _big_delta_coeff(aa, bb, ee, prec) * \
|
||
_big_delta_coeff(cc, dd, ee, prec) * \
|
||
_big_delta_coeff(aa, cc, ff, prec) * \
|
||
_big_delta_coeff(bb, dd, ff, prec)
|
||
if prefac == 0:
|
||
return 0
|
||
imin = max(aa + bb + ee, cc + dd + ee, aa + cc + ff, bb + dd + ff)
|
||
imax = min(aa + bb + cc + dd, aa + dd + ee + ff, bb + cc + ee + ff)
|
||
|
||
maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff,
|
||
bb + cc + ee + ff)
|
||
_calc_factlist(maxfact)
|
||
|
||
sumres = 0
|
||
for kk in range(int(imin), int(imax) + 1):
|
||
den = _Factlist[int(kk - aa - bb - ee)] * \
|
||
_Factlist[int(kk - cc - dd - ee)] * \
|
||
_Factlist[int(kk - aa - cc - ff)] * \
|
||
_Factlist[int(kk - bb - dd - ff)] * \
|
||
_Factlist[int(aa + bb + cc + dd - kk)] * \
|
||
_Factlist[int(aa + dd + ee + ff - kk)] * \
|
||
_Factlist[int(bb + cc + ee + ff - kk)]
|
||
sumres = sumres + Integer((-1) ** kk * _Factlist[kk + 1]) / den
|
||
|
||
res = prefac * sumres * (-1) ** int(aa + bb + cc + dd)
|
||
return res
|
||
|
||
|
||
def wigner_6j(j_1, j_2, j_3, j_4, j_5, j_6, prec=None):
|
||
r"""
|
||
Calculate the Wigner 6j symbol `\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)`.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
j_1, ..., j_6 :
|
||
Integer or half integer.
|
||
prec :
|
||
Precision, default: ``None``. Providing a precision can
|
||
drastically speed up the calculation.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number
|
||
(if ``prec=None``), or real number if a precision is given.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy.physics.wigner import wigner_6j
|
||
>>> wigner_6j(3,3,3,3,3,3)
|
||
-1/14
|
||
>>> wigner_6j(5,5,5,5,5,5)
|
||
1/52
|
||
|
||
It is an error to have arguments that are not integer or half
|
||
integer values or do not fulfill the triangle relation::
|
||
|
||
sage: wigner_6j(2.5,2.5,2.5,2.5,2.5,2.5)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: j values must be integer or half integer and fulfill the triangle relation
|
||
sage: wigner_6j(0.5,0.5,1.1,0.5,0.5,1.1)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: j values must be integer or half integer and fulfill the triangle relation
|
||
|
||
Notes
|
||
=====
|
||
|
||
The Wigner 6j symbol is related to the Racah symbol but exhibits
|
||
more symmetries as detailed below.
|
||
|
||
.. math::
|
||
|
||
\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)
|
||
=(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6)
|
||
|
||
The Wigner 6j symbol obeys the following symmetry rules:
|
||
|
||
- Wigner 6j symbols are left invariant under any permutation of
|
||
the columns:
|
||
|
||
.. math::
|
||
|
||
\begin{aligned}
|
||
\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)
|
||
&=\operatorname{Wigner6j}(j_3,j_1,j_2,j_6,j_4,j_5) \\
|
||
&=\operatorname{Wigner6j}(j_2,j_3,j_1,j_5,j_6,j_4) \\
|
||
&=\operatorname{Wigner6j}(j_3,j_2,j_1,j_6,j_5,j_4) \\
|
||
&=\operatorname{Wigner6j}(j_1,j_3,j_2,j_4,j_6,j_5) \\
|
||
&=\operatorname{Wigner6j}(j_2,j_1,j_3,j_5,j_4,j_6)
|
||
\end{aligned}
|
||
|
||
- They are invariant under the exchange of the upper and lower
|
||
arguments in each of any two columns, i.e.
|
||
|
||
.. math::
|
||
|
||
\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)
|
||
=\operatorname{Wigner6j}(j_1,j_5,j_6,j_4,j_2,j_3)
|
||
=\operatorname{Wigner6j}(j_4,j_2,j_6,j_1,j_5,j_3)
|
||
=\operatorname{Wigner6j}(j_4,j_5,j_3,j_1,j_2,j_6)
|
||
|
||
- additional 6 symmetries [Regge59]_ giving rise to 144 symmetries
|
||
in total
|
||
|
||
- only non-zero if any triple of `j`'s fulfill a triangle relation
|
||
|
||
Algorithm
|
||
=========
|
||
|
||
This function uses the algorithm of [Edmonds74]_ to calculate the
|
||
value of the 6j symbol exactly. Note that the formula contains
|
||
alternating sums over large factorials and is therefore unsuitable
|
||
for finite precision arithmetic and only useful for a computer
|
||
algebra system [Rasch03]_.
|
||
|
||
"""
|
||
res = (-1) ** int(j_1 + j_2 + j_4 + j_5) * \
|
||
racah(j_1, j_2, j_5, j_4, j_3, j_6, prec)
|
||
return res
|
||
|
||
|
||
def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None):
|
||
r"""
|
||
Calculate the Wigner 9j symbol
|
||
`\operatorname{Wigner9j}(j_1,j_2,j_3,j_4,j_5,j_6,j_7,j_8,j_9)`.
|
||
|
||
Parameters
|
||
==========
|
||
|
||
j_1, ..., j_9 :
|
||
Integer or half integer.
|
||
prec : precision, default
|
||
``None``. Providing a precision can
|
||
drastically speed up the calculation.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number
|
||
(if ``prec=None``), or real number if a precision is given.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy.physics.wigner import wigner_9j
|
||
>>> wigner_9j(1,1,1, 1,1,1, 1,1,0 ,prec=64) # ==1/18
|
||
0.05555555...
|
||
|
||
>>> wigner_9j(1/2,1/2,0, 1/2,3/2,1, 0,1,1 ,prec=64) # ==1/6
|
||
0.1666666...
|
||
|
||
It is an error to have arguments that are not integer or half
|
||
integer values or do not fulfill the triangle relation::
|
||
|
||
sage: wigner_9j(0.5,0.5,0.5, 0.5,0.5,0.5, 0.5,0.5,0.5,prec=64)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: j values must be integer or half integer and fulfill the triangle relation
|
||
sage: wigner_9j(1,1,1, 0.5,1,1.5, 0.5,1,2.5,prec=64)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: j values must be integer or half integer and fulfill the triangle relation
|
||
|
||
Algorithm
|
||
=========
|
||
|
||
This function uses the algorithm of [Edmonds74]_ to calculate the
|
||
value of the 3j symbol exactly. Note that the formula contains
|
||
alternating sums over large factorials and is therefore unsuitable
|
||
for finite precision arithmetic and only useful for a computer
|
||
algebra system [Rasch03]_.
|
||
"""
|
||
imax = int(min(j_1 + j_9, j_2 + j_6, j_4 + j_8) * 2)
|
||
imin = imax % 2
|
||
sumres = 0
|
||
for kk in range(imin, int(imax) + 1, 2):
|
||
sumres = sumres + (kk + 1) * \
|
||
racah(j_1, j_2, j_9, j_6, j_3, kk / 2, prec) * \
|
||
racah(j_4, j_6, j_8, j_2, j_5, kk / 2, prec) * \
|
||
racah(j_1, j_4, j_9, j_8, j_7, kk / 2, prec)
|
||
return sumres
|
||
|
||
|
||
def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None):
|
||
r"""
|
||
Calculate the Gaunt coefficient.
|
||
|
||
Explanation
|
||
===========
|
||
|
||
The Gaunt coefficient is defined as the integral over three
|
||
spherical harmonics:
|
||
|
||
.. math::
|
||
|
||
\begin{aligned}
|
||
\operatorname{Gaunt}(l_1,l_2,l_3,m_1,m_2,m_3)
|
||
&=\int Y_{l_1,m_1}(\Omega)
|
||
Y_{l_2,m_2}(\Omega) Y_{l_3,m_3}(\Omega) \,d\Omega \\
|
||
&=\sqrt{\frac{(2l_1+1)(2l_2+1)(2l_3+1)}{4\pi}}
|
||
\operatorname{Wigner3j}(l_1,l_2,l_3,0,0,0)
|
||
\operatorname{Wigner3j}(l_1,l_2,l_3,m_1,m_2,m_3)
|
||
\end{aligned}
|
||
|
||
Parameters
|
||
==========
|
||
|
||
l_1, l_2, l_3, m_1, m_2, m_3 :
|
||
Integer.
|
||
prec - precision, default: ``None``.
|
||
Providing a precision can
|
||
drastically speed up the calculation.
|
||
|
||
Returns
|
||
=======
|
||
|
||
Rational number times the square root of a rational number
|
||
(if ``prec=None``), or real number if a precision is given.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy.physics.wigner import gaunt
|
||
>>> gaunt(1,0,1,1,0,-1)
|
||
-1/(2*sqrt(pi))
|
||
>>> gaunt(1000,1000,1200,9,3,-12).n(64)
|
||
0.00689500421922113448...
|
||
|
||
It is an error to use non-integer values for `l` and `m`::
|
||
|
||
sage: gaunt(1.2,0,1.2,0,0,0)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: l values must be integer
|
||
sage: gaunt(1,0,1,1.1,0,-1.1)
|
||
Traceback (most recent call last):
|
||
...
|
||
ValueError: m values must be integer
|
||
|
||
Notes
|
||
=====
|
||
|
||
The Gaunt coefficient obeys the following symmetry rules:
|
||
|
||
- invariant under any permutation of the columns
|
||
|
||
.. math::
|
||
\begin{aligned}
|
||
Y(l_1,l_2,l_3,m_1,m_2,m_3)
|
||
&=Y(l_3,l_1,l_2,m_3,m_1,m_2) \\
|
||
&=Y(l_2,l_3,l_1,m_2,m_3,m_1) \\
|
||
&=Y(l_3,l_2,l_1,m_3,m_2,m_1) \\
|
||
&=Y(l_1,l_3,l_2,m_1,m_3,m_2) \\
|
||
&=Y(l_2,l_1,l_3,m_2,m_1,m_3)
|
||
\end{aligned}
|
||
|
||
- invariant under space inflection, i.e.
|
||
|
||
.. math::
|
||
Y(l_1,l_2,l_3,m_1,m_2,m_3)
|
||
=Y(l_1,l_2,l_3,-m_1,-m_2,-m_3)
|
||
|
||
- symmetric with respect to the 72 Regge symmetries as inherited
|
||
for the `3j` symbols [Regge58]_
|
||
|
||
- zero for `l_1`, `l_2`, `l_3` not fulfilling triangle relation
|
||
|
||
- zero for violating any one of the conditions: `l_1 \ge |m_1|`,
|
||
`l_2 \ge |m_2|`, `l_3 \ge |m_3|`
|
||
|
||
- non-zero only for an even sum of the `l_i`, i.e.
|
||
`L = l_1 + l_2 + l_3 = 2n` for `n` in `\mathbb{N}`
|
||
|
||
Algorithms
|
||
==========
|
||
|
||
This function uses the algorithm of [Liberatodebrito82]_ to
|
||
calculate the value of the Gaunt coefficient exactly. Note that
|
||
the formula contains alternating sums over large factorials and is
|
||
therefore unsuitable for finite precision arithmetic and only
|
||
useful for a computer algebra system [Rasch03]_.
|
||
|
||
Authors
|
||
=======
|
||
|
||
Jens Rasch (2009-03-24): initial version for Sage.
|
||
"""
|
||
if int(l_1) != l_1 or int(l_2) != l_2 or int(l_3) != l_3:
|
||
raise ValueError("l values must be integer")
|
||
if int(m_1) != m_1 or int(m_2) != m_2 or int(m_3) != m_3:
|
||
raise ValueError("m values must be integer")
|
||
|
||
sumL = l_1 + l_2 + l_3
|
||
bigL = sumL // 2
|
||
a1 = l_1 + l_2 - l_3
|
||
if a1 < 0:
|
||
return 0
|
||
a2 = l_1 - l_2 + l_3
|
||
if a2 < 0:
|
||
return 0
|
||
a3 = -l_1 + l_2 + l_3
|
||
if a3 < 0:
|
||
return 0
|
||
if sumL % 2:
|
||
return 0
|
||
if (m_1 + m_2 + m_3) != 0:
|
||
return 0
|
||
if (abs(m_1) > l_1) or (abs(m_2) > l_2) or (abs(m_3) > l_3):
|
||
return 0
|
||
|
||
imin = max(-l_3 + l_1 + m_2, -l_3 + l_2 - m_1, 0)
|
||
imax = min(l_2 + m_2, l_1 - m_1, l_1 + l_2 - l_3)
|
||
|
||
maxfact = max(l_1 + l_2 + l_3 + 1, imax + 1)
|
||
_calc_factlist(maxfact)
|
||
|
||
argsqrt = (2 * l_1 + 1) * (2 * l_2 + 1) * (2 * l_3 + 1) * \
|
||
_Factlist[l_1 - m_1] * _Factlist[l_1 + m_1] * _Factlist[l_2 - m_2] * \
|
||
_Factlist[l_2 + m_2] * _Factlist[l_3 - m_3] * _Factlist[l_3 + m_3] / \
|
||
(4*pi)
|
||
ressqrt = sqrt(argsqrt)
|
||
|
||
prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] *
|
||
_Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3])/ \
|
||
_Factlist[2 * bigL + 1]/ \
|
||
(_Factlist[bigL - l_1] *
|
||
_Factlist[bigL - l_2] * _Factlist[bigL - l_3])
|
||
|
||
sumres = 0
|
||
for ii in range(int(imin), int(imax) + 1):
|
||
den = _Factlist[ii] * _Factlist[ii + l_3 - l_1 - m_2] * \
|
||
_Factlist[l_2 + m_2 - ii] * _Factlist[l_1 - ii - m_1] * \
|
||
_Factlist[ii + l_3 - l_2 + m_1] * _Factlist[l_1 + l_2 - l_3 - ii]
|
||
sumres = sumres + Integer((-1) ** ii) / den
|
||
|
||
res = ressqrt * prefac * sumres * Integer((-1) ** (bigL + l_3 + m_1 - m_2))
|
||
if prec is not None:
|
||
res = res.n(prec)
|
||
return res
|
||
|
||
|
||
|
||
class Wigner3j(Function):
|
||
|
||
def doit(self, **hints):
|
||
if all(obj.is_number for obj in self.args):
|
||
return wigner_3j(*self.args)
|
||
else:
|
||
return self
|
||
|
||
def dot_rot_grad_Ynm(j, p, l, m, theta, phi):
|
||
r"""
|
||
Returns dot product of rotational gradients of spherical harmonics.
|
||
|
||
Explanation
|
||
===========
|
||
|
||
This function returns the right hand side of the following expression:
|
||
|
||
.. math ::
|
||
\vec{R}Y{_j^{p}} \cdot \vec{R}Y{_l^{m}} = (-1)^{m+p}
|
||
\sum\limits_{k=|l-j|}^{l+j}Y{_k^{m+p}} * \alpha_{l,m,j,p,k} *
|
||
\frac{1}{2} (k^2-j^2-l^2+k-j-l)
|
||
|
||
|
||
Arguments
|
||
=========
|
||
|
||
j, p, l, m .... indices in spherical harmonics (expressions or integers)
|
||
theta, phi .... angle arguments in spherical harmonics
|
||
|
||
Example
|
||
=======
|
||
|
||
>>> from sympy import symbols
|
||
>>> from sympy.physics.wigner import dot_rot_grad_Ynm
|
||
>>> theta, phi = symbols("theta phi")
|
||
>>> dot_rot_grad_Ynm(3, 2, 2, 0, theta, phi).doit()
|
||
3*sqrt(55)*Ynm(5, 2, theta, phi)/(11*sqrt(pi))
|
||
|
||
"""
|
||
j = sympify(j)
|
||
p = sympify(p)
|
||
l = sympify(l)
|
||
m = sympify(m)
|
||
theta = sympify(theta)
|
||
phi = sympify(phi)
|
||
k = Dummy("k")
|
||
|
||
def alpha(l,m,j,p,k):
|
||
return sqrt((2*l+1)*(2*j+1)*(2*k+1)/(4*pi)) * \
|
||
Wigner3j(j, l, k, S.Zero, S.Zero, S.Zero) * \
|
||
Wigner3j(j, l, k, p, m, -m-p)
|
||
|
||
return (S.NegativeOne)**(m+p) * Sum(Ynm(k, m+p, theta, phi) * alpha(l,m,j,p,k) / 2 \
|
||
*(k**2-j**2-l**2+k-j-l), (k, abs(l-j), l+j))
|
||
|
||
|
||
def wigner_d_small(J, beta):
|
||
"""Return the small Wigner d matrix for angular momentum J.
|
||
|
||
Explanation
|
||
===========
|
||
|
||
J : An integer, half-integer, or sympy symbol for the total angular
|
||
momentum of the angular momentum space being rotated.
|
||
beta : A real number representing the Euler angle of rotation about
|
||
the so-called line of nodes. See [Edmonds74]_.
|
||
|
||
Returns
|
||
=======
|
||
|
||
A matrix representing the corresponding Euler angle rotation( in the basis
|
||
of eigenvectors of `J_z`).
|
||
|
||
.. math ::
|
||
\\mathcal{d}_{\\beta} = \\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big)
|
||
|
||
The components are calculated using the general form [Edmonds74]_,
|
||
equation 4.1.15.
|
||
|
||
Examples
|
||
========
|
||
|
||
>>> from sympy import Integer, symbols, pi, pprint
|
||
>>> from sympy.physics.wigner import wigner_d_small
|
||
>>> half = 1/Integer(2)
|
||
>>> beta = symbols("beta", real=True)
|
||
>>> pprint(wigner_d_small(half, beta), use_unicode=True)
|
||
⎡ ⎛β⎞ ⎛β⎞⎤
|
||
⎢cos⎜─⎟ sin⎜─⎟⎥
|
||
⎢ ⎝2⎠ ⎝2⎠⎥
|
||
⎢ ⎥
|
||
⎢ ⎛β⎞ ⎛β⎞⎥
|
||
⎢-sin⎜─⎟ cos⎜─⎟⎥
|
||
⎣ ⎝2⎠ ⎝2⎠⎦
|
||
|
||
>>> pprint(wigner_d_small(2*half, beta), use_unicode=True)
|
||
⎡ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎤
|
||
⎢ cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟ sin ⎜─⎟ ⎥
|
||
⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎥
|
||
⎢ ⎥
|
||
⎢ ⎛β⎞ ⎛β⎞ 2⎛β⎞ 2⎛β⎞ ⎛β⎞ ⎛β⎞⎥
|
||
⎢-√2⋅sin⎜─⎟⋅cos⎜─⎟ - sin ⎜─⎟ + cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟⎥
|
||
⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠⎥
|
||
⎢ ⎥
|
||
⎢ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎥
|
||
⎢ sin ⎜─⎟ -√2⋅sin⎜─⎟⋅cos⎜─⎟ cos ⎜─⎟ ⎥
|
||
⎣ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎦
|
||
|
||
From table 4 in [Edmonds74]_
|
||
|
||
>>> pprint(wigner_d_small(half, beta).subs({beta:pi/2}), use_unicode=True)
|
||
⎡ √2 √2⎤
|
||
⎢ ── ──⎥
|
||
⎢ 2 2 ⎥
|
||
⎢ ⎥
|
||
⎢-√2 √2⎥
|
||
⎢──── ──⎥
|
||
⎣ 2 2 ⎦
|
||
|
||
>>> pprint(wigner_d_small(2*half, beta).subs({beta:pi/2}),
|
||
... use_unicode=True)
|
||
⎡ √2 ⎤
|
||
⎢1/2 ── 1/2⎥
|
||
⎢ 2 ⎥
|
||
⎢ ⎥
|
||
⎢-√2 √2 ⎥
|
||
⎢──── 0 ── ⎥
|
||
⎢ 2 2 ⎥
|
||
⎢ ⎥
|
||
⎢ -√2 ⎥
|
||
⎢1/2 ──── 1/2⎥
|
||
⎣ 2 ⎦
|
||
|
||
>>> pprint(wigner_d_small(3*half, beta).subs({beta:pi/2}),
|
||
... use_unicode=True)
|
||
⎡ √2 √6 √6 √2⎤
|
||
⎢ ── ── ── ──⎥
|
||
⎢ 4 4 4 4 ⎥
|
||
⎢ ⎥
|
||
⎢-√6 -√2 √2 √6⎥
|
||
⎢──── ──── ── ──⎥
|
||
⎢ 4 4 4 4 ⎥
|
||
⎢ ⎥
|
||
⎢ √6 -√2 -√2 √6⎥
|
||
⎢ ── ──── ──── ──⎥
|
||
⎢ 4 4 4 4 ⎥
|
||
⎢ ⎥
|
||
⎢-√2 √6 -√6 √2⎥
|
||
⎢──── ── ──── ──⎥
|
||
⎣ 4 4 4 4 ⎦
|
||
|
||
>>> pprint(wigner_d_small(4*half, beta).subs({beta:pi/2}),
|
||
... use_unicode=True)
|
||
⎡ √6 ⎤
|
||
⎢1/4 1/2 ── 1/2 1/4⎥
|
||
⎢ 4 ⎥
|
||
⎢ ⎥
|
||
⎢-1/2 -1/2 0 1/2 1/2⎥
|
||
⎢ ⎥
|
||
⎢ √6 √6 ⎥
|
||
⎢ ── 0 -1/2 0 ── ⎥
|
||
⎢ 4 4 ⎥
|
||
⎢ ⎥
|
||
⎢-1/2 1/2 0 -1/2 1/2⎥
|
||
⎢ ⎥
|
||
⎢ √6 ⎥
|
||
⎢1/4 -1/2 ── -1/2 1/4⎥
|
||
⎣ 4 ⎦
|
||
|
||
"""
|
||
M = [J-i for i in range(2*J+1)]
|
||
d = zeros(2*J+1)
|
||
for i, Mi in enumerate(M):
|
||
for j, Mj in enumerate(M):
|
||
|
||
# We get the maximum and minimum value of sigma.
|
||
sigmamax = max([-Mi-Mj, J-Mj])
|
||
sigmamin = min([0, J-Mi])
|
||
|
||
dij = sqrt(factorial(J+Mi)*factorial(J-Mi) /
|
||
factorial(J+Mj)/factorial(J-Mj))
|
||
terms = [(-1)**(J-Mi-s) *
|
||
binomial(J+Mj, J-Mi-s) *
|
||
binomial(J-Mj, s) *
|
||
cos(beta/2)**(2*s+Mi+Mj) *
|
||
sin(beta/2)**(2*J-2*s-Mj-Mi)
|
||
for s in range(sigmamin, sigmamax+1)]
|
||
|
||
d[i, j] = dij*Add(*terms)
|
||
|
||
return ImmutableMatrix(d)
|
||
|
||
|
||
def wigner_d(J, alpha, beta, gamma):
|
||
"""Return the Wigner D matrix for angular momentum J.
|
||
|
||
Explanation
|
||
===========
|
||
|
||
J :
|
||
An integer, half-integer, or sympy symbol for the total angular
|
||
momentum of the angular momentum space being rotated.
|
||
alpha, beta, gamma - Real numbers representing the Euler.
|
||
Angles of rotation about the so-called vertical, line of nodes, and
|
||
figure axes. See [Edmonds74]_.
|
||
|
||
Returns
|
||
=======
|
||
|
||
A matrix representing the corresponding Euler angle rotation( in the basis
|
||
of eigenvectors of `J_z`).
|
||
|
||
.. math ::
|
||
\\mathcal{D}_{\\alpha \\beta \\gamma} =
|
||
\\exp\\big( \\frac{i\\alpha}{\\hbar} J_z\\big)
|
||
\\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big)
|
||
\\exp\\big( \\frac{i\\gamma}{\\hbar} J_z\\big)
|
||
|
||
The components are calculated using the general form [Edmonds74]_,
|
||
equation 4.1.12.
|
||
|
||
Examples
|
||
========
|
||
|
||
The simplest possible example:
|
||
|
||
>>> from sympy.physics.wigner import wigner_d
|
||
>>> from sympy import Integer, symbols, pprint
|
||
>>> half = 1/Integer(2)
|
||
>>> alpha, beta, gamma = symbols("alpha, beta, gamma", real=True)
|
||
>>> pprint(wigner_d(half, alpha, beta, gamma), use_unicode=True)
|
||
⎡ ⅈ⋅α ⅈ⋅γ ⅈ⋅α -ⅈ⋅γ ⎤
|
||
⎢ ─── ─── ─── ───── ⎥
|
||
⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞ ⎥
|
||
⎢ ℯ ⋅ℯ ⋅cos⎜─⎟ ℯ ⋅ℯ ⋅sin⎜─⎟ ⎥
|
||
⎢ ⎝2⎠ ⎝2⎠ ⎥
|
||
⎢ ⎥
|
||
⎢ -ⅈ⋅α ⅈ⋅γ -ⅈ⋅α -ⅈ⋅γ ⎥
|
||
⎢ ───── ─── ───── ───── ⎥
|
||
⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞⎥
|
||
⎢-ℯ ⋅ℯ ⋅sin⎜─⎟ ℯ ⋅ℯ ⋅cos⎜─⎟⎥
|
||
⎣ ⎝2⎠ ⎝2⎠⎦
|
||
|
||
"""
|
||
d = wigner_d_small(J, beta)
|
||
M = [J-i for i in range(2*J+1)]
|
||
D = [[exp(I*Mi*alpha)*d[i, j]*exp(I*Mj*gamma)
|
||
for j, Mj in enumerate(M)] for i, Mi in enumerate(M)]
|
||
return ImmutableMatrix(D)
|