1313from quaternion .calculus import indefinite_integral as integrate
1414
1515from scipy .interpolate import CubicSpline
16-
16+ from scipy . optimize import least_squares
1717
1818def 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