""" The implementation of BMS transformations on the waveforms. """
#############################
# Imports
#############################
import numpy as np
from waveformtools.waveformtools import message
from scipy.interpolate import InterpolatedUnivariateSpline
from waveformtools.dataIO import construct_mode_list
[docs]
def compute_supertransl_alpha(supertransl_alpha_modes, theta, phi):
"""Compute the spherical Alpha supertranslation variable
:math:`\\alpha(\\theta, \\phi)` given its modes. This method
just multiplies the alpha modes with their corresponding spherical
harmonic basis functions and returns the summed result.
Parameters
----------
supertransl_alpha_modes : dict
A dictionary of lists, each sublist
containing the set of super-translation
modes corresponding to a particular
:math:`\\ell'.
theta : float
The polar angle :math:`\\theta'.
phi : float
The azimuthal angle :math:`\\phi'.
Returns
--------
supertransl_alpha_sphere : func
A function on the sphere
(arguments :math:`\\theta', math:`\\phi').
"""
# For partial evaluation of functions
# from functools import partial
message(supertransl_alpha_modes.keys())
# Find the extreme ell values.
keys_list = sorted(list(supertransl_alpha_modes.keys()))
# ell_min = int(keys_list[0][1])
# ell_max = int(keys_list[-1][1])
# Import the Spherical Harmonic function
from spectral.spherical.swsh import Yslm_vec
spin_weight = 0
# Ylm = partial(Yslm, spin_weight=0)
# The final function
supertransl_alpha_sphere = 0
theta = np.pi / 2
phi = 0.0
for item in keys_list:
ell = int(item[1])
for m_index in range(2 * ell + 1):
emm = m_index - ell
message("ell is", ell, type(ell), "emm is ", emm)
supertransl_alpha_sphere += supertransl_alpha_modes[item][
m_index
] * Yslm_vec(spin_weight, ell, emm, theta, phi)
return supertransl_alpha_sphere
[docs]
def compute_linear_momentum_contribution_from_news(news_modes, ell, emm):
#dPxdt = np.zeros(len(hdot_lm), dtype=np.complex128)
#dPydt = np.zeros(len(hdot_lm), dtype=np.complex128)
dpdt_xy_lm = news_modes.mode(ell, emm)*(
linear_momentum_alm_func(ell, emm)*np.conj(news_modes.mode(ell, emm+1)) +
linear_momentum_blm_func(ell, -emm)*np.conj(news_modes.mode(ell-1, emm+1)) -
linear_momentum_blm_func(ell+1, emm+1)*np.conj(news_modes.mode(ell+1, emm+1))
)
dpdt_z_lm = news_modes.mode(ell, emm)*(
linear_momentum_clm_func(ell, emm)*np.conj(news_modes.mode(ell, emm)) +
linear_momentum_dlm_func(ell, emm)*np.conj(news_modes.mode(ell-1, emm)) +
linear_momentum_dlm_func(ell+1, emm)*np.conj(news_modes.mode(ell+1, emm))
)
dPxdt_lm = dpdt_xy_lm.real/(8*np.pi)
dPydt_lm = dpdt_xy_lm.imag/(8*np.pi)
dPzdt_lm = dpdt_z_lm/(16*np.pi)
#print("dPzdt", dPzdt_lm)
return dPxdt_lm, dPydt_lm, dPzdt_lm
[docs]
def linear_momentum_alm_func(ell, emm):
return np.sqrt((ell-emm)*(ell+emm+1))/(ell*(ell+1))
[docs]
def linear_momentum_blm_func(ell, emm):
return (1/(2*ell))*np.sqrt((ell-2)*(ell+2)*(ell+emm)*(ell+emm-1)/((2*ell-1)*(2*ell+1)))
[docs]
def linear_momentum_clm_func(ell, emm):
return 2*emm/(ell*(ell+1))
[docs]
def linear_momentum_dlm_func(ell, emm):
return (1/ell)*np.sqrt((ell-2)*(ell+2)*(ell-emm)*(ell+emm)/((2*ell-1)*(2*ell+1)))
[docs]
def compute_impulse_from_force(time_axis, dPxdt, dPydt, dPzdt):
spline_dPxdt = InterpolatedUnivariateSpline(time_axis, dPxdt, k=5)
#spline_dPxdt_imag = InterpolatedUnivariateSpline(time_axis, dPxdt.imag, k=5)
spline_dPydt = InterpolatedUnivariateSpline(time_axis, dPydt, k=5)
#spline_dPydt_imag = InterpolatedUnivariateSpline(time_axis, dPydt.imag, k=5)
spline_dPzdt_real = InterpolatedUnivariateSpline(time_axis, dPzdt.real, k=5)
spline_dPzdt_imag = InterpolatedUnivariateSpline(time_axis, dPzdt.imag, k=5)
dPx = spline_dPxdt.integral(time_axis[0], time_axis[-1]) #+ 1j*spline_dPxdt_imag.integral(time_axis[0], time_axis[-1])
dPy = spline_dPydt.integral(time_axis[0], time_axis[-1]) #+ 1j*spline_dPydt_imag.integral(time_axis[0], time_axis[-1])
dPz = spline_dPzdt_real.integral(time_axis[0], time_axis[-1]) + 1j*spline_dPzdt_imag.integral(time_axis[0], time_axis[-1])
# Factor = lal.C_SI/1000 to get in km/s
return np.array([dPx, dPy, dPz])
[docs]
def f_lm(ell, emm):
''' The flm factor for the angular momentum modes '''
f_lm = np.sqrt( ell*(ell+1) - emm*(emm+1) )
return f_lm
[docs]
def compute_angular_momentum_evolution(strain_modes, news_modes):
dJcx_dt = 0
dJcy_dt = 0
dJcz_dt = 0
factor = 16*np.pi
news_modes_conj = np.conjugate(news_modes)
modes_list = construct_mode_list(ell_max=strain_modes.ell_max-1, spin_weight=-2)
#for ell, emm_list in strain_modes.modes_list:
for ell, emm_list in modes_list:
for emm in emm_list:
#if abs(emm+1)>ell or abs(emm-1)>ell:
# continue
t1 = f_lm(ell, emm)*news_modes_conj.mode(ell, emm+1)
t2 = f_lm(ell, -emm)*news_modes_conj.mode(ell, emm-1)
dJcx_dt += strain_modes.mode(ell, emm)*(t1 + t2)
dJcy_dt += strain_modes.mode(ell, emm)*(t1 - t2)
dJcz_dt += emm*(strain_modes.mode(ell, emm) * news_modes_conj.mode(ell, emm))
dJx_dt = dJcx_dt.imag/(2*factor)
dJy_dt = -dJcy_dt.real/(2*factor)
dJz_dt = dJcz_dt.imag/factor
return np.array([strain_modes.time_axis, dJx_dt, dJy_dt, dJz_dt])
[docs]
def compute_angular_momentum(strain_modes,
news_modes,
t_start=None,
t_end=None,
since_peak=False,
inspiral_only=False):
#modes_list = construct_mode_list(ell_max=strain_modes.ell_max-1, spin_weight=-2)
if since_peak or inspiral_only:
power = strain_modes.get_power_from_news_modes(news_modes)
if since_peak:
t_start = strain_modes.time_axis[np.argmax(power)]
if inspiral_only:
t_end = strain_modes.time_axis[np.argmax(power)]
if t_start is None:
t_start = strain_modes.time_axis[0]
if t_end is None:
t_end = strain_modes.time_axis[-1]
dJ_dt_vec = compute_angular_momentum_evolution(strain_modes, news_modes)
time_axis, dJx_dt, dJy_dt, dJz_dt = dJ_dt_vec
spline_dJx_dt = InterpolatedUnivariateSpline(time_axis, dJx_dt, k=5)
spline_dJy_dt = InterpolatedUnivariateSpline(time_axis, dJy_dt, k=5)
spline_dJz_dt = InterpolatedUnivariateSpline(time_axis, dJz_dt, k=5)
dJx = spline_dJx_dt.integral(t_start, t_end)
dJy = spline_dJy_dt.integral(t_start, t_end)
dJz = spline_dJz_dt.integral(t_start, t_end)
return np.array([dJx, dJy, dJz])