|
|
|
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) |
|
.. [Homeier96] 'Some Properties of the Coupling Coefficients of Real |
|
Spherical Harmonics and Their Relation to Gaunt Coefficients', |
|
H. H. H. Homeier and E. O. Steinborn J. Mol. Struct., Volume 368, |
|
pp. 31-37 (1996) |
|
|
|
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 |
|
|
|
- Phil Adam LeMaitre (2022-09-19): added real Gaunt coefficient |
|
|
|
Copyright (C) 2008 Jens Rasch <jyr2000@gmail.com> |
|
|
|
""" |
|
from sympy.concrete.summations import Sum |
|
from sympy.core.add import Add |
|
from sympy.core.numbers import int_valued |
|
from sympy.core.function import Function |
|
from sympy.core.numbers import (Float, I, Integer, pi, Rational) |
|
from sympy.core.singleton import S |
|
from sympy.core.symbol import Dummy |
|
from sympy.core.sympify import sympify |
|
from sympy.functions.combinatorial.factorials import (binomial, factorial) |
|
from sympy.functions.elementary.complexes import re |
|
from sympy.functions.elementary.exponential import exp |
|
from sympy.functions.elementary.miscellaneous import sqrt |
|
from sympy.functions.elementary.trigonometric import (cos, sin) |
|
from sympy.functions.special.spherical_harmonics import Ynm |
|
from sympy.matrices.dense import zeros |
|
from sympy.matrices.immutable import ImmutableMatrix |
|
from sympy.utilities.misc import as_int |
|
|
|
|
|
|
|
_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 _int_or_halfint(value): |
|
"""return Python int unless value is half-int (then return float)""" |
|
if isinstance(value, int): |
|
return value |
|
elif type(value) is float: |
|
if value.is_integer(): |
|
return int(value) |
|
if (2*value).is_integer(): |
|
return value |
|
elif isinstance(value, Rational): |
|
if value.q == 2: |
|
return value.p/value.q |
|
elif value.q == 1: |
|
return value.p |
|
elif isinstance(value, Float): |
|
return _int_or_halfint(float(value)) |
|
raise ValueError("expecting integer or half-integer, got %s" % value) |
|
|
|
|
|
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 |
|
`m_1 \in \{-|j_1|, \ldots, |j_1|\}`, |
|
`m_2 \in \{-|j_2|, \ldots, |j_2|\}`, |
|
`m_3 \in \{-|j_3|, \ldots, |j_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 |
|
""" |
|
|
|
j_1, j_2, j_3, m_1, m_2, m_3 = \ |
|
map(_int_or_halfint, map(sympify, |
|
[j_1, j_2, j_3, m_1, m_2, m_3])) |
|
|
|
if m_1 + m_2 + m_3 != 0: |
|
return S.Zero |
|
a1 = j_1 + j_2 - j_3 |
|
if a1 < 0: |
|
return S.Zero |
|
a2 = j_1 - j_2 + j_3 |
|
if a2 < 0: |
|
return S.Zero |
|
a3 = -j_1 + j_2 + j_3 |
|
if a3 < 0: |
|
return S.Zero |
|
if (abs(m_1) > j_1) or (abs(m_2) > j_2) or (abs(m_3) > j_3): |
|
return S.Zero |
|
if not (int_valued(j_1 - m_1) and \ |
|
int_valued(j_2 - m_2) and \ |
|
int_valued(j_3 - m_3)): |
|
return S.Zero |
|
|
|
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 |
|
|
|
prefid = Integer((-1) ** int(j_1 - j_2 - m_3)) |
|
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 |
|
""" |
|
j_1 = sympify(j_1) |
|
j_2 = sympify(j_2) |
|
j_3 = sympify(j_3) |
|
m_1 = sympify(m_1) |
|
m_2 = sympify(m_2) |
|
m_3 = sympify(m_3) |
|
|
|
w = wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3) |
|
|
|
return (-1) ** (j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * w |
|
|
|
|
|
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 not int_valued(aa + bb - cc): |
|
raise ValueError("j values must be integer or half integer and fulfill the triangle relation") |
|
if not int_valued(aa + cc - bb): |
|
raise ValueError("j values must be integer or half integer and fulfill the triangle relation") |
|
if not int_valued(bb + cc - aa): |
|
raise ValueError("j values must be integer or half integer and fulfill the triangle relation") |
|
if (aa + bb - cc) < 0: |
|
return S.Zero |
|
if (aa + cc - bb) < 0: |
|
return S.Zero |
|
if (bb + cc - aa) < 0: |
|
return S.Zero |
|
|
|
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 S.Zero |
|
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:: |
|
|
|
\begin{aligned} |
|
\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) |
|
\end{aligned} |
|
|
|
- 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]_. |
|
|
|
""" |
|
j_1, j_2, j_3, j_4, j_5, j_6 = map(sympify, \ |
|
[j_1, j_2, j_3, j_4, j_5, j_6]) |
|
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) |
|
0.05555555555555555555555555555555555555555555555555555555555555555 |
|
|
|
>>> wigner_9j(1/2,1/2,0, 1/2,3/2,1, 0,1,1, prec=64) |
|
0.1666666666666666666666666666666666666666666666666666666666666667 |
|
|
|
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]_. |
|
""" |
|
j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9 = map(sympify, \ |
|
[j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9]) |
|
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.006895004219221134484332976156744208248842039317638217822322799675 |
|
|
|
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. |
|
""" |
|
l_1, l_2, l_3, m_1, m_2, m_3 = [ |
|
as_int(i) for i in (l_1, l_2, l_3, m_1, m_2, m_3)] |
|
|
|
if l_1 + l_2 - l_3 < 0: |
|
return S.Zero |
|
if l_1 - l_2 + l_3 < 0: |
|
return S.Zero |
|
if -l_1 + l_2 + l_3 < 0: |
|
return S.Zero |
|
if (m_1 + m_2 + m_3) != 0: |
|
return S.Zero |
|
if (abs(m_1) > l_1) or (abs(m_2) > l_2) or (abs(m_3) > l_3): |
|
return S.Zero |
|
bigL, remL = divmod(l_1 + l_2 + l_3, 2) |
|
if remL % 2: |
|
return S.Zero |
|
|
|
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) |
|
|
|
_calc_factlist(max(l_1 + l_2 + l_3 + 1, imax + 1)) |
|
|
|
ressqrt = sqrt((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)) |
|
|
|
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 |
|
|
|
|
|
def real_gaunt(l_1, l_2, l_3, mu_1, mu_2, mu_3, prec=None): |
|
r""" |
|
Calculate the real Gaunt coefficient. |
|
|
|
Explanation |
|
=========== |
|
|
|
The real Gaunt coefficient is defined as the integral over three |
|
real spherical harmonics: |
|
|
|
.. math:: |
|
\begin{aligned} |
|
\operatorname{RealGaunt}(l_1,l_2,l_3,\mu_1,\mu_2,\mu_3) |
|
&=\int Z^{\mu_1}_{l_1}(\Omega) |
|
Z^{\mu_2}_{l_2}(\Omega) Z^{\mu_3}_{l_3}(\Omega) \,d\Omega \\ |
|
\end{aligned} |
|
|
|
Alternatively, it can be defined in terms of the standard Gaunt |
|
coefficient by relating the real spherical harmonics to the standard |
|
spherical harmonics via a unitary transformation `U`, i.e. |
|
`Z^{\mu}_{l}(\Omega)=\sum_{m'}U^{\mu}_{m'}Y^{m'}_{l}(\Omega)` [Homeier96]_. |
|
The real Gaunt coefficient is then defined as |
|
|
|
.. math:: |
|
\begin{aligned} |
|
\operatorname{RealGaunt}(l_1,l_2,l_3,\mu_1,\mu_2,\mu_3) |
|
&=\int Z^{\mu_1}_{l_1}(\Omega) |
|
Z^{\mu_2}_{l_2}(\Omega) Z^{\mu_3}_{l_3}(\Omega) \,d\Omega \\ |
|
&=\sum_{m'_1 m'_2 m'_3} U^{\mu_1}_{m'_1}U^{\mu_2}_{m'_2}U^{\mu_3}_{m'_3} |
|
\operatorname{Gaunt}(l_1,l_2,l_3,m'_1,m'_2,m'_3) |
|
\end{aligned} |
|
|
|
The unitary matrix `U` has components |
|
|
|
.. math:: |
|
\begin{aligned} |
|
U^\mu_{m} = \delta_{|\mu||m|}*(\delta_{m0}\delta_{\mu 0} + \frac{1}{\sqrt{2}}\big[\Theta(\mu)\big(\delta_{m\mu}+(-1)^{m}\delta_{m-\mu}\big) |
|
+i \Theta(-\mu)\big((-1)^{m}\delta_{m\mu}-\delta_{m-\mu}\big)\big]) |
|
\end{aligned} |
|
|
|
|
|
where `\delta_{ij}` is the Kronecker delta symbol and `\Theta` is a step |
|
function defined as |
|
|
|
.. math:: |
|
\begin{aligned} |
|
\Theta(x) = \begin{cases} 1 \,\text{for}\, x > 0 \\ 0 \,\text{for}\, x \leq 0 \end{cases} |
|
\end{aligned} |
|
|
|
Parameters |
|
========== |
|
|
|
l_1, l_2, l_3, mu_1, mu_2, mu_3 : |
|
Integer degree and order |
|
|
|
prec - precision, default: ``None``. |
|
Providing a precision can |
|
drastically speed up the calculation. |
|
|
|
Returns |
|
======= |
|
|
|
Rational number times the square root of a rational number. |
|
|
|
Examples |
|
======== |
|
>>> from sympy.physics.wigner import real_gaunt |
|
>>> real_gaunt(1,1,2,-1,1,-2) |
|
sqrt(15)/(10*sqrt(pi)) |
|
>>> real_gaunt(10,10,20,-9,-9,0,prec=64) |
|
-0.00002480019791932209313156167176797577821140084216297395518482071448 |
|
|
|
It is an error to use non-integer values for `l` and `\mu`:: |
|
real_gaunt(2.8,0.5,1.3,0,0,0) |
|
Traceback (most recent call last): |
|
... |
|
ValueError: l values must be integer |
|
|
|
real_gaunt(2,2,4,0.7,1,-3.4) |
|
Traceback (most recent call last): |
|
... |
|
ValueError: mu values must be integer |
|
|
|
Notes |
|
===== |
|
|
|
The real Gaunt coefficient inherits from the standard Gaunt coefficient, |
|
the invariance under any permutation of the pairs `(l_i, \mu_i)` and the |
|
requirement that the sum of the `l_i` be even to yield a non-zero value. |
|
It also obeys the following symmetry rules: |
|
|
|
- zero for `l_1`, `l_2`, `l_3` not fulfilling the condition |
|
`l_1 \in \{l_{\text{max}}, l_{\text{max}}-2, \ldots, l_{\text{min}}\}`, |
|
where `l_{\text{max}} = l_2+l_3`, |
|
|
|
.. math:: |
|
\begin{aligned} |
|
l_{\text{min}} = \begin{cases} \kappa(l_2, l_3, \mu_2, \mu_3) & \text{if}\, |
|
\kappa(l_2, l_3, \mu_2, \mu_3) + l_{\text{max}}\, \text{is even} \\ |
|
\kappa(l_2, l_3, \mu_2, \mu_3)+1 & \text{if}\, \kappa(l_2, l_3, \mu_2, \mu_3) + |
|
l_{\text{max}}\, \text{is odd}\end{cases} |
|
\end{aligned} |
|
|
|
and `\kappa(l_2, l_3, \mu_2, \mu_3) = \max{\big(|l_2-l_3|, \min{\big(|\mu_2+\mu_3|, |
|
|\mu_2-\mu_3|\big)}\big)}` |
|
|
|
- zero for an odd number of negative `\mu_i` |
|
|
|
Algorithms |
|
========== |
|
|
|
This function uses the algorithms of [Homeier96]_ and [Rasch03]_ to |
|
calculate the value of the real Gaunt coefficient exactly. Note that |
|
the formula used in [Rasch03]_ contains alternating sums over large |
|
factorials and is therefore unsuitable for finite precision arithmetic |
|
and only useful for a computer algebra system [Rasch03]_. However, this |
|
function can in principle use any algorithm that computes the Gaunt |
|
coefficient, so it is suitable for finite precision arithmetic in so far |
|
as the algorithm which computes the Gaunt coefficient is. |
|
""" |
|
l_1, l_2, l_3, mu_1, mu_2, mu_3 = [ |
|
as_int(i) for i in (l_1, l_2, l_3, mu_1, mu_2, mu_3)] |
|
|
|
|
|
if sum(1 for i in (mu_1, mu_2, mu_3) if i < 0) % 2: |
|
return S.Zero |
|
if (l_1 + l_2 + l_3) % 2: |
|
return S.Zero |
|
lmax = l_2 + l_3 |
|
lmin = max(abs(l_2 - l_3), min(abs(mu_2 + mu_3), abs(mu_2 - mu_3))) |
|
if (lmin + lmax) % 2: |
|
lmin += 1 |
|
if lmin not in range(lmax, lmin - 2, -2): |
|
return S.Zero |
|
|
|
kron_del = lambda i, j: 1 if i == j else 0 |
|
s = lambda e: -1 if e % 2 else 1 |
|
|
|
t = lambda x: 1 if x > 0 else 0 |
|
A = lambda mu, m: t(-mu) * (s(m) * kron_del(m, mu) - kron_del(m, -mu)) |
|
B = lambda mu, m: t(mu) * (kron_del(m, mu) + s(m) * kron_del(m, -mu)) |
|
U = lambda mu, m: kron_del(abs(mu), abs(m)) * (kron_del(mu, 0) * kron_del(m, 0) + (B(mu, m) + I * A(mu, m))/sqrt(2)) |
|
|
|
ugnt = 0 |
|
for m1 in range(-l_1, l_1+1): |
|
U1 = U(mu_1, m1) |
|
for m2 in range(-l_2, l_2+1): |
|
U2 = U(mu_2, m2) |
|
U3 = U(mu_3,-m1-m2) |
|
ugnt = ugnt + re(U1*U2*U3)*gaunt(l_1, l_2, l_3, m1, m2, -m1 - m2, prec=prec) |
|
|
|
return ugnt |
|
|
|
|
|
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) |
|
|
|
such that |
|
|
|
.. math :: |
|
d^{(J)}_{m',m}(\\beta) = \\mathtt{wigner\\_d\\_small(J,beta)[J-mprime,J-m]} |
|
|
|
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): |
|
|
|
|
|
sigmamax = min([J-Mi, J-Mj]) |
|
sigmamin = max([0, -Mi-Mj]) |
|
|
|
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 figure axis, line of nodes, |
|
and vertical. See [Edmonds74]_, however note that the symbols alpha |
|
and gamma are swapped in this implementation. |
|
|
|
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) |
|
|
|
such that |
|
|
|
.. math :: |
|
\\mathcal{D}^{(J)}_{m',m}(\\alpha, \\beta, \\gamma) = |
|
\\mathtt{wigner_d(J, alpha, beta, gamma)[J-mprime,J-m]} |
|
|
|
The components are calculated using the general form [Edmonds74]_, |
|
equation 4.1.12, however note that the angles alpha and gamma are swapped |
|
in this implementation. |
|
|
|
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) |
|
|