From 2623a5b166a49a383c02cd70065848015d940e4d Mon Sep 17 00:00:00 2001 From: Aniket Khairnar Date: Fri, 27 Mar 2026 18:03:44 -0500 Subject: [PATCH 1/4] Adding documentation for the PNBMS frame fixing method --- docs/tutorial_abd.rst | 132 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/docs/tutorial_abd.rst b/docs/tutorial_abd.rst index 7d5766a..1b8aec5 100644 --- a/docs/tutorial_abd.rst +++ b/docs/tutorial_abd.rst @@ -294,8 +294,12 @@ that are easier to understand/analyze. Effectively, mapping to this frame amount in the center-of-mass frame, with no instananeous memory, and its angular velocity in the z-direction. For example, for a remnant black hole, this corresponds to making the coordinates match those of the usual Kerr metric and is therefore incredibly useful (and necessary) for fitting QNMs to NR waveforms. +There is another choice of frame which we call the Post-Newtonian BMS frame (or +PNBMS frame). In this frame, the waveform will agree with the Post-Newtonian +description of the system at early times. -The function ``scri.asymptotic_bondi_data.map_to_superrest_frame`` maps to this exact frame. +The function ``scri.asymptotic_bondi_data.map_to_superrest_frame`` can map to +one of these frames. In particular, it takes as input: * ``t_0``, the time at which to map to the superrest frame; @@ -357,10 +361,16 @@ Example usage of this function could be: For more on the :meth:`scri.WaveformModes` class, i.e., what :math:`h` is in the above code, see https://github.com/moble/scri/blob/main/docs/tutorial_waveformmodes.rst. The CCE output is sometimes very densely sampled in time, which causes the BMS -transformation to the superrest frame to take a long time (more than 10 +transformation to the superrest frame or PNBMS frame to take a long time (more than 10 minutes). An effective way around this is to down sample the CCE data, compute -the BMS transformation to the superrest frame with the down sampled data, and -then apply to the full data. This can be done with the following two functions +the BMS transformation to the appropriate frame with the down sampled data, and +then apply to the full data. + +-------------------------- +Fixing the superrest frame +-------------------------- +The superrest frame of the CCE waveforms can be fixed using the following two +functions. .. code-block:: python @@ -387,6 +397,120 @@ then apply to the full data. This can be done with the following two functions frame_rotation=BMS.frame_rotation.components, boost_velocity=BMS.boost_velocity,) +------------------------------------------ +Fixing the PNBMS frame using PN CoM charge +------------------------------------------ + +The PNBMS frame fixing of CCE waveforms requires ``target_PsiM_input`` (the +Moreschi supermomentum), and ``target_strain_input`` (the PN strain). These +post-Newtonian waveform modes can be generated using the `PostNewtonian.jl +`_ module. We can generate these +waveform modes and provide them as input arguments to the +``map_to_superrest_frame`` function for fixing the PNBMS frame. The generation +of these waveform modes and fixing the frame can be performed using the +following functions. + +.. code-block:: python + + from sxs.julia import PNWaveform + import numpy as np + import sxs + import scri + + def generate_h_and_Psi_M_from_abd(abd, params, t0_pnbms, pnbms_padding): + """This function computes the target strain and target PsiM waveform required for PNBMS frame fixing. + + Parameters + ---------- + abd : AsymptoticBondiData + AsymptoticBondiData object from which the PN waveforms will be computed. + params: tuple + List of intrinsic parameters corresponding to the simulation. Its content should follow the form: + params = M1, M2, chi1, chi2 + where M1, M2 are floats, + chi1 : list of floats (n,3) + chi2 : list of floats (n,3) + t0_pnbms : float + When to map to the PNBMS frame. + pnbms_padding : float + Amount by which to pad around t0 to speed up computations. + This also determines the range over which certain BMS charges will be + computed. + + Returns + ------- + h_pn_scri, Psi_M_scri : scri.WaveformModes object + """ + # First we create a window for frame-fixing using t0 and padding time. + # The window is padded by an additional 200M on both sides of t0. + t_left = t0_pnbms - (pnbms_padding + 200) + t_right = t0_pnbms + (pnbms_padding + 200) + + left_idx = np.abs(abd.t - t_left).argmin() + right_idx = np.abs(abd.t - t_right).argmin() + + h = abd.h[left_idx : right_idx] + t = h.t - h.t[0] + + # The convention for choosing the phase from h_{21} mode and the factor of + # pi/2 is described in . + h_21 = h.data[:, h.index(2,1)] + θ = -1 * np.unwrap(np.angle(-h_21) - np.pi/2) + ω = np.gradient(θ, t) + + cosθ, sinθ = np.cos(θ/2), np.sin(θ/2) + R_i = np.array([cosθ, 0*θ, 0*θ, sinθ]).T + + M1, M2, chi1, chi2 = params + + h_PN = PNWaveform(M1, M2, chi1, chi2, ω[0], modes_function=sxs.julia.h_bang, R_i = R_i[0], saveat = t) + Psi_M_PN = PNWaveform(M1, M2, chi1, chi2, ω[0], modes_function=sxs.julia.Ψ_M_bang, R_i = R_i[0], saveat = t) + + # The PNWaveform function needs the kwarg times to start from t=0. Thus, we + # translate the time array of PN waveform modes to match with the inspiral + # window constructed from the abd object at the end. + h_PN.t += t0_pnbms - (pnbms_padding + 200) + Psi_M_PN.t += t0_pnbms - (pnbms_padding + 200) + + # The sxs.WaveformModes objects should be converted to scri.WaveformModes + # before passing to map_to_superrest_frame. + h_pn_scri = scri.WaveformModes.from_sxs(h_PN) + Psi_M_scri = scri.WaveformModes.from_sxs(Psi_M_PN) + + return h_pn_scri, Psi_M_scri + + def load_waveform_and_fix_to_pnbms(filename: str, params, dt: float = 1.0, + t0_pnbms: float = 1800.0, + pnbms_padding: float = 200.0,) -> + scri.AsymptoticBondiData: + abd = load_waveform(filename, dt) + # params should take the same signature as it does in the previous function. + M1, M2, chi1, chi2 = params + M = M1 + M2 + ν = M1*M2/M**2 + + # We use the parameters of the simulation, and the window information + # (t0_pnbms and pnbms_padding) to generate PN strain and Moreschi + # supermomentum modes data during that window. + h_PN, Psi_M_PN = generate_h_and_Psi_M_from_abd(abd, params, t0_pnbms, pnbms_padding) + + # Compute the BMS transformation to the PNBMS frame and the transformed + # abd object. + abd_prime, BMS, _ = abd.map_to_superrest_frame(t_0=t0_pnbms, padding_time=pnbms_padding, target_PsiM_input=Psi_M_PN, target_strain_input=h_PN, Gfun=analytical_CoM_func, Gparams0=np.zeros(8), Gargsfun=PN_charges(M, ν)) + + return abd_prime + + +This is the recent method for fixing the PNBMS frame described in Khairnar et +al. ``_. The function ``map_to_superrest_frame`` +takes 3 additional keyword arguments - ``Gfun``, ``Gparams0`` and ``Gargsfun``. ``Gfun`` +is the analtyical function used for fitting the CoM charge, ``Gparams0`` is the +initial guess for the fitting parameters, and ``Gargsfun`` are additional +arguments passed to Gfun. See the documentation of +``com_transformation_to_map_to_superrest_frame`` in +``scri.asymptotic_bondi_data.map_to_superrest_frame`` for additional details on +the signature of ``Gfun`` and ``Gargsfun``. + The parameter `dt` can be used to choose the time sampling for the waveform ABD object you get back, with default of `1M`. Reducing the time sampling for the waveform ABD is also useful if the CCE data was written too From ecb18a1ca0ab4ea38d5af63952ec6c6041165396 Mon Sep 17 00:00:00 2001 From: Aniket Khairnar Date: Sat, 28 Mar 2026 16:48:06 -0500 Subject: [PATCH 2/4] Adding line breaks and fixing minor bugs --- docs/tutorial_abd.rst | 166 +++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 75 deletions(-) diff --git a/docs/tutorial_abd.rst b/docs/tutorial_abd.rst index 1b8aec5..a8ccf45 100644 --- a/docs/tutorial_abd.rst +++ b/docs/tutorial_abd.rst @@ -298,8 +298,8 @@ There is another choice of frame which we call the Post-Newtonian BMS frame (or PNBMS frame). In this frame, the waveform will agree with the Post-Newtonian description of the system at early times. -The function ``scri.asymptotic_bondi_data.map_to_superrest_frame`` can map to -one of these frames. +The function :meth:`scri.asymptotic_bondi_data.map_to_superrest_frame.map_to_superrest_frame` can map +to one of these frames. In particular, it takes as input: * ``t_0``, the time at which to map to the superrest frame; @@ -337,7 +337,7 @@ It also can perform a number of other important post-processing steps, such as: We recommend including all of these post-processing steps when processing SpECTRE CCE output. -To obtain the strain :math:`h` from the ``abd`` object, one can use the function ``scri.asymptotic_bondi_data.map_to_superrest_frame.MT_to_WM`` via ``h = MT_to_WM(2.0*abd.sigma.bar)``. +To obtain the strain :math:`h` from the ``abd`` object, one can use the function :meth:`scri.asymptotic_bondi_data.map_to_superrest_frame.MT_to_WM` via ``h = MT_to_WM(2.0*abd.sigma.bar)``. This is because the strain :math:`h` is related to the shear :math:`\sigma` via :math:`h=2\overline{\sigma}`. Example usage of this function could be: @@ -401,7 +401,7 @@ functions. Fixing the PNBMS frame using PN CoM charge ------------------------------------------ -The PNBMS frame fixing of CCE waveforms requires ``target_PsiM_input`` (the +The PNBMS frame fixing of CCE waveforms requires ``target_PsiM_input`` (the PN Moreschi supermomentum), and ``target_strain_input`` (the PN strain). These post-Newtonian waveform modes can be generated using the `PostNewtonian.jl `_ module. We can generate these @@ -416,78 +416,86 @@ following functions. import numpy as np import sxs import scri + from scri.pn.boosted_comcharge import PN_charges, analytical_CoM_func def generate_h_and_Psi_M_from_abd(abd, params, t0_pnbms, pnbms_padding): - """This function computes the target strain and target PsiM waveform required for PNBMS frame fixing. - - Parameters - ---------- - abd : AsymptoticBondiData - AsymptoticBondiData object from which the PN waveforms will be computed. - params: tuple - List of intrinsic parameters corresponding to the simulation. Its content should follow the form: - params = M1, M2, chi1, chi2 - where M1, M2 are floats, - chi1 : list of floats (n,3) - chi2 : list of floats (n,3) - t0_pnbms : float - When to map to the PNBMS frame. - pnbms_padding : float - Amount by which to pad around t0 to speed up computations. - This also determines the range over which certain BMS charges will be - computed. - - Returns - ------- - h_pn_scri, Psi_M_scri : scri.WaveformModes object - """ - # First we create a window for frame-fixing using t0 and padding time. - # The window is padded by an additional 200M on both sides of t0. - t_left = t0_pnbms - (pnbms_padding + 200) - t_right = t0_pnbms + (pnbms_padding + 200) - - left_idx = np.abs(abd.t - t_left).argmin() - right_idx = np.abs(abd.t - t_right).argmin() - - h = abd.h[left_idx : right_idx] - t = h.t - h.t[0] - - # The convention for choosing the phase from h_{21} mode and the factor of - # pi/2 is described in . - h_21 = h.data[:, h.index(2,1)] - θ = -1 * np.unwrap(np.angle(-h_21) - np.pi/2) - ω = np.gradient(θ, t) - - cosθ, sinθ = np.cos(θ/2), np.sin(θ/2) - R_i = np.array([cosθ, 0*θ, 0*θ, sinθ]).T - - M1, M2, chi1, chi2 = params - - h_PN = PNWaveform(M1, M2, chi1, chi2, ω[0], modes_function=sxs.julia.h_bang, R_i = R_i[0], saveat = t) - Psi_M_PN = PNWaveform(M1, M2, chi1, chi2, ω[0], modes_function=sxs.julia.Ψ_M_bang, R_i = R_i[0], saveat = t) - - # The PNWaveform function needs the kwarg times to start from t=0. Thus, we - # translate the time array of PN waveform modes to match with the inspiral - # window constructed from the abd object at the end. - h_PN.t += t0_pnbms - (pnbms_padding + 200) - Psi_M_PN.t += t0_pnbms - (pnbms_padding + 200) - - # The sxs.WaveformModes objects should be converted to scri.WaveformModes - # before passing to map_to_superrest_frame. - h_pn_scri = scri.WaveformModes.from_sxs(h_PN) - Psi_M_scri = scri.WaveformModes.from_sxs(Psi_M_PN) - - return h_pn_scri, Psi_M_scri - - def load_waveform_and_fix_to_pnbms(filename: str, params, dt: float = 1.0, - t0_pnbms: float = 1800.0, - pnbms_padding: float = 200.0,) -> - scri.AsymptoticBondiData: + """This function computes the target strain and target PsiM waveform + required for PNBMS frame fixing. + + Parameters + ---------- + abd : AsymptoticBondiData + AsymptoticBondiData object from which the PN waveforms will be computed. + params: tuple + List of intrinsic parameters corresponding to the simulation. Its + content should follow the form: + params = M1, M2, chi1, chi2 + where M1, M2 are floats, + chi1 : list of floats (n,3) + chi2 : list of floats (n,3) + t0_pnbms : float + When to map to the PNBMS frame. + pnbms_padding : float + Amount by which to pad around t0 to speed up computations. + This also determines the range over which certain BMS charges will be + computed. + + Returns + ------- + h_pn_scri, Psi_M_scri : scri.WaveformModes object + """ + # First we create a window for frame-fixing using t0 and padding time. + # The window is padded by an additional 200M on both sides of t0. + t_left = t0_pnbms - (pnbms_padding + 200) + t_right = t0_pnbms + (pnbms_padding + 200) + + left_idx = np.abs(abd.t - t_left).argmin() + right_idx = np.abs(abd.t - t_right).argmin() + + h = abd.h[left_idx:right_idx] + t = h.t - h.t[0] + + # The convention for choosing the phase from h_{21} mode and the factor of + # pi/2 is described in . + h_21 = h.data[:, h.index(2, 1)] + θ = -1 * np.unwrap(np.angle(-h_21) - np.pi / 2) + ω = np.gradient(θ, t)[0] + + R_i = np.array([np.cos(θ[0] / 2), 0, 0, np.sin(θ[0] / 2)]).T + + M1, M2, chi1, chi2 = params + + h_PN = PNWaveform(M1, M2, chi1, chi2, ω, modes_function=sxs.julia.h_bang, + R_i=R_i, saveat=t) + Psi_M_PN = PNWaveform(M1, M2, chi1, chi2, ω, + modes_function=sxs.julia.Ψ_M_bang, R_i=R_i, saveat=t) + + # The PNWaveform function needs the kwarg times to start from t=0. Thus, we + # translate the time array of PN waveform modes to match with the inspiral + # window constructed from the abd object at the end. + h_PN.t += t0_pnbms - (pnbms_padding + 200) + Psi_M_PN.t += t0_pnbms - (pnbms_padding + 200) + + # The sxs.WaveformModes objects should be converted to scri.WaveformModes + # before passing to map_to_superrest_frame. + h_pn_scri = scri.WaveformModes.from_sxs(h_PN) + Psi_M_scri = scri.WaveformModes.from_sxs(Psi_M_PN) + + return h_pn_scri, Psi_M_scri + + def load_waveform_and_fix_to_pnbms( + filename: str, + params, + dt: float = 1.0, + t0_pnbms: float = 1800.0, + pnbms_padding: float = 200.0, + ) -> scri.AsymptoticBondiData: abd = load_waveform(filename, dt) - # params should take the same signature as it does in the previous function. + # params should take the same signature as it does in the previous + # function. M1, M2, chi1, chi2 = params M = M1 + M2 - ν = M1*M2/M**2 + ν = M1 * M2 / M**2 # We use the parameters of the simulation, and the window information # (t0_pnbms and pnbms_padding) to generate PN strain and Moreschi @@ -496,7 +504,15 @@ following functions. # Compute the BMS transformation to the PNBMS frame and the transformed # abd object. - abd_prime, BMS, _ = abd.map_to_superrest_frame(t_0=t0_pnbms, padding_time=pnbms_padding, target_PsiM_input=Psi_M_PN, target_strain_input=h_PN, Gfun=analytical_CoM_func, Gparams0=np.zeros(8), Gargsfun=PN_charges(M, ν)) + abd_prime, BMS, _ = abd.map_to_superrest_frame( + t_0=t0_pnbms, + padding_time=pnbms_padding, + target_PsiM_input=Psi_M_PN, + target_strain_input=h_PN, + Gfun=analytical_CoM_func, + Gparams0=np.zeros(8), + Gargsfun=PN_charges(M, ν), + ) return abd_prime @@ -507,9 +523,9 @@ takes 3 additional keyword arguments - ``Gfun``, ``Gparams0`` and ``Gargsfun``. is the analtyical function used for fitting the CoM charge, ``Gparams0`` is the initial guess for the fitting parameters, and ``Gargsfun`` are additional arguments passed to Gfun. See the documentation of -``com_transformation_to_map_to_superrest_frame`` in -``scri.asymptotic_bondi_data.map_to_superrest_frame`` for additional details on -the signature of ``Gfun`` and ``Gargsfun``. +:meth:`scri.asymptotic_bondi_data.map_to_superrest_frame.com_transformation_to_map_to_superrest_frame` +in :meth:`scri.asymptotic_bondi_data.map_to_superrest_frame` for additional +details on the signature of ``Gfun`` and ``Gargsfun``. The parameter `dt` can be used to choose the time sampling for the waveform ABD object you get back, with default of `1M`. Reducing the time From f2feed8ddd3b427fb8468f09b07894ccb9693621 Mon Sep 17 00:00:00 2001 From: Aniket Khairnar Date: Mon, 30 Mar 2026 06:19:56 -0500 Subject: [PATCH 3/4] Fixed the rendering of tutorial_bms --- docs/tutorial_bms.rst | 229 ++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 107 deletions(-) diff --git a/docs/tutorial_bms.rst b/docs/tutorial_bms.rst index 13f9367..b0a65ed 100644 --- a/docs/tutorial_bms.rst +++ b/docs/tutorial_bms.rst @@ -6,13 +6,13 @@ Tutorial: BMSTransformation/LorentzTransformation The :meth:`scri.bms_transformations.BMSTransformation` and :meth:`scri.bms_transformations.LorentzTransformation` classes are a convenient way -to store and work with BMS and Lorentz transformations. The LorentzTransformation class +to store and work with BMS and Lorentz transformations. The ``LorentzTransformation`` class takes as input a frame rotation and a boost and then enables one to convert these -transformations from their axis-angle representation to their $SL(2,\\mathbb{C})$ representation. -The BMSTransformation class is effectively the LorentzTransformation class, but also takes as input +transformations from their axis-angle representation to their :math:`\text{SL}(2,\mathbb{C})` representation. +The ``BMSTransformation`` class is effectively the ``LorentzTransformation`` class, but also takes as input a supertranslation (which includes the usual spacetime translations). -The BMSTransformation and LorentzTransformation classes make it simple to reorder the +The ``BMSTransformation`` and ``LorentzTransformation`` classes make it simple to reorder the individual components of a transformation, compute the inverse of a transformation, and compose two transformations. @@ -20,129 +20,142 @@ and compose two transformations. Theory behind the Code ====================== -We consider a spacetime $(\\hat{M},\\hat{g}_{ab})$ to be asymptotically Minkowskian at null infinity -if there exists a manifold $M$ equipped with a metric $g_{ab}$ and boundary $\\mathcal{I}$, -and a diffeomorphism from $\\hat{M}$ to the interior $M\\backslash I$ such that: - -#. there exists a smooth function $\\Omega$ (the conformal factor) on $M$ such that - $g_{ab}=\\Omega^{2}\\hat{g}_{ab}$ on $\\hat{M}$, $\\Omega=0$ on $\\mathcal{I}$, - and $n_{a}=\\nabla_{a}\\Omega$ is nowhere vanishing on $\\mathcal{I}$; -#. $\\mathcal{I}$ is topologically $\\mathbb{S}^{2}\\times\\mathbb{R}$; -#. $\\hat{g}_{ab}$ satisfies Einstein's equations - $\\hat{R}_{ab}-\\frac{1}{2}\\hat{R}\\hat{g}_{ab}=8\\pi G\\hat{T}_{ab}$, where - $\\Omega^{-2}\\hat{T}_{ab}$ has a smooth limit to $\\mathcal{I}$; and, -#. the integral curves of $n^{a}$ are complete on $\\mathcal{I}$ for any choice of - the conformal factor such that $\\nabla_{a}n^{a}=0$ on $\\mathcal{I}$. +We consider a spacetime :math:`(\hat{M},\hat{g}_{ab})` to be asymptotically Minkowskian at null infinity +if there exists a manifold :math:`M` equipped with a metric :math:`g_{ab}` and boundary :math:`\mathscr{I}`, +and a diffeomorphism from :math:`\hat{M}` to the interior :math:`M\backslash \mathscr{I}` such that: + +#. there exists a smooth function :math:`\Omega` (the conformal factor) on + :math:`M` such that :math:`g_{ab}=\Omega^{2}\hat{g}_{ab}` on :math:`\hat{M}`, + :math:`\Omega=0` on :math:`\mathscr{I}`, + and :math:`n_{a}=\nabla_{a}\Omega` is nowhere vanishing on :math:`\mathscr{I}`; +#. :math:`\mathscr{I}` is topologically :math:`\mathbb{S}^{2}\times\mathbb{R}`; +#. :math:`\hat{g}_{ab}` satisfies Einstein's equations + :math:`\hat{R}_{ab}-\frac{1}{2}\hat{R}\hat{g}_{ab}=8\pi G\hat{T}_{ab}`, where + :math:`\Omega^{-2}\hat{T}_{ab}` has a smooth limit to :math:`\mathscr{I}`; and, +#. the integral curves of :math:`n^{a}` are complete on :math:`\mathscr{I}` for any choice of + the conformal factor such that :math:`\nabla_{a}n^{a}=0` on :math:`\mathscr{I}`. -For these spacetimes, their asymptotic symmetry group is known as BMS group $\\mathfrak{B}$. -Formally, the BMS group is the semi-direct product of the Lorentz group $\\mathcal{L}\\simeq SL(2,\\mathbb{C})$ -and an infinite-dimensional (Abelian) group $\\mathcal{S}$ of supertranslations $\\mathcal{S}$. -That is, $\\mathfrak{B}\\equiv SL(2,\\mathbb{C})\\ltimes\\mathcal{S}$, where $\\mathcal{S}$ is the -group generated by vector fields $fn^{a}$ on $\\mathcal{I}$ for $f$ a -real-valued scalar function on $\\mathbb{S}^{2}$ satisfying $\\mathcal{L}_{n}f=0$, -with $\\mathcal{L}_{n}f$ being the Lie derivative of $f$ along the vector field $n$. -(Note that $\\mathcal{S}$ is an extension of the usual translation group $\\mathcal{T}$; -this can be realized by taking $f$ to be the $\\ell\\leq1$ spherical harmonics.) - -Consequently, any element of $\\mathfrak{B}$ can be written as a supertranslation +For these spacetimes, their asymptotic symmetry group is known as BMS group :math:`\mathfrak{B}`. +Formally, the BMS group is the semi-direct product of the Lorentz group :math:`\mathcal{L}\simeq SL(2,\mathbb{C})` +and an infinite-dimensional (Abelian) group :math:`\mathcal{S}` of supertranslations :math:`\mathcal{S}`. +That is, :math:`\mathfrak{B}\equiv SL(2,\mathbb{C})\ltimes\mathcal{S}`, where :math:`\mathcal{S}` is the +group generated by vector fields :math:`fn^{a}` on :math:`\mathscr{I}` for `f` a +real-valued scalar function on :math:`\mathbb{S}^{2}` satisfying :math:`\mathcal{L}_{n}f=0`, +with :math:`\mathcal{L}_{n}f` being the Lie derivative of `f` along the vector field `n`. +(Note that :math:`\mathcal{S}` is an extension of the usual translation group :math:`\mathcal{T}`; +this can be realized by taking `f` to be the :math:`\ell\leq1` spherical harmonics.) + +Consequently, any element of :math:`\mathfrak{B}` can be written as a supertranslation followed by a rotation and a boost, seeing as any Lorentz transformation itself can be written as a rotation followed by a boost or vice versa. ----------------------------------------------------------------------------------- -Determining the $SL(2,\\mathbb{C})$ representation of a Lorentz transformation +Determining the :math:`\text{SL}(2,\mathbb{C})` representation of a Lorentz transformation ----------------------------------------------------------------------------------- -For a rotation $R$ by angle $\\theta$ about the axis $\\hat{r}=\\left(r_{x},r_{y},r_{z}\\right)$, +For a rotation `R` by angle :math:`\theta` about the axis :math:`\hat{r}=\left(r_{x},r_{y},r_{z}\right)`, one may write this as the quaternion -$$\\mathbf{q}=\\exp\\left(\\frac{1}{2}\\theta\\,\\hat{r}\\right)= -\\cos(\\theta/2)\\mathbf{I}+\\left(r_{x}\\mathbf{i}+r_{y}\\mathbf{j}+r_{z}\\mathbf{k}\\right)\\sin(\\theta/2),$$ - -where $\\mathbf{I}$, $\\mathbf{i}$, $\\mathbf{j}$, and $\\mathbf{k}$ are the elementary quaternions -obeying the usual multiplication rules. Using spin matrices, i.e., elements of $SL(2,\\mathbb{C})$, +.. math:: + \mathbf{q}=\exp\left(\frac{1}{2}\theta\,\hat{r}\right)= + \cos(\theta/2)\mathbf{I}+\left(r_{x}\mathbf{i}+r_{y}\mathbf{j}+r_{z}\mathbf{k}\right)\sin(\theta/2), + +where :math:`\mathbf{I}`, :math:`\mathbf{i}`, :math:`\mathbf{j}`, and :math:`\mathbf{k}` are the elementary quaternions +obeying the usual multiplication rules. Using spin matrices, i.e., elements of :math:`\text{SL}(2,\mathbb{C})`, one may also write these elementary quaternions as -$$\\mathbf{\\sigma}\\equiv\\left(\\mathbf{I},\\mathbf{i},\\mathbf{j},\\mathbf{k}\\right)= -\\left(\\begin{pmatrix}1&0\\\\0&1\\end{pmatrix},\\begin{pmatrix}0&i\\\\i&0\\end{pmatrix}, -\\begin{pmatrix}0&-1\\\\1&0\\end{pmatrix},\\begin{pmatrix}i&0\\\\0&-i\\end{pmatrix}\\right).$$ +.. math:: + \mathbf{\sigma}\equiv\left(\mathbf{I},\mathbf{i},\mathbf{j},\mathbf{k}\right)= + \left(\begin{pmatrix}1&0\\0&1\end{pmatrix},\begin{pmatrix}0&i\\i&0\end{pmatrix}, + \begin{pmatrix}0&-1\\1&0\end{pmatrix},\begin{pmatrix}i&0\\0&-i\end{pmatrix}\right). -Therefore, a rotation by angle $\\theta$ about the axis $\\hat{r}=\\left(r_{x},r_{y},r_{z}\\right)$ -has the $SL(2,\\mathbb{C})$ representation +Therefore, a rotation by angle :math:`\theta` about the axis :math:`\hat{r}=\left(r_{x},r_{y},r_{z}\right)` +has the :math:`\text{SL}(2,\mathbb{C})` representation -$$\\tilde{R}=\\left(\\cos(\\theta/2),\\hat{r}\\sin(\\theta/2)\\right)\\mathbf{\\sigma}.$$ +.. math:: + \tilde{R}=\left(\cos(\theta/2),\hat{r}\sin(\theta/2)\right)\mathbf{\sigma}. -Note that in this equation $\\tilde{R}$ is a unitary matrix. -Furthermore, since a boost $B$ by rapidity $w$ along -the axis $\\hat{v}=\\left(v_{x},v_{y},v_{z}\\right)$ is nothing more than a rotation -by angle $iw$ about the axis $\\hat{v}=\\left(v_{x},v_{y},v_{z}\\right)$, a boost -has the $SL(2,\\mathbb{C})$ representation +Note that in this equation :math:`\tilde{R}` is a unitary matrix. +Furthermore, since a boost `B` by rapidity `w` along +the axis :math:`\hat{v}=\left(v_{x},v_{y},v_{z}\right)` is nothing more than a rotation +by angle `iw` about the axis :math:`\hat{v}=\left(v_{x},v_{y},v_{z}\right)`, a boost +has the :math:`\text{SL}(2,\mathbb{C})` representation -$$\\tilde{B}=\\left(\\cosh(w/2),i\\hat{v}\\sinh(w/2)\\right)\\cdot\\mathbf{\\sigma}.$$ +.. math:: + \tilde{B}=\left(\cosh(w/2),i\hat{v}\sinh(w/2)\right)\cdot\mathbf{\sigma}. -Note that in this equation $\\tilde{B}$ is a Hermitian matrix; by a similarity transformation, -it can be brought to the form $\\text{diag}(\\exp(w/2),\\exp(-w/2))$. -Consequently, a Lorentz transformation $L=B\\cdot R$ has the $SL(2,\\mathbb{C})$ representation +Note that in this equation :math:`\tilde{B}` is a Hermitian matrix; by a similarity transformation, +it can be brought to the form :math:`\text{diag}(\exp(w/2),\exp(-w/2))`. +Consequently, a Lorentz transformation :math:`L=B\cdot R` has the :math:`\text{SL}(2,\mathbb{C})` representation + +.. math:: + \tilde{L}=\tilde{B}\cdot\tilde{R}=\left[\left(\cosh(w/2),i\hat{v}\sinh(w/2)\right)\cdot\mathbf{\sigma}\right] + \cdot\left[\left(\cos(\theta/2),\hat{r}\sin(\theta/2)\right)\cdot\mathbf{\sigma}\right]. -$$\\tilde{L}=\\tilde{B}\\cdot\\tilde{R}=\\left[\\left(\\cosh(w/2),i\\hat{v}\\sinh(w/2)\\right)\\cdot\\mathbf{\\sigma}\\right] -\\cdot\\left[\\left(\\cos(\\theta/2),\\hat{r}\\sin(\\theta/2)\\right)\\cdot\\mathbf{\\sigma}\\right].$$ Let us make the following remark. What is shown above is for a *passive* Lorentz transformation. Put differently, the transformation is acting on the coordinates themselves. -Under $L$, our original Minkowski coordinates $X$ are transformed to -an intermediate coordinate system $X'$ by a rotation, and then to a -final coordinate system $X''$ by a boost. The parameters of the boost vector $\\vec{v}$ -can be interpreted *as a boost vector in the* $X'$ *coordinate system*. +Under :math:`L`, our original Minkowski coordinates `X` are transformed to +an intermediate coordinate system `X'` by a rotation, and then to a +final coordinate system `X''` by a boost. The parameters of the boost vector :math:`\vec{v}` +can be interpreted *as a boost vector in the* `X'` *coordinate system*. --------------------------------------------------------------------------------- -Determining the rotation and boost from a $SL(2,\\mathbb{C})$ representation +Determining the rotation and boost from a :math:`\text{SL}(2,\mathbb{C})` representation --------------------------------------------------------------------------------- -Given the $SL(2,\\mathbb{C})$ representation of a Lorentz transformation $L$, say +Given the :math:`\text{SL}(2,\mathbb{C})` representation of a Lorentz transformation :math:`L`, say -$$\\tilde{L}=\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}$$ +.. math:: + \tilde{L}=\begin{pmatrix}a&b\\c&d\end{pmatrix} -for $a,b,c,d\\in\\mathbb{C}$ with $ad-bc=1$, using singular value decomposition we may write $\\tilde{L}$ as +for :math:`a,b,c,d\in\mathbb{C}` with :math:`ad-bc=1`, using singular value decomposition we may write :math:`\tilde{L}` as -$$\\tilde{L}=U\\cdot\\Sigma\\cdot V^{\\dagger},$$ +.. math:: + \tilde{L}=U\cdot\Sigma\cdot V^{\dagger}, -where $U$ is a unitary matrix, $\\Sigma$ is a diagonal Hermitian matrix, and $V$ -is a complex unitary matrix with $V^{\\dagger}$ being its conjugate transpose. -Because of this, we may also write $\\tilde{L}$ as +where :math:`U` is a unitary matrix, :math:`\Sigma` is a diagonal Hermitian matrix, and :math:`V` +is a complex unitary matrix with :math:`V^{\dagger}` being its conjugate transpose. +Because of this, we may also write :math:`\tilde{L}` as -$$\\tilde{L}=\\left(U\\cdot\\Sigma\\cdot U^{\\dagger}\\right)\\cdot\\left(U\\cdot V^{\\dagger}\\right)$$ +.. math:: + \tilde{L}=\left(U\cdot\Sigma\cdot U^{\dagger}\right)\cdot\left(U\cdot V^{\dagger}\right) or -$$\\tilde{L}=\\left(U\\cdot V^{\\dagger}\\right)\\cdot\\left(V\\cdot\\Sigma\\cdot V^{\\dagger}\\right),$$ +.. math:: + \tilde{L}=\left(U\cdot V^{\dagger}\right)\cdot\left(V\cdot\Sigma\cdot V^{\dagger}\right), which may then be interpreted in terms of a pure rotation and a pure boost as -$$\\tilde{L}=\\tilde{B}\\cdot\\tilde{R}\\quad\\text{with}\\quad -\\tilde{B}\\equiv U\\cdot\\Sigma\\cdot U^{\\dagger}\\quad\\text{and} -\\quad\\tilde{R}\\equiv U\\cdot V^{\\dagger}$$ +.. math:: + \tilde{L}=\tilde{B}\cdot\tilde{R}\quad\text{with}\quad + \tilde{B}\equiv U\cdot\Sigma\cdot U^{\dagger}\quad\text{and} + \quad\tilde{R}\equiv U\cdot V^{\dagger} or -$$\\tilde{L}=\\tilde{R}'\\cdot\\tilde{B}'\\quad\\text{with}\\quad -\\tilde{R}'\\equiv U\\cdot V^{\\dagger}\\quad\\text{and} -\\quad\\tilde{B}'\\equiv V\\cdot\\Sigma\\cdot V^{\\dagger},$$ +.. math:: + \tilde{L}=\tilde{R}'\cdot\tilde{B}'\quad\text{with}\quad + \tilde{R}'\equiv U\cdot V^{\dagger}\quad\text{and} + \quad\tilde{B}'\equiv V\cdot\Sigma\cdot V^{\dagger}, since pure rotations and pure boosts have unitary spin-matrix and positive definite Hermitian spin-matrix representations. These are examples of polar decompositions, which for invertible matrices are unique. -In what follows we drop the primes on $\\tilde{R}'$ and $\\tilde{B}'$ in the final equation -if using the form of $\\tilde{L}$ in said equation. -With these $SL(2,\\mathbb{C})$ representations, one may then obtain the +In what follows we drop the primes on :math:`\tilde{R}'` and :math:`\tilde{B}'` in the final equation +if using the form of :math:`\tilde{L}` in said equation. +With these :math:`\text{SL}(2,\mathbb{C})` representations, one may then obtain the angle-axis representation of these pure Lorentz transformations via -$$ -R=\\left(\\cos(\\theta/2),\\hat{r}\\sin(\\theta/2)\\right)_{k}= -\\frac{1}{2}\\eta_{k}\\text{Tr}\\left[\\tilde{R}\\cdot\\mathbf{\\sigma}_{k}\\right];\\\\ -B=\\left(\\cosh(w/2),i\\hat{v}\\sinh(w/2)\\right)_{k}= -\\frac{1}{2}\\eta_{k}\\text{Tr}\\left[\\tilde{B}\\cdot\\mathbf{\\sigma}_{k}\\right],$$ +.. math:: + R&=\left(\cos(\theta/2),\hat{r}\sin(\theta/2)\right)_{k}= + \frac{1}{2}\eta_{k}\text{Tr}\left[\tilde{R}\cdot\mathbf{\sigma}_{k}\right];\\ + B&=\left(\cosh(w/2),i\hat{v}\sinh(w/2)\right)_{k}= + \frac{1}{2}\eta_{k}\text{Tr}\left[\tilde{B}\cdot\mathbf{\sigma}_{k}\right], -where $\\eta_{k}=(1,-1,-1,-1)_{k}$. With an understanding of how to map an -arbitrary Lorentz transformation to its unique $SL(2,\\mathbb{C})$ representation and back, +where :math:`\eta_{k}=(1,-1,-1,-1)_{k}`. With an understanding of how to map an +arbitrary Lorentz transformation to its unique :math:`\text{SL}(2,\mathbb{C})` representation and back, reordering, inverting, and composing Lorentz transformations now becomes trivial. Thus, working with BMS transformations is also trivial, since supertranslations are normal in the BMS group. @@ -153,44 +166,46 @@ Compose two elements of the BMS group We will write a BMS element as -$$g=l\\circ s$$ +.. math:: + g=l\circ s -and avoid using $b$ or $B$, which could ambiguously stand for either BMS or boost. +and avoid using `b` or `B`, which could ambiguously stand for either BMS or boost. The first thing to note is that since supertranslations are normal in BMS, this decomposition is well-defined. Specifically, consider the quotient homomorphism -$\\varphi:\\mathfrak{B}\\to\\mathfrak{B}/\\mathcal{S}\\simeq\\mathcal{L}$. -We can say that a BMS element is a ``pure supertranslation'' if it is in -$\\ker\\varphi$, i.e. $\\varphi(s)=e\\in\\mathcal{L}$. -The Lorentz transformation of a BMS transformation $L=\\varphi(g)$ is well-defined. -All the elements in the preimage $\\varphi^{-1}(L)$ differ by pure supertranslations (elements of the kernel). -But the element $l\\in \\varphi^{-1}(L)$ above is unique whether we choose to do a left or right decomposition: -since supertranslations are a normal subgroup, we can write $s = l^{-1} \\circ \\hat{s} \\circ l$, -where $\\hat{s}=l \\circ s \\circ l^{-1}$ is another supertranslation that is distinct unless $l=e$. -This provides the other decomposition of $g$ in terms of a pure supertranlsation and a Lorentz transformation, -$g=\\hat{s}\\circ l$. - -With this, consider taking the composition of $g_{1},g_{2}\\in\\mathfrak{B}$, - -$$g=g_2 \\circ g_1$$ - -$$g=l_2 \\circ s_2\\circ l_1\\circ s_1.$$ - -As before, since $s_2$ is in the normal subgroup, we can write it as +:math:`\varphi:\mathfrak{B}\to\mathfrak{B}/\mathcal{S}\simeq\mathcal{L}`. +We can say that a BMS element is a `pure supertranslation` if it is in +ker :math:`\varphi`, i.e. :math:`\varphi(s)=e\in\mathcal{L}`. +The Lorentz transformation of a BMS transformation :math:`L=\varphi(g)` is well-defined. +All the elements in the preimage :math:`\varphi^{-1}(L)` differ by pure supertranslations (elements of the kernel). +But the element :math:`l\in \varphi^{-1}(L)` above is unique whether we choose to do a left or right decomposition: +since supertranslations are a normal subgroup, we can write :math:`s = l^{-1} \circ \hat{s} \circ l`, +where :math:`\hat{s}=l \circ s \circ l^{-1}` is another supertranslation that is distinct unless :math:`l=e`. +This provides the other decomposition of `g` in terms of a pure supertranlsation and a Lorentz transformation, +:math:`g=\hat{s}\circ l`. + +With this, consider taking the composition of :math:`g_{1},g_{2}\in\mathfrak{B}`, + +.. math:: + g&=g_2 \circ g_1\\ + g&=l_2 \circ s_2\circ l_1\circ s_1. + +As before, since :math:`S_2` is in the normal subgroup, we can write it as conjugate to another pure supertranslation, namely -$$s_2=l_1\\circ s'\\circ l_1^{-1},$$ - -$$l_1^{-1}\\circ s_2\\circ l_1 = s'.$$ +.. math:: + s_2=l_1\circ s'\circ l_1^{-1},\\ + l_1^{-1}\circ s_2\circ l_1 = s'. Combining and adding parentheses we get -$$g = (l_2\\circ l_1)\\circ(s'\\circ s_1).$$ +.. math:: + g = (l_2 \circ l_1)\circ(s'\circ s_1). ============================ Creating a BMSTransformation ============================ -A BMSTransformation object consisting of a +A ``BMSTransformation`` object consisting of a supertranslation, frame rotation, and boost (in that order) can be created via the following: From 48517eca28aacfb0a722187cb578ef816b27db93 Mon Sep 17 00:00:00 2001 From: Aniket Khairnar Date: Mon, 6 Apr 2026 16:10:35 -0500 Subject: [PATCH 4/4] Minor changes to abd tutorial --- docs/tutorial_abd.rst | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/tutorial_abd.rst b/docs/tutorial_abd.rst index a8ccf45..29f6dc8 100644 --- a/docs/tutorial_abd.rst +++ b/docs/tutorial_abd.rst @@ -452,16 +452,21 @@ following functions. left_idx = np.abs(abd.t - t_left).argmin() right_idx = np.abs(abd.t - t_right).argmin() - h = abd.h[left_idx:right_idx] + h = abd.h[left_idx : right_idx] t = h.t - h.t[0] + N = h.copy() + N.dataType = scri.hdot + N.data = h.data_dot + ω = np.linalg.norm(N.angular_velocity(), axis=1)[0] + # The convention for choosing the phase from h_{21} mode and the factor of - # pi/2 is described in . + # pi/2 is described in . This choice + # does not work for q=1. h_21 = h.data[:, h.index(2, 1)] - θ = -1 * np.unwrap(np.angle(-h_21) - np.pi / 2) - ω = np.gradient(θ, t)[0] + θ = -1 * np.unwrap(np.angle(-h_21))[0] + np.pi/2 - R_i = np.array([np.cos(θ[0] / 2), 0, 0, np.sin(θ[0] / 2)]).T + R_i = np.array([np.cos(θ / 2), 0, 0, np.sin(θ / 2)]).T M1, M2, chi1, chi2 = params @@ -481,6 +486,8 @@ following functions. h_pn_scri = scri.WaveformModes.from_sxs(h_PN) Psi_M_scri = scri.WaveformModes.from_sxs(Psi_M_PN) + h_pn_scri.data *= -1 + return h_pn_scri, Psi_M_scri def load_waveform_and_fix_to_pnbms( @@ -527,6 +534,12 @@ arguments passed to Gfun. See the documentation of in :meth:`scri.asymptotic_bondi_data.map_to_superrest_frame` for additional details on the signature of ``Gfun`` and ``Gargsfun``. +Note that we have used :math:`h_{21}` mode to define the initial phase for the +PN waveform. This choice won't work for symmetric mass ratio systems because +of the degeneracy in the choice of phase angle by :math:`\pi`. Therefore, we +will have to carefully choose the initial phase to break this degeneracy for +such cases. + The parameter `dt` can be used to choose the time sampling for the waveform ABD object you get back, with default of `1M`. Reducing the time sampling for the waveform ABD is also useful if the CCE data was written too