def _LVector(data1, data2, lm, Lvec): """Helper function for the LVector function""" # Big, bad, ugly, obvious way to do the calculation # ================================================= # L+ = Lx + i Ly Lx = (L+ + L-) / 2 # L- = Lx - i Ly Ly = -i (L+ - L-) / 2 for i_mode in range(lm.shape[0]): L = lm[i_mode, 0] M = lm[i_mode, 1] for i_time in range(data1.shape[0]): # Compute first in (+,-,z) basis Lp = (np.conjugate(data1[i_time, i_mode + 1]) * data2[i_time, i_mode] * ladder(L, M) if M + 1 <= L else 0.0 + 0.0j) Lm = (np.conjugate(data1[i_time, i_mode - 1]) * data2[i_time, i_mode] * ladder(L, -M) if M - 1 >= -L else 0.0 + 0.0j) Lz = np.conjugate(data1[i_time, i_mode]) * data2[i_time, i_mode] * M # Convert into (x,y,z) basis Lvec[i_time, 0] += 0.5 * (Lp + Lm) Lvec[i_time, 1] += -0.5j * (Lp - Lm) Lvec[i_time, 2] += Lz return
def _LdtVector(data, datadot, lm, Ldt): """Helper function for the LdtVector function""" # Big, bad, ugly, obvious way to do the calculation # ================================================= # L+ = Lx + i Ly Lx = (L+ + L-) / 2 # L- = Lx - i Ly Ly = -i (L+ - L-) / 2 for i_mode in range(lm.shape[0]): L = lm[i_mode, 0] M = lm[i_mode, 1] for i_time in range(data.shape[0]): # Compute first in (+,-,z) basis Lp = (np.conjugate(data[i_time, i_mode + 1]) * datadot[i_time, i_mode] * ladder(L, M) if M + 1 <= L else 0.0 + 0.0j) Lm = (np.conjugate(data[i_time, i_mode - 1]) * datadot[i_time, i_mode] * ladder(L, -M) if M - 1 >= -L else 0.0 + 0.0j) Lz = np.conjugate(data[i_time, i_mode]) * datadot[i_time, i_mode] * M # Convert into (x,y,z) basis Ldt[i_time, 0] += 0.5 * (Lp.imag + Lm.imag) Ldt[i_time, 1] += -0.5 * (Lp.real - Lm.real) Ldt[i_time, 2] += Lz.imag return
def j_plusminus(ell_min, ell_max, sign): r"""Produce the function j_plus or j_minus, based on sign. The conventions for these matrix elements, to agree with Ruiz+ (2008) [0707.4654], should be: <ellp, mp|j^+|ell, m> = 1.j * np.sqrt((l-m)(l+m+1)) \delta{ellp, ell} \delta{mp, (m+1)} <ellp, mp|j^-|ell, m> = 1.j * np.sqrt((l+m)(l-m+1)) \delta{ellp, ell} \delta{mp, (m-1)} The spinsfast function ladder_operator_coefficient(l, m) gives np.sqrt((l-m)(l+m+1)). """ from spherical_functions import ladder_operator_coefficient as ladder if (sign != 1) and (sign != -1): raise ValueError("sign must be either 1 or -1 in j_plusminus") for ell in range(ell_min, ell_max + 1): for m in range(-ell, ell + 1): mp = round(m + 1 * sign) if (mp < -ell) or (mp > ell): continue yield ell, mp, ell, m, (1.0j * ladder(ell, m * sign))
def j_plusminus(ell_min, ell_max, sign): r"""Produce the function j_plus or j_minus, based on sign. The conventions for these matrix elements, to agree with Ruiz et al. (2008) [0707.4654], should be: ⟨j,n|j⁺|l,m⟩ = i √[(l-m)(l+m+1)] δⱼₗ δₙₘ₊₁ ⟨j,n|j⁻|l,m⟩ = i √[(l+m)(l-m+1)] δⱼₗ δₙₘ₋₁ The spinsfast function `ladder_operator_coefficient(l, m)` gives √[(l-m)(l+m+1)]. """ from spherical_functions import ladder_operator_coefficient as ladder if (sign != 1) and (sign != -1): raise ValueError("sign must be either 1 or -1 in j_plusminus") for ell in range(ell_min, ell_max + 1): for m in range(-ell, ell + 1): mp = round(m + 1 * sign) if (mp < -ell) or (mp > ell): continue yield ell, mp, ell, m, (1.0j * ladder(ell, m * sign))
def _LLMatrix(data, lm, LL): """Helper function for the LLMatrix function""" # Big, bad, ugly, obvious way to do the calculation # ================================================= # L+ = Lx + i Ly Lx = (L+ + L-) / 2 Im(Lx) = ( Im(L+) + Im(L-) ) / 2 # L- = Lx - i Ly Ly = -i (L+ - L-) / 2 Im(Ly) = -( Re(L+) - Re(L-) ) / 2 # Lz = Lz Lz = Lz Im(Lz) = Im(Lz) # LxLx = (L+ + L-)(L+ + L-) / 4 # LxLy = -i(L+ + L-)(L+ - L-) / 4 # LxLz = (L+ + L-)( Lz ) / 2 # LyLx = -i(L+ - L-)(L+ + L-) / 4 # LyLy = -(L+ - L-)(L+ - L-) / 4 # LyLz = -i(L+ - L-)( Lz ) / 2 # LzLx = ( Lz )(L+ + L-) / 2 # LzLy = -i( Lz )(L+ - L-) / 2 # LzLz = ( Lz )( Lz ) for i_mode in range(lm.shape[0]): L = lm[i_mode, 0] M = lm[i_mode, 1] for i_time in range(data.shape[0]): # Compute first in (+,-,z) basis LpLp = (np.conjugate(data[i_time, i_mode + 2]) * data[i_time, i_mode] * (ladder(L, M + 1) * ladder(L, M)) if M + 2 <= L else 0.0 + 0.0j) LpLm = (np.conjugate(data[i_time, i_mode]) * data[i_time, i_mode] * (ladder(L, M - 1) * ladder(L, -M)) if M - 1 >= -L else 0.0 + 0.0j) LmLp = (np.conjugate(data[i_time, i_mode]) * data[i_time, i_mode] * (ladder(L, -(M + 1)) * ladder(L, M)) if M + 1 <= L else 0.0 + 0.0j) LmLm = (np.conjugate(data[i_time, i_mode - 2]) * data[i_time, i_mode] * (ladder(L, -(M - 1)) * ladder(L, -M)) if M - 2 >= -L else 0.0 + 0.0j) LpLz = (np.conjugate(data[i_time, i_mode + 1]) * data[i_time, i_mode] * (ladder(L, M) * M) if M + 1 <= L else 0.0 + 0.0j) LzLp = (np.conjugate(data[i_time, i_mode + 1]) * data[i_time, i_mode] * ((M + 1) * ladder(L, M)) if M + 1 <= L else 0.0 + 0.0j) LmLz = (np.conjugate(data[i_time, i_mode - 1]) * data[i_time, i_mode] * (ladder(L, -M) * M) if M - 1 >= -L else 0.0 + 0.0j) LzLm = (np.conjugate(data[i_time, i_mode - 1]) * data[i_time, i_mode] * ((M - 1) * ladder(L, -M)) if M - 1 >= -L else 0.0 + 0.0j) LzLz = np.conjugate(data[i_time, i_mode]) * data[i_time, i_mode] * M**2 # Convert into (x,y,z) basis LxLx = 0.25 * (LpLp + LmLm + LmLp + LpLm) LxLy = -0.25j * (LpLp - LmLm + LmLp - LpLm) LxLz = 0.5 * (LpLz + LmLz) LyLx = -0.25j * (LpLp - LmLp + LpLm - LmLm) LyLy = -0.25 * (LpLp - LmLp - LpLm + LmLm) LyLz = -0.5j * (LpLz - LmLz) LzLx = 0.5 * (LzLp + LzLm) LzLy = -0.5j * (LzLp - LzLm) # LzLz = (LzLz) # Symmetrize LL[i_time, 0, 0] += LxLx.real LL[i_time, 0, 1] += (LxLy + LyLx).real / 2.0 LL[i_time, 0, 2] += (LxLz + LzLx).real / 2.0 LL[i_time, 1, 0] += (LyLx + LxLy).real / 2.0 LL[i_time, 1, 1] += LyLy.real LL[i_time, 1, 2] += (LyLz + LzLy).real / 2.0 LL[i_time, 2, 0] += (LzLx + LxLz).real / 2.0 LL[i_time, 2, 1] += (LzLy + LyLz).real / 2.0 LL[i_time, 2, 2] += LzLz.real return