LALSimulation  5.4.0.1-fe68b98
LALSimIMRSEOBNRv4TSurrogate.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Michael Puerrer, Ben Lackey
3  * Reduced Order Model for SEOBNRv4T spin-aligned tidal effective-one-body model
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 #ifdef __GNUC__
22 #define UNUSED __attribute__ ((unused))
23 #else
24 #define UNUSED
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <complex.h>
31 #include <time.h>
32 #include <stdbool.h>
33 #include <alloca.h>
34 #include <string.h>
35 #include <libgen.h>
36 
37 #include <gsl/gsl_errno.h>
38 #include <gsl/gsl_bspline.h>
39 #include <gsl/gsl_blas.h>
40 #include <gsl/gsl_min.h>
41 #include <gsl/gsl_spline.h>
42 #include <gsl/gsl_poly.h>
43 #include <lal/Units.h>
44 #include <lal/SeqFactories.h>
45 #include <lal/LALConstants.h>
46 #include <lal/XLALError.h>
47 #include <lal/FrequencySeries.h>
48 #include <lal/Date.h>
49 #include <lal/StringInput.h>
50 #include <lal/Sequence.h>
51 #include <lal/LALStdio.h>
52 #include <lal/FileIO.h>
53 
54 
55 #ifdef LAL_HDF5_ENABLED
56 #include <lal/H5FileIO.h>
57 static const char SurDataHDF5[] = "SEOBNRv4T_surrogate_v1.0.0.hdf5";
58 static const INT4 SurDataHDF5_VERSION_MAJOR = 1;
59 static const INT4 SurDataHDF5_VERSION_MINOR = 0;
60 static const INT4 SurDataHDF5_VERSION_MICRO = 0;
61 #endif
62 
63 #include <lal/LALSimInspiral.h>
64 #include <lal/LALSimIMR.h>
65 
66 #include "LALSimIMREOBNRv2.h"
70 
71 #include <lal/LALConfig.h>
72 #ifdef LAL_PTHREAD_LOCK
73 #include <pthread.h>
74 #endif
75 
76 
77 
78 #ifdef LAL_PTHREAD_LOCK
79 static pthread_once_t Surrogate_is_initialized = PTHREAD_ONCE_INIT;
80 #endif
81 
82 /*************** type definitions ******************/
83 
85 {
86  gsl_matrix *hyp_amp; // GP hyperparameters log amplitude
87  gsl_matrix *hyp_phi; // GP hyperparameters for dephasing
88  gsl_matrix *kinv_dot_y_amp; // kinv_dot_y for log amplitude
89  gsl_matrix *kinv_dot_y_phi; // kinv_dot_y for dephasing
90  gsl_matrix *x_train; // Training points
91 
92  // location of surrogate spline nodes
93  gsl_vector *mf_amp; // location of spline nodes for log amplitude
94  gsl_vector *mf_phi; // location of spline nodes for dephasing
95 
96  // location of spline nodes for TaylorF2 at low frequency
97  gsl_vector *TF2_mf_amp_cubic; // cubic spline nodes for TaylorF2 amplitude
98  gsl_vector *TF2_mf_phi_cubic; // cubic spline nodes for TaylorF2 phasing
99  gsl_vector *TF2_mf_amp_linear; // linear spline nodes for TaylorF2 amplitude
100  gsl_vector *TF2_mf_phi_linear; // linear spline nodes for TaylorF2 phasing
101 
102  // 5D parameter space bounds of surrogate
103  gsl_vector *q_bounds; // [q_min, q_max]
104  gsl_vector *chi1_bounds; // [chi1_min, chi1_max]
105  gsl_vector *chi2_bounds; // [chi2_min, chi2_max]
106  gsl_vector *lambda1_bounds; // [lambda1_min, lambda1_max]
107  gsl_vector *lambda2_bounds; // [lambda2_min, lambda2_max]
108 };
109 typedef struct tagSurrogatedata_submodel Surrogatedata_submodel;
110 
112 {
114  Surrogatedata_submodel* sub1;
115 };
116 typedef struct tagSurrogatedata Surrogatedata;
117 
118 static Surrogatedata __lalsim_SurrogateDS_data;
119 
120 typedef int (*load_dataPtr)(const char*, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *);
121 
122 /**************** Internal functions **********************/
123 
124 UNUSED static void save_gsl_frequency_series(const char filename[], gsl_vector *x, gsl_vector *y);
125 
126 static gsl_vector *gsl_vector_prepend_value(gsl_vector *v, double value);
127 
128 double kernel(
129  gsl_vector *x1, // array with shape ndim
130  gsl_vector *x2, // array with shape ndim
131  gsl_vector *hyperparams, // Hyperparameters
132  gsl_vector *work // work array
133 );
134 
135 double gp_predict(
136  gsl_vector *xst, // Point x_* where you want to evaluate the function.
137  gsl_vector *hyperparams, // Hyperparameters for the GPR kernel.
138  gsl_matrix *x_train, // Training set points.
139  gsl_vector *Kinv_dot_y, // The interpolating weights at each training set point.
140  gsl_vector *work // work array for kernel
141 );
142 
143 
144 UNUSED static void Surrogate_Init_LALDATA(void);
145 UNUSED static int Surrogate_Init(const char dir[]);
146 UNUSED static bool Surrogate_IsSetup(void);
147 
148 UNUSED static int Surrogatedata_Init(Surrogatedata *romdata, const char dir[]);
149 UNUSED static void Surrogatedata_Cleanup(Surrogatedata *romdata);
150 
151 static double xi_of_lambda(double lambda);
152 
153 static int GPR_evaluation_5D(
154  double q, // Input: q-value (q >= 1)
155  double chi1, // Input: chi1-value
156  double chi2, // Input: chi2-value
157  double lambda1, // Input: lambda1-value
158  double lambda2, // Input: lambda2-value
159  gsl_matrix *hyp_amp, // Input: GPR hyperparameters for log amplitude
160  gsl_matrix *hyp_phi, // Input: GPR hyperparameters for dephasing
161  gsl_matrix *kinv_dot_y_amp, // Input: kinv_dot_y for log amplitude
162  gsl_matrix *kinv_dot_y_phi, // Input: kinv_dot_y for dephasing
163  gsl_matrix *x_train, // Input: GPR training points
164  gsl_vector *amp_at_EI_nodes, // Output: log amplitude at EI nodes (preallocated)
165  gsl_vector *phi_at_EI_nodes, // Output: dephasing at EI nodes (preallocated)
166  gsl_vector *work // Input: work array
167 );
168 
169 UNUSED static int Surrogatedata_Init_submodel(
170  UNUSED Surrogatedata_submodel **submodel,
171  UNUSED const char dir[],
172  UNUSED const char grp_name[]
173 );
174 
175 UNUSED static void Surrogatedata_Cleanup_submodel(Surrogatedata_submodel *submodel);
176 
177 UNUSED static int CheckParameterSpaceBounds(
178  Surrogatedata_submodel *sur,
179  double q, // mass-ratio q >= 1
180  double chi1,
181  double chi2,
182  double lambda1,
183  double lambda2
184 );
185 
186 /**
187  * Core function for computing the ROM waveform.
188  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
189  * Construct 1D splines for amplitude and phase.
190  * Compute strain waveform from amplitude and phase.
191 */
192 UNUSED static int SurrogateCore(
193  COMPLEX16FrequencySeries **hptilde,
194  COMPLEX16FrequencySeries **hctilde,
195  double phiRef,
196  double fRef,
197  double distance,
198  double inclination,
199  double Mtot_sec,
200  double eta,
201  double chi1,
202  double chi2,
203  double lambda1,
204  double lambda2,
205  const REAL8Sequence *freqs, /* Frequency points at which to evaluate the waveform (Hz) */
206  double deltaF,
207  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
208  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
209  * Then we will use deltaF = 0 to create the frequency series we return. */
211 );
212 
213 static size_t NextPow2(const size_t n);
214 
215 static int TaylorF2Phasing(
216  double Mtot, // Total mass in solar masses
217  double q, // Mass-ration m1/m2 >= 1
218  double chi1, // Dimensionless aligned spin of body 1
219  double chi2, // Dimensionless aligned spin of body 2
220  double lambda1, // Tidal deformability of body 1
221  double lambda2, // Tidal deformability of body 2
222  gsl_vector *Mfs, // Input geometric frequencies
223  gsl_vector **PNphase // Output: TaylorF2 phase at frequencies Mfs
224 );
225 
226 static int TaylorF2Amplitude1PN(
227  double eta, // Symmetric mass-ratio
228  gsl_vector *Mfs, // Input geometric frequencies
229  gsl_vector **PNamp // Output: TaylorF2 amplitude at frequencies Mfs
230 );
231 
232 /********************* Definitions begin here ********************/
233 
234 UNUSED static void save_gsl_frequency_series(const char filename[], gsl_vector *x, gsl_vector *y) {
235  FILE *fp = fopen(filename, "w");
236  fprintf(stderr, "save_gsl_frequency_series: %s: %zu %zu\n", filename, x->size, y->size);
237  XLAL_CHECK_ABORT(x->size == y->size);
238  for (size_t i=0; i<x->size; i++) {
239  fprintf(fp, "%g\t%g\n", gsl_vector_get(x, i), gsl_vector_get(y, i));
240  }
241  fclose(fp);
242 }
243 
244 static gsl_vector *gsl_vector_prepend_value(gsl_vector *v, double value) {
245 // Helper function to prepend a value to a gsl_vector
246 // Returns the augmented gsl_vector
247 // Deallocates the input gsl_vector
248  int n = v->size;
249  gsl_vector *vout = gsl_vector_alloc(n+1);
250 
251  gsl_vector_set(vout, 0, value);
252  for (int i=1; i<=n; i++)
253  gsl_vector_set(vout, i, gsl_vector_get(v, i-1));
254  gsl_vector_free(v);
255 
256  return vout;
257 }
258 
259 double kernel(
260  gsl_vector *x1, // parameter space point 1
261  gsl_vector *x2, // parameter space point 2
262  gsl_vector *hyperparams, // GPR Hyperparameters
263  gsl_vector *work // work array
264 )
265 {
266  // Matern covariance function for n-dimensional data.
267  //
268  // Parameters
269  // ----------
270  // x1 : array with shape ndim
271  // x2 : array with shape ndim
272  // hyperparams : array with shape ndim+2 [sigma_f, ls0, ls1, ..., sigma_n]
273  // sigma_f : Approximately the range (ymax-ymin) of values that the data takes.
274  // sigma_f^2 called the signal variance.
275  // sigma_n : Noise term. The uncertainty in the y values of the data.
276  // lsi : Length scales for the variation in dimension i.
277  //
278  // Returns
279  // -------
280  // covariance : double
281 
282  double sigma_f = gsl_vector_get(hyperparams, 0);
283  double sigma_n = gsl_vector_get(hyperparams, hyperparams->size-1);
284  gsl_vector ls = gsl_vector_subvector(hyperparams, 1, hyperparams->size-2).vector;
285 
286  XLAL_CHECK((x1->size == x2->size) && (x1->size == ls.size), XLAL_EDIMS,
287  "kernel(): dimensions of vectors x1, x2 and ls: %zu, %zu, %zu have to be consistent.\n",
288  x1->size, x2->size, ls.size);
289 
290  // Noise nugget for diagonal elements
291  double nugget = 0.0;
292  if (gsl_vector_equal(x1, x2))
293  nugget = sigma_n*sigma_n;
294 
295  gsl_vector_memcpy(work, x1);
296  gsl_vector_sub(work, x2);
297  gsl_vector_div(work, &ls); // (x1 - x2) / ls
298  double r = gsl_blas_dnrm2(work);
299 
300  // nu = 5/2 Matern covariance
301  double matern = (1.0 + sqrt(5.0)*r + 5.0*r*r/3.0) * exp(-sqrt(5.0)*r);
302 
303  // Full covariance
304  // Include the nugget to agree with scikit-learn when the points x1, x2 are exactly the same.
305  return sigma_f*sigma_f * matern + nugget;
306 }
307 
308 double gp_predict(
309  gsl_vector *xst, // Point x_* where you want to evaluate the function.
310  gsl_vector *hyperparams, // Hyperparameters for the GPR kernel.
311  gsl_matrix *x_train, // Training set points.
312  gsl_vector *Kinv_dot_y, // The interpolating weights at each training set point.
313  gsl_vector *work
314 )
315 {
316  // Interpolate the function at the point xst using Gaussian process regression.
317  //
318  // Parameters
319  // ----------
320  // xst : array of shape ndim.
321  // Point x_* where you want to evaluate the function.
322  // hyperparams : array with shape ndim+2 [sigma_f, ls0, ls1, ..., sigma_n].
323  // Hyperparameters for the GPR kernel.
324  // x_train : array of shape (n_train, ndim).
325  // Training set points.
326  // Kinv_dot_y : array of shape n_train.
327  // The interpolating weights at each training set point.
328  //
329  // Returns
330  // -------
331  // yst : double
332  // Interpolated value at the point xst.
333 
334  // Evaluate vector K_*
335  int n = x_train->size1;
336  gsl_vector *Kst = gsl_vector_alloc(n);
337  for (int i=0; i < n; i++) {
338  gsl_vector x = gsl_matrix_const_row(x_train, i).vector;
339  double ker = kernel(xst, &x, hyperparams, work);
340  gsl_vector_set(Kst, i, ker);
341  }
342 
343  // Evaluate y_*
344  double res = 0;
345  gsl_blas_ddot(Kst, Kinv_dot_y, &res);
346  gsl_vector_free(Kst);
347  return res;
348 }
349 
350 /** Setup Surrogate model using data files installed in dir */
351 static int Surrogate_Init(const char dir[]) {
352  if(__lalsim_SurrogateDS_data.setup) {
353  XLALPrintError("Error: Surrogate data was already set up!");
355  }
357 
358  if(__lalsim_SurrogateDS_data.setup) {
359  return(XLAL_SUCCESS);
360  }
361  else {
362  return(XLAL_EFAILED);
363  }
364 }
365 
366 /** Helper function to check if the Surrogate model has been initialised */
367 static bool Surrogate_IsSetup(void) {
368  if(__lalsim_SurrogateDS_data.setup)
369  return true;
370  else
371  return false;
372 }
373 
374 /** Coordinate transformation */
375 static double xi_of_lambda(double lambda) {
376  const double a = 100.0;
377  return log10(lambda / a + 1.0);
378 }
379 
380 // Compute amplitude and phase at empirical interpolant nodes from GPRs.
381 // This entails interpolation over the 5D parameter space (q, chi1, chi2, lambda1, lambda2).
382 static int GPR_evaluation_5D(
383  double q, // Input: q-value (q >= 1)
384  double chi1, // Input: chi1-value
385  double chi2, // Input: chi2-value
386  double lambda1, // Input: lambda1-value
387  double lambda2, // Input: lambda2-value
388  gsl_matrix *hyp_amp, // Input: GPR hyperparameters for log amplitude
389  gsl_matrix *hyp_phi, // Input: GPR hyperparameters for dephasing
390  gsl_matrix *kinv_dot_y_amp, // Input: kinv_dot_y for log amplitude
391  gsl_matrix *kinv_dot_y_phi, // Input: kinv_dot_y for dephasing
392  gsl_matrix *x_train, // Input: GPR training points
393  gsl_vector *amp_at_nodes, // Output: log amplitude at frequency nodes (preallocated)
394  gsl_vector *phi_at_nodes, // Output: dephasing at frequency nodes (preallocated)
395  gsl_vector *work // Input: workspace
396 )
397 {
398  // Assemble evaluation point
399  gsl_vector *xst = gsl_vector_alloc(5);
400  double q_inv = 1.0/q;
401  gsl_vector_set(xst, 0, q_inv);
402  gsl_vector_set(xst, 1, chi1);
403  gsl_vector_set(xst, 2, chi2);
404  gsl_vector_set(xst, 3, xi_of_lambda(lambda1));
405  gsl_vector_set(xst, 4, xi_of_lambda(lambda2));
406 
407  // Evaluate GPR for amplitude spline nodes
408  for (size_t i=0; i<amp_at_nodes->size; i++) {
409  gsl_vector hyp_amp_i = gsl_matrix_const_row(hyp_amp, i).vector;
410  gsl_vector kinv_dot_y_amp_i = gsl_matrix_const_row(kinv_dot_y_amp, i).vector;
411  double pred = gp_predict(xst, &hyp_amp_i, x_train, &kinv_dot_y_amp_i, work);
412  gsl_vector_set(amp_at_nodes, i, pred);
413  }
414 
415  // Evaluate GPR for phase spline nodes
416  for (size_t i=0; i<phi_at_nodes->size; i++) {
417  gsl_vector hyp_phi_i = gsl_matrix_const_row(hyp_phi, i).vector;
418  gsl_vector kinv_dot_y_phi_i = gsl_matrix_const_row(kinv_dot_y_phi, i).vector;
419  double pred = gp_predict(xst, &hyp_phi_i, x_train, &kinv_dot_y_phi_i, work);
420  gsl_vector_set(phi_at_nodes, i, pred);
421  }
422 
423  gsl_vector_free(xst);
424 
425  return XLAL_SUCCESS;
426 }
427 
428 /* Set up a new submodel, using data contained in dir */
429 UNUSED static int Surrogatedata_Init_submodel(
430  Surrogatedata_submodel **submodel,
431  UNUSED const char dir[],
432  UNUSED const char grp_name[]
433 ) {
434  int ret = XLAL_FAILURE;
435 
436  if(!submodel) exit(1);
437  /* Create storage for submodel structures */
438  if (!*submodel)
439  *submodel = XLALCalloc(1,sizeof(Surrogatedata_submodel));
440  else
442 
443 #ifdef LAL_HDF5_ENABLED
444  size_t size = strlen(dir) + strlen(SurDataHDF5) + 2;
445  char *path = XLALMalloc(size);
446  snprintf(path, size, "%s/%s", dir, SurDataHDF5);
447 
449  //LALH5File *file = XLALH5FileOpen("/Users/mpuer/Documents/gpsurrogate/src/TEOB-LAL-implementation/TEOBv4_surrogate.hdf5", "r");
450  LALH5File *root = XLALH5GroupOpen(file, "/");
451 
452  //////////////////////////////////////////////////////////////////////////////
453  // load everything we need
454  // GP hyperparameters
455  ReadHDF5RealMatrixDataset(root, "hyp_amp", & (*submodel)->hyp_amp);
456  ReadHDF5RealMatrixDataset(root, "hyp_phi", & (*submodel)->hyp_phi);
457 
458  // K^{-1} . y
459  ReadHDF5RealMatrixDataset(root, "kinv_dot_y_amp", & (*submodel)->kinv_dot_y_amp);
460  ReadHDF5RealMatrixDataset(root, "kinv_dot_y_phi", & (*submodel)->kinv_dot_y_phi);
461 
462  // Training points
463  ReadHDF5RealMatrixDataset(root, "x_train", & (*submodel)->x_train);
464 
465  // Frequency grids for surrogate corrections
466  ReadHDF5RealVectorDataset(root, "spline_nodes_amp", & (*submodel)->mf_amp);
467  ReadHDF5RealVectorDataset(root, "spline_nodes_phase", & (*submodel)->mf_phi);
468 
469  // Frequency grids for TaylorF2
470  ReadHDF5RealVectorDataset(root, "TF2_Mf_amp_cubic", & (*submodel)->TF2_mf_amp_cubic);
471  ReadHDF5RealVectorDataset(root, "TF2_Mf_phi_cubic", & (*submodel)->TF2_mf_phi_cubic);
472  ReadHDF5RealVectorDataset(root, "TF2_Mf_amp_linear", & (*submodel)->TF2_mf_amp_linear);
473  ReadHDF5RealVectorDataset(root, "TF2_Mf_phi_linear", & (*submodel)->TF2_mf_phi_linear);
474 
475  // Physical domain covered by surrogate
476  ReadHDF5RealVectorDataset(root, "q_bounds", & (*submodel)->q_bounds);
477  ReadHDF5RealVectorDataset(root, "chi1_bounds", & (*submodel)->chi1_bounds);
478  ReadHDF5RealVectorDataset(root, "chi2_bounds", & (*submodel)->chi2_bounds);
479  ReadHDF5RealVectorDataset(root, "lambda1_bounds", & (*submodel)->lambda1_bounds);
480  ReadHDF5RealVectorDataset(root, "lambda2_bounds", & (*submodel)->lambda2_bounds);
481 
482  // Prepend the point [mf_amp[0], 0] to the phase nodes
483  double mf_min = gsl_vector_get( (*submodel)->mf_amp, 0); // Follow definition of mf_a in GPSplineSurrogate constructor
484  gsl_vector *phi_nodes = gsl_vector_prepend_value((*submodel)->mf_phi, mf_min);
485  (*submodel)->mf_phi = phi_nodes;
486 
487  XLALFree(path);
489  ret = XLAL_SUCCESS;
490 #else
491  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
492 #endif
493 
494  return ret;
495 }
496 
497 /* Deallocate contents of the given Surrogatedata_submodel structure */
498 static void Surrogatedata_Cleanup_submodel(Surrogatedata_submodel *submodel) {
499  if(submodel->hyp_amp) gsl_matrix_free(submodel->hyp_amp);
500  if(submodel->hyp_phi) gsl_matrix_free(submodel->hyp_phi);
501  if(submodel->kinv_dot_y_amp) gsl_matrix_free(submodel->kinv_dot_y_amp);
502  if(submodel->kinv_dot_y_phi) gsl_matrix_free(submodel->kinv_dot_y_phi);
503  if(submodel->x_train) gsl_matrix_free(submodel->x_train);
504  if(submodel->mf_amp) gsl_vector_free(submodel->mf_amp);
505  if(submodel->mf_phi) gsl_vector_free(submodel->mf_phi);
506  if(submodel->TF2_mf_amp_cubic) gsl_vector_free(submodel->TF2_mf_amp_cubic);
507  if(submodel->TF2_mf_phi_cubic) gsl_vector_free(submodel->TF2_mf_phi_cubic);
508  if(submodel->TF2_mf_amp_linear) gsl_vector_free(submodel->TF2_mf_amp_linear);
509  if(submodel->TF2_mf_phi_linear) gsl_vector_free(submodel->TF2_mf_phi_linear);
510 
511  if(submodel->q_bounds) gsl_vector_free(submodel->q_bounds);
512  if(submodel->chi1_bounds) gsl_vector_free(submodel->chi1_bounds);
513  if(submodel->chi2_bounds) gsl_vector_free(submodel->chi2_bounds);
514  if(submodel->lambda1_bounds) gsl_vector_free(submodel->lambda1_bounds);
515  if(submodel->lambda2_bounds) gsl_vector_free(submodel->lambda2_bounds);
516 }
517 
518 /* Set up a new ROM model, using data contained in dir */
520  UNUSED Surrogatedata *romdata,
521  UNUSED const char dir[])
522 {
523  int ret = XLAL_FAILURE;
524 
525  /* Create storage for structures */
526  if(romdata->setup) {
527  XLALPrintError("WARNING: You tried to setup the Surrogate model that was already initialised. Ignoring\n");
528  return (XLAL_FAILURE);
529  }
530 
531 #ifdef LAL_HDF5_ENABLED
532  // First, check we got the correct version number
533  size_t size = strlen(dir) + strlen(SurDataHDF5) + 2;
534  char *path = XLALMalloc(size);
535  snprintf(path, size, "%s/%s", dir, SurDataHDF5);
537 
538  XLALPrintInfo("Surrogate metadata\n============\n");
539  PrintInfoStringAttribute(file, "Email");
540  PrintInfoStringAttribute(file, "Description");
541  ret = ROM_check_version_number(file, SurDataHDF5_VERSION_MAJOR,
542  SurDataHDF5_VERSION_MINOR,
543  SurDataHDF5_VERSION_MICRO);
544 
545  XLALFree(path);
547 
548  ret = Surrogatedata_Init_submodel(&(romdata)->sub1, dir, "sub1");
549  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel 1 loaded successfully.\n", __func__);
550 
551  if(XLAL_SUCCESS==ret)
552  romdata->setup=1;
553  else
554  Surrogatedata_Cleanup(romdata);
555 #else
556  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
557 #endif
558 
559  return (ret);
560 }
561 
562 /* Deallocate contents of the given Surrogatedata structure */
563 static void Surrogatedata_Cleanup(Surrogatedata *romdata) {
565  XLALFree((romdata)->sub1);
566  (romdata)->sub1 = NULL;
567  romdata->setup=0;
568 }
569 
570 /* Return the closest higher power of 2 */
571 // Note: NextPow(2^k) = 2^k for integer values k.
572 static size_t NextPow2(const size_t n) {
573  return 1 << (size_t) ceil(log2(n));
574 }
575 
576 
577 static int TaylorF2Phasing(
578  double Mtot, // Total mass in solar masses
579  double q, // Mass-ration m1/m2 >= 1
580  double chi1, // Dimensionless aligned spin of body 1
581  double chi2, // Dimensionless aligned spin of body 2
582  double lambda1, // Tidal deformability of body 1
583  double lambda2, // Tidal deformability of body 2
584  gsl_vector *Mfs, // Input geometric frequencies
585  gsl_vector **PNphase // Output: TaylorF2 phase at frequencies Mfs
586 ) {
587  XLAL_CHECK(PNphase != NULL, XLAL_EFAULT);
588  XLAL_CHECK(*PNphase == NULL, XLAL_EFAULT);
589  *PNphase = gsl_vector_alloc(Mfs->size);
590 
591  PNPhasingSeries *pn = NULL;
592  LALDict *extraParams = XLALCreateDict();
597 
598  // Use the universal relation fit to determine the quadrupole-monopole terms.
599  double dquadmon1 = XLALSimUniversalRelationQuadMonVSlambda2Tidal(lambda1) - 1.0;
600  double dquadmon2 = XLALSimUniversalRelationQuadMonVSlambda2Tidal(lambda2) - 1.0;
601 
602  if ((dquadmon1 > 0) || (dquadmon2 > 0)) {
603  XLALPrintInfo("Using quadrupole-monopole terms from fit: %g, %g\n", dquadmon1, dquadmon2);
604  XLALSimInspiralWaveformParamsInsertdQuadMon1(extraParams, dquadmon1);
605  XLALSimInspiralWaveformParamsInsertdQuadMon2(extraParams, dquadmon2);
606  }
607 
608  double m1OverM = q / (1.0+q);
609  double m2OverM = 1.0 / (1.0+q);
610  double m1 = Mtot * m1OverM * LAL_MSUN_SI;
611  double m2 = Mtot * m2OverM * LAL_MSUN_SI;
612  // This function is a thin wrapper around XLALSimInspiralPNPhasing_F2
613  XLALSimInspiralTaylorF2AlignedPhasing(&pn, m1, m2, chi1, chi2, extraParams);
614 
615  // Compute and subtract pn_ss3 term (See LALSimInspiralPNCoefficients.c: XLALSimInspiralPNPhasing_F2()).
616  // Rationale: SEOBNRv4T does not contain this ss3 term, therefore
617  // we remove it from the TF2 phasing that is used as a base waveform for the surrogate.
618  double m1M = m1OverM;
619  double m2M = m2OverM;
620  double chi1L = chi1;
621  double chi2L = chi2;
622  double chi1sq = chi1*chi1;
623  double chi2sq = chi2*chi2;
624  double qm_def1 = 1 + dquadmon1;
625  double qm_def2 = 1 + dquadmon2;
626  double eta = q / ((1.0 + q)*(1.0 + q));
627  double pn_ss3 = XLALSimInspiralTaylorF2Phasing_6PNS1S2OCoeff(eta)*chi1L*chi2L
630  pn->v[6] -= pn_ss3 * pn->v[0];
631 
632  for (size_t i=0; i < Mfs->size; i++) {
633  const double Mf = gsl_vector_get(Mfs, i);
634  const double v = cbrt(LAL_PI * Mf);
635  const double logv = log(v);
636  const double v2 = v * v;
637  const double v3 = v * v2;
638  const double v4 = v * v3;
639  const double v5 = v * v4;
640  const double v6 = v * v5;
641  const double v7 = v * v6;
642  const double v8 = v * v7;
643  const double v9 = v * v8;
644  const double v10 = v * v9;
645  const double v12 = v2 * v10;
646  double phasing = 0.0;
647 
648  phasing += pn->v[7] * v7;
649  phasing += (pn->v[6] + pn->vlogv[6] * logv) * v6;
650  phasing += (pn->v[5] + pn->vlogv[5] * logv) * v5;
651  phasing += pn->v[4] * v4;
652  phasing += pn->v[3] * v3;
653  phasing += pn->v[2] * v2;
654  phasing += pn->v[1] * v;
655  phasing += pn->v[0];
656 
657  /* Tidal terms in phasing */
658  phasing += pn->v[12] * v12;
659  phasing += pn->v[10] * v10;
660 
661  phasing /= v5;
662 
663  gsl_vector_set(*PNphase, i, -phasing);
664  }
665 
666  XLALDestroyDict(extraParams);
667  XLALFree(pn);
668 
669  return XLAL_SUCCESS;
670 }
671 
672 // 1PN point-particle amplitude.
673 // Expression from Eq. (6.10) of arXiv:0810.5336.
675  double eta, // Symmetric mass-ratio
676  gsl_vector *Mfs, // Input geometric frequencies
677  gsl_vector **PNamp // Output: TaylorF2 amplitude at frequencies Mfs
678 ) {
679  XLAL_CHECK(PNamp != NULL, XLAL_EFAULT);
680  XLAL_CHECK(*PNamp == NULL, XLAL_EFAULT);
681  *PNamp = gsl_vector_alloc(Mfs->size);
682 
683  for (size_t i=0; i < Mfs->size; i++) {
684  const double Mf = gsl_vector_get(Mfs, i);
685  const double v = cbrt(LAL_PI * Mf);
686  const double x = v*v;
687 
688  double a00 = sqrt( (5.0*LAL_PI/24.0)*eta );
689  double a10 = -323.0/224.0 + 451.0*eta/168.0;
690  double amp = -a00 * pow(x, -7.0/4.0) * (1.0 + a10*x);
691  gsl_vector_set(*PNamp, i, amp);
692  }
693 
694  return XLAL_SUCCESS;
695 }
696 
698  Surrogatedata_submodel *sur,
699  double q, // mass-ratio q >= 1
700  double chi1,
701  double chi2,
702  double lambda1,
703  double lambda2
704 ) {
705  // convert to q >= 1
706  double q_max = 1.0 / gsl_vector_get(sur->q_bounds, 0);
707  double q_min = 1.0 / gsl_vector_get(sur->q_bounds, 1);
708 
709  double chi1_min = gsl_vector_get(sur->chi1_bounds, 0);
710  double chi1_max = gsl_vector_get(sur->chi1_bounds, 1);
711  double chi2_min = gsl_vector_get(sur->chi2_bounds, 0);
712  double chi2_max = gsl_vector_get(sur->chi2_bounds, 1);
713 
714  double lambda1_min = gsl_vector_get(sur->lambda1_bounds, 0);
715  double lambda1_max = gsl_vector_get(sur->lambda1_bounds, 1);
716  double lambda2_min = gsl_vector_get(sur->lambda2_bounds, 0);
717  double lambda2_max = gsl_vector_get(sur->lambda2_bounds, 1);
718 
719  if (q < q_min || q > q_max) {
720  XLALPrintError("XLAL Error - %s: mass-ratio q (%f) out of bounds: [%f, %f]!\n", __func__, q, q_min, q_max);
722  }
723 
724  if (chi1 < chi1_min || chi1 > chi1_max) {
725  XLALPrintError("XLAL Error - %s: aligned-spin chi1 (%f) out of bounds: [%f, %f]!\n", __func__, chi1, chi1_min, chi1_max);
727  }
728 
729  if (chi2 < chi2_min || chi2 > chi2_max) {
730  XLALPrintError("XLAL Error - %s: aligned-spin chi2 (%f) out of bounds: [%f, %f]!\n", __func__, chi2, chi2_min, chi2_max);
732  }
733 
734  if (lambda1 < lambda1_min || lambda1 > lambda1_max) {
735  XLALPrintError("XLAL Error - %s: tidal deformability lambda1 (%f) out of bounds: [%f, %f]!\n", __func__, lambda1, lambda1_min, lambda1_max);
737  }
738 
739  if (lambda2 < lambda2_min || lambda2 > lambda2_max) {
740  XLALPrintError("XLAL Error - %s: tidal deformability lambda2 (%f) out of bounds: [%f, %f]!\n", __func__, lambda2, lambda2_min, lambda2_max);
742  }
743 
744  return XLAL_SUCCESS;
745 }
746 
747 /**
748  * Core function for computing the ROM waveform.
749  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi1, chi2).
750  * Construct 1D splines for amplitude and phase.
751  * Compute strain waveform from amplitude and phase.
752 */
753 static int SurrogateCore(
754  COMPLEX16FrequencySeries **hptilde,
755  COMPLEX16FrequencySeries **hctilde,
756  double phiRef, // orbital reference phase
757  double fRef,
758  double distance,
759  double inclination,
760  double Mtot_sec,
761  double eta,
762  double chi1,
763  double chi2,
764  double lambda1,
765  double lambda2,
766  const REAL8Sequence *freqs_in, /* Frequency points at which to evaluate the waveform (Hz) */
767  double deltaF,
768  /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
769  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
770  * Then we will use deltaF = 0 to create the frequency series we return. */
772  )
773 {
774  /* Check output arrays */
775  if(!hptilde || !hctilde)
777 
778  Surrogatedata *romdata=&__lalsim_SurrogateDS_data;
779  if (!Surrogate_IsSetup()) {
781  "Error setting up Surrogate data - check your $LAL_DATA_PATH\n");
782  }
783 
784  if(*hptilde || *hctilde) {
785  XLALPrintError("(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p",
786  (*hptilde), (*hctilde));
788  }
789  int retcode=0;
790 
791  double Mtot = Mtot_sec / LAL_MTSUN_SI;
792  double q = (1.0 + sqrt(1.0 - 4.0*eta) - 2.0*eta) / (2.0*eta);
793 
794  Surrogatedata_submodel *sur;
795  sur = romdata->sub1;
796 
797  retcode = CheckParameterSpaceBounds(sur, q, chi1, chi2, lambda1, lambda2);
798  if(retcode != 0) XLAL_ERROR(retcode);
799 
800  /* Find frequency bounds */
801  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
802  double fLow = freqs_in->data[0];
803  double fHigh = freqs_in->data[freqs_in->length - 1];
804 
805  if(fRef==0.0)
806  fRef=fLow;
807 
808  int N_amp = sur->mf_amp->size;
809  int N_phi = sur->mf_phi->size;
810 
811  // Point to linear or cubic spline nodes and set order for gsl calls lateron
812  gsl_vector *TF2_mf_amp = NULL;
813  gsl_vector *TF2_mf_phi = NULL;
814  const gsl_interp_type *spline_type = NULL;
815  switch (spline_order) {
817  TF2_mf_amp = sur->TF2_mf_amp_cubic;
818  TF2_mf_phi = sur->TF2_mf_phi_cubic;
819  spline_type = gsl_interp_cspline;
820  break;
822  TF2_mf_amp = sur->TF2_mf_amp_linear;
823  TF2_mf_phi = sur->TF2_mf_phi_linear;
824  spline_type = gsl_interp_linear;
825  break;
826  default:
827  XLAL_ERROR( XLAL_EINVAL, "Unknown spline order!\n. Must be LINEAR or CUBIC." );
828  }
829  int N_amp_TF2 = TF2_mf_amp->size;
830  int N_phi_TF2 = TF2_mf_phi->size;
831 
832  // Allowed geometric frequency ranges for
833  // surrogate and supported TaylorF2 low frequency extension
834  double Mf_TF2_min = fmax(gsl_vector_get(TF2_mf_amp, 0),
835  gsl_vector_get(TF2_mf_phi, 0));
836  double Mf_TF2_max = fmin(gsl_vector_get(TF2_mf_amp, N_amp_TF2-1),
837  gsl_vector_get(TF2_mf_phi, N_phi_TF2-1));
838  double Mf_sur_min = fmax(gsl_vector_get(sur->mf_amp, 0),
839  gsl_vector_get(sur->mf_phi, 0));
840  double Mf_sur_max = fmin(gsl_vector_get(sur->mf_amp, N_amp-1),
841  gsl_vector_get(sur->mf_phi, N_phi-1));
842 
843  // sanity checks: sparse grids for TaylorF2 need to contain the
844  // frequency range where the surrogate corrections are applied
845  XLAL_CHECK(Mf_TF2_min < Mf_sur_min, XLAL_EFAULT);
846  XLAL_CHECK(Mf_TF2_max >= Mf_sur_max, XLAL_EFAULT);
847 
848  double fLow_geom = fLow * Mtot_sec;
849  double fHigh_geom = fHigh * Mtot_sec;
850  double fRef_geom = fRef * Mtot_sec;
851  double deltaF_geom = deltaF * Mtot_sec;
852 
853  // Enforce allowed geometric frequency range
854  if (fLow_geom < Mf_TF2_min)
855  XLAL_ERROR(XLAL_EDOM, "Starting frequency Mflow=%g is smaller than lowest frequency in surrogate Mf=%g.\n", fLow_geom, Mf_TF2_min);
856  if (fHigh_geom == 0 || fHigh_geom > Mf_sur_max)
857  fHigh_geom = Mf_sur_max;
858  else if (fHigh_geom < Mf_sur_min)
859  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than surrogate starting frequency %g!\n", fHigh_geom, Mf_TF2_min);
860  if (fHigh_geom <= fLow_geom)
861  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than (or equal to) starting frequency %g!\n", fHigh_geom, fLow_geom);
862  if (fRef_geom > Mf_sur_max) {
863  XLALPrintWarning("Reference frequency Mf_ref=%g is greater than maximal frequency in surrogate Mf=%g. Starting at maximal frequency in ROM.\n", fRef_geom, Mf_sur_max);
864  fRef_geom = Mf_sur_max; // If fref > fhigh we reset fref to default value of cutoff frequency.
865  }
866  if (fRef_geom < Mf_TF2_min) {
867  XLALPrintWarning("Reference frequency Mf_ref=%g is smaller than lowest frequency in surrogate Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_TF2_min);
868  fRef_geom = Mf_TF2_min;
869  }
870 
871  // Evaluate GPR for log amplitude and dephasing
872  gsl_vector *sur_amp_at_nodes = gsl_vector_alloc(N_amp);
873  gsl_vector *sur_phi_at_nodes_tmp = gsl_vector_alloc(N_phi - 1); // Will prepend a point below
874 
875  // Allocate workspace for the kernel function
876  gsl_vector *work = gsl_vector_alloc(5);
877 
878  retcode |= GPR_evaluation_5D(
879  q, chi1, chi2, lambda1, lambda2,
880  sur->hyp_amp,
881  sur->hyp_phi,
882  sur->kinv_dot_y_amp,
883  sur->kinv_dot_y_phi,
884  sur->x_train,
885  sur_amp_at_nodes,
886  sur_phi_at_nodes_tmp,
887  work
888  );
889 
890  gsl_vector_free(work);
891 
892  if(retcode != 0) {
893  gsl_vector_free(sur_amp_at_nodes);
894  gsl_vector_free(sur_phi_at_nodes_tmp);
895  XLAL_ERROR(retcode);
896  }
897 
898  // Prepend the point [mf_min, 0] to the phase nodes
899  // This has already been done in the setup for mf_phi
900  gsl_vector *sur_phi_at_nodes = gsl_vector_prepend_value(sur_phi_at_nodes_tmp, 0.0);
901 
902  // Spline the surrogate amplitude and phase corrections in frequency
903  gsl_interp_accel *acc_amp_sur = gsl_interp_accel_alloc();
904  gsl_spline *spline_amp_sur = gsl_spline_alloc(gsl_interp_cspline, N_amp);
905  gsl_spline_init(spline_amp_sur, gsl_vector_const_ptr(sur->mf_amp, 0),
906  gsl_vector_const_ptr(sur_amp_at_nodes, 0), N_amp);
907 
908  gsl_interp_accel *acc_phi_sur = gsl_interp_accel_alloc();
909  gsl_spline *spline_phi_sur = gsl_spline_alloc(gsl_interp_cspline, N_phi);
910  gsl_spline_init(spline_phi_sur, gsl_vector_const_ptr(sur->mf_phi, 0),
911  gsl_vector_const_ptr(sur_phi_at_nodes, 0), N_phi);
912 
913  gsl_vector_free(sur_amp_at_nodes);
914  gsl_vector_free(sur_phi_at_nodes);
915 
916 
917  // Evaluate TaylorF2 amplitude and phase on sparse grids
918  gsl_vector *TF2_phi_at_nodes = NULL;
919  retcode |= TaylorF2Phasing(Mtot, q, chi1, chi2, lambda1, lambda2, TF2_mf_phi, &TF2_phi_at_nodes);
920 
921  gsl_vector *TF2_amp_at_nodes = NULL;
922  retcode |= TaylorF2Amplitude1PN(eta, TF2_mf_amp, &TF2_amp_at_nodes);
923 
924  if(retcode != 0) {
925  gsl_vector_free(TF2_amp_at_nodes);
926  gsl_vector_free(TF2_phi_at_nodes);
927  XLAL_ERROR(retcode);
928  }
929 
930  // Spline TaylorF2 amplitude and phase
931  // We add the surrogate corrections to the TaylorF2 spline data
932  // in the frequency range where the surrogate has support.
933 
934  // amplitude
935  gsl_interp_accel *acc_amp_TF2 = gsl_interp_accel_alloc();
936  gsl_spline *spline_amp_TF2 = gsl_spline_alloc(spline_type, N_amp_TF2);
937  gsl_vector *spline_amp_values = gsl_vector_alloc(N_amp_TF2);
938  for (int i=0; i<N_amp_TF2; i++) {
939  double Mf = gsl_vector_get(TF2_mf_amp, i);
940  double amp_i = gsl_vector_get(TF2_amp_at_nodes, i);
941  if ((Mf >= Mf_sur_min) & (Mf <= Mf_sur_max))
942  amp_i *= exp(gsl_spline_eval(spline_amp_sur, Mf, acc_amp_sur));
943  gsl_vector_set(spline_amp_values, i, amp_i);
944  }
945  gsl_spline_init(spline_amp_TF2, gsl_vector_const_ptr(TF2_mf_amp, 0),
946  gsl_vector_const_ptr(spline_amp_values, 0), N_amp_TF2);
947 
948  // phase
949  gsl_interp_accel *acc_phi_TF2 = gsl_interp_accel_alloc();
950  gsl_spline *spline_phi_TF2 = gsl_spline_alloc(spline_type, N_phi_TF2);
951  gsl_vector *spline_phi_values = gsl_vector_alloc(N_phi_TF2);
952  for (int i=0; i<N_phi_TF2; i++) {
953  double Mf = gsl_vector_get(TF2_mf_phi, i);
954  double phi_i = gsl_vector_get(TF2_phi_at_nodes, i);
955  if ((Mf >= Mf_sur_min) & (Mf <= Mf_sur_max))
956  phi_i += gsl_spline_eval(spline_phi_sur, Mf, acc_phi_sur);
957  gsl_vector_set(spline_phi_values, i, phi_i);
958  }
959  gsl_spline_init(spline_phi_TF2, gsl_vector_const_ptr(TF2_mf_phi, 0),
960  gsl_vector_const_ptr(spline_phi_values, 0), N_phi_TF2);
961 
962  gsl_vector_free(TF2_amp_at_nodes);
963  gsl_vector_free(TF2_phi_at_nodes);
964  gsl_vector_free(spline_amp_values);
965  gsl_vector_free(spline_phi_values);
966 
967  gsl_spline_free(spline_amp_sur);
968  gsl_spline_free(spline_phi_sur);
969  gsl_interp_accel_free(acc_amp_sur);
970  gsl_interp_accel_free(acc_phi_sur);
971 
972 
973  // Now setup LAL datastructures for waveform polarizations
974  size_t npts = 0;
975  LIGOTimeGPS tC = {0, 0};
976  UINT4 offset = 0; // Index shift between freqs and the frequency series
977  REAL8Sequence *freqs = NULL;
978  if (deltaF > 0) { // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
979  /* Set up output array with size closest power of 2 */
980  npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
981  if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
982  npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;
983 
984  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
985  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
986  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
987 
988  // Recreate freqs using only the lower and upper bounds
989  // Use fLow, fHigh and deltaF rather than geometric frequencies for numerical accuracy
990  double fHigh_temp = fHigh_geom / Mtot_sec;
991  UINT4 iStart = (UINT4) ceil(fLow / deltaF);
992  UINT4 iStop = (UINT4) ceil(fHigh_temp / deltaF);
993  freqs = XLALCreateREAL8Sequence(iStop - iStart);
994  if (!freqs) {
995  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
996  }
997  for (UINT4 i=iStart; i<iStop; i++)
998  freqs->data[i-iStart] = i*deltaF_geom;
999 
1000  offset = iStart;
1001  } else { // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
1002  npts = freqs_in->length;
1003  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
1004  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, fLow, 0, &lalStrainUnit, npts);
1005  offset = 0;
1006 
1007  freqs = XLALCreateREAL8Sequence(freqs_in->length);
1008  if (!freqs) {
1009  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
1010  }
1011  for (UINT4 i=0; i<freqs_in->length; i++)
1012  freqs->data[i] = freqs_in->data[i] * Mtot_sec;
1013  }
1014 
1015  if (!(*hptilde) || !(*hctilde)) {
1016  XLALDestroyREAL8Sequence(freqs);
1017  gsl_interp_accel_free(acc_phi_TF2);
1018  gsl_spline_free(spline_phi_TF2);
1019  gsl_interp_accel_free(acc_amp_TF2);
1020  gsl_spline_free(spline_amp_TF2);
1022  }
1023  memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
1024  memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));
1025 
1026  XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
1027  XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
1028 
1029  COMPLEX16 *pdata=(*hptilde)->data->data;
1030  COMPLEX16 *cdata=(*hctilde)->data->data;
1031 
1032  REAL8 cosi = cos(inclination);
1033  REAL8 pcoef = 0.5*(1.0 + cosi*cosi);
1034  REAL8 ccoef = cosi;
1035 
1036  double amp0 = Mtot * Mtot_sec * LAL_MRSUN_SI / (distance); // amplitude prefactor
1037 
1038  // Evaluate reference phase for setting phiRef correctly
1039  double phase_change = 0.0;
1040  phase_change = gsl_spline_eval(spline_phi_TF2, fRef_geom, acc_phi_TF2) - 2*phiRef;
1041 
1042  // The maximum frequency for which we generate waveform data is set to the
1043  // maximum frequency covered by the surrogate.
1044  Mf_sur_max = gsl_vector_get(sur->mf_phi, N_phi-1);
1045  double Mf_final = Mf_sur_max;
1046 
1047  // Assemble waveform from aplitude and phase
1048  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
1049  double f = freqs->data[i];
1050  if (f > Mf_final) continue; // We're beyond the highest allowed frequency;
1051  // since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
1052  int j = i + offset; // shift index for frequency series if needed
1053  double A = gsl_spline_eval(spline_amp_TF2, f, acc_amp_TF2);
1054  double phase = gsl_spline_eval(spline_phi_TF2, f, acc_phi_TF2) - phase_change;
1055  COMPLEX16 htilde = amp0*A * (cos(phase) + I*sin(phase));//cexp(I*phase);
1056  pdata[j] = pcoef * htilde;
1057  cdata[j] = -I * ccoef * htilde;
1058  }
1059 
1060  /* Correct phasing so we coalesce at t=0 (with the definition of the epoch=-1/deltaF above) */
1061  UINT4 L = freqs->length;
1062  // prevent gsl interpolation errors
1063  if (Mf_final > freqs->data[L-1])
1064  Mf_final = freqs->data[L-1];
1065  if (Mf_final < freqs->data[0]) {
1066  XLALDestroyREAL8Sequence(freqs);
1067  gsl_interp_accel_free(acc_phi_TF2);
1068  gsl_spline_free(spline_phi_TF2);
1069  gsl_interp_accel_free(acc_amp_TF2);
1070  gsl_spline_free(spline_amp_TF2);
1071  XLAL_ERROR(XLAL_EDOM, "f_ringdown < f_min");
1072  }
1073 
1074  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
1075  // We compute the dimensionless time correction t/M since we use geometric units.
1076  // We use the Schwarzschild ISCO as a rough proxy for the amplitude peak of the BNS waveform.
1077  // We used XLALSimNSNSMergerFreq() earlier and it turned out not to be reliable for extreme input parameters.
1078  REAL8 Mf_ISCO_Schwrazschild = 1.0 / (pow(6.,3./2.)*LAL_PI);
1079  REAL8 t_corr = gsl_spline_eval_deriv(spline_phi_TF2, Mf_ISCO_Schwrazschild, acc_phi_TF2) / (2*LAL_PI);
1080 
1081  // Now correct phase
1082  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
1083  double f = freqs->data[i] - fRef_geom;
1084  int j = i + offset; // shift index for frequency series if needed
1085  double phase_factor = -2*LAL_PI * f * t_corr;
1086  COMPLEX16 t_factor = (cos(phase_factor) + I*sin(phase_factor));//cexp(I*phase_factor);
1087  pdata[j] *= t_factor;
1088  cdata[j] *= t_factor;
1089  }
1090 
1091  XLALDestroyREAL8Sequence(freqs);
1092  gsl_interp_accel_free(acc_phi_TF2);
1093  gsl_spline_free(spline_phi_TF2);
1094  gsl_interp_accel_free(acc_amp_TF2);
1095  gsl_spline_free(spline_amp_TF2);
1096 
1097  return(XLAL_SUCCESS);
1098 }
1099 
1100 /**
1101  * @addtogroup LALSimIMRSEOBNRv4TSurrogate_c
1102  *
1103  * \author Michael Puerrer, Ben Lackey
1104  *
1105  * \brief C code for SEOBNRv4T surrogate model
1106  * See arXiv:1812.08643
1107  *
1108  * This is a frequency domain model that approximates the time domain TEOBv4 model.
1109  *
1110  * The binary data HDF5 file (SEOBNRv4T_surrogate_v1.0.0.hdf5)
1111  * will be available at on LIGO clusters in /home/cbc/ and can be downloaded from
1112  * https://git.ligo.org/lscsoft/lalsuite-extra/blob/master/data/lalsimulation/SEOBNRv4T_surrogate_v1.0.0.hdf5.
1113  * Make sure the files are in your LAL_DATA_PATH.
1114  *
1115  * @note Note that due to its construction the iFFT of the surrogate has a small (~ 20 M) offset
1116  * in the peak time that scales with total mass as compared to the time-domain SEOBNRv4T model.
1117  *
1118  * @note Parameter ranges:
1119  * 1 <= q <= 3
1120  * -0.5 <= chi1 <= 0.5
1121  * -0.5 <= chi2 <= 0.5
1122  * 0 <= lambda1 <= 5000
1123  * 0 <= lambda2 <= 5000
1124  *
1125  * Aligned component spins chi1, chi2.
1126  * Tidal deformabilities of neutron stars lambda1, lambda2.
1127  * Mass-ratio q = m1/m2
1128  *
1129  * @{
1130  */
1131 
1132 
1133 /**
1134  * Compute waveform in LAL format at specified frequencies for the SEOBNRv4T_surrogate model.
1135  *
1136  * XLALSimIMRSEOBNRv4TSurrogate() returns the plus and cross polarizations as a complex
1137  * frequency series with equal spacing deltaF and contains zeros from zero frequency
1138  * to the starting frequency and zeros beyond the cutoff frequency in the ringdown.
1139  *
1140  * In contrast, XLALSimIMRSEOBNRv4TSurrogateFrequencySequence() returns a
1141  * complex frequency series with entries exactly at the frequencies specified in
1142  * the sequence freqs (which can be unequally spaced). No zeros are added.
1143  *
1144  * If XLALSimIMRSEOBNRv4TSurrogateFrequencySequence() is called with frequencies that
1145  * are beyond the maxium allowed geometric frequency for the ROM, zero strain is returned.
1146  * It is not assumed that the frequency sequence is ordered.
1147  *
1148  * This function is designed as an entry point for reduced order quadratures.
1149  */
1151  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
1152  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
1153  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz) */
1154  REAL8 phiRef, /**< Orbital phase at reference time */
1155  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1156  REAL8 distance, /**< Distance of source (m) */
1157  REAL8 inclination, /**< Inclination of source (rad) */
1158  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1159  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1160  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1161  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
1162  REAL8 lambda1, /**< Dimensionless tidal deformability 1 */
1163  REAL8 lambda2, /**< Dimensionless tidal deformability 2 */
1164  SEOBNRv4TSurrogate_spline_order spline_order) /**< Spline order in frequency */
1165 {
1166  /* Internally we need m1 > m2, so change around if this is not the case */
1167  if (m1SI < m2SI) {
1168  // Swap m1 and m2
1169  double m1temp = m1SI;
1170  double chi1temp = chi1;
1171  double lambda1temp = lambda1;
1172  m1SI = m2SI;
1173  chi1 = chi2;
1174  lambda1 = lambda2;
1175  m2SI = m1temp;
1176  chi2 = chi1temp;
1177  lambda2 = lambda1temp;
1178  }
1179 
1180  /* Get masses in terms of solar mass */
1181  double mass1 = m1SI / LAL_MSUN_SI;
1182  double mass2 = m2SI / LAL_MSUN_SI;
1183  double Mtot = mass1+mass2;
1184  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1185  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1186 
1187  if (!freqs) XLAL_ERROR(XLAL_EFAULT);
1188 
1189  // Load ROM data if not loaded already
1190 #ifdef LAL_PTHREAD_LOCK
1191  (void) pthread_once(&Surrogate_is_initialized, Surrogate_Init_LALDATA);
1192 #else
1194 #endif
1195 
1196  if(!Surrogate_IsSetup()) {
1198  "Error setting up Surrogate data - check your $LAL_DATA_PATH\n");
1199  }
1200 
1201  // Call the internal core function with deltaF = 0 to indicate that freqs is non-uniformly
1202  // spaced and we want the strain only at these frequencies
1203  int retcode = SurrogateCore(hptilde, hctilde, phiRef, fRef, distance,
1204  inclination, Mtot_sec, eta, chi1, chi2,
1205  lambda1, lambda2, freqs, 0, spline_order);
1206 
1207  return(retcode);
1208 }
1209 
1210 /**
1211  * Compute waveform in LAL format for the SEOBNRv4T_surrogate model.
1212  *
1213  * Returns the plus and cross polarizations as a complex frequency series with
1214  * equal spacing deltaF and contains zeros from zero frequency to the starting
1215  * frequency fLow and zeros beyond the cutoff frequency in the ringdown.
1216  */
1218  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
1219  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
1220  REAL8 phiRef, /**< Phase at reference time */
1221  REAL8 deltaF, /**< Sampling frequency (Hz) */
1222  REAL8 fLow, /**< Starting GW frequency (Hz) */
1223  REAL8 fHigh, /**< End frequency; 0 defaults to Mf=0.14 */
1224  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1225  REAL8 distance, /**< Distance of source (m) */
1226  REAL8 inclination, /**< Inclination of source (rad) */
1227  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1228  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1229  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1230  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
1231  REAL8 lambda1, /**< Dimensionless tidal deformability 1 */
1232  REAL8 lambda2, /**< Dimensionless tidal deformability 2 */
1233  SEOBNRv4TSurrogate_spline_order spline_order) /**< Spline order in frequency */
1234 {
1235  /* Internally we need m1 > m2, so change around if this is not the case */
1236  if (m1SI < m2SI) {
1237  // Swap m1 and m2
1238  double m1temp = m1SI;
1239  double chi1temp = chi1;
1240  double lambda1temp = lambda1;
1241  m1SI = m2SI;
1242  chi1 = chi2;
1243  lambda1 = lambda2;
1244  m2SI = m1temp;
1245  chi2 = chi1temp;
1246  lambda2 = lambda1temp;
1247  }
1248 
1249  /* Get masses in terms of solar mass */
1250  double mass1 = m1SI / LAL_MSUN_SI;
1251  double mass2 = m2SI / LAL_MSUN_SI;
1252  double Mtot = mass1+mass2;
1253  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
1254  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1255 
1256  if(fRef==0.0)
1257  fRef=fLow;
1258 
1259  // Load ROM data if not loaded already
1260 #ifdef LAL_PTHREAD_LOCK
1261  (void) pthread_once(&Surrogate_is_initialized, Surrogate_Init_LALDATA);
1262 #else
1264 #endif
1265 
1266  // Use fLow, fHigh, deltaF to compute freqs sequence
1267  // Instead of building a full sequency we only transfer the boundaries and let
1268  // the internal core function do the rest (and properly take care of corner cases).
1270  freqs->data[0] = fLow;
1271  freqs->data[1] = fHigh;
1272 
1273  int retcode = SurrogateCore(hptilde, hctilde, phiRef, fRef, distance,
1274  inclination, Mtot_sec, eta, chi1, chi2,
1275  lambda1, lambda2, freqs, deltaF, spline_order);
1276 
1277  XLALDestroyREAL8Sequence(freqs);
1278 
1279  return(retcode);
1280 }
1281 
1282 /** @} */
1283 
1284 
1285 /** Setup Surrogate model using data files installed in $LAL_DATA_PATH
1286  */
1287 UNUSED static void Surrogate_Init_LALDATA(void)
1288 {
1289  if (Surrogate_IsSetup()) return;
1290 
1291  // Expect ROM datafile in a directory listed in LAL_DATA_PATH,
1292 #ifdef LAL_HDF5_ENABLED
1293 #define datafile SurDataHDF5
1294  char *path = XLAL_FILE_RESOLVE_PATH(datafile);
1295  if (path==NULL)
1296  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile);
1297  char *dir = dirname(path);
1298  int ret = Surrogate_Init(dir);
1299  XLALFree(path);
1300 
1301  if(ret!=XLAL_SUCCESS)
1302  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find Surrogate data files in $LAL_DATA_PATH\n");
1303 #else
1304  XLAL_ERROR_VOID(XLAL_EFAILED, "Surrogate requires HDF5 support which is not enabled\n");
1305 #endif
1306 }
struct tagLALH5File LALH5File
void XLALDestroyDict(LALDict *dict)
LALDict * XLALCreateDict(void)
static const REAL8 q_max
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
static UNUSED int Surrogate_Init(const char dir[])
Setup Surrogate model using data files installed in dir.
static UNUSED void save_gsl_frequency_series(const char filename[], gsl_vector *x, gsl_vector *y)
int(* load_dataPtr)(const char *, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *)
static Surrogatedata __lalsim_SurrogateDS_data
static int GPR_evaluation_5D(double q, double chi1, double chi2, double lambda1, double lambda2, gsl_matrix *hyp_amp, gsl_matrix *hyp_phi, gsl_matrix *kinv_dot_y_amp, gsl_matrix *kinv_dot_y_phi, gsl_matrix *x_train, gsl_vector *amp_at_EI_nodes, gsl_vector *phi_at_EI_nodes, gsl_vector *work)
double gp_predict(gsl_vector *xst, gsl_vector *hyperparams, gsl_matrix *x_train, gsl_vector *Kinv_dot_y, gsl_vector *work)
static UNUSED int Surrogatedata_Init(Surrogatedata *romdata, const char dir[])
static UNUSED int Surrogatedata_Init_submodel(UNUSED Surrogatedata_submodel **submodel, UNUSED const char dir[], UNUSED const char grp_name[])
static UNUSED void Surrogatedata_Cleanup_submodel(Surrogatedata_submodel *submodel)
static UNUSED void Surrogatedata_Cleanup(Surrogatedata *romdata)
static int TaylorF2Amplitude1PN(double eta, gsl_vector *Mfs, gsl_vector **PNamp)
static UNUSED void Surrogate_Init_LALDATA(void)
Setup Surrogate model using data files installed in $LAL_DATA_PATH.
static double xi_of_lambda(double lambda)
Coordinate transformation.
static gsl_vector * gsl_vector_prepend_value(gsl_vector *v, double value)
double kernel(gsl_vector *x1, gsl_vector *x2, gsl_vector *hyperparams, gsl_vector *work)
static UNUSED bool Surrogate_IsSetup(void)
Helper function to check if the Surrogate model has been initialised.
static size_t NextPow2(const size_t n)
static UNUSED int CheckParameterSpaceBounds(Surrogatedata_submodel *sur, double q, double chi1, double chi2, double lambda1, double lambda2)
static UNUSED int SurrogateCore(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, double phiRef, double fRef, double distance, double inclination, double Mtot_sec, double eta, double chi1, double chi2, double lambda1, double lambda2, const REAL8Sequence *freqs, double deltaF, SEOBNRv4TSurrogate_spline_order spline_order)
Core function for computing the ROM waveform.
static int TaylorF2Phasing(double Mtot, double q, double chi1, double chi2, double lambda1, double lambda2, gsl_vector *Mfs, gsl_vector **PNphase)
static REAL8 UNUSED XLALSimInspiralTaylorF2Phasing_6PNS1S2OCoeff(REAL8 eta)
static REAL8 UNUSED XLALSimInspiralTaylorF2Phasing_6PNQM2SCoeff(REAL8 mByM)
static REAL8 UNUSED XLALSimInspiralTaylorF2Phasing_6PNSelf2SCoeff(REAL8 mByM)
int XLALSimInspiralWaveformParamsInsertTidalLambda1(LALDict *params, REAL8 value)
int XLALSimInspiralWaveformParamsInsertPNSpinOrder(LALDict *params, INT4 value)
int XLALSimInspiralWaveformParamsInsertTidalLambda2(LALDict *params, REAL8 value)
int XLALSimInspiralWaveformParamsInsertdQuadMon2(LALDict *params, REAL8 value)
int XLALSimInspiralWaveformParamsInsertPNTidalOrder(LALDict *params, INT4 value)
int XLALSimInspiralWaveformParamsInsertdQuadMon1(LALDict *params, REAL8 value)
REAL8 XLALSimUniversalRelationQuadMonVSlambda2Tidal(REAL8 lambda2bar)
#define fprintf
double i
Definition: bh_ringdown.c:118
const double pn
sigmaKerr data[0]
#define XLAL_FILE_RESOLVE_PATH(fname)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALH5FileClose(LALH5File UNUSED *file)
LALH5File * XLALH5GroupOpen(LALH5File UNUSED *file, const char UNUSED *name)
LALH5File * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALCalloc(size_t m, size_t n)
void * XLALMalloc(size_t n)
void XLALFree(void *p)
SEOBNRv4TSurrogate_spline_order
Definition: LALSimIMR.h:88
@ SEOBNRv4TSurrogate_CUBIC
use cubic splines in frequency
Definition: LALSimIMR.h:89
@ SEOBNRv4TSurrogate_LINEAR
use linear splines in frequency
Definition: LALSimIMR.h:90
int XLALSimIMRSEOBNRv4TSurrogateFrequencySequence(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, REAL8 phiRef, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, REAL8 lambda1, REAL8 lambda2, SEOBNRv4TSurrogate_spline_order spline_order)
Compute waveform in LAL format at specified frequencies for the SEOBNRv4T_surrogate model.
int XLALSimIMRSEOBNRv4TSurrogate(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, REAL8 lambda1, REAL8 lambda2, SEOBNRv4TSurrogate_spline_order spline_order)
Compute waveform in LAL format for the SEOBNRv4T_surrogate model.
@ LAL_SIM_INSPIRAL_SPIN_ORDER_35PN
@ LAL_SIM_INSPIRAL_TIDAL_ORDER_6PN
int XLALSimInspiralTaylorF2AlignedPhasing(PNPhasingSeries **pfa, const REAL8 m1, const REAL8 m2, const REAL8 chi1, const REAL8 chi2, LALDict *extraPars)
Returns structure containing TaylorF2 phasing coefficients for given physical parameters.
static const INT4 r
static const INT4 q
static const INT4 a
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_ERROR_VOID(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_ABORT(assertion)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EDIMS
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list x
list y
path
filename
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
REAL8 * data
Surrogatedata_submodel * sub1
FILE * fp