From b91a123136b6b4f77032c6870c86959f1ca95eb9 Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 09:38:31 -0800 Subject: [PATCH 01/36] added BMS fit evaluator fit_3dq8BMS.py --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 210 ++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 surfinBH/_fit_evaluators/fit_3dq8BMS.py diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py new file mode 100644 index 0000000..d3e422a --- /dev/null +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -0,0 +1,210 @@ +import numpy as np +import spherical_functions as sf +from surfinBH import surfinBH +import warnings + +#------------------------------------------------------------------------- +def get_positive_modes_indices(ell_min = 2,ell_max = 8): + """ This function gives all the indices corresponding to m >= 0 modes + of a spherical harmonics decomposition using spherical_functions package ordering convention + """ + d = [] + for ell in range(ell_min,ell_max + 1): + for m in range(0,ell + 1): + d.append(sf.LM_index(ell,m,ell_min)) + return d + +#------------------------------------------------------------------------- +def get_zero_modes_indices(ell_min = 2, ell_max = 8): + """ This function gives all the indices corresponding to m = 0 modes + of a spherical harmonics decomposition using spherical_functions package ordering convention + """ + d = [] + for ell in range(ell_min,ell_max + 1): + d.append(sf.LM_index(ell,0,ell_min)) + return d + +#------------------------------------------------------------------------- +def get_ellm(i,ell_min = 2, ell_max = 8): + """ This function converts an index labelling a spherical harmonics component in the + spherical_functions package convention back into a tuple (ell,m) + """ + for ell in range(ell_min,ell_max +1): + for m in range(-ell,ell + 1): + if i == sf.LM_index(ell, m, ell_min): + return ell,m + raise ValueError('Wrong index') + +#------------------------------------------------------------------------- +def get_full_supertranslation_array(positive_m_modes,ell_max): + """ This function recreates the full array of all the (ell,m) modes of the supertranslation parameter from + the m >= 0 modes only (it's real). The output array uses the spherical_functions package ordering + [(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] + """ + positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + res = [] + for i in range(sf.LM_index(2,-2,2),sf.LM_index(ell_max,ell_max,2)+1): + if i in positive_m_modes_indices: + res.append(positive_m_modes[i]) + else: + ell, m = get_ellm(i, ell_min = 2, ell_max = ell_max) + alpha_bar = positive_m_modes[sf.LM_index(ell,-m,2)].conjugate() + res.append(alpha_bar*(-1)**m) + return np.array(res) + + + +#============================================================================= +class Fit3dq8BMS(surfinBH.SurFinBH): + """ A class for the NRSur3dq8BMSRemnant model presented in Da Re et al., + arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper. + + This model predicts the supertransation modes up to ell = 8 and the + 3 components of the boost velocity of the BMS transformation from the inspiral (PN) + BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing + binary black hole systems. The fits are done using Gaussian Process + Regression (GPR) and also provide an error estimate along with the fit + value. + + This model has been trained in the parameter space: + q <= 8, |chiAz| <= 0.8, |chiBz| <= 0.8 + + ========================================================================= + Usage: + + import surfinBH + + # Load the fit + fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant') + + We provide the following call methods: + # supertranslation and 1-sigma error estimate + supertranslation, supertranslation_err = fit.supertranslation(q, chiA, chiB, **kwargs) + + # boost_velocity and 1-sigma error estimate + boost_velocity, boost_velocity_err = fit.boost_velocity(q, chiA, chiB, **kwargs) + + The arguments for each of these call methods are as follows: + Arguments: + q: Mass ratio (q>=1) + + chiA: Dimensionless spin of the larger BH (array of size 3). + + chiB: Dimensionless spin of the smaller BH (array of size 3). + This model allows only nonprecessing spins, so only the + z-components of these arrays should be non-zero. + + Optional arguments: + allow_extrap: + If False, raises a warning when q > 8.1 or |chiA|,|chiB| > 0.81, + and raises an error when q > 10.1 or |chiA|,|chiB| > 1. + If True, allows extrapolation to any q and |chiA|,|chiB| <= 1. + Use at your own risk. + Default: False. + + The spin and kick vectors are defined in the coorbital frame at t=-100 M + from the peak of the waveform. This frame is defined as: + The z-axis is along the orbital angular momentum direction of the binary. + The x-axis is along the line of separation from the smaller BH to + the larger BH at this time. + The y-axis completes the triad. + We obtain this frame from the waveform as defined in arxiv:1705.07089. + """ + + #------------------------------------------------------------------------- + def __init__(self, name): + + # Param limits beyond which to raise a warning + soft_param_lims = { + 'q': 8.1, + 'chiAmag': 0.81, + 'chiBmag': 0.81, + } + + # Param limits beyond which to raise an error + hard_param_lims = { + 'q': 10.1, + 'chiAmag': 1, + 'chiBmag': 1, + } + super(Fit3dq8BMS, self).__init__(name, soft_param_lims, hard_param_lims, + aligned_spin_only=True) + + #------------------------------------------------------------------------- + def _load_fits(self, h5file): + """ Loads fits from h5file and returns a dictionary of fits. """ + fits = {} + ell_max = 8 + positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) + keys_sup_real = [f'sup_real({i})' for i in positive_m_modes_indices] + keys_sup_imag = [f'sup_imag({i})' for i in positive_m_modes_indices if i not in zero_m_modes_indices] + keys_vel = ['vfx','vfy','vfz'] + for key in keys_vel + keys_sup_real + keys_sup_imag: + fits[key] = self._load_scalar_fit(fit_key=key, h5file=h5file) + return fits + + #------------------------------------------------------------------------- + def _get_fit_params(self, x, fit_key): + """ Transforms the input parameter to fit parameters for the 3dq8 model. + That is, maps from [q, chiAz, chiBz] to [np.log(q), chiHat, chi_a] + chiHat is defined in Eq.(3) of 1508.07253. + chi_a = (chiAz - chiBz)/2. + """ + q, chiAz, chiBz = x + eta = q/(1.+q)**2 + chi_wtAvg = (q*chiAz+chiBz)/(1.+q) + chiHat = (chi_wtAvg - 38.*eta/113.*(chiAz + chiBz))/(1. - 76.*eta/113.) + chi_a = (chiAz - chiBz)/2. + fit_params = [np.log(q), chiHat, chi_a] + return fit_params + + #------------------------------------------------------------------------- + def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): + """ Evaluates the NRSur3dq8Remnant model. + """ + chiA = np.array(chiA) + chiB = np.array(chiB) + + # Warn/Exit if extrapolating + allow_extrap = kwargs.pop('allow_extrap', False) + self._check_param_limits(q, chiA, chiB, allow_extrap) + + self._check_unused_kwargs(kwargs) + + x = [q, chiA[2], chiB[2]] + if fit_key == 'supertranslation' or fit_key == 'all': + ell_max = 8 + sur_predictions_positive_m_modes = {} + sur_predictions_positive_m_modes_err = {} + positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) + for i in positive_m_modes_indices: + sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') + if i not in zero_m_modes_indices: + sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({i})') + sur_predictions_positive_m_modes[i] = sup_real + (1j)*sup_imag + sur_predictions_positive_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err + else: + sur_predictions_positive_m_modes[i] = sup_real + sur_predictions_positive_m_modes_err[i] = sup_real_err + alpha = get_full_supertranslation_array(sur_predictions_positive_m_modes,ell_max) + alpha_err = get_full_supertranslation_array(sur_predictions_positive_m_modes_err,ell_max) + if fit_key == 'supertranslation': + return alpha, alpha_err + if fit_key == 'boost_velocity' or fit_key == 'all': + vfx, vfx_err = self._evaluate_fits(x, 'vfx') + vfy, vfy_err = self._evaluate_fits(x, 'vfy') + vfz, vfz_err = self._evaluate_fits(x, 'vfz') + vf = np.array([vfx, vfy, vfz]) + vf_err = np.array([vfx_err, vfy_err, vfz_err]) + if fit_key == 'boost_velocity': + return vf, vf_err + if fit_key == 'all': + return alpha, vf, alpha_err, vf_err + if fit_key != 'supertranslation' or fit_key != 'boost_velocity': + raise ValueError('method not implemented') + + + + From 8b59ddb5aa23685905e2eb578edacc14190cda7c Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 09:41:23 -0800 Subject: [PATCH 02/36] imported Fit3dq8BMS from fit_3dq8BMS.py in __init__.py --- surfinBH/_fit_evaluators/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/surfinBH/_fit_evaluators/__init__.py b/surfinBH/_fit_evaluators/__init__.py index f34a214..5864a4e 100644 --- a/surfinBH/_fit_evaluators/__init__.py +++ b/surfinBH/_fit_evaluators/__init__.py @@ -3,3 +3,4 @@ from .fit_7dq4 import Fit7dq4 from .fit_7dq4Emri import Fit7dq4Emri from .fit_3dq8_RD import Fit3dq8_RD +from .fit_3dq8BMS import Fit3dq8BMS From 2e6929c71d63fcc2fc59faa5bc41de6a25dbd7d7 Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 09:48:20 -0800 Subject: [PATCH 03/36] added NRSur3dq8BMSRemnant key to fits_collection in _loadFits.py --- surfinBH/_loadFits.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/surfinBH/_loadFits.py b/surfinBH/_loadFits.py index 68fd0ac..f958731 100644 --- a/surfinBH/_loadFits.py +++ b/surfinBH/_loadFits.py @@ -113,3 +113,11 @@ def DownloadData(name='all', data_dir=DataPath()): data_url = 'https://zenodo.org/records/13307895/files/fit_3dq8_RD.h5', refs = 'arxiv:2408.05300', ) + +fits_collection['NRSur3dq8BMSRemnant'] = FitAttributes( \ + fit_class = _fit_evaluators.Fit3dq8BMS, + desc = 'Fits for supertranslation parameter modes and boost velocity of the BMS' + 'transformation from the PN BMS frame to the remnant BMS frame', + data_url = '/fit_3dq8BMS.h5', + refs = 'arxiv:????.?????', + ) From 514de89e42ba22358e3c42d4c1c7fd395daa2714 Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 09:52:08 -0800 Subject: [PATCH 04/36] added supertranslation and boost_velocity evaluation methods, modified the description of all method in surfinBH.py --- surfinBH/surfinBH.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/surfinBH/surfinBH.py b/surfinBH/surfinBH.py index 8cb29e2..89f79c2 100644 --- a/surfinBH/surfinBH.py +++ b/surfinBH/surfinBH.py @@ -310,6 +310,37 @@ def all(self, *args, **kwargs): mf, chif, vf, mf_err_est, chif_err_est, vf_err_est chif, vf, chif_err_est and vf_err_est are arrays of size 3. + + In the case of NRsur3dq8BMSRemnant evaluates fit and 1-sigma error estimate for the + supertranslation parameter's modes and boost velocity of the BMS transformation from the PN + BMS frame to the remnant BMS frame. + Returns: + alpha, vf, alpha_err, vf_err + + alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering. + vf,vf_err are arrays of size 3. """ return self._eval_wrapper('all', *args, **kwargs) + def supertranslation(self, *args, **kwargs): + """ Evaluates fit and 1-sigma error estimate for the supertranslation parameter of the BMS transformation from the PN + BMS frame to the remnant BMS frame. + Returns: + alpha, alpha_err + + alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering. + + """ + return self._eval_wrapper('supertranslation', *args, **kwargs) + + def boost_velocity(self, *args, **kwargs): + """ Evaluates fit and 1-sigma error estimate for the boost velocity of the BMS transformation from the PN + BMS frame to the remnant BMS frame. + Returns: + vf, alpha_err, vf_err + + vf,vf_err are arrays of size 3. + """ + return self._eval_wrapper('boost_velocity', *args, **kwargs) + + From f36126c0e3d86895ea90eac278e20856fc0e2f6a Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 09:58:34 -0800 Subject: [PATCH 05/36] added the example notebook for the BMS surrogate --- examples/example_3dq8BMS.ipynb | 282 +++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 examples/example_3dq8BMS.ipynb diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb new file mode 100644 index 0000000..44bbed7 --- /dev/null +++ b/examples/example_3dq8BMS.ipynb @@ -0,0 +1,282 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example usage of NRSur3dq8BMSRemnant fit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH\")\n", + "import surfinBH" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "fit_name = 'NRSur3dq8BMSRemnant'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load the fit, this only needs to be done once at the start of a script" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loaded NRSur3dq8BMSRemnant fit.\n" + ] + } + ], + "source": [ + "fit = surfinBH.LoadFits(fit_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read the documentation" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on Fit3dq8BMS in module surfinBH._fit_evaluators.fit_3dq8BMS object:\n", + "\n", + "class Fit3dq8BMS(surfinBH.surfinBH.SurFinBH)\n", + " | Fit3dq8BMS(name)\n", + " |\n", + " | A class for the NRSur3dq8BMSRemnant model presented in Da Re et al.,\n", + " | arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper.\n", + " |\n", + " | This model predicts the supertransation modes up to ell = 8 and the\n", + " | 3 components of the boost velocity of the BMS transformation from the inspiral (PN)\n", + " | BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing\n", + " | binary black hole systems. The fits are done using Gaussian Process\n", + " | Regression (GPR) and also provide an error estimate along with the fit\n", + " | value.\n", + " |\n", + " | This model has been trained in the parameter space:\n", + " | q <= 8, |chiAz| <= 0.8, |chiBz| <= 0.8\n", + " |\n", + " | =========================================================================\n", + " | Usage:\n", + " |\n", + " | import surfinBH\n", + " |\n", + " | # Load the fit\n", + " | fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant')\n", + " |\n", + " | We provide the following call methods:\n", + " | # supertranslation and 1-sigma error estimate\n", + " | supertranslation, supertranslation_err = fit.supertranslation(q, chiA, chiB, **kwargs)\n", + " |\n", + " | # boost_velocity and 1-sigma error estimate\n", + " | boost_velocity, boost_velocity_err = fit.boost_velocity(q, chiA, chiB, **kwargs)\n", + " |\n", + " | The arguments for each of these call methods are as follows:\n", + " | Arguments:\n", + " | q: Mass ratio (q>=1)\n", + " |\n", + " | chiA: Dimensionless spin of the larger BH (array of size 3).\n", + " |\n", + " | chiB: Dimensionless spin of the smaller BH (array of size 3).\n", + " | This model allows only nonprecessing spins, so only the\n", + " | z-components of these arrays should be non-zero.\n", + " |\n", + " | Optional arguments:\n", + " | allow_extrap:\n", + " | If False, raises a warning when q > 8.1 or |chiA|,|chiB| > 0.81,\n", + " | and raises an error when q > 10.1 or |chiA|,|chiB| > 1.\n", + " | If True, allows extrapolation to any q and |chiA|,|chiB| <= 1.\n", + " | Use at your own risk.\n", + " | Default: False.\n", + " |\n", + " | The spin and kick vectors are defined in the coorbital frame at t=-100 M\n", + " | from the peak of the waveform. This frame is defined as:\n", + " | The z-axis is along the orbital angular momentum direction of the binary.\n", + " | The x-axis is along the line of separation from the smaller BH to\n", + " | the larger BH at this time.\n", + " | The y-axis completes the triad.\n", + " | We obtain this frame from the waveform as defined in arxiv:1705.07089.\n", + " |\n", + " | Method resolution order:\n", + " | Fit3dq8BMS\n", + " | surfinBH.surfinBH.SurFinBH\n", + " | builtins.object\n", + " |\n", + " | Methods defined here:\n", + " |\n", + " | __init__(self, name)\n", + " | name: Name of the fit excluding the surfinBH prefix. Ex: 7dq2.\n", + " | soft_param_lims: param limits beyond which to raise a warning.\n", + " | hard_param_lims: param limits beyond which to raise an error.\n", + " | aligned_spin_only: raise an error if given precessing spins.\n", + " | See _fit_evaluators.fit_7dq2.py for an example.\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Methods inherited from surfinBH.surfinBH.SurFinBH:\n", + " |\n", + " | all(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for remnant mass, spin\n", + " | and kick velocity.\n", + " | Returns:\n", + " | mf, chif, vf, mf_err_est, chif_err_est, vf_err_est\n", + " |\n", + " | chif, vf, chif_err_est and vf_err_est are arrays of size 3.\n", + " |\n", + " | In the case of NRsur3dq8BMSRemnant evaluates fit and 1-sigma error estimate for the\n", + " | supertranslation parameter's modes and boost velocity of the BMS transformation from the PN\n", + " | BMS frame to the remnant BMS frame.\n", + " | Returns:\n", + " | alpha, vf, alpha_err, vf_err\n", + " |\n", + " | alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering.\n", + " | vf,vf_err are arrays of size 3.\n", + " |\n", + " | boost_velocity(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for the boost velocity of the BMS transformation from the PN\n", + " | BMS frame to the remnant BMS frame.\n", + " | Returns:\n", + " | vf, alpha_err, vf_err\n", + " |\n", + " | vf,vf_err are arrays of size 3.\n", + " |\n", + " | chif(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for remnant spin.\n", + " | Returns:\n", + " | chif, chif_err_est\n", + " |\n", + " | chif and chif_err_est are arrays of size 3.\n", + " |\n", + " | mf(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for remnant mass.\n", + " | Returns:\n", + " | mf, mf_err_est\n", + " |\n", + " | supertranslation(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for the supertranslation parameter of the BMS transformation from the PN\n", + " | BMS frame to the remnant BMS frame.\n", + " | Returns:\n", + " | alpha, alpha_err\n", + " |\n", + " | alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering.\n", + " |\n", + " | vf(self, *args, **kwargs)\n", + " | Evaluates fit and 1-sigma error estimate for remnant kick velocity.\n", + " | Returns:\n", + " | vf, vf_err_est\n", + " |\n", + " | vf and vf_err_est are arrays of size 3.\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors inherited from surfinBH.surfinBH.SurFinBH:\n", + " |\n", + " | __dict__\n", + " | dictionary for instance variables\n", + " |\n", + " | __weakref__\n", + " | list of weak references to the object\n", + "\n" + ] + } + ], + "source": [ + "help(fit)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluate the fits" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "q = 4.3 # Mass ratio q>=1\n", + "chiA = [0,0,0.6] # Spin of larger BH (z-direction only)\n", + "chiB = [0,0,-0.7] # Spin of smaller BH (z-direction only)\n", + "\n", + "## Evaluate the fits and GPR error estimate.\n", + "\n", + "#this model fits the supertranslation parameter alpha and the boost \n", + "#velocity v associated to the BMS transformation from the PN BMS frame to\n", + "#the remnant BMS frame\n", + "\n", + "# supertranslation parameter alpha and 1-sigma error estimate\n", + "#NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", + "# the order of the modes in the array is (2,-2),(2,-1),(2,0),(2,1),(2,2),(3,-3),(3,-2),(3,-1),...\n", + "# (same order used in spherical_functions package)\n", + "\n", + "alpha, alpha_err = fit.supertranslation(q, chiA, chiB)\n", + "\n", + "# boost velocity v and 1-sigma error estimate\n", + "v, v_err = fit.boost_velocity(q, chiA, chiB)\n", + "\n", + "# All of these together\n", + "alpha, v, alpha_err, v_err = fit.all(q, chiA, chiB)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 066f97c19d97b7c926da247cae4255b0844b6679 Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 10:03:28 -0800 Subject: [PATCH 06/36] added function save_data_BMS to generate_regression_data.py to evaluate the BMS surrogate --- test/generate_regression_data.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index 0f882f1..2f74cb9 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -5,6 +5,31 @@ import surfinBH +def save_data_BMS(h5grp, fit, num_tests, kwargs={}): + + for i in range(num_tests): + # save each test evaluation as group + test_h5grp = h5grp.create_group('test_%d'%i) + + # Generate params randomly within allowed values + q, chiA, chiB = fit._generate_random_params_for_tests() + + # save params + test_h5grp.create_dataset('q', data=q) + test_h5grp.create_dataset('chiA', data=chiA) + test_h5grp.create_dataset('chiB', data=chiB) + + # save evaluations as a group + y_h5grp = test_h5grp.create_group('y') + + # supertranslation + y = fit.supertranslation(q, chiA, chiB, **kwargs) + y_h5grp.create_dataset('supertranslation', data=y) + + # boost_velocity + y = fit.boost_velocity(q, chiA, chiB, **kwargs) + y_h5grp.create_dataset('boost_velocity', data=y) + def save_data(h5grp, fit, num_tests, kwargs={}): for i in range(num_tests): @@ -62,7 +87,10 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save regression without optional kwargs h5grp = h5file.create_group('No_kwargs') - save_data(h5grp, fit, num_tests) + if name_tag == '3dq8BMS': + save_data_BMS(h5grp, fit, num_tests) + else: + save_data(h5grp, fit, num_tests) # save regression with optional kwargs. # NOTE: this would be empty unless _extra_regression_kwargs() is From def320c82ed1d078828a058ba51356000a51af72 Mon Sep 17 00:00:00 2001 From: gdare Date: Sat, 21 Dec 2024 11:23:12 -0800 Subject: [PATCH 07/36] generated regression data for BMS surrogate --- test/regression_data/fit_3dq8BMS.h5 | Bin 0 -> 63512 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/regression_data/fit_3dq8BMS.h5 diff --git a/test/regression_data/fit_3dq8BMS.h5 b/test/regression_data/fit_3dq8BMS.h5 new file mode 100644 index 0000000000000000000000000000000000000000..fc829fca8d08c2e6421e51370e78dd9b5aabfd52 GIT binary patch literal 63512 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
VH4q zIp`l!@BLBpzmxwV`S_FiH`UL-_r2-j!|n0p{`y(^|1TXsCIj^MCV4s(+yAxyU-j?* zy8eBDo58+c$W*U-U$rAAC4EGOSLs0PS4ZrM5|D2s$+D z(}uz0TUZHwmB(q-j=Xvi#)06JJ?Pt*nU_ruK+8u>Yk!=(2L*{{`Q9JU&K{jID`S~Z zEqm$4Omof5=cu;?f6|#FH_+AtCY|MsYLD`t{i?1lP|6 zIIj(>LFBq)oFO=6Pxx8FPx*&^H%4fO2u(wu!ULs4TXR6cOIiA=u^4z}7vG%Foga-% znbEM(bQ{VyESz?*i!T&UK7D`1$yUaDN%6ecV15|syT!xg$sUB(y3BpuFBDC1?{{*c z;VPa!j03?bd%_QdpYl)i0nyj3%1FEC9)FZO+ahfB0u~jXao<)H+R92;uQ2Gc^A6)S z#6I2lofVpK+4yep(MT}R88329){)I?lljnkwiA>#H4l;*WQ80z>+jrqc`=e}c(?I= zZYe9dHn;G7)JOK@?t>b=uZQujFUA>yQ}%?PA^enoqK_f^DE)BM-CX~8aX8q>d1@NJ zJA!)N8Gbj(zB6*N8ox(H;WjhwRPO;6y^kXEySJ14>|kOkQ=df1ck zyXEY8@nIYYPT4b<9}#}aKhXz7AElqg@gWl57~75WH{Xs#_HlJ*1>H`er~RwbTG}5o zkLR|GGSKV{DmNc2(0LvTxA%5y)^ynhGVPjgUT4&?Rj1PHcdpK53>`v0jq#a^rnXS}%Wm@Tt5Q6vJw6xDeXT)}6O@o9=y# zZ7-eWU*WNg7eB@sf>ZW{pCSB|e}wfhL?5M}#K)5OsQ6)J{E3|O)g3Uz!6uo}6Uu4K zRll>9Gyi)@YuNT2OA|1EeX?cTx-a!_j03?bd;O^{a>HkF=70B4Gij?ndIt8`r-!z# zmw^LS22mE><%_j&zq z7&X7l!T&m%=d^3j$5G-)<;rN|-Pfg|?D}lep1WAsP!`sjz*+x$#BC$-L;L%nzzrf@ z+%~Dew832~+rqE&t_Q|};FLXJejxmme{hL#x;aO>2;Gy*9vZ@VZ)94grqW0yad;Xi z7x?+Tkry-*taYbdLbC*gB@{UGzh`{tld0cN24ss>#`Uc3iMlEdnsAk~{`YMY%`*Sx zg^=i>nW~%cB|jJkf>ZW@`GN3L{)s*y`g&+_*Z*GG$REI2wFoT|f3LP|Q6IF{>qNKv zBAohXt75HrbqrW1%#c#Ol7vdP@^#USmPDSt7@K>>O0eZ=%g}Y!5nwhXr|VA6`rj9t zJL`7Zr-ZhQGb-(AtqLv9D-}0Q{<8iz#)06JJz#zy{FHyd`he)8^n;zQVnGkVA~a94 zA$L8e{vGVFXd7RpJah}MyEW%sHzZ!?7d4Et{`c}$flDnR$&fI*=bf$Q$}qY?=+(Y7 zDRgA=oaKVc641Tiz;z~Lk3)oM)}wbC;&28!Y0Wv+4cW#M?CKyb<)Fh3A}%0FOzK=e`iNqj)!+xym}oS!rQd+?mw1)tv=X~?{Y`_xYn z`K{ucFq%`JE;4B7dy+H%yH=uQmxX*BDw|X>uqLW6s!=K2p|`Cs)QyRgD^WfP$!WE} zt^a+pa#e%&8*%jh?lrH?;%aaw#@M8SQ~z$38fd*Z>Kv**)BM(hGyi+k_}=T6u2TfT zsVlx({~O~#aLOJqKM;P(KVW@8^ilc&#|I=nD*nH*{#}5_^<;!Yo{)ah`u7p8zN`># z`@M0z!7=W6%G~DH-+x&K=yALTj=u``ACiuLPW`(L->+n(OCtD()xX1t?mupM_3!XM z#>r8V1)WfG+qcf$wM#7^7q#9Vy+l{21~q>W@Rh%yg>ozAU!J^O6y-ddSCwb9 zomcZVk=0}8o*VN_pzI46$?ydo#+A-J5T>m_?bnJ|)%O2feVu#P(aZmaNBG(<`EWs&z zg!vi5Px(ieEjFD9o8*Zc99@LU+~XlZV^sI9;vbopH?_<3<62n7*1Wj}`uJ zUhf8togdx}@q5k;S~{ZHLQ4=bkKZ|;xOg8r8qnq7v_@aF$9RFkrwl8eK8ypwDSL$Z zf$&rQ8LSV8KGlV9t|o2_LN87Y3p<2TkxK6IJe5uF*z+&$c?~(i4?{mzE}ebT7J{_w z7cq_(k!?t>d+OqLCazO^%eFl1)`CdO#uhC}sw!f0zu zSktjvfpBH@^ec;t7)|JfrWjmDare ziE)PDls(~R2|wi@VSOyoN9iZ=u_Qh!erWB6W)6ENtl!0C^lPEJA~|kZ`{sXM|76X? z6LTuJn!t;^jSBhgU+Ui&2ZB@f`U|ery`ICVf2%sAYp<0&2m5b?9xNOy2e*t<{in9d zqEq>Ay87{#qj~40yT6)W1~$vO+tsDa;PnTL1HmbK!2Ce?$@(Lb)sJ20`j(&x6)jg} zj*6pOLY#LMoRR`V72$RBuU~}l8MTwFf{M}1MNbS;W-Fkmyy|WCuY1EGZ^22a>%Y{$ zF%AT$>;dxw;ivq=0#{Mf*NR2xxMgO=@o_b9x6R0CPlE&uHJ$p~`!BoZB`;w{UqCCJ zyNZ8a|757y>M9e?{BNm{{xO5Iq*1%>l6{4o`nO!I-3x7zLf9;kU$kD-gqI(T1HmbK z!2Ce?DgQ(t5Pf9+^!${W^{t%x_sq0O61#@VqNBCbl$4$2;m{54`!BVhR(DMmjtmxiq83k%e&PR7~>fdTncV};ytc0$WeE2kUb8k2;a=|rt z%9r{##)06JJz#zy{FHyd`he)8^g~0w=Epu}WoW_e;%VzR_3wPmuKtf)R3N~lVCv`f zPf9!a=1k<&zqKnLGV>-T!^Ol#i#rnXuxI>&4RozB9u?6_p)^W}Zi7zct=_JH|;@KgQ)>jR>X z(of<85??>duh&1(-9OpeJ--){G%9(poWDQBzpG+DuYcl~H&5(dWjr#QGAnTT!d}R{ zWk}u_^*&JDH|6myPW_v#f1*F4!@T}=Po(y#zww)kD)7WFx@R?~{yjy(d))P-=g{7{ z=6s*mKdCAe+O}rf@8^GG90*R?1Lg<9Px%L|4~RZWKj8R)#7D*dH`c#(@VK6gaL5zV zPg?&@;p)pu+>Rb z^%#sZ1gGo~=4S{$ls$v_f$&rQ8LSV8KC8KB3`<+Q(FNI2^9Ku@Mpk+!@^t4%F}?+>H}&Cv!mLm$ zJ$|KW6;y0&o+_Vo4Q&nRRkSF(h}E{+c6eAx7r6FHN=0aYAWA;FE#d(G8dR|<&!W7n znz7xtd+ytd1&r>+hx77_ahBkeJz#!@@KgQ)>tl&NNq8<6A(H0BK$Js+%(e5dGd)Q5gM=$DZ>O`Hs ztY43DAUI_Ym>&o~<)7#SqL0$g;`o5XXCalKR&YEVotfd$>@OLGdiT+eep_9|Y}LpZ zQ!k?erw0{xa*+#!ON9=Kg!h} zlA+{56@4)jGk#u+)U&SeFy2x8QvY0VY^vEjv#AIT@ZP&2L`xLO?X{U*zC{)WBu!@e z&;PRi3C4lols#a6ApDenD4uWU7A;wX+zJ-x1$3!~Ig7P6SZ9gDksE>WpXYzq*S?CJ zy*?M+-zIzcjYI~NY0JxfUjKWz@-wxGk`n0A!R$J-z)VyimvrLThfB~iPxF3_$Cvsy z#)06JJz#zy{FHy94~RZeKOQa3t$&|(NE-5FG-v&i>_;C>cgR6Xs=yu5yD@OoVdq9a z(Ik{KOt_~0kpRj#Y&)R7NgN)HzP3O~ITV%`^k1T|G98_E6gsEAR1S?3iPjO#mx57; zeb4Nc{!;(OI1rq&2h0zIpYjh_AMo@I=gwcp`r+!Uft%+nFGYqY(MUOu3t&>gEZKfb z1`3ZReE3}dUh7w&eP1REjZilWI6gB99v_^q)SU<*<4DW!~49(I1rq& z2h0zIpYjh_9}s<%ei9#$_{jPnBhQFk`#k@<&m6foF*794e#7IdkC`h#nR?jd1Wx_? zoKJ^W_{&(-pfX@wi>M@8?>B8+z!N#>x!APxr;sn}pM=FvQ{LLp8QsfFU1jdC2>kpj zW*hCyh6O?atAx6rL638VI~H*2-;cs1XEYq^^}F>?Fb)K#>;dxw;ivoq)(1o%r5|v7 zK;om~{~PPyL3mtGMmXfj*oAETE$yGKe^S7elXZpLes3JFTf{w2ncMvO`!CA?J&xDF z@mJygL(=iTu749=r)7>#i#fN}Z|xA=4#n*-+z!X>2;7du?I_&p;&wD2AF12UCl3Bc zEq8sAPJARk_IRCr;xC9=cb|M(*yHtxc;`{;6LF;f_Rk*we;d5>sQ-_{fSiYa-{PHz z_sQ>FM&vyFIlwy)?~~636MSB>Fn5ETXYhc#Z}kwL@IP*TUyl{}%>(iO*Vnx%5aUYa z@_msV^kwrW+@jaL*;)K;k#ZRJE&29&BnukXzkQxEhCQi%5MIg!a?8GL|FfXK?^oPR z{qNVkDZ%}WTnUl^PqOh-v_CE%b^nNbeD68P=qC5Fk^APSxQM?*{ICqr&p|raa}D+R z_v`nJ|MvF`-wJLj|Jv^vIyK+!0_1+xE&uj;|2EWfwY_Q3_5xJ0Iq==I)rnvm75q4| zp9ZS%-kAU5fdZO2FeN|q{x)9y592^^${vY!avXO1n!>Xls4h2vKjj}B%|{LO85jm}2{9T%XIPlgdCH@TpeAOeZ0ioU z$1SXCuTGw&&mG|W_>N|qHC~_+1amI!eaKHv6(wYV` z-XTMf#vwGUE>hAaQw%wXs_%baP{24VA5GcZDFBIEx)=@%4nQZ`)CcH?%W# zikK$5F_J|FE5Nr$cHva1BSUUDo9;jfvZ?XNoJlK$S zak6RB5?*{52ZB@ffcX*Or~I>69}s<%eip}vNPHa@+pLEyj6e&JnakscaVR=3$Wp4` zYbL*_ZI6_TD7<(Rook+Y5V95tS#%EG14cf(8>iIYVso^!W4d%LWX-RrI&QREg<@kY zUTjKpgQszZw;ry2%r0Ce{nB$|E~BI{GT?acba~_1rNI1gGo?KM?-$!xaKQ zuV>RIAg;A$eF++_<9ILLNgN%JZj25Tm4StxZx5Z8L$Gg_-lpt;Vzj%nrqrr2%BWAt zrmOChx@cJXhf#8%qV16L{lz%w?cH!qpHWGUzCKy zyCbqb|DJJ6_(hwU?j_XJKB`%XGoQb&o~<)7#SqL2KZp(tbY+kE~VZh>se)844C5yX7lWguL~ zTt|%ad&a2%5wla3Dab-u)U{~4B!c2fqvqCr zqIr+*+9vf=g$HKs0rg|Q{GNevAUI_Ym>&o~eX?7&v3u3d}>0NBFa74*ZW4S zBJ5P$tNwXD|HI>3*XvrvqobAi!D~JHqQYr0yRX~zg^=QgCtCmUK2!5|DNfE$#L?Jr zseXgB^zpZQAHgYfGU#n}2y#00;Aor`-^KYN` zZ$k&)IJIiVtq({?Pifbx#8kzc)YtrAr_oJ~>^t4cd+n9)7}us2r-yEP z(LM{woxZO&g5*ArVcoV1qaahGYtDnjKrLmJ%ZdXXh+KD!1HmbK!p{(X%0KkIU*06_@9PxQR4^NI@im)rx-#sM`3g|oJf(-)5Fap*OO>nd*BNSF zjWml3yvb;d^~|tea1d-I9<|+g;)}{fhgD4*v4W=$f@$pYqROeTe7_kKA&8 zwnzk+q-~q!8l8%goNJG4i220sRE*!`8pMwTMk=o9bj1@TvCi@4p4N~kEEA)ybc5X! zdMIti6iK+SV2;N*$;D_zx4nif$_}t~(c>e5;`L1R;pU)h2{Cl!vJ&W~f0?I`ahBke zJ;MA9;ivo)eGJh@>4%Jynh6!^>EQU@a(g=Khtdk3U-L3jK($s|hu#r=#&p^?A#LjD z!)W;9*W(o)9!1@%$BFF_dC#oup_SZi;6vu7?(QRldIY1s4@c>&Qg=g1)qC;`Tko?5 z*Y_!ng=_4aQEKZnHhZ8FoBc{zhaAud<(D%|x3A&VfiMmPr|bzo5Pr%(i}eA~N9kvA ze2Bystnn;d&NUoKX1pnwJ}w?@5@}XG-1#k|y32A+`E7BK6p}IUo3tNlo_&1xwxa8#Ombtv`G5=H+^J>k(H|VZGbz^C5#} z=B^A!c_+$bOjwuXLuzti!?NMBIB#<;_}-Y2Cj7C^-qkm1gGo?KSTH_{|M`2 zi9Sj{iH{}mQSn2t-#xnl_d4nKm4C9arAwEb-~{e_N{^@B=whx*# zbdZ<$qVQrg$8F9u`Styf;Jdee`DrTfT6V^%+Ji56{xJ>&r|dcJ6a9@J2tVZ?Uh1h0 zde2#>#;>xY>oHDU+vQWy^l^I9oXQ| z$VvX}kvp8awtRfPRG>p4T+Ghp6KtKu(}!^&IAsr*9|%9?pXdXkkJN=ty}9%B*(wWF z%`M7Ez9dsj+@Lqur0O4d!&#@js%zKqH|<%-_jz=?M71p1;l1Ky?k6pfcjR>X(huhg zEZwb+l%oK-+%uavb!{1Qgsj0ZZ|FO7-4!R!!r)r_`@(a_wGu6{I?5{z}crzMvUcT6N$*>e}-o&76CxN}yp@ zuH~$$8hG5R8uR%*rH^lij50|%hvM*iN{!7lMF;%BdrC151gGo)^8?|h`~%hpL?5Le baC|`GqvHP?>)N(>Tu(+g Date: Tue, 14 Jan 2025 11:23:42 -0800 Subject: [PATCH 08/36] fixed example_3dq8BMS.ipynb --- examples/example_3dq8BMS.ipynb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 44bbed7..d8ad652 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -13,8 +13,6 @@ "metadata": {}, "outputs": [], "source": [ - "import sys\n", - "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH\")\n", "import surfinBH" ] }, @@ -222,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ From 4197712feb709a77915210e970e6cdb7158366bf Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 16:45:19 -0800 Subject: [PATCH 09/36] added if statements in test_interface.py to check if mf and mf_err or chif and chif_err are None, needed for NRsur3dq8BMSRemnant --- test/test_interface.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/test/test_interface.py b/test/test_interface.py index 2035efe..86ccb81 100644 --- a/test/test_interface.py +++ b/test/test_interface.py @@ -37,18 +37,21 @@ def single_kwargs_test(fit, num_tests, kwargs={}): # Check that all_data has the right ordering rtol = 1e-11 - if hasattr(mf_and_err, '__len__'): # has both fit val and err_est - np.testing.assert_allclose(mf_and_err[0], all_data[0], rtol=rtol) - np.testing.assert_allclose(mf_and_err[1], all_data[3], rtol=rtol) - else: - np.testing.assert_allclose(mf_and_err, all_data[0], rtol=rtol) - - if hasattr(chif_and_err, '__len__'): # has both fit val and err_est - np.testing.assert_allclose(chif_and_err[0], all_data[1], rtol=rtol) - np.testing.assert_allclose(chif_and_err[1], all_data[4], rtol=rtol) - else: - np.testing.assert_allclose(chif_and_err, all_data[1], rtol=rtol) - # Needed for NRSur7dq4EmriRemnant + # Needed for NRSur3dq8BMSRemnant + if mf_and_err[0] is not None: + if hasattr(mf_and_err, '__len__'): # has both fit val and err_est + np.testing.assert_allclose(mf_and_err[0], all_data[0], rtol=rtol) + np.testing.assert_allclose(mf_and_err[1], all_data[3], rtol=rtol) + else: + np.testing.assert_allclose(mf_and_err, all_data[0], rtol=rtol) + # Needed for NRSur3dq8BMSRemnant + if chif_and_err[0] is not None: + if hasattr(chif_and_err, '__len__'): # has both fit val and err_est + np.testing.assert_allclose(chif_and_err[0], all_data[1], rtol=rtol) + np.testing.assert_allclose(chif_and_err[1], all_data[4], rtol=rtol) + else: + np.testing.assert_allclose(chif_and_err, all_data[1], rtol=rtol) + # Needed for NRSur7dq4EmriRemnant and NRSur3dq8BMSRemnant if vf_and_err[0] is not None: if hasattr(vf_and_err, '__len__'): # has both fit val and err_est np.testing.assert_allclose(vf_and_err[0], all_data[2], rtol=rtol) From ba1f9bbf75c03ca15a51895b8e919fc6192ab27c Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 16:46:24 -0800 Subject: [PATCH 10/36] Removed methods supertranslation and boost_velocity in surfinBH.py, restored original version --- surfinBH/surfinBH.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/surfinBH/surfinBH.py b/surfinBH/surfinBH.py index 89f79c2..da39b75 100644 --- a/surfinBH/surfinBH.py +++ b/surfinBH/surfinBH.py @@ -322,25 +322,4 @@ def all(self, *args, **kwargs): """ return self._eval_wrapper('all', *args, **kwargs) - def supertranslation(self, *args, **kwargs): - """ Evaluates fit and 1-sigma error estimate for the supertranslation parameter of the BMS transformation from the PN - BMS frame to the remnant BMS frame. - Returns: - alpha, alpha_err - - alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering. - - """ - return self._eval_wrapper('supertranslation', *args, **kwargs) - - def boost_velocity(self, *args, **kwargs): - """ Evaluates fit and 1-sigma error estimate for the boost velocity of the BMS transformation from the PN - BMS frame to the remnant BMS frame. - Returns: - vf, alpha_err, vf_err - - vf,vf_err are arrays of size 3. - """ - return self._eval_wrapper('boost_velocity', *args, **kwargs) - From e299539937d7337f7bf71343fd2999b64e7841f2 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 16:47:47 -0800 Subject: [PATCH 11/36] Made fit_3dq8BMS compliant with the standard provided by fit_3dq8_RD.py --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 99 +++++++++++++++---------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index d3e422a..ebceb85 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -77,12 +77,8 @@ class Fit3dq8BMS(surfinBH.SurFinBH): # Load the fit fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant') - We provide the following call methods: - # supertranslation and 1-sigma error estimate - supertranslation, supertranslation_err = fit.supertranslation(q, chiA, chiB, **kwargs) - - # boost_velocity and 1-sigma error estimate - boost_velocity, boost_velocity_err = fit.boost_velocity(q, chiA, chiB, **kwargs) + #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call: + alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) The arguments for each of these call methods are as follows: Arguments: @@ -139,7 +135,7 @@ def _load_fits(self, h5file): zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) keys_sup_real = [f'sup_real({i})' for i in positive_m_modes_indices] keys_sup_imag = [f'sup_imag({i})' for i in positive_m_modes_indices if i not in zero_m_modes_indices] - keys_vel = ['vfx','vfy','vfz'] + keys_vel = ['boost_velx','boost_vely','boost_velz'] for key in keys_vel + keys_sup_real + keys_sup_imag: fits[key] = self._load_scalar_fit(fit_key=key, h5file=h5file) return fits @@ -159,6 +155,27 @@ def _get_fit_params(self, x, fit_key): fit_params = [np.log(q), chiHat, chi_a] return fit_params + #------------------------------------------------------------------------- + def mf(self, *args, **kwargs): + """mf is not implemented in this model. Will return (None, None),""" + return self._eval_wrapper('mf', *args, **kwargs) + + def chif(self, *args, **kwargs): + """chif is not implemented in this model. Will return (None, None),""" + return self._eval_wrapper('chif', *args, **kwargs) + + def vf(self, *args, **kwargs): + """vf is not implemented in this model. Will return (None, None),""" + return self._eval_wrapper('vf', *args, **kwargs) + + def all(self, *args, **kwargs): + """ Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity + of the BMS transformation from the inspiral BMS frame to the remnant BMS frame + Returns: + alpha, boost_vel, alpha_err, boost_vel_err + """ + return self._eval_wrapper('all', *args, **kwargs) + #------------------------------------------------------------------------- def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): """ Evaluates the NRSur3dq8Remnant model. @@ -173,38 +190,44 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): self._check_unused_kwargs(kwargs) x = [q, chiA[2], chiB[2]] - if fit_key == 'supertranslation' or fit_key == 'all': - ell_max = 8 - sur_predictions_positive_m_modes = {} - sur_predictions_positive_m_modes_err = {} - positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) - zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) - for i in positive_m_modes_indices: - sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') - if i not in zero_m_modes_indices: - sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({i})') - sur_predictions_positive_m_modes[i] = sup_real + (1j)*sup_imag - sur_predictions_positive_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err - else: - sur_predictions_positive_m_modes[i] = sup_real - sur_predictions_positive_m_modes_err[i] = sup_real_err - alpha = get_full_supertranslation_array(sur_predictions_positive_m_modes,ell_max) - alpha_err = get_full_supertranslation_array(sur_predictions_positive_m_modes_err,ell_max) - if fit_key == 'supertranslation': - return alpha, alpha_err - if fit_key == 'boost_velocity' or fit_key == 'all': - vfx, vfx_err = self._evaluate_fits(x, 'vfx') - vfy, vfy_err = self._evaluate_fits(x, 'vfy') - vfz, vfz_err = self._evaluate_fits(x, 'vfz') - vf = np.array([vfx, vfy, vfz]) - vf_err = np.array([vfx_err, vfy_err, vfz_err]) - if fit_key == 'boost_velocity': - return vf, vf_err - if fit_key == 'all': - return alpha, vf, alpha_err, vf_err - if fit_key != 'supertranslation' or fit_key != 'boost_velocity': - raise ValueError('method not implemented') + ell_max = 8 + sur_predictions_positive_m_modes = {} + sur_predictions_positive_m_modes_err = {} + positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) + for i in positive_m_modes_indices: + sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') + if i not in zero_m_modes_indices: + sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({i})') + sur_predictions_positive_m_modes[i] = sup_real + (1j)*sup_imag + sur_predictions_positive_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err + else: + sur_predictions_positive_m_modes[i] = sup_real + sur_predictions_positive_m_modes_err[i] = sup_real_err + alpha = get_full_supertranslation_array(sur_predictions_positive_m_modes,ell_max) + alpha_err = get_full_supertranslation_array(sur_predictions_positive_m_modes_err,ell_max) + + boost_velx, boost_velx_err = self._evaluate_fits(x, 'boost_velx') + boost_vely, boost_vely_err = self._evaluate_fits(x, 'boost_vely') + boost_velz, boost_velz_err = self._evaluate_fits(x, 'boost_velz') + boost_vel = np.array([boost_velx, boost_vely, boost_velz]) + boost_vel_err = np.array([boost_velx_err, boost_vely_err, boost_velz_err]) + + if fit_key == 'mf': + mf, mf_err = None, None + return mf, mf_err + + if fit_key == 'chif': + chif, chif_err = None, None + return chif, chif_err + + if fit_key == 'vf': + vf, vf_err = None, None + return vf, vf_err + + if fit_key == 'all': + return alpha, boost_vel, alpha_err, boost_vel_err From 0d860ff81059481947e5deb3b1ba4e7912a55e74 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 17:28:02 -0800 Subject: [PATCH 12/36] restored original version of generate_regression_data.py --- test/generate_regression_data.py | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index 2f74cb9..c0309f3 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -5,30 +5,6 @@ import surfinBH -def save_data_BMS(h5grp, fit, num_tests, kwargs={}): - - for i in range(num_tests): - # save each test evaluation as group - test_h5grp = h5grp.create_group('test_%d'%i) - - # Generate params randomly within allowed values - q, chiA, chiB = fit._generate_random_params_for_tests() - - # save params - test_h5grp.create_dataset('q', data=q) - test_h5grp.create_dataset('chiA', data=chiA) - test_h5grp.create_dataset('chiB', data=chiB) - - # save evaluations as a group - y_h5grp = test_h5grp.create_group('y') - - # supertranslation - y = fit.supertranslation(q, chiA, chiB, **kwargs) - y_h5grp.create_dataset('supertranslation', data=y) - - # boost_velocity - y = fit.boost_velocity(q, chiA, chiB, **kwargs) - y_h5grp.create_dataset('boost_velocity', data=y) def save_data(h5grp, fit, num_tests, kwargs={}): @@ -87,10 +63,7 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save regression without optional kwargs h5grp = h5file.create_group('No_kwargs') - if name_tag == '3dq8BMS': - save_data_BMS(h5grp, fit, num_tests) - else: - save_data(h5grp, fit, num_tests) + save_data(h5grp, fit, num_tests) # save regression with optional kwargs. # NOTE: this would be empty unless _extra_regression_kwargs() is From 0f5a182c56d7f44152b251655a4c41379465536d Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 17:46:28 -0800 Subject: [PATCH 13/36] remove fit NRSur3dq8BMS from the the tests of test_regression.py because generate_regression_data.py does not work on these fits yet --- test/test_regression.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_regression.py b/test/test_regression.py index c5ec973..c4c496f 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -25,8 +25,15 @@ def test_fit_regression(): """ # List of all available fits fit_names = surfinBH.fits_collection.keys() + for name in fit_names: + # For now NRSur3dq8BMSRemnant has to be skipped, as generate_regression_data.py needs to be updated + # to accomodate for the BMS transformation + # parameters fits + if name == 'NRSur3dq8BMSRemnant': + continue + if name == 'NRSur7dq4EmriRemnant': # FIXME Somehow, the error estimate for this fit seems particularly # finnicky accross different machines. For now, essentially From 0f5ca010fa563326143e66e0b6f4ecf2960c38b4 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 17:47:38 -0800 Subject: [PATCH 14/36] fixed example_3dq8BMS.ipynb to use only the all method --- examples/example_3dq8BMS.ipynb | 76 ++++++---------------------------- 1 file changed, 13 insertions(+), 63 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index d8ad652..3941d16 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -58,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "scrolled": true }, @@ -93,12 +93,8 @@ " | # Load the fit\n", " | fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant')\n", " |\n", - " | We provide the following call methods:\n", - " | # supertranslation and 1-sigma error estimate\n", - " | supertranslation, supertranslation_err = fit.supertranslation(q, chiA, chiB, **kwargs)\n", - " |\n", - " | # boost_velocity and 1-sigma error estimate\n", - " | boost_velocity, boost_velocity_err = fit.boost_velocity(q, chiA, chiB, **kwargs)\n", + " | #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call:\n", + " | alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs)\n", " |\n", " | The arguments for each of these call methods are as follows:\n", " | Arguments:\n", @@ -140,60 +136,19 @@ " | aligned_spin_only: raise an error if given precessing spins.\n", " | See _fit_evaluators.fit_7dq2.py for an example.\n", " |\n", - " | ----------------------------------------------------------------------\n", - " | Methods inherited from surfinBH.surfinBH.SurFinBH:\n", - " |\n", " | all(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for remnant mass, spin\n", - " | and kick velocity.\n", - " | Returns:\n", - " | mf, chif, vf, mf_err_est, chif_err_est, vf_err_est\n", - " |\n", - " | chif, vf, chif_err_est and vf_err_est are arrays of size 3.\n", - " |\n", - " | In the case of NRsur3dq8BMSRemnant evaluates fit and 1-sigma error estimate for the\n", - " | supertranslation parameter's modes and boost velocity of the BMS transformation from the PN\n", - " | BMS frame to the remnant BMS frame.\n", - " | Returns:\n", - " | alpha, vf, alpha_err, vf_err\n", - " |\n", - " | alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering.\n", - " | vf,vf_err are arrays of size 3.\n", - " |\n", - " | boost_velocity(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for the boost velocity of the BMS transformation from the PN\n", - " | BMS frame to the remnant BMS frame.\n", + " | Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity of the BMS transformation from the inspiral BMS frame to the remnant BMS frame\n", " | Returns:\n", - " | vf, alpha_err, vf_err\n", - " |\n", - " | vf,vf_err are arrays of size 3.\n", + " | alpha, boost_vel, alpha_err, boost_vel_err\n", " |\n", " | chif(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for remnant spin.\n", - " | Returns:\n", - " | chif, chif_err_est\n", - " |\n", - " | chif and chif_err_est are arrays of size 3.\n", + " | chif is not implemented in this model. Will return (None, None),\n", " |\n", " | mf(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for remnant mass.\n", - " | Returns:\n", - " | mf, mf_err_est\n", - " |\n", - " | supertranslation(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for the supertranslation parameter of the BMS transformation from the PN\n", - " | BMS frame to the remnant BMS frame.\n", - " | Returns:\n", - " | alpha, alpha_err\n", - " |\n", - " | alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering.\n", + " | mf is not implemented in this model. Will return (None, None),\n", " |\n", " | vf(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for remnant kick velocity.\n", - " | Returns:\n", - " | vf, vf_err_est\n", - " |\n", - " | vf and vf_err_est are arrays of size 3.\n", + " | vf is not implemented in this model. Will return (None, None),\n", " |\n", " | ----------------------------------------------------------------------\n", " | Data descriptors inherited from surfinBH.surfinBH.SurFinBH:\n", @@ -220,7 +175,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -235,17 +190,12 @@ "#the remnant BMS frame\n", "\n", "# supertranslation parameter alpha and 1-sigma error estimate\n", - "#NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", + "# NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", "# the order of the modes in the array is (2,-2),(2,-1),(2,0),(2,1),(2,2),(3,-3),(3,-2),(3,-1),...\n", "# (same order used in spherical_functions package)\n", - "\n", - "alpha, alpha_err = fit.supertranslation(q, chiA, chiB)\n", - "\n", "# boost velocity v and 1-sigma error estimate\n", - "v, v_err = fit.boost_velocity(q, chiA, chiB)\n", "\n", - "# All of these together\n", - "alpha, v, alpha_err, v_err = fit.all(q, chiA, chiB)" + "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)" ] }, { From 347238128f982f09c5ab092a1ad95d908d04c1e4 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 18:23:03 -0800 Subject: [PATCH 15/36] added zeros for the ell=0,1 modes in the supertranslation parameter --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index ebceb85..0ed6a1f 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -38,8 +38,8 @@ def get_ellm(i,ell_min = 2, ell_max = 8): #------------------------------------------------------------------------- def get_full_supertranslation_array(positive_m_modes,ell_max): """ This function recreates the full array of all the (ell,m) modes of the supertranslation parameter from - the m >= 0 modes only (it's real). The output array uses the spherical_functions package ordering - [(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] + the m >= 0 modes only (it's real). The output array uses the spherical_functions (and scri) package ordering + [(0,0),(1,-1),(1,0),(1,1),(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] """ positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) res = [] @@ -50,6 +50,8 @@ def get_full_supertranslation_array(positive_m_modes,ell_max): ell, m = get_ellm(i, ell_min = 2, ell_max = ell_max) alpha_bar = positive_m_modes[sf.LM_index(ell,-m,2)].conjugate() res.append(alpha_bar*(-1)**m) + #the modes with ell = 0,1, corresponding to a spacetime translation are set to zero + res = [complex(0)] * 4 + res return np.array(res) @@ -59,7 +61,7 @@ class Fit3dq8BMS(surfinBH.SurFinBH): """ A class for the NRSur3dq8BMSRemnant model presented in Da Re et al., arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper. - This model predicts the supertransation modes up to ell = 8 and the + This model predicts the proper supertransation modes up to ell = 8 and the 3 components of the boost velocity of the BMS transformation from the inspiral (PN) BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing binary black hole systems. The fits are done using Gaussian Process @@ -80,6 +82,10 @@ class Fit3dq8BMS(surfinBH.SurFinBH): #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call: alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, depend on the location of + the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry + no physical significance. Consequently they are set to be identically zero. + The arguments for each of these call methods are as follows: Arguments: q: Mass ratio (q>=1) From dee62c36699df6be46158b5fec5c11ce678c110d Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 18:24:56 -0800 Subject: [PATCH 16/36] fixed the example to evaluate the new supertranslation array complete with the ell=0,1 modes --- examples/example_3dq8BMS.ipynb | 74 +++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 3941d16..eb42277 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -9,16 +9,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/gdare/miniconda3/envs/scri/lib/python3.12/site-packages/lalsuite-7.23-py3.12-linux-x86_64.egg/lalsimulation/lalsimulation.py:8: UserWarning: Wswiglal-redir-stdio:\n", + "\n", + "SWIGLAL standard output/error redirection is enabled in IPython.\n", + "This may lead to performance penalties. To disable locally, use:\n", + "\n", + "with lal.no_swig_redirect_standard_output_error():\n", + " ...\n", + "\n", + "To disable globally, use:\n", + "\n", + "lal.swig_redirect_standard_output_error(False)\n", + "\n", + "Note however that this will likely lead to error messages from\n", + "LAL functions being either misdirected or lost when called from\n", + "Jupyter notebooks.\n", + "\n", + "To suppress this warning, use:\n", + "\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\", \"Wswiglal-redir-stdio\")\n", + "import lal\n", + "\n", + " import lal\n" + ] + } + ], "source": [ + "import sys\n", + "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH/\")\n", "import surfinBH" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -34,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -58,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "scrolled": true }, @@ -75,7 +107,7 @@ " | A class for the NRSur3dq8BMSRemnant model presented in Da Re et al.,\n", " | arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper.\n", " |\n", - " | This model predicts the supertransation modes up to ell = 8 and the\n", + " | This model predicts the proper supertransation modes up to ell = 8 and the\n", " | 3 components of the boost velocity of the BMS transformation from the inspiral (PN)\n", " | BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing\n", " | binary black hole systems. The fits are done using Gaussian Process\n", @@ -96,6 +128,10 @@ " | #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call:\n", " | alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs)\n", " |\n", + " | # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, depend on the location of\n", + " | the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry\n", + " | no physical significance. Consequently they are set to be identically zero.\n", + " |\n", " | The arguments for each of these call methods are as follows:\n", " | Arguments:\n", " | q: Mass ratio (q>=1)\n", @@ -137,7 +173,8 @@ " | See _fit_evaluators.fit_7dq2.py for an example.\n", " |\n", " | all(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity of the BMS transformation from the inspiral BMS frame to the remnant BMS frame\n", + " | Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity\n", + " | of the BMS transformation from the inspiral BMS frame to the remnant BMS frame\n", " | Returns:\n", " | alpha, boost_vel, alpha_err, boost_vel_err\n", " |\n", @@ -175,9 +212,20 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(0.011456326974619718+0j)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "q = 4.3 # Mass ratio q>=1\n", "chiA = [0,0,0.6] # Spin of larger BH (z-direction only)\n", @@ -195,7 +243,13 @@ "# (same order used in spherical_functions package)\n", "# boost velocity v and 1-sigma error estimate\n", "\n", - "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)" + "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)\n", + "\n", + "# to get a specific supertranslation mode from alpha you can use the spherical_function package\n", + "import spherical_functions as sf\n", + "\n", + "#20 mode, the last index in LM_index indicates that the lowest ell mode is ell=0\n", + "alpha[sf.LM_index(2,0,0)]" ] }, { From 673110840ab46d84b6aae4dd723a7cf8c2306ed6 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 18:32:55 -0800 Subject: [PATCH 17/36] fixed a typo in a comment --- examples/example_3dq8BMS.ipynb | 40 ++++------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index eb42277..23231c2 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -9,42 +9,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/gdare/miniconda3/envs/scri/lib/python3.12/site-packages/lalsuite-7.23-py3.12-linux-x86_64.egg/lalsimulation/lalsimulation.py:8: UserWarning: Wswiglal-redir-stdio:\n", - "\n", - "SWIGLAL standard output/error redirection is enabled in IPython.\n", - "This may lead to performance penalties. To disable locally, use:\n", - "\n", - "with lal.no_swig_redirect_standard_output_error():\n", - " ...\n", - "\n", - "To disable globally, use:\n", - "\n", - "lal.swig_redirect_standard_output_error(False)\n", - "\n", - "Note however that this will likely lead to error messages from\n", - "LAL functions being either misdirected or lost when called from\n", - "Jupyter notebooks.\n", - "\n", - "To suppress this warning, use:\n", - "\n", - "import warnings\n", - "warnings.filterwarnings(\"ignore\", \"Wswiglal-redir-stdio\")\n", - "import lal\n", - "\n", - " import lal\n" - ] - } - ], + "outputs": [], "source": [ - "import sys\n", - "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH/\")\n", "import surfinBH" ] }, @@ -239,8 +207,8 @@ "\n", "# supertranslation parameter alpha and 1-sigma error estimate\n", "# NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", - "# the order of the modes in the array is (2,-2),(2,-1),(2,0),(2,1),(2,2),(3,-3),(3,-2),(3,-1),...\n", - "# (same order used in spherical_functions package)\n", + "# the order of the modes in the array is (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),(2,1),(2,2),...\n", + "# (same order used in spherical_functions and scri package)\n", "# boost velocity v and 1-sigma error estimate\n", "\n", "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)\n", From 39c970b4d3d065f5b5b9e867748106e7ff2a8163 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 18:40:58 -0800 Subject: [PATCH 18/36] fixed a comment --- examples/example_3dq8BMS.ipynb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 23231c2..a1edb51 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -205,11 +205,12 @@ "#velocity v associated to the BMS transformation from the PN BMS frame to\n", "#the remnant BMS frame\n", "\n", - "# supertranslation parameter alpha and 1-sigma error estimate\n", - "# NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", - "# the order of the modes in the array is (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),(2,1),(2,2),...\n", - "# (same order used in spherical_functions and scri package)\n", - "# boost velocity v and 1-sigma error estimate\n", + "# Outputs:\n", + "# - supertranslation parameter alpha and 1-sigma error estimate alpha_err\n", + "# NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", + "# the order of the modes in the array is (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),(2,1),(2,2),...\n", + "# (same order used in spherical_functions and scri package)\n", + "# - boost velocity and 1-sigma error estimate boost_vel_err\n", "\n", "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)\n", "\n", From 5ba8c53d17d387a8adf5809bbc98e0a0ef60d419 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 14 Jan 2025 18:41:48 -0800 Subject: [PATCH 19/36] added more docs comments --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index 0ed6a1f..88f0bd1 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -50,7 +50,7 @@ def get_full_supertranslation_array(positive_m_modes,ell_max): ell, m = get_ellm(i, ell_min = 2, ell_max = ell_max) alpha_bar = positive_m_modes[sf.LM_index(ell,-m,2)].conjugate() res.append(alpha_bar*(-1)**m) - #the modes with ell = 0,1, corresponding to a spacetime translation are set to zero + #the modes with ell = 0,1, corresponding to a spacetime translation are identically set to zero res = [complex(0)] * 4 + res return np.array(res) @@ -86,6 +86,9 @@ class Fit3dq8BMS(surfinBH.SurFinBH): the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry no physical significance. Consequently they are set to be identically zero. + # alpha is expressed as a complex array of spherical harmonics modes in the order (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),... + (same convention as the spherical_functions and scri packages) + The arguments for each of these call methods are as follows: Arguments: q: Mass ratio (q>=1) From 10e783f83b505d0ad79ede899a733e3ebe7a1ce4 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 21 Jan 2025 16:53:42 -0800 Subject: [PATCH 20/36] added tests for 3dq8BMS --- test/test_regression.py | 52 ++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/test/test_regression.py b/test/test_regression.py index c4c496f..7028570 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -27,12 +27,6 @@ def test_fit_regression(): fit_names = surfinBH.fits_collection.keys() for name in fit_names: - - # For now NRSur3dq8BMSRemnant has to be skipped, as generate_regression_data.py needs to be updated - # to accomodate for the BMS transformation - # parameters fits - if name == 'NRSur3dq8BMSRemnant': - continue if name == 'NRSur7dq4EmriRemnant': # FIXME Somehow, the error estimate for this fit seems particularly @@ -77,22 +71,38 @@ def test_fit_regression(): q = test_h5grp['q'][()] chiA = test_h5grp['chiA'][()] chiB = test_h5grp['chiB'][()] - - # remnant mass - y_reg = test_h5grp['y/mf'][()] - y_fit = fit.mf(q, chiA, chiB, **kwargs) - np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) - - # remnant spin - y_reg = test_h5grp['y/chif'][()] - y_fit = fit.chif(q, chiA, chiB, **kwargs) - np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) - # remnant kick - # Needed for NRSur7dq4EmriRemnant - if 'vf' in test_h5grp['y'].keys(): - y_reg = test_h5grp['y/vf'][()] - y_fit = fit.vf(q, chiA, chiB, **kwargs) + if name == 'NRSur3dq8BMSRemnant': + #compute fits + alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + + # supertranslation + y_reg = test_h5grp['y/alpha'][()] + y_fit = alpha, alpha_err np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) + # boost velocity + y_reg = test_h5grp['y/boost_vel'][()] + y_fit = boost_vel, boost_vel_err + np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) + + else: + # remnant mass + y_reg = test_h5grp['y/mf'][()] + y_fit = fit.mf(q, chiA, chiB, **kwargs) + np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) + + # remnant spin + y_reg = test_h5grp['y/chif'][()] + y_fit = fit.chif(q, chiA, chiB, **kwargs) + np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) + + # remnant kick + # Needed for NRSur7dq4EmriRemnant + if 'vf' in test_h5grp['y'].keys(): + y_reg = test_h5grp['y/vf'][()] + y_fit = fit.vf(q, chiA, chiB, **kwargs) + np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) + + regression_h5file.close() From 9d6af896812cedc18b8ac94bd360623788ed161a Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 21 Jan 2025 16:54:43 -0800 Subject: [PATCH 21/36] added function to generate regression data for 3dq8BMS --- test/generate_regression_data.py | 35 ++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index c0309f3..d21059c 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -5,6 +5,34 @@ import surfinBH +def save_data_3dq8BMS(h5grp, fit, num_tests, kwargs={}): + + for i in range(num_tests): + # save each test evaluation as group + test_h5grp = h5grp.create_group('test_%d'%i) + + # Generate params randomly within allowed values + q, chiA, chiB = fit._generate_random_params_for_tests() + + # save params + test_h5grp.create_dataset('q', data=q) + test_h5grp.create_dataset('chiA', data=chiA) + test_h5grp.create_dataset('chiB', data=chiB) + + # save evaluations as a group + y_h5grp = test_h5grp.create_group('y') + + alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + + # supertranslation + y = alpha, alpha_err + y_h5grp.create_dataset('alpha', data=y) + + # boost velocity + y = boost_vel, boost_vel_err + y_h5grp.create_dataset('boost_vel', data=y) + + def save_data(h5grp, fit, num_tests, kwargs={}): @@ -23,7 +51,7 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save evaluations as a group y_h5grp = test_h5grp.create_group('y') - # remnant mass + # remnant mass y = fit.mf(q, chiA, chiB, **kwargs) y_h5grp.create_dataset('mf', data=y) @@ -63,7 +91,10 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save regression without optional kwargs h5grp = h5file.create_group('No_kwargs') - save_data(h5grp, fit, num_tests) + if name_tag == '3dq8BMS': + save_data_3dq8BMS(h5grp, fit, num_tests) + else: + save_data(h5grp, fit, num_tests) # save regression with optional kwargs. # NOTE: this would be empty unless _extra_regression_kwargs() is From 4949652d60fb058449dbac382dae2bd30ee157a1 Mon Sep 17 00:00:00 2001 From: gdare Date: Tue, 21 Jan 2025 16:55:12 -0800 Subject: [PATCH 22/36] generated regression data for 3dq8BMS --- test/regression_data/fit_3dq8BMS.h5 | Bin 63512 -> 64792 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/regression_data/fit_3dq8BMS.h5 b/test/regression_data/fit_3dq8BMS.h5 index fc829fca8d08c2e6421e51370e78dd9b5aabfd52..066a7846fe76cf68809190e2f7b3795a0578b611 100644 GIT binary patch literal 64792 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 literal 63512 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
VH4q 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 baC|`GqvHP?>)N(>Tu(+g Date: Wed, 22 Jan 2025 12:24:20 -0800 Subject: [PATCH 23/36] added url for NRSur3dq8BMSRemnant --- surfinBH/_loadFits.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/surfinBH/_loadFits.py b/surfinBH/_loadFits.py index f958731..7ad3efe 100644 --- a/surfinBH/_loadFits.py +++ b/surfinBH/_loadFits.py @@ -114,10 +114,12 @@ def DownloadData(name='all', data_dir=DataPath()): refs = 'arxiv:2408.05300', ) +#update arxiv number and url (zenodo) when available fits_collection['NRSur3dq8BMSRemnant'] = FitAttributes( \ fit_class = _fit_evaluators.Fit3dq8BMS, desc = 'Fits for supertranslation parameter modes and boost velocity of the BMS' - 'transformation from the PN BMS frame to the remnant BMS frame', - data_url = '/fit_3dq8BMS.h5', + ' transformation from the PN BMS frame to the remnant BMS frame ' + ' for nonprecessing BBH systems.', + data_url = 'https://raw.githubusercontent.com/gda98re/files/surfinBH/fit_3dq8BMS.h5', refs = 'arxiv:????.?????', ) From c677f9db0fed79e73b5e768a9b775a1f90687d61 Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 15:59:26 -0800 Subject: [PATCH 24/36] modified few minor typos in comments or docs --- examples/example_3dq8BMS.ipynb | 5 ++++- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 6 +++--- surfinBH/surfinBH.py | 8 +++++--- test/test_regression.py | 1 - 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index a1edb51..f41022c 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -73,7 +73,7 @@ " | Fit3dq8BMS(name)\n", " |\n", " | A class for the NRSur3dq8BMSRemnant model presented in Da Re et al.,\n", - " | arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper.\n", + " | arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper.\n", " |\n", " | This model predicts the proper supertransation modes up to ell = 8 and the\n", " | 3 components of the boost velocity of the BMS transformation from the inspiral (PN)\n", @@ -100,6 +100,9 @@ " | the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry\n", " | no physical significance. Consequently they are set to be identically zero.\n", " |\n", + " | # alpha is expressed as a complex array of spherical harmonics modes in the order (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),...\n", + " | (same convention as the spherical_functions and scri packages)\n", + " |\n", " | The arguments for each of these call methods are as follows:\n", " | Arguments:\n", " | q: Mass ratio (q>=1)\n", diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index 88f0bd1..4fbdd7a 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -59,7 +59,7 @@ def get_full_supertranslation_array(positive_m_modes,ell_max): #============================================================================= class Fit3dq8BMS(surfinBH.SurFinBH): """ A class for the NRSur3dq8BMSRemnant model presented in Da Re et al., - arxiv:xxxxxxxxx. This model is referred to as surfinBH3dq8BMS in the paper. + arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper. This model predicts the proper supertransation modes up to ell = 8 and the 3 components of the boost velocity of the BMS transformation from the inspiral (PN) @@ -151,7 +151,7 @@ def _load_fits(self, h5file): #------------------------------------------------------------------------- def _get_fit_params(self, x, fit_key): - """ Transforms the input parameter to fit parameters for the 3dq8 model. + """ Transforms the input parameter to fit parameters for the 3dq8BMS model. That is, maps from [q, chiAz, chiBz] to [np.log(q), chiHat, chi_a] chiHat is defined in Eq.(3) of 1508.07253. chi_a = (chiAz - chiBz)/2. @@ -187,7 +187,7 @@ def all(self, *args, **kwargs): #------------------------------------------------------------------------- def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): - """ Evaluates the NRSur3dq8Remnant model. + """ Evaluates the NRSur3dq8BMSRemnant model. """ chiA = np.array(chiA) chiB = np.array(chiB) diff --git a/surfinBH/surfinBH.py b/surfinBH/surfinBH.py index da39b75..3c580b5 100644 --- a/surfinBH/surfinBH.py +++ b/surfinBH/surfinBH.py @@ -315,10 +315,12 @@ def all(self, *args, **kwargs): supertranslation parameter's modes and boost velocity of the BMS transformation from the PN BMS frame to the remnant BMS frame. Returns: - alpha, vf, alpha_err, vf_err + alpha, boost_vel, alpha_err, boost_vel_err - alpha, alpha_err arrays of modes from (2,-2) to (8,8) with spherical_function ordering. - vf,vf_err are arrays of size 3. + alpha, alpha_err complex arrays of spherical harmonics modes from ell = 0 to ell = 8 with spherical_function package mode ordering. + [(0,0),(1,-1),(1,0),(1,1),(2,-2),...,(8,8)] + + boost_vel, boost_vel_err are arrays of size 3. """ return self._eval_wrapper('all', *args, **kwargs) diff --git a/test/test_regression.py b/test/test_regression.py index 7028570..4ced497 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -25,7 +25,6 @@ def test_fit_regression(): """ # List of all available fits fit_names = surfinBH.fits_collection.keys() - for name in fit_names: if name == 'NRSur7dq4EmriRemnant': From d87e2cdc4c7637579daa31c0c1cd1f7e9f37f2f0 Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 16:01:23 -0800 Subject: [PATCH 25/36] restored single_kwargs_test function to its original way, removed 3dq8BMS from the models to loop over in test_interface.py --- test/test_interface.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/test/test_interface.py b/test/test_interface.py index 86ccb81..d5b4389 100644 --- a/test/test_interface.py +++ b/test/test_interface.py @@ -37,21 +37,18 @@ def single_kwargs_test(fit, num_tests, kwargs={}): # Check that all_data has the right ordering rtol = 1e-11 - # Needed for NRSur3dq8BMSRemnant - if mf_and_err[0] is not None: - if hasattr(mf_and_err, '__len__'): # has both fit val and err_est - np.testing.assert_allclose(mf_and_err[0], all_data[0], rtol=rtol) - np.testing.assert_allclose(mf_and_err[1], all_data[3], rtol=rtol) - else: - np.testing.assert_allclose(mf_and_err, all_data[0], rtol=rtol) - # Needed for NRSur3dq8BMSRemnant - if chif_and_err[0] is not None: - if hasattr(chif_and_err, '__len__'): # has both fit val and err_est - np.testing.assert_allclose(chif_and_err[0], all_data[1], rtol=rtol) - np.testing.assert_allclose(chif_and_err[1], all_data[4], rtol=rtol) - else: - np.testing.assert_allclose(chif_and_err, all_data[1], rtol=rtol) - # Needed for NRSur7dq4EmriRemnant and NRSur3dq8BMSRemnant + if hasattr(mf_and_err, '__len__'): # has both fit val and err_est + np.testing.assert_allclose(mf_and_err[0], all_data[0], rtol=rtol) + np.testing.assert_allclose(mf_and_err[1], all_data[3], rtol=rtol) + else: + np.testing.assert_allclose(mf_and_err, all_data[0], rtol=rtol) + + if hasattr(chif_and_err, '__len__'): # has both fit val and err_est + np.testing.assert_allclose(chif_and_err[0], all_data[1], rtol=rtol) + np.testing.assert_allclose(chif_and_err[1], all_data[4], rtol=rtol) + else: + np.testing.assert_allclose(chif_and_err, all_data[1], rtol=rtol) + # Needed for NRSur7dq4EmriRemnant if vf_and_err[0] is not None: if hasattr(vf_and_err, '__len__'): # has both fit val and err_est np.testing.assert_allclose(vf_and_err[0], all_data[2], rtol=rtol) @@ -67,6 +64,11 @@ def test_interface(): # List of all available fits fit_names = surfinBH.fits_collection.keys() for name in fit_names: + + # since there are no methods for the fit parameters of 3dq8BMS yet, these tests + # cannot be applied to this model + if name == 'NRSur3dq8BMSRemnant': continue + # Load fit fit = surfinBH.LoadFits(name) From 91535b49fb5b6b7d4171dfe1a39e6c6cf7f841e9 Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 16:14:53 -0800 Subject: [PATCH 26/36] removed unnecessary tabs --- test/generate_regression_data.py | 2 +- test/test_regression.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index d21059c..9692224 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -51,7 +51,7 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save evaluations as a group y_h5grp = test_h5grp.create_group('y') - # remnant mass + # remnant mass y = fit.mf(q, chiA, chiB, **kwargs) y_h5grp.create_dataset('mf', data=y) diff --git a/test/test_regression.py b/test/test_regression.py index 4ced497..c811110 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -26,7 +26,7 @@ def test_fit_regression(): # List of all available fits fit_names = surfinBH.fits_collection.keys() for name in fit_names: - + if name == 'NRSur7dq4EmriRemnant': # FIXME Somehow, the error estimate for this fit seems particularly # finnicky accross different machines. For now, essentially From 9af9faccf1805168a5b6d427ada4545713589d24 Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 16:17:31 -0800 Subject: [PATCH 27/36] removed one more unnecessary tab --- test/generate_regression_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index 9692224..7703f27 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -51,7 +51,7 @@ def save_data(h5grp, fit, num_tests, kwargs={}): # save evaluations as a group y_h5grp = test_h5grp.create_group('y') - # remnant mass + # remnant mass y = fit.mf(q, chiA, chiB, **kwargs) y_h5grp.create_dataset('mf', data=y) From 466a2415f9101fe445ae0c97c67a3121afa585bf Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 20:02:09 -0800 Subject: [PATCH 28/36] changed name positive -> non_negative, simplified first two functions of fit_3dq8BMS.py,no use of lists in get_full_supertranslation_array() --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 44 +++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index 4fbdd7a..d20dfab 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -4,25 +4,19 @@ import warnings #------------------------------------------------------------------------- -def get_positive_modes_indices(ell_min = 2,ell_max = 8): +def get_non_negative_modes_indices(ell_min = 2,ell_max = 8): """ This function gives all the indices corresponding to m >= 0 modes of a spherical harmonics decomposition using spherical_functions package ordering convention """ - d = [] - for ell in range(ell_min,ell_max + 1): - for m in range(0,ell + 1): - d.append(sf.LM_index(ell,m,ell_min)) - return d + return [sf.LM_index(ell,m,ell_min) for ell in range(ell_min,ell_max + 1) + for m in range(0,ell + 1)] #------------------------------------------------------------------------- def get_zero_modes_indices(ell_min = 2, ell_max = 8): """ This function gives all the indices corresponding to m = 0 modes of a spherical harmonics decomposition using spherical_functions package ordering convention """ - d = [] - for ell in range(ell_min,ell_max + 1): - d.append(sf.LM_index(ell,0,ell_min)) - return d + return [sf.LM_index(ell,0,ell_min) for ell in range(ell_min,ell_max + 1)] #------------------------------------------------------------------------- def get_ellm(i,ell_min = 2, ell_max = 8): @@ -36,23 +30,25 @@ def get_ellm(i,ell_min = 2, ell_max = 8): raise ValueError('Wrong index') #------------------------------------------------------------------------- -def get_full_supertranslation_array(positive_m_modes,ell_max): - """ This function recreates the full array of all the (ell,m) modes of the supertranslation parameter from - the m >= 0 modes only (it's real). The output array uses the spherical_functions (and scri) package ordering +def get_full_supertranslation_array(non_negative_m_modes,ell_max): + """ This function recreates the full array of all the (ell,m) modes of the supertranslation parameter alpha from + the m >= 0 modes only (alpha it's real). The output array uses the spherical_functions (and scri) package ordering [(0,0),(1,-1),(1,0),(1,1),(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] """ - positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) - res = [] + non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) + res = np.zeros((sf.LM_total_size(0,ell_max),), dtype=complex) + for i in range(sf.LM_index(2,-2,2),sf.LM_index(ell_max,ell_max,2)+1): - if i in positive_m_modes_indices: - res.append(positive_m_modes[i]) + if i in non_negative_m_modes_indices: + #first 4 indices are reserved for the ell=0,1 modes with values set to 0 + res[i + 4] = non_negative_m_modes[i] else: ell, m = get_ellm(i, ell_min = 2, ell_max = ell_max) - alpha_bar = positive_m_modes[sf.LM_index(ell,-m,2)].conjugate() - res.append(alpha_bar*(-1)**m) - #the modes with ell = 0,1, corresponding to a spacetime translation are identically set to zero - res = [complex(0)] * 4 + res - return np.array(res) + alpha_bar = non_negative_m_modes[sf.LM_index(ell,-m,2)].conjugate() + #first 4 indices are reserved for the ell=0,1 modes with values set to 0 + res[i + 4] = alpha_bar*(-1)**m + + return res @@ -140,7 +136,7 @@ def _load_fits(self, h5file): """ Loads fits from h5file and returns a dictionary of fits. """ fits = {} ell_max = 8 - positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + positive_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) keys_sup_real = [f'sup_real({i})' for i in positive_m_modes_indices] keys_sup_imag = [f'sup_imag({i})' for i in positive_m_modes_indices if i not in zero_m_modes_indices] @@ -203,7 +199,7 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): ell_max = 8 sur_predictions_positive_m_modes = {} sur_predictions_positive_m_modes_err = {} - positive_m_modes_indices = get_positive_modes_indices(ell_min = 2,ell_max = ell_max) + positive_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) for i in positive_m_modes_indices: sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') From 090f525a658acdd5886eae2638411e44769aab4f Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 20:08:08 -0800 Subject: [PATCH 29/36] get_ellm -> ind_to_LM, faster evaluation with analytic formula --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index d20dfab..b408db9 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -19,15 +19,13 @@ def get_zero_modes_indices(ell_min = 2, ell_max = 8): return [sf.LM_index(ell,0,ell_min) for ell in range(ell_min,ell_max + 1)] #------------------------------------------------------------------------- -def get_ellm(i,ell_min = 2, ell_max = 8): - """ This function converts an index labelling a spherical harmonics component in the - spherical_functions package convention back into a tuple (ell,m) - """ - for ell in range(ell_min,ell_max +1): - for m in range(-ell,ell + 1): - if i == sf.LM_index(ell, m, ell_min): - return ell,m - raise ValueError('Wrong index') +def ind_to_LM(ind, ell_min): + """Inverse function of spherical_functions.LM_index. + (ell,m) = ind_to_LM(ind, ell_min) corresponds to + ind = sf.LM_index(ell, m, ell_min).""" + + ell = np.floor(np.sqrt(ind + ell_min**2)) + return ell, ind - ell*(ell+1) + ell_min**2 #------------------------------------------------------------------------- def get_full_supertranslation_array(non_negative_m_modes,ell_max): @@ -35,15 +33,15 @@ def get_full_supertranslation_array(non_negative_m_modes,ell_max): the m >= 0 modes only (alpha it's real). The output array uses the spherical_functions (and scri) package ordering [(0,0),(1,-1),(1,0),(1,1),(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] """ - non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) - res = np.zeros((sf.LM_total_size(0,ell_max),), dtype=complex) + non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2, ell_max = ell_max) + res = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) - for i in range(sf.LM_index(2,-2,2),sf.LM_index(ell_max,ell_max,2)+1): + for i in range(sf.LM_index(2,-2,2),sf.LM_index(ell_max, ell_max,2)+1): if i in non_negative_m_modes_indices: #first 4 indices are reserved for the ell=0,1 modes with values set to 0 res[i + 4] = non_negative_m_modes[i] else: - ell, m = get_ellm(i, ell_min = 2, ell_max = ell_max) + ell, m = ind_to_LM(ind = i, ell_min = 2) alpha_bar = non_negative_m_modes[sf.LM_index(ell,-m,2)].conjugate() #first 4 indices are reserved for the ell=0,1 modes with values set to 0 res[i + 4] = alpha_bar*(-1)**m From 06f01b5a9a92a883334ab6fe875c9d86f0ae9d57 Mon Sep 17 00:00:00 2001 From: gdare Date: Wed, 22 Jan 2025 20:11:27 -0800 Subject: [PATCH 30/36] fixed a typo in a doc string --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index b408db9..52ee207 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -22,8 +22,8 @@ def get_zero_modes_indices(ell_min = 2, ell_max = 8): def ind_to_LM(ind, ell_min): """Inverse function of spherical_functions.LM_index. (ell,m) = ind_to_LM(ind, ell_min) corresponds to - ind = sf.LM_index(ell, m, ell_min).""" - + ind = sf.LM_index(ell, m, ell_min). + """ ell = np.floor(np.sqrt(ind + ell_min**2)) return ell, ind - ell*(ell+1) + ell_min**2 From d8992c7ae7844775231524b83c6d199e1e041a85 Mon Sep 17 00:00:00 2001 From: gdare Date: Thu, 23 Jan 2025 11:16:38 -0800 Subject: [PATCH 31/36] fixed more positive -> non_negative, moved if statements up --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 52 +++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index 52ee207..ec47862 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -134,10 +134,10 @@ def _load_fits(self, h5file): """ Loads fits from h5file and returns a dictionary of fits. """ fits = {} ell_max = 8 - positive_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) + non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) - keys_sup_real = [f'sup_real({i})' for i in positive_m_modes_indices] - keys_sup_imag = [f'sup_imag({i})' for i in positive_m_modes_indices if i not in zero_m_modes_indices] + keys_sup_real = [f'sup_real({i})' for i in non_negative_m_modes_indices] + keys_sup_imag = [f'sup_imag({i})' for i in non_negative_m_modes_indices if i not in zero_m_modes_indices] keys_vel = ['boost_velx','boost_vely','boost_velz'] for key in keys_vel + keys_sup_real + keys_sup_imag: fits[key] = self._load_scalar_fit(fit_key=key, h5file=h5file) @@ -183,6 +183,20 @@ def all(self, *args, **kwargs): def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): """ Evaluates the NRSur3dq8BMSRemnant model. """ + + # mf,chif,vf not implemented for this model + if fit_key == 'mf': + mf, mf_err = None, None + return mf, mf_err + + if fit_key == 'chif': + chif, chif_err = None, None + return chif, chif_err + + if fit_key == 'vf': + vf, vf_err = None, None + return vf, vf_err + chiA = np.array(chiA) chiB = np.array(chiB) @@ -195,39 +209,27 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): x = [q, chiA[2], chiB[2]] ell_max = 8 - sur_predictions_positive_m_modes = {} - sur_predictions_positive_m_modes_err = {} - positive_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) + sur_predictions_non_negative_m_modes = {} + sur_predictions_non_negative_m_modes_err = {} + non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) - for i in positive_m_modes_indices: + for i in non_negative_m_modes_indices: sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') if i not in zero_m_modes_indices: sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({i})') - sur_predictions_positive_m_modes[i] = sup_real + (1j)*sup_imag - sur_predictions_positive_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err + sur_predictions_non_negative_m_modes[i] = sup_real + (1j)*sup_imag + sur_predictions_non_negative_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err else: - sur_predictions_positive_m_modes[i] = sup_real - sur_predictions_positive_m_modes_err[i] = sup_real_err - alpha = get_full_supertranslation_array(sur_predictions_positive_m_modes,ell_max) - alpha_err = get_full_supertranslation_array(sur_predictions_positive_m_modes_err,ell_max) + sur_predictions_non_negative_m_modes[i] = sup_real + sur_predictions_non_negative_m_modes_err[i] = sup_real_err + alpha = get_full_supertranslation_array(sur_predictions_non_negative_m_modes,ell_max) + alpha_err = get_full_supertranslation_array(sur_predictions_non_negative_m_modes_err,ell_max) boost_velx, boost_velx_err = self._evaluate_fits(x, 'boost_velx') boost_vely, boost_vely_err = self._evaluate_fits(x, 'boost_vely') boost_velz, boost_velz_err = self._evaluate_fits(x, 'boost_velz') boost_vel = np.array([boost_velx, boost_vely, boost_velz]) boost_vel_err = np.array([boost_velx_err, boost_vely_err, boost_velz_err]) - - if fit_key == 'mf': - mf, mf_err = None, None - return mf, mf_err - - if fit_key == 'chif': - chif, chif_err = None, None - return chif, chif_err - - if fit_key == 'vf': - vf, vf_err = None, None - return vf, vf_err if fit_key == 'all': return alpha, boost_vel, alpha_err, boost_vel_err From 196889e6eb4ee92b5a4476c0cbd588f695b9f6b0 Mon Sep 17 00:00:00 2001 From: gdare Date: Thu, 23 Jan 2025 20:08:07 -0800 Subject: [PATCH 32/36] removed unnecessary methods, simplified _eval_wrapper --- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 85 ++++++------------------- 1 file changed, 20 insertions(+), 65 deletions(-) diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index ec47862..ed71d11 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -3,52 +3,6 @@ from surfinBH import surfinBH import warnings -#------------------------------------------------------------------------- -def get_non_negative_modes_indices(ell_min = 2,ell_max = 8): - """ This function gives all the indices corresponding to m >= 0 modes - of a spherical harmonics decomposition using spherical_functions package ordering convention - """ - return [sf.LM_index(ell,m,ell_min) for ell in range(ell_min,ell_max + 1) - for m in range(0,ell + 1)] - -#------------------------------------------------------------------------- -def get_zero_modes_indices(ell_min = 2, ell_max = 8): - """ This function gives all the indices corresponding to m = 0 modes - of a spherical harmonics decomposition using spherical_functions package ordering convention - """ - return [sf.LM_index(ell,0,ell_min) for ell in range(ell_min,ell_max + 1)] - -#------------------------------------------------------------------------- -def ind_to_LM(ind, ell_min): - """Inverse function of spherical_functions.LM_index. - (ell,m) = ind_to_LM(ind, ell_min) corresponds to - ind = sf.LM_index(ell, m, ell_min). - """ - ell = np.floor(np.sqrt(ind + ell_min**2)) - return ell, ind - ell*(ell+1) + ell_min**2 - -#------------------------------------------------------------------------- -def get_full_supertranslation_array(non_negative_m_modes,ell_max): - """ This function recreates the full array of all the (ell,m) modes of the supertranslation parameter alpha from - the m >= 0 modes only (alpha it's real). The output array uses the spherical_functions (and scri) package ordering - [(0,0),(1,-1),(1,0),(1,1),(2,2),(2,-1),(2,0),(2,1),(2,2),(3,-3),...] - """ - non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2, ell_max = ell_max) - res = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) - - for i in range(sf.LM_index(2,-2,2),sf.LM_index(ell_max, ell_max,2)+1): - if i in non_negative_m_modes_indices: - #first 4 indices are reserved for the ell=0,1 modes with values set to 0 - res[i + 4] = non_negative_m_modes[i] - else: - ell, m = ind_to_LM(ind = i, ell_min = 2) - alpha_bar = non_negative_m_modes[sf.LM_index(ell,-m,2)].conjugate() - #first 4 indices are reserved for the ell=0,1 modes with values set to 0 - res[i + 4] = alpha_bar*(-1)**m - - return res - - #============================================================================= class Fit3dq8BMS(surfinBH.SurFinBH): @@ -134,10 +88,10 @@ def _load_fits(self, h5file): """ Loads fits from h5file and returns a dictionary of fits. """ fits = {} ell_max = 8 - non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) - zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) - keys_sup_real = [f'sup_real({i})' for i in non_negative_m_modes_indices] - keys_sup_imag = [f'sup_imag({i})' for i in non_negative_m_modes_indices if i not in zero_m_modes_indices] + keys_sup_real = [f'sup_real({ell}{m})' for ell in range(2,ell_max + 1) + for m in range(0,ell + 1)] + keys_sup_imag = [f'sup_imag({ell}{m})' for ell in range(2,ell_max + 1) + for m in range(1,ell + 1)] keys_vel = ['boost_velx','boost_vely','boost_velz'] for key in keys_vel + keys_sup_real + keys_sup_imag: fits[key] = self._load_scalar_fit(fit_key=key, h5file=h5file) @@ -209,21 +163,22 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): x = [q, chiA[2], chiB[2]] ell_max = 8 - sur_predictions_non_negative_m_modes = {} - sur_predictions_non_negative_m_modes_err = {} - non_negative_m_modes_indices = get_non_negative_modes_indices(ell_min = 2,ell_max = ell_max) - zero_m_modes_indices = get_zero_modes_indices(ell_min = 2, ell_max = ell_max) - for i in non_negative_m_modes_indices: - sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({i})') - if i not in zero_m_modes_indices: - sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({i})') - sur_predictions_non_negative_m_modes[i] = sup_real + (1j)*sup_imag - sur_predictions_non_negative_m_modes_err[i] = sup_real_err + (1j)*sup_imag_err - else: - sur_predictions_non_negative_m_modes[i] = sup_real - sur_predictions_non_negative_m_modes_err[i] = sup_real_err - alpha = get_full_supertranslation_array(sur_predictions_non_negative_m_modes,ell_max) - alpha_err = get_full_supertranslation_array(sur_predictions_non_negative_m_modes_err,ell_max) + alpha = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) + alpha_err = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) + LMs = sf.LM_range(2,ell_max) + for i, (ell, m) in enumerate(LMs): + k = i + 4 #first four slots are reserved for ell = 0,1 modes + sgn = int(np.sign(m)) + sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({ell}{abs(m)})') + if m == 0: + alpha[k] = sup_real + alpha_err[k] = sup_real_err + # avoid the else to be faster + continue + sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({ell}{abs(m)})') + # general formula alpha_{ell m} = (Re{alpha_{ell |m|}} + i sgn(m) Im{alpha_{ell |m|}}) sgn(m)^m for all ell,m + alpha[k] = (sup_real + sgn * 1j * sup_imag) * sgn**int(m) + alpha_err[k] = (sup_real_err + sgn * 1j * sup_imag_err) * sgn**int(m) boost_velx, boost_velx_err = self._evaluate_fits(x, 'boost_velx') boost_vely, boost_vely_err = self._evaluate_fits(x, 'boost_vely') From 3f84a0f2209ea19f3cbeab8e4672d157319d9f00 Mon Sep 17 00:00:00 2001 From: gdare Date: Fri, 24 Jan 2025 11:46:37 -0800 Subject: [PATCH 33/36] removed spherical_function dependency, 'sup_' -> 'alpha_', 'boost_vel' -> 'boost_', changed some docs strings --- examples/example_3dq8BMS.ipynb | 81 +++++++++++++----------- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 75 ++++++++++++---------- test/generate_regression_data.py | 6 +- test/regression_data/fit_3dq8BMS.h5 | Bin 64792 -> 64792 bytes test/test_regression.py | 6 +- 5 files changed, 94 insertions(+), 74 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index f41022c..9d9cfaa 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -76,11 +76,14 @@ " | arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper.\n", " |\n", " | This model predicts the proper supertransation modes up to ell = 8 and the\n", - " | 3 components of the boost velocity of the BMS transformation from the inspiral (PN)\n", - " | BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing\n", - " | binary black hole systems. The fits are done using Gaussian Process\n", - " | Regression (GPR) and also provide an error estimate along with the fit\n", - " | value.\n", + " | 3 components of the boost velocity of the BMS transformation from the\n", + " | inspiral (PN) BMS frame to the remnant black hole BMS frame. The boost\n", + " | velocity coincides with the remnant black hole kick velocity as observed\n", + " | from the inspiral (PN) BMS frame.\n", + " |\n", + " | The model was trained on nonprecessing binary black hole systems. The fits\n", + " | are done using Gaussian Process Regression (GPR) and also provide an error\n", + " | estimate along with the fit value.\n", " |\n", " | This model has been trained in the parameter space:\n", " | q <= 8, |chiAz| <= 0.8, |chiBz| <= 0.8\n", @@ -93,14 +96,18 @@ " | # Load the fit\n", " | fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant')\n", " |\n", - " | #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call:\n", - " | alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs)\n", + " | #To evaluate the supertranslation parameter \"alpha\" and the boost velocity\n", + " | \"boost\" together with their respective 1-sigma error estimates call:\n", + " | alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs)\n", " |\n", - " | # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, depend on the location of\n", - " | the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry\n", - " | no physical significance. Consequently they are set to be identically zero.\n", + " | # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation,\n", + " | depend on the location of the center-of-mass at the specific mapping\n", + " | times used to fix the BMS frames and thus carry no physical significance.\n", + " | Consequently they are set to be identically zero.\n", " |\n", - " | # alpha is expressed as a complex array of spherical harmonics modes in the order (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),...\n", + " | # alpha is expressed as a complex array of spherical harmonics modes in the\n", + " | order\n", + " | (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),...\n", " | (same convention as the spherical_functions and scri packages)\n", " |\n", " | The arguments for each of these call methods are as follows:\n", @@ -121,13 +128,16 @@ " | Use at your own risk.\n", " | Default: False.\n", " |\n", - " | The spin and kick vectors are defined in the coorbital frame at t=-100 M\n", - " | from the peak of the waveform. This frame is defined as:\n", + " | The inspiral frame can be defined up to an arbitrary U(1) rotation about\n", + " | the z-axis. We fix this gauge freedom using the same frame alignment choice\n", + " | used in NrSur3dq8Remnant. The inspiral frame at -100M from the peak of the\n", + " | waveform is defined as:\n", " | The z-axis is along the orbital angular momentum direction of the binary.\n", " | The x-axis is along the line of separation from the smaller BH to\n", " | the larger BH at this time.\n", " | The y-axis completes the triad.\n", - " | We obtain this frame from the waveform as defined in arxiv:1705.07089.\n", + " | The rotation leading to this frame choice is included in the BMS transformation\n", + " | as outlined in arxiv:????.?????.\n", " |\n", " | Method resolution order:\n", " | Fit3dq8BMS\n", @@ -144,10 +154,11 @@ " | See _fit_evaluators.fit_7dq2.py for an example.\n", " |\n", " | all(self, *args, **kwargs)\n", - " | Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity\n", - " | of the BMS transformation from the inspiral BMS frame to the remnant BMS frame\n", + " | Evaluates fit and 1-sigma error estimate for supertranslation parameter\n", + " | alpha, and boost velocity of the BMS transformation from the inspiral BMS\n", + " | frame to the remnant BMS frame.\n", " | Returns:\n", - " | alpha, boost_vel, alpha_err, boost_vel_err\n", + " | alpha, boost, alpha_err, boost_err\n", " |\n", " | chif(self, *args, **kwargs)\n", " | chif is not implemented in this model. Will return (None, None),\n", @@ -183,20 +194,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.011456326974619718+0j)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "q = 4.3 # Mass ratio q>=1\n", "chiA = [0,0,0.6] # Spin of larger BH (z-direction only)\n", @@ -213,15 +213,24 @@ "# NOTE: alpha is a complex array. Each component is a spherical harmonic mode of alpha\n", "# the order of the modes in the array is (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),(2,1),(2,2),...\n", "# (same order used in spherical_functions and scri package)\n", - "# - boost velocity and 1-sigma error estimate boost_vel_err\n", + "# - boost velocity boost and 1-sigma error estimate boost_err\n", + "\n", + "alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB)\n", "\n", - "alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB)\n", + "# to get a specific supertranslation mode from alpha you can also use the spherical_function package function LM_index\n", + "def LM_index(ell,m):\n", + " \"\"\" Returns the index in the alpha array corresponding to the ell,m mode\n", + " \"\"\"\n", + " return ell * (ell + 1) + m\n", "\n", - "# to get a specific supertranslation mode from alpha you can use the spherical_function package\n", - "import spherical_functions as sf\n", "\n", - "#20 mode, the last index in LM_index indicates that the lowest ell mode is ell=0\n", - "alpha[sf.LM_index(2,0,0)]" + "# access a specific ell,m mode of alpha\n", + "ell,m = 2,0\n", + "alpha[LM_index(ell,m)]\n", + "# cartesian components of boost velocity\n", + "boost[0] # x-component\n", + "boost[1] # y-component\n", + "boost[2] # z-component" ] }, { diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index ed71d11..964c0ce 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -1,5 +1,4 @@ import numpy as np -import spherical_functions as sf from surfinBH import surfinBH import warnings @@ -10,11 +9,14 @@ class Fit3dq8BMS(surfinBH.SurFinBH): arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper. This model predicts the proper supertransation modes up to ell = 8 and the - 3 components of the boost velocity of the BMS transformation from the inspiral (PN) - BMS frame to the remnant black hole BMS frame. The model was trained on nonprecessing - binary black hole systems. The fits are done using Gaussian Process - Regression (GPR) and also provide an error estimate along with the fit - value. + 3 components of the boost velocity of the BMS transformation from the + inspiral (PN) BMS frame to the remnant black hole BMS frame. The boost + velocity coincides with the remnant black hole kick velocity as observed + from the inspiral (PN) BMS frame. + + The model was trained on nonprecessing binary black hole systems. The fits + are done using Gaussian Process Regression (GPR) and also provide an error + estimate along with the fit value. This model has been trained in the parameter space: q <= 8, |chiAz| <= 0.8, |chiBz| <= 0.8 @@ -27,14 +29,18 @@ class Fit3dq8BMS(surfinBH.SurFinBH): # Load the fit fit = surfinBH.LoadFits('NRSur3dq8BMSRemnant') - #To evaluate the supertranslation parameter alpha and the boost_velocity together with their respective 1-sigma error estimates call: - alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + #To evaluate the supertranslation parameter "alpha" and the boost velocity + "boost" together with their respective 1-sigma error estimates call: + alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs) - # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, depend on the location of - the center-of-mass at the specific mapping times used to fix the BMS frames and thus carry - no physical significance. Consequently they are set to be identically zero. + # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, + depend on the location of the center-of-mass at the specific mapping + times used to fix the BMS frames and thus carry no physical significance. + Consequently they are set to be identically zero. - # alpha is expressed as a complex array of spherical harmonics modes in the order (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),... + # alpha is expressed as a complex array of spherical harmonics modes in the + order + (0,0),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0),... (same convention as the spherical_functions and scri packages) The arguments for each of these call methods are as follows: @@ -55,13 +61,16 @@ class Fit3dq8BMS(surfinBH.SurFinBH): Use at your own risk. Default: False. - The spin and kick vectors are defined in the coorbital frame at t=-100 M - from the peak of the waveform. This frame is defined as: + The inspiral frame can be defined up to an arbitrary U(1) rotation about + the z-axis. We fix this gauge freedom using the same frame alignment choice + used in NrSur3dq8Remnant. The inspiral frame at -100M from the peak of the + waveform is defined as: The z-axis is along the orbital angular momentum direction of the binary. The x-axis is along the line of separation from the smaller BH to the larger BH at this time. The y-axis completes the triad. - We obtain this frame from the waveform as defined in arxiv:1705.07089. + The rotation leading to this frame choice is included in the BMS transformation + as outlined in arxiv:????.?????. """ #------------------------------------------------------------------------- @@ -88,11 +97,11 @@ def _load_fits(self, h5file): """ Loads fits from h5file and returns a dictionary of fits. """ fits = {} ell_max = 8 - keys_sup_real = [f'sup_real({ell}{m})' for ell in range(2,ell_max + 1) + keys_sup_real = [f'alpha_{ell}{m}_real' for ell in range(2,ell_max + 1) for m in range(0,ell + 1)] - keys_sup_imag = [f'sup_imag({ell}{m})' for ell in range(2,ell_max + 1) + keys_sup_imag = [f'alpha_{ell}{m}_imag' for ell in range(2,ell_max + 1) for m in range(1,ell + 1)] - keys_vel = ['boost_velx','boost_vely','boost_velz'] + keys_vel = ['boost_x','boost_y','boost_z'] for key in keys_vel + keys_sup_real + keys_sup_imag: fits[key] = self._load_scalar_fit(fit_key=key, h5file=h5file) return fits @@ -126,10 +135,11 @@ def vf(self, *args, **kwargs): return self._eval_wrapper('vf', *args, **kwargs) def all(self, *args, **kwargs): - """ Evaluates fit and 1-sigma error estimate for supertranslation parameter alpha, and boost velocity - of the BMS transformation from the inspiral BMS frame to the remnant BMS frame + """ Evaluates fit and 1-sigma error estimate for supertranslation parameter + alpha, and boost velocity of the BMS transformation from the inspiral BMS + frame to the remnant BMS frame. Returns: - alpha, boost_vel, alpha_err, boost_vel_err + alpha, boost, alpha_err, boost_err """ return self._eval_wrapper('all', *args, **kwargs) @@ -163,31 +173,32 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): x = [q, chiA[2], chiB[2]] ell_max = 8 - alpha = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) - alpha_err = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex) - LMs = sf.LM_range(2,ell_max) + LM_total_size = ell_max * (ell_max + 2) + 1 + alpha = np.zeros((LM_total_size,), dtype=complex) + alpha_err = np.zeros((LM_total_size,), dtype=complex) + LMs = [(ell,m) for ell in range(2,ell_max + 1) for m in range(-ell,ell + 1)] for i, (ell, m) in enumerate(LMs): k = i + 4 #first four slots are reserved for ell = 0,1 modes sgn = int(np.sign(m)) - sup_real, sup_real_err = self._evaluate_fits(x, f'sup_real({ell}{abs(m)})') + sup_real, sup_real_err = self._evaluate_fits(x, f'alpha_{ell}{abs(m)}_real') if m == 0: alpha[k] = sup_real alpha_err[k] = sup_real_err # avoid the else to be faster continue - sup_imag, sup_imag_err = self._evaluate_fits(x, f'sup_imag({ell}{abs(m)})') + sup_imag, sup_imag_err = self._evaluate_fits(x, f'alpha_{ell}{abs(m)}_imag') # general formula alpha_{ell m} = (Re{alpha_{ell |m|}} + i sgn(m) Im{alpha_{ell |m|}}) sgn(m)^m for all ell,m alpha[k] = (sup_real + sgn * 1j * sup_imag) * sgn**int(m) alpha_err[k] = (sup_real_err + sgn * 1j * sup_imag_err) * sgn**int(m) - boost_velx, boost_velx_err = self._evaluate_fits(x, 'boost_velx') - boost_vely, boost_vely_err = self._evaluate_fits(x, 'boost_vely') - boost_velz, boost_velz_err = self._evaluate_fits(x, 'boost_velz') - boost_vel = np.array([boost_velx, boost_vely, boost_velz]) - boost_vel_err = np.array([boost_velx_err, boost_vely_err, boost_velz_err]) + boost_x, boost_x_err = self._evaluate_fits(x, 'boost_x') + boost_y, boost_y_err = self._evaluate_fits(x, 'boost_y') + boost_z, boost_z_err = self._evaluate_fits(x, 'boost_z') + boost = np.array([boost_x, boost_y, boost_z]) + boost_err = np.array([boost_x_err, boost_y_err, boost_z_err]) if fit_key == 'all': - return alpha, boost_vel, alpha_err, boost_vel_err + return alpha, boost, alpha_err, boost_err diff --git a/test/generate_regression_data.py b/test/generate_regression_data.py index 7703f27..cfa7681 100644 --- a/test/generate_regression_data.py +++ b/test/generate_regression_data.py @@ -22,15 +22,15 @@ def save_data_3dq8BMS(h5grp, fit, num_tests, kwargs={}): # save evaluations as a group y_h5grp = test_h5grp.create_group('y') - alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs) # supertranslation y = alpha, alpha_err y_h5grp.create_dataset('alpha', data=y) # boost velocity - y = boost_vel, boost_vel_err - y_h5grp.create_dataset('boost_vel', data=y) + y = boost, boost_err + y_h5grp.create_dataset('boost', data=y) diff --git a/test/regression_data/fit_3dq8BMS.h5 b/test/regression_data/fit_3dq8BMS.h5 index 066a7846fe76cf68809190e2f7b3795a0578b611..aa5e93f0ae68ce555b13fcab463fbf3eb7cbda78 100644 GIT binary patch literal 64792 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 ZAEh5~d_dx(;{OlU)$MUz;m4}0|37o)&qn|N literal 64792 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 diff --git a/test/test_regression.py b/test/test_regression.py index c811110..c1f104f 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -73,7 +73,7 @@ def test_fit_regression(): if name == 'NRSur3dq8BMSRemnant': #compute fits - alpha, boost_vel, alpha_err, boost_vel_err = fit.all(q, chiA, chiB, **kwargs) + alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs) # supertranslation y_reg = test_h5grp['y/alpha'][()] @@ -81,8 +81,8 @@ def test_fit_regression(): np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) # boost velocity - y_reg = test_h5grp['y/boost_vel'][()] - y_fit = boost_vel, boost_vel_err + y_reg = test_h5grp['y/boost'][()] + y_fit = boost, boost_err np.testing.assert_allclose(y_fit, y_reg, rtol=rtol, atol=atol) else: From 057e41a0168044f31bff54c56a37a974b623fdfc Mon Sep 17 00:00:00 2001 From: gdare Date: Mon, 27 Jan 2025 11:23:45 -0800 Subject: [PATCH 34/36] added ell=1 modes fits --- examples/example_3dq8BMS.ipynb | 8 +++---- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 30 ++++++++++++------------ test/regression_data/fit_3dq8BMS.h5 | Bin 64792 -> 64792 bytes 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 9d9cfaa..86e2fb4 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -75,7 +75,7 @@ " | A class for the NRSur3dq8BMSRemnant model presented in Da Re et al.,\n", " | arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper.\n", " |\n", - " | This model predicts the proper supertransation modes up to ell = 8 and the\n", + " | This model predicts the supertransation modes up to ell = 8 and the\n", " | 3 components of the boost velocity of the BMS transformation from the\n", " | inspiral (PN) BMS frame to the remnant black hole BMS frame. The boost\n", " | velocity coincides with the remnant black hole kick velocity as observed\n", @@ -100,10 +100,8 @@ " | \"boost\" together with their respective 1-sigma error estimates call:\n", " | alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs)\n", " |\n", - " | # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation,\n", - " | depend on the location of the center-of-mass at the specific mapping\n", - " | times used to fix the BMS frames and thus carry no physical significance.\n", - " | Consequently they are set to be identically zero.\n", + " | # NOTE: the modes with ell=0 corresponding to a time translation,\n", + " | is set to be identically zero.\n", " |\n", " | # alpha is expressed as a complex array of spherical harmonics modes in the\n", " | order\n", diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index 964c0ce..dea121d 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -8,7 +8,7 @@ class Fit3dq8BMS(surfinBH.SurFinBH): """ A class for the NRSur3dq8BMSRemnant model presented in Da Re et al., arxiv:????.?????. This model is referred to as surfinBH3dq8BMS in the paper. - This model predicts the proper supertransation modes up to ell = 8 and the + This model predicts the supertransation modes up to ell = 8 and the 3 components of the boost velocity of the BMS transformation from the inspiral (PN) BMS frame to the remnant black hole BMS frame. The boost velocity coincides with the remnant black hole kick velocity as observed @@ -33,10 +33,8 @@ class Fit3dq8BMS(surfinBH.SurFinBH): "boost" together with their respective 1-sigma error estimates call: alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs) - # NOTE: the modes with ell=0,1 corresponding to a Poincaré translation, - depend on the location of the center-of-mass at the specific mapping - times used to fix the BMS frames and thus carry no physical significance. - Consequently they are set to be identically zero. + # NOTE: the modes with ell=0 corresponding to a time translation, + is set to be identically zero. # alpha is expressed as a complex array of spherical harmonics modes in the order @@ -97,9 +95,9 @@ def _load_fits(self, h5file): """ Loads fits from h5file and returns a dictionary of fits. """ fits = {} ell_max = 8 - keys_sup_real = [f'alpha_{ell}{m}_real' for ell in range(2,ell_max + 1) + keys_sup_real = [f'S_{ell}{m}_real' for ell in range(1,ell_max + 1) for m in range(0,ell + 1)] - keys_sup_imag = [f'alpha_{ell}{m}_imag' for ell in range(2,ell_max + 1) + keys_sup_imag = [f'S_{ell}{m}_imag' for ell in range(1,ell_max + 1) for m in range(1,ell + 1)] keys_vel = ['boost_x','boost_y','boost_z'] for key in keys_vel + keys_sup_real + keys_sup_imag: @@ -176,20 +174,22 @@ def _eval_wrapper(self, fit_key, q, chiA, chiB, **kwargs): LM_total_size = ell_max * (ell_max + 2) + 1 alpha = np.zeros((LM_total_size,), dtype=complex) alpha_err = np.zeros((LM_total_size,), dtype=complex) - LMs = [(ell,m) for ell in range(2,ell_max + 1) for m in range(-ell,ell + 1)] + LMs = [(ell,m) for ell in range(1,ell_max + 1) for m in range(-ell,ell + 1)] for i, (ell, m) in enumerate(LMs): - k = i + 4 #first four slots are reserved for ell = 0,1 modes + k = i + 1 #first slot is reserved for ell = 0 mode sgn = int(np.sign(m)) - sup_real, sup_real_err = self._evaluate_fits(x, f'alpha_{ell}{abs(m)}_real') + # the fits are trained with the variable S_{ell |m|} = 1/2(alpha_{ell |m|} + (-1)^m alpha_{ell -|m|}) + # the variable S_{ell |m|} coincides with alpha_{ell |m|} because alpha is real + S_real, S_real_err = self._evaluate_fits(x, f'S_{ell}{abs(m)}_real') if m == 0: - alpha[k] = sup_real - alpha_err[k] = sup_real_err + alpha[k] = S_real + alpha_err[k] = S_real_err # avoid the else to be faster continue - sup_imag, sup_imag_err = self._evaluate_fits(x, f'alpha_{ell}{abs(m)}_imag') + S_imag, S_imag_err = self._evaluate_fits(x, f'S_{ell}{abs(m)}_imag') # general formula alpha_{ell m} = (Re{alpha_{ell |m|}} + i sgn(m) Im{alpha_{ell |m|}}) sgn(m)^m for all ell,m - alpha[k] = (sup_real + sgn * 1j * sup_imag) * sgn**int(m) - alpha_err[k] = (sup_real_err + sgn * 1j * sup_imag_err) * sgn**int(m) + alpha[k] = (S_real + sgn * 1j * S_imag) * sgn**int(m) + alpha_err[k] = (S_real_err + sgn * 1j * S_imag_err) * sgn**int(m) boost_x, boost_x_err = self._evaluate_fits(x, 'boost_x') boost_y, boost_y_err = self._evaluate_fits(x, 'boost_y') diff --git a/test/regression_data/fit_3dq8BMS.h5 b/test/regression_data/fit_3dq8BMS.h5 index aa5e93f0ae68ce555b13fcab463fbf3eb7cbda78..900fb87adc442865cb41d95256e44dd04d292a6d 100644 GIT binary patch literal 64792 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 z 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 KzQV8NtN(wV*D)vn literal 64792 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 ZAEh5~d_dx(;{OlU)$MUz;m4}0|37o)&qn|N From 7805d5d760e35ad00e921896b63f514466ed1d8a Mon Sep 17 00:00:00 2001 From: gdare Date: Mon, 27 Jan 2025 11:30:09 -0800 Subject: [PATCH 35/36] fixed typo in docs --- examples/example_3dq8BMS.ipynb | 4 +++- surfinBH/_fit_evaluators/fit_3dq8BMS.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 86e2fb4..7c628ea 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -13,6 +13,8 @@ "metadata": {}, "outputs": [], "source": [ + "import sys\n", + "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH\")\n", "import surfinBH" ] }, @@ -100,7 +102,7 @@ " | \"boost\" together with their respective 1-sigma error estimates call:\n", " | alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs)\n", " |\n", - " | # NOTE: the modes with ell=0 corresponding to a time translation,\n", + " | # NOTE: The ell=0 mode, corresponding to a time translation,\n", " | is set to be identically zero.\n", " |\n", " | # alpha is expressed as a complex array of spherical harmonics modes in the\n", diff --git a/surfinBH/_fit_evaluators/fit_3dq8BMS.py b/surfinBH/_fit_evaluators/fit_3dq8BMS.py index dea121d..2666052 100644 --- a/surfinBH/_fit_evaluators/fit_3dq8BMS.py +++ b/surfinBH/_fit_evaluators/fit_3dq8BMS.py @@ -33,7 +33,7 @@ class Fit3dq8BMS(surfinBH.SurFinBH): "boost" together with their respective 1-sigma error estimates call: alpha, boost, alpha_err, boost_err = fit.all(q, chiA, chiB, **kwargs) - # NOTE: the modes with ell=0 corresponding to a time translation, + # NOTE: The ell=0 mode, corresponding to a time translation, is set to be identically zero. # alpha is expressed as a complex array of spherical harmonics modes in the From 237966cefae7d099ea0eb59e8bf36cc9eade2b0e Mon Sep 17 00:00:00 2001 From: gdare Date: Mon, 27 Jan 2025 11:31:37 -0800 Subject: [PATCH 36/36] remove a test line --- examples/example_3dq8BMS.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/example_3dq8BMS.ipynb b/examples/example_3dq8BMS.ipynb index 7c628ea..5caf359 100644 --- a/examples/example_3dq8BMS.ipynb +++ b/examples/example_3dq8BMS.ipynb @@ -13,8 +13,6 @@ "metadata": {}, "outputs": [], "source": [ - "import sys\n", - "sys.path.insert(0, \"/groups/sxs/gdare/Mbot/BMS_surrogate/surfinBH\")\n", "import surfinBH" ] },