Skip to content

Commit d879f02

Browse files
committed
Generalized CoM frame fixing method
User can pass a function to model the CoM charge to fit for the translation and boost.
1 parent 1eeb841 commit d879f02

1 file changed

Lines changed: 83 additions & 11 deletions

File tree

scri/asymptotic_bondi_data/map_to_superrest_frame.py

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from quaternion.calculus import indefinite_integral as integrate
1414

1515
from scipy.interpolate import CubicSpline
16-
16+
from scipy.optimize import least_squares
1717

1818
def MT_to_WM(h_mts, sxs_version=False, dataType=scri.h):
1919
"""Convert a ModesTimeSeries object to a scri or a sxs WaveformModes object.
@@ -319,7 +319,7 @@ def supertranslation_to_map_to_superrest_frame(
319319
return scri.bms_transformations.BMSTransformation(supertranslation=supertranslation), rel_errs
320320

321321

322-
def transformation_from_CoM_charge(G, t):
322+
def transformation_from_CoM_charge(G, t, Gfun=None, Gparams0=None, Gargs=None):
323323
"""Obtain the space translation and boost velocity from the center-of-mass charge.
324324
325325
This is defined in Eq (18) of https://journals.aps.org/prd/abstract/10.1103/PhysRevD.104.024051.
@@ -330,19 +330,40 @@ def transformation_from_CoM_charge(G, t):
330330
Center-of-mass charge.
331331
t: ndarray, real
332332
Time array corresponding to the size of the center-of-mass charge.
333+
Gfun: callable, optional
334+
Analytical function used for fitting the center-of-mass charge.
335+
Default is None i.e., a linear fit.
336+
Gparams0: ndarray, optional
337+
Initial guess for the fitting process. Default is None.
338+
Gargs: tuple, optional
339+
Additional arguments passed to `Gfun`. Default is None.
340+
341+
For documentation on Gfun, refer to the documentation of com_transformation_to_map_to_superrest_frame.
333342
"""
334-
polynomial_fit = np.polyfit(t, G, deg=1)
343+
344+
if Gfun is None and Gargs is None:
345+
Gfun = lambda Gparams, time, *args: - time[:, None] @ Gparams[:3][None, :] + Gparams[3:6][None, :]
346+
Gargs = ()
347+
348+
Gparams0 = np.zeros(6) if Gparams0 is None else Gparams0
349+
350+
residual = lambda Gparams, time, *args: (G - Gfun(Gparams, time, *args)).ravel()
351+
352+
fit = least_squares(residual, Gparams0, args=(t, *Gargs), method='trf')
335353

336354
CoM_transformation = scri.bms_transformations.BMSTransformation(
337-
supertranslation=-np.insert(sf.vector_as_ell_1_modes(polynomial_fit[1]), 0, 0),
338-
boost_velocity=polynomial_fit[0],
355+
supertranslation=-np.insert(sf.vector_as_ell_1_modes(fit.x[3:6]), 0, 0),
356+
boost_velocity=-fit.x[0:3],
339357
order=["supertranslation", "boost_velocity", "frame_rotation"],
340358
)
341-
342359
return CoM_transformation
343360

344361

345-
def com_transformation_to_map_to_superrest_frame(abd, N_itr_max=10, rel_err_tol=1e-12, print_conv=False):
362+
def com_transformation_to_map_to_superrest_frame(
363+
abd,
364+
N_itr_max=10, rel_err_tol=1e-12,
365+
print_conv=False,
366+
Gfun=None, Gparams0=None, Gargsfun=None):
346367
"""Determine the space translation and boost needed to map an abd object to the superrest frame.
347368
348369
These are found through an iterative solve; e.g., compute the transformations needed to minimize
@@ -357,9 +378,40 @@ def com_transformation_to_map_to_superrest_frame(abd, N_itr_max=10, rel_err_tol=
357378
N_itr_max: int, defaults to 10
358379
Maximum number of iterations to perform. Default is 10.
359380
rel_err_tol: float, defaults to 1e-12
360-
Minimum relativie error tolerance between transformation iterations. Default is 1e-12.
381+
Minimum relative error tolerance between transformation iterations. Default is 1e-12.
361382
print_conv: bool, defaults to False
362383
Whether or not to print the termination criterion. Default is False.
384+
Gfun: callable, optional
385+
Function used for fitting the center-of-mass charge,
386+
described further below.
387+
Default is None which implies a linear fit.
388+
Gparams0: ndarray, optional
389+
Initial guess for the fitting process. Default is None.
390+
Gargsfun: tuple of callables, optional. Default is None.
391+
These are used to determine the Gargs parameters to
392+
transformation_from_CoM_charge. They are called as
393+
Gargs = [func(abd) for func in Gargsfun] if Gargsfun else None
394+
395+
Gfun is used for producing a model timeseries of CoM charge (the G vector)
396+
for the purpose of fitting translation and boost parameters. The signature
397+
of Gfun should be like:
398+
def Gfun(Gparams, time, *Gargs):
399+
... # produce a model timeseries of G
400+
return G
401+
Here Gparams[0:3] should be the components of boost_velocity, Gparams[3:6]
402+
should be the components of the spatial translation (l=1 supertranslation),
403+
and there can be any extra fit parameters desired (but their fitted values
404+
are ignored). The shape of G that is returned by Gfun should be (n,3) where
405+
n is the length of the time argument. The Gargs arguments are determined
406+
from the Gargsfun tuple above from the whole abd object (for example, so
407+
that Gfun can have access to a timeseries of angular velocity or Bondi mass aspect).
408+
409+
Returns
410+
-------
411+
best_CoM_transformation: BMSTransformation
412+
Translations and boost velocity to map to the CoM frame.
413+
rel_errs: list[float]
414+
List of relative errors obtained at each iteration.
363415
"""
364416
CoM_transformation = scri.bms_transformations.BMSTransformation()
365417
best_CoM_transformation = scri.bms_transformations.BMSTransformation()
@@ -371,8 +423,9 @@ def com_transformation_to_map_to_superrest_frame(abd, N_itr_max=10, rel_err_tol=
371423
if itr == 0:
372424
abd_prime = abd.copy()
373425
G_prime = abd_prime.bondi_CoM_charge() / abd_prime.bondi_four_momentum()[:, 0, None]
426+
Gargs = [func(abd_prime) for func in Gargsfun] if Gargsfun else None
374427

375-
new_CoM_transformation = transformation_from_CoM_charge(G_prime, abd_prime.t)
428+
new_CoM_transformation = transformation_from_CoM_charge(G_prime, abd_prime.t, Gfun=Gfun, Gparams0=Gparams0, Gargs=Gargs)
376429
CoM_transformation = (new_CoM_transformation * CoM_transformation).reorder(
377430
["supertranslation", "frame_rotation", "boost_velocity"]
378431
)
@@ -387,6 +440,7 @@ def com_transformation_to_map_to_superrest_frame(abd, N_itr_max=10, rel_err_tol=
387440
)
388441

389442
G_prime = abd_prime.bondi_CoM_charge() / abd_prime.bondi_four_momentum()[:, 0, None]
443+
Gargs = [func(abd_prime) for func in Gargsfun] if Gargsfun else None
390444

391445
rel_err = integrate(np.linalg.norm(G_prime, axis=-1), abd_prime.t)[-1] / (abd_prime.t[-1] - abd_prime.t[0])
392446
if rel_err < min(rel_errs):
@@ -686,6 +740,9 @@ def map_to_superrest_frame(
686740
fix_time_phase_freedom=False,
687741
modes=None,
688742
print_conv=False,
743+
Gfun=None,
744+
Gparams0=None,
745+
Gargsfun=None,
689746
):
690747
"""Transform an abd object to the superrest frame.
691748
@@ -753,15 +810,27 @@ def map_to_superrest_frame(
753810
Default is every mode.
754811
print_conv: bool, defaults to False
755812
Whether or not to print the termination criterion. Default is False.
756-
813+
Gfun: callable, optional
814+
Analytical function used for fitting the center-of-mass charge.
815+
Default is None i.e., a linear fit.
816+
Gparams0: ndarray, optional
817+
Initial guess for the fitting process. Default is None.
818+
Gargsfun: tuple, optional
819+
Additional arguments passed to `Gfun`. Default is None.
820+
821+
For documentation on Gfun and Gargsfun, refer to the documentation of
822+
com_transformation_to_map_to_superrest_frame.
823+
757824
Returns
758825
-------
759826
abd_prime : AsymptoticBondiData
760827
Result of self.transform(...) where the input transformations are
761828
the transformations found in the BMSTransformations object.
762829
transformations : BMSTransformation
763830
BMS transformation to map to the target BMS frame.
764-
831+
best_rel_err: (float, float, float)
832+
(rel_err_CoM_transformation, rel_err_rotation, rel_err_PsiM)
833+
Best relative errors obtained during the routine.
765834
"""
766835
abd = self.copy()
767836

@@ -839,6 +908,9 @@ def map_to_superrest_frame(
839908
N_itr_max=N_itr_maxes["CoM_transformation"],
840909
rel_err_tol=rel_err_tols["CoM_transformation"],
841910
print_conv=print_conv,
911+
Gfun=Gfun,
912+
Gparams0=Gparams0,
913+
Gargsfun=Gargsfun,
842914
)
843915
elif transformation == "time_phase":
844916
if target_strain is not None:

0 commit comments

Comments
 (0)