LALSimulation  5.4.0.1-fe68b98
LALSimNRSur3dq8Remnant.c
Go to the documentation of this file.
1 /* Copyright (C) 2019 Vijay Varma
2  * Evaluates NRSur3dq8Remnant model for remnant BH mass, spin and recoil kick
3  * for aligned-spin BBH.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with with program; see the file COPYING. If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  */
20 
21 /**
22  * \author Vijay Varma
23  *
24  * \file
25  *
26  * \brief NRSur3dq8Remnant model for remnant BH mass, spin and recoil kick for
27  * aligned-spin BBH.
28  *
29  * The binary data file is available at:
30  * https://dcc.ligo.org/LIGO-T1900034/public.
31  * Get the lalsuite-extra repo or put the data into a location in your
32  * LAL_DATA_PATH.
33  *
34  * **Paper**: https://arxiv.org/abs/1809.09125,
35  * https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.122.011101.
36  * The model is referred to as surfinBH3dq8 in the paper.
37  *
38  * **Parameter ranges**:
39  *
40  * q = [1, 9.1]
41  * \f$\chi_{1z}, \chi_{2z}\f$ = [-0.91, 0.91]
42  *
43  * OR
44  *
45  * q = [1, 10.1]
46  * \f$\chi_{1z}, \chi_{2z}\f$ = [-0.81, 0.81]
47  *
48  * **Training parameter ranges**:
49  *
50  * q = [1, 8]
51  * \f$\chi_{1z}, \chi_{2z}\f$ = [-0.81, 0.81]
52  *
53  * But extrapolates reasonably to the above mass ratios and spins. However,
54  * if a guarantee of accuracy is required, this model should be used within
55  * the training parameter range.
56  */
57 
58 #ifdef __GNUC__
59 #define UNUSED __attribute__ ((unused))
60 #else
61 #define UNUSED
62 #endif
63 
64 
65 #include <libgen.h>
66 
67 #include <gsl/gsl_bspline.h>
68 #include <gsl/gsl_blas.h>
69 #include <gsl/gsl_spline.h>
70 #include <gsl/gsl_complex_math.h>
71 
72 #include <lal/SeqFactories.h>
73 #include <lal/FileIO.h>
74 #include <lal/H5FileIO.h>
75 
76 #include <lal/XLALError.h>
77 #include <lal/LALSimIMR.h>
78 
80 
81 #include "LALSimNRSur3dq8Remnant.h"
82 
83 
84 
85 #ifdef LAL_PTHREAD_LOCK
86 #include <pthread.h>
87 #endif
88 
89 #ifdef LAL_PTHREAD_LOCK
90 static pthread_once_t NRSur3dq8Remnant_is_initialized = PTHREAD_ONCE_INIT;
91 #endif
92 
93 
94 /**
95  * Global surrogate data. This data will be loaded at most once. Any
96  * executable which calls NRSur3dq8Remnant_Init_LALDATA directly or by calling
97  * the XLALNRSur3dq8Remnant function will have a memory leak according to
98  * valgrind, because we never free this memory. This memory, however, gets freed
99  * after the executable terminates.
100  */
102 
103 //*************************************************************************/
104 //************************* function definitions **************************/
105 //*************************************************************************/
106 
107 /**
108  * Helper function to check if the NRSur3dq8Remnant model has been initialized.
109  */
110 static bool NRSur3dq8Remnant_IsSetup(void) {
112  return true;
113  else
114  return false;
115 }
116 
117 /**
118  * Surrogate initialization.
119  *
120  * This needs to be called once, before __lalsim_NRSur3dq8Remnant_data is used.
121  * It finds the H5 data file with the NRSur3dq8Remnant data and loads the
122  * surrogate. Can be called multiple times, will just return true if surrogate
123  * is already loaded.
124  */
125 static void NRSur3dq8Remnant_Init_LALDATA(void) {
126 
127  if (NRSur3dq8Remnant_IsSetup()) return;
128 
129  LALH5File *file = NULL;
131 
133  file);
134 
136  if (ret != XLAL_SUCCESS) {
137  XLAL_ERROR_VOID(XLAL_FAILURE, "Failure loading data from %s\n",
139  }
140 }
141 
142 /**
143  * Map from mass ratio and spins to surrogate fit parameters.
144  *
145  * The fit parameters are \f$[log_e(q), \hat{\chi}, \chi_a]\f$.
146  * \f$\hat{\chi}\f$ is defined in Eq.(S5) of arxiv:1809.09125.
147  * \f$\chi_a = (\chi_{1z} - \chi_{2z})/2 \f$.
148  */
150  gsl_vector* fit_params, /**< Output: mapped fit parameters. */
151  const REAL8 q, /**< Mass ratio m1 / m2 >= 1. */
152  const REAL8 chiAz, /**< Dimless z-spin of heavier BH. */
153  const REAL8 chiBz, /**< Dimless z-spin of lighter BH. */
154  LALDict* LALparams /**< Dict with extra parameters */
155 ) {
156 
157  //// Sanity check parameter ranges
158  const char *param_validity = "This model is valid for q <= 9.1 & "
159  "|chiAz,chiBz| <= 0.91, or q <= 10.1 & |chiAz,chiBz| <= 0.81";
160 
161  // By default we do not allow unlimited_extrapolation
162  UINT4 unlim_extrap = 0;
163  if (LALparams != NULL &&
164  XLALDictContains(LALparams, "unlimited_extrapolation")) {
165  // Unless the user asks for it
166  unlim_extrap
167  = XLALDictLookupUINT4Value(LALparams, "unlimited_extrapolation");
168  }
169 
170  if (q < 1) {
171  XLAL_ERROR(XLAL_FAILURE, "Invalid mass ratio q = %0.4f < 1\n", q);
172  }
173  if (fabs(chiAz) > 1) {
175  "Invalid spin magnitude |chiA| = %0.4f > 1\n", fabs(chiAz));
176  }
177  if (fabs(chiBz) > 1) {
179  "Invalid spin magnitude |chiB| = %0.4f > 1\n", fabs(chiBz));
180  }
181  if ((q > 10.1) && (unlim_extrap == 0)) {
183  "Too much extrapolation in mass ratio; q=%0.4f > 10.1\n%s\n", q,
184  param_validity);
185  }
186  if (q > 8) {
188  "Extrapolating outside training range q=%0.4f > 8\n", q);
189  }
190  if (fabs(chiAz) > 0.91 && (unlim_extrap == 0)) {
192  "Too much extrapolation; |chiAz|=%0.4f > 0.91\n%s\n", fabs(chiAz),
193  param_validity);
194  }
195  if (fabs(chiBz) > 0.91 && (unlim_extrap == 0)) {
197  "Too much extrapolation; |chiBz|=%0.4f > 0.91\n%s\n", fabs(chiBz),
198  param_validity);
199  }
200  if (fabs(chiAz) > 0.81) {
201  if ((q > 9.1) && (unlim_extrap == 0)) {
203  "Too much extrapolation; q=%0.4f > 9.1 & |chiAz|=%.04f"
204  " >0.81\n%s\n", q, fabs(chiAz), param_validity);
205  }
207  "Extrapolating outside training range |chiAz|=%0.4f > 0.81\n",
208  fabs(chiAz));
209  }
210  if (fabs(chiBz) > 0.81) {
211  if ((q > 9.1) && (unlim_extrap == 0)) {
213  "Too much extrapolation; q=%0.4f > 9.1 & |chiBz|=%.04f"
214  " >0.81\n%s\n", q, fabs(chiBz), param_validity);
215  }
217  "Extrapolating outside training range |chiBz|=%0.4f > 0.81\n",
218  fabs(chiBz));
219  }
220 
221  const REAL8 eta = q/(1.+q)/(1.+q);
222  const REAL8 chi_wtAvg = (q*chiAz+chiBz)/(1.+q);
223  const REAL8 chi_hat
224  = (chi_wtAvg - 38.*eta/113.*(chiAz + chiBz))/(1. - 76.*eta/113.);
225  const REAL8 chi_a = (chiAz - chiBz)/2.;
226 
227  XLAL_CHECK((fit_params != NULL) && (fit_params->size == 3), XLAL_EDIMS,
228  "Size of fit_params should be 3, not %zu.\n", fit_params->size);
229 
230  gsl_vector_set(fit_params, 0, log(q));
231  gsl_vector_set(fit_params, 1, chi_hat);
232  gsl_vector_set(fit_params, 2, chi_a);
233 
234  return XLAL_SUCCESS;
235 }
236 
237 //************************ main functions ***************************/
238 
239 /**
240  * Returns the remnant BH's mass, spin, or kick according to NRSur3dq8Remnant
241  * model.
242  *
243  * Reference: arxiv:1809.09125. This model is referred to as surfinBH3dq8 in
244  * the paper.
245  *
246  * The remnant mass is returned in units of total mass, the remnant spin is
247  * dimensionless, and the recoil kick is in units of c.
248  *
249  * remnant_property can be one of "mf", "chifz", "vfx" or "vfy", respectively,
250  * for the remnant mass, the z-component of remnant spin, and the x and y
251  * components of the kick. The kick components are given in the coorbital frame
252  * at t=-100M from the total amplitude peak, as described in the paper. All
253  * other components of the spin and kick are zero due to the symmetries of
254  * aligned-spin systems and are not modelled by the surrogate.
255  *
256  * Usage examples:
257  * mf = lalsim.NRSur3dq8Remnant(q, s1z, s2z, "mf")
258  * chifz = lalsim.NRSur3dq8Remnant(q, s1z, s2z, "chifz")
259  */
261  REAL8 *result, /**<Output: The requested remnant property. */
262  REAL8 q, /**< Mass ratio of Bh1/Bh2. q>=1. */
263  REAL8 s1z, /**< S1z z-spin of Bh1 */
264  REAL8 s2z, /**< S2z z-spin of Bh2 */
265  char *remnant_property, /**< One of "mf", "chifz", "vfx" or "vfy" */
266  LALDict* LALparams /**< Dict with extra parameters */
267 ) {
268 
269 #ifdef LAL_PTHREAD_LOCK
270  (void) pthread_once(&NRSur3dq8Remnant_is_initialized,
272 #else
274 #endif
275 
276  // Loaded surrogate data
278  if (!sur_data->setup) {
279  XLAL_ERROR(XLAL_EFAILED, "Error loading surrogate data.\n");
280  }
281 
282  // assign size to dummy_worker
283  gsl_vector *dummy_worker = gsl_vector_alloc(sur_data->params_dim);
284 
285  // Compute fit_params (initialize with dimension of the surrogate)
286  gsl_vector *fit_params = gsl_vector_alloc(sur_data->params_dim);
287  int ret = NRSur3dq8Remnant_fitParams(fit_params, q, s1z, s2z, LALparams);
288  if(ret != XLAL_SUCCESS) {
289  XLAL_ERROR(XLAL_EFUNC, "Failed to evaluate fit_params.");
290  }
291 
292  // All quantities are treated as scalars
293  ScalarFitData *fit_data = NULL;
294  if (strcmp(remnant_property, "mf") == 0) {
295  // final mass
296  fit_data = sur_data->mf_data;
297  } else if (strcmp(remnant_property, "chifz") == 0) {
298  // z-component of final spin (other components are zero)
299  fit_data = sur_data->chifz_data;
300  } else if (strcmp(remnant_property, "vfx") == 0) {
301  // x-component of recoil kick
302  fit_data = sur_data->vfx_data;
303  } else if (strcmp(remnant_property, "vfy") == 0) {
304  // y-component of recoil kick, z-component is zero
305  fit_data = sur_data->vfy_data;
306  } else {
307  XLAL_ERROR(XLAL_EINVAL, "Invalid remnant_property, should be one "
308  "of 'mf', 'chifz', 'vfx' or 'vfy'");
309  }
310 
311  *result = NRHybSur_eval_fit(fit_data, fit_params, sur_data->x_train,
312  dummy_worker);
313  return XLAL_SUCCESS;
314 
315 }
struct tagLALH5File LALH5File
int XLALDictContains(const LALDict *dict, const char *key)
UINT4 XLALDictLookupUINT4Value(LALDict *dict, const char *key)
REAL8 NRHybSur_eval_fit(const NRHybSurFitData *fit_data, const gsl_vector *fit_params, const gsl_matrix *x_train, gsl_vector *dummy_worker)
Evaluate a NRHybSur fit.
static int NRSur3dq8Remnant_fitParams(gsl_vector *fit_params, const REAL8 q, const REAL8 chiAz, const REAL8 chiBz, LALDict *LALparams)
Map from mass ratio and spins to surrogate fit parameters.
int XLALNRSur3dq8Remnant(REAL8 *result, REAL8 q, REAL8 s1z, REAL8 s2z, char *remnant_property, LALDict *LALparams)
Returns the remnant BH's mass, spin, or kick according to NRSur3dq8Remnant model.
static void NRSur3dq8Remnant_Init_LALDATA(void)
Surrogate initialization.
static bool NRSur3dq8Remnant_IsSetup(void)
Helper function to check if the NRSur3dq8Remnant model has been initialized.
static AlignedSpinRemnantFitData __lalsim_NRSur3dq8Remnant_data
Global surrogate data.
NRSur3dq8Remnant model for remnant BH mass, spin and recoil kick for aligned-spin BBH.
static const char NRSur3dq8Remnant_DATAFILE[]
void NRSurRemnant_LoadH5File(LALH5File **file, const char *NRSurRemnant_DATAFILE)
Loads H5 file for a NRSurRemnant model.
int AlignedSpinNRSurRemnant_Init(AlignedSpinRemnantFitData *sur_data, LALH5File *file)
Initializes fit data for an aligned-spin NRSurRemnant.
Utils for NR surrogates for remnant BH mass, spin and recoil kick.
#define print_warning(...)
#define ScalarFitData
void XLALH5FileClose(LALH5File UNUSED *file)
double REAL8
uint32_t UINT4
static const INT4 q
#define XLAL_ERROR_VOID(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDIMS
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
NRSurRemnant GPR fit data for the mass, spin, and recoil kick for aligned-spin BBHs.
ScalarFitData * mf_data
Fit data for final mass.
UINT4 params_dim
Dimensions of the model.
gsl_matrix * x_train
Training set parameters, needed for GPR fits.
ScalarFitData * vfy_data
Fit data for final mass.
ScalarFitData * vfx_data
Fit data for final mass.
ScalarFitData * chifz_data
Fit data for final mass.
UINT4 setup
Indicates if NRSurRemnant has been initialized.