from __future__ import annotations
from typing import SupportsFloat, SupportsInt
import numpy as np
import sympy as sp
[docs]def generate_ls_couplings(
parent_spin: SupportsFloat,
child1_spin: SupportsFloat,
child2_spin: SupportsFloat,
max_L: int = 3,
) -> list[tuple[int, sp.Rational]]:
r"""
>>> generate_ls_couplings(1.5, 0.5, 0)
[(1, 1/2), (2, 1/2)]
"""
s1 = float(child1_spin)
s2 = float(child2_spin)
angular_momenta = create_rational_range(0, max_L)
coupled_spins = create_rational_range(abs(s1 - s2), s1 + s2)
ls_couplings = {
(int(L), S)
for L in angular_momenta
for S in coupled_spins
if abs(L - S) <= parent_spin <= L + S
}
return sorted(ls_couplings)
[docs]def filter_parity_violating_ls(
ls_couplings: list[tuple[int, sp.Rational]],
parent_parity: SupportsInt,
child1_parity: SupportsInt,
child2_parity: SupportsInt,
) -> list[tuple[int, sp.Rational]]:
r"""
>>> LS = generate_ls_couplings(0.5, 1.5, 0) # Λc → Λ(1520)π
>>> LS
[(1, 3/2), (2, 3/2)]
>>> filter_parity_violating_ls(LS, +1, -1, -1)
[(2, 3/2)]
"""
η0, η1, η2 = (
int(parent_parity),
int(child1_parity),
int(child2_parity),
)
return [(L, S) for L, S in ls_couplings if η0 == η1 * η2 * (-1) ** L]
[docs]def create_spin_range(spin: SupportsFloat) -> list[sp.Rational]:
"""
>>> create_spin_range(1.5)
[-3/2, -1/2, 1/2, 3/2]
"""
return create_rational_range(-spin, spin)
[docs]def create_rational_range(
__from: SupportsFloat, __to: SupportsFloat
) -> list[sp.Rational]:
"""
>>> create_rational_range(-0.5, +1.5)
[-1/2, 1/2, 3/2]
"""
spin_range = np.arange(float(__from), +float(__to) + 0.5)
return list(map(sp.Rational, spin_range))