LALSimulation  5.4.0.1-fe68b98
LALSimIMRNRSur4d2s.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Jonathan Blackman
3  * NRSur4d2s_FDROM model, Reduced Order Model for NRSur4d2s.
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_complex_math.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 #include <lal/SphericalHarmonics.h>
54 #include <lal/LALSimInspiral.h>
55 #include <lal/LALSimIMR.h>
56 
58 
59 #include <lal/LALConfig.h>
60 #ifdef LAL_PTHREAD_LOCK
61 #include <pthread.h>
62 #endif
63 
64 
65 /******* Surrogate model parameter space ********/
66 static const double Q_MIN = 1.;
67 static const double Q_MAX = 2.;
68 static const double CHI1_MAG_MAX = 0.8;
69 static const double CHI2_MIN = -0.8;
70 static const double CHI2_MAX = 0.8;
71 
72 static const char NRSUR4D2S_DATAFILE[] = "NRSur4d2s_FDROM.hdf5";
73 
74 #ifdef LAL_PTHREAD_LOCK
75 static pthread_once_t NRSur4d2s_is_initialized = PTHREAD_ONCE_INIT;
76 #endif
77 
78 /*************** type definitions ******************/
79 
80 struct tagNRSurrogateData_submodel // A submodel is one (l, m) mode.
81 {
82  gsl_vector* cvec_re; // Flattened real spline coefficients
83  gsl_vector* cvec_im; // Flattened imag spline coefficients
84  gsl_matrix *EI_re; // Empirical interpolation matrix (real part)
85  gsl_matrix *EI_im; // Empirical interpolation matrix (imag part)
86 };
87 typedef struct tagNRSurrogateData_submodel NRSurrogateData_submodel;
88 
89 typedef struct tagSplineData5d
90 {
91  gsl_bspline_workspace *bw_x0; // Spline workspace for the first parameter
92  gsl_bspline_workspace *bw_x1; // etc
93  gsl_bspline_workspace *bw_x2;
94  gsl_bspline_workspace *bw_x3;
95  gsl_bspline_workspace *bw_x4;
96 } SplineData5d;
97 
99 {
101  int n_nodes; // Number of empirical nodes
102  int n_freqs; // Number of frequency samples in empirical interpolant output
103  int *nc; // Number of spline coefficients in each parameter dimension
104  double *qvec; //q points in tensor grid
105  double *chi1vec; //chi1 points in tensor grid
106  double *chi1thetavec;
107  double *chi1phivec;
108  double *chi2vec;
109  NRSurrogateData_submodel* mode_2m2;
110  NRSurrogateData_submodel* mode_2m1;
111  NRSurrogateData_submodel* mode_2p0;
112  NRSurrogateData_submodel* mode_2p1;
113  NRSurrogateData_submodel* mode_2p2;
114  NRSurrogateData_submodel* mode_3m3;
115  NRSurrogateData_submodel* mode_3m2;
116  NRSurrogateData_submodel* mode_3m1;
117  NRSurrogateData_submodel* mode_3p0;
118  NRSurrogateData_submodel* mode_3p1;
119  NRSurrogateData_submodel* mode_3p2;
120  NRSurrogateData_submodel* mode_3p3;
121 
122  gsl_vector* fEI; // Frequency samples of empirical interpolant output
123  SplineData5d* splinedata; // Data associated with the tensor product grid in parameter space
124 };
125 typedef struct tagNRSurrogateData NRSurrogateData;
126 
127 static NRSurrogateData __lalsim_NRSurrogate_data;
128 
129 /**************** Internal functions **********************/
130 
131 static void err_handler(const char *reason, const char *file, int line, int gsl_errno);
132 static void NRSurrogate_Init_LALDATA(void);
133 static int NRSurrogate_Init(const char dir[]);
134 static bool NRSurrogate_IsSetup(void);
135 
136 static int NRSurrogateData_Init(NRSurrogateData *data, const char dir[]);
137 static void NRSurrogateData_Cleanup(NRSurrogateData *data);
138 
139 // Helper function to interpolate all empirical nodes in 5d for one waveform mode
140 static int TP_Spline_interpolation_5d(
141  REAL8 x0, // Coordinates onto which we interpolate
142  REAL8 x1,
143  REAL8 x2,
144  REAL8 x3,
145  REAL8 x4,
146  int n_nodes, // Input: number of empirical nodes
147  int *nc, // Input: number of spline coefs per dimension
148  gsl_vector *cvec_re, // Input: flattened real spline coefficients
149  gsl_vector *cvec_im, // Input: flattened imag spline coefficients
150  SplineData5d *splinedata, // Input: Data associated with the tensor grid in parameter space
151  gsl_vector *nodes_re, // Output: interpolated real empirical nodes
152  gsl_vector *nodes_im // Output: interpolated imag empirical nodes
153 );
154 
156  NRSurrogateData_submodel **submodel,
157  LALH5File *file,
158  const int i_mode,
159  int n_nodes,
160  int n_freqs,
161  int *nc
162 );
163 
164 static void NRSurrogateData_Cleanup_submodel(NRSurrogateData_submodel *submodel);
165 
166 /**
167  * Evaluates one mode of the surrogate model and adds it to the waveform
168  * Real and imaginary parts used due to lack of gsl_vector_complex_conjugate() function
169  * Note that here the output waveform is a single complex function containing positive
170  * and negative frequency content, from which we may obtain hplus and hcross.
171  * The output is evaluated at the empirical interpolation output samples.
172  * Output frequencies and waveform are dimensionless.
173 */
174 static void AddModeContribution(
175  double q, // Parameters at which we evaluate the surrogate mode
176  double chi1mag,
177  double chi1theta,
178  double chi1phi,
179  double chi2z,
180  double spheretheta, // The polar angle of the direction of GW propagation from the source
181  double spherephi, // The azimuthal angle of the direction of GW propagation from the source
182  int swsh_L, // The mode L
183  int swsh_m, // The mode m
184  int n_nodes,
185  int *nc,
186  gsl_vector *h_re, // Gets modified - the real part of the waveform
187  gsl_vector *h_im, // Gets modified - the imag part of the waveform
188  NRSurrogateData_submodel *modeData, // The surrogate data for this mode
189  SplineData5d *splinedata, // Data associated with the tensor product grid in param space
190  gsl_vector *nodes_re, // Intermediate result - the real part of the empirical nodes for this mode
191  gsl_vector *nodes_im, // Intermediate result - the imag part of the empirical nodes for this mode
192  gsl_vector *mode_re, // Intermediate result - the real part of the evaluated mode
193  gsl_vector *mode_im // Intermediate result - the imag part of the evaluated mode
194 );
195 
196 /**
197  * Core function for computing the ROM waveform.
198  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
199  * Construct 1D splines for amplitude and phase.
200  * Compute strain waveform from amplitude and phase.
201 */
202 static int NRSurrogateCore(
203  COMPLEX16FrequencySeries **hptilde,
204  COMPLEX16FrequencySeries **hctilde,
205  double phiRef,
206  double distance,
207  double inclination,
208  double Mtot_sec,
209  double q,
210  double chi1mag,
211  double chi1theta,
212  double chi1phi,
213  double chi2z,
214  const REAL8Sequence *freqs /* Frequency points at which to evaluate the waveform (Hz) */
215 );
216 
218 static void SplineData5d_Init(
220  int *nc, // Number of spline coefs per dimension
221  double *x1, // Parameter grid values
222  double *x2,
223  double *x3,
224  double *x4,
225  double *x5
226 );
227 
228 static int load_data_sub(
229  const int i_mode,
230  LALH5File *file,
231  gsl_vector *cvec_re,
232  gsl_vector *cvec_im,
233  gsl_matrix *EI_re,
234  gsl_matrix *EI_im
235 );
236 
237 // Function which sums over all contributing basis splines
239  gsl_vector *v,
240  gsl_vector *B0, // 4 non-zero basis splines
241  gsl_vector *B1,
242  gsl_vector *B2,
243  gsl_vector *B3,
244  gsl_vector *B4,
245  size_t is0, // Index of first of 4 coefficients to evaluate
246  size_t is1,
247  size_t is2,
248  size_t is3,
249  size_t is4,
250  int *nc // Number of spline coefficients in each dimension
251 );
252 
253 /********************* Definitions begin here ********************/
254 
255 static void err_handler(const char *reason, const char *file, int line, int gsl_errno) {
256  XLALPrintError("gsl: %s:%d: %s - %d\n", file, line, reason, gsl_errno);
257 }
258 
259 // Function which sums over all contributing basis splines
261  gsl_vector *v,
262  gsl_vector *B0, // 4 non-zero basis splines
263  gsl_vector *B1,
264  gsl_vector *B2,
265  gsl_vector *B3,
266  gsl_vector *B4,
267  size_t is0, // Index of first of 4 coefficients to evaluate
268  size_t is1,
269  size_t is2,
270  size_t is3,
271  size_t is4,
272  int *nc // Number of coefficients in each dimension
273 ) {
274  // Compute coefficient at desired parameters from
275  // C = c_{i0, i1, i2, i3, i4} * B1[i0] * B2[i1] * ...
276  // while summing over indices i0,...,i4 where the B-splines are nonzero.
277  double sum = 0;
278 
279  for (int i0=0; i0<4; i0++) {
280  int ii0 = is0 + i0;
281  for (int i1=0; i1<4; i1++) {
282  int ii1 = is1 + i1;
283  for (int i2=0; i2<4; i2++) {
284  int ii2 = is2 + i2;
285  for (int i3=0; i3<4; i3++) {
286  int ii3 = is3 + i3;
287  for (int i4=0; i4<4; i4++) {
288  int ii4 = is4 + i4;
289  double c = gsl_vector_get(v, (((ii0*nc[1] + ii1)*nc[2] + ii2)*nc[3] + ii3)*nc[4] + ii4);
290  sum += c * gsl_vector_get(B0, i0) * gsl_vector_get(B1, i1) * gsl_vector_get(B2, i2) *
291  gsl_vector_get(B3, i3) * gsl_vector_get(B4, i4);
292  }
293  }
294  }
295  }
296  }
297 
298  return sum;
299 }
300 
301 /** Setup NRSurrogate model using data files installed in dir
302  */
303 static int NRSurrogate_Init(const char dir[]) {
304  if(__lalsim_NRSurrogate_data.setup) {
305  XLALPrintError("Error: NRSurrogate was already set up!");
307  }
308 
310 
311  if(__lalsim_NRSurrogate_data.setup) {
312  return(XLAL_SUCCESS);
313  }
314  else {
315  return(XLAL_EFAILED);
316  }
317 }
318 
319 /** Helper function to check if the NRSurrogate model has been initialised */
320 static bool NRSurrogate_IsSetup(void) {
321  if(__lalsim_NRSurrogate_data.setup)
322  return true;
323  else
324  return false;
325 }
326 
327 // Read binary ROM data for basis functions and coefficients for submodel 1
328 static int load_data_sub(
329  const int i_mode,
330  LALH5File *file,
331  gsl_vector *cvec_re,
332  gsl_vector *cvec_im,
333  gsl_matrix *EI_re,
334  gsl_matrix *EI_im
335 ) {
336  // Load H5 data sets for spline coefficients and empirical interpolation matrix
337 
338  int ret = XLAL_SUCCESS;
339  size_t name_length = 22;
340  if (i_mode > 9) name_length = 23;
341  char *dataset_name = malloc(name_length);
342 
343  snprintf(dataset_name, name_length, "NRSurrogate_cre_%d", i_mode);
344  ret |= ReadHDF5RealVectorDataset(file, dataset_name, &cvec_re);
345 
346  snprintf(dataset_name, name_length, "NRSurrogate_cim_%d", i_mode);
347  ret |= ReadHDF5RealVectorDataset(file, dataset_name, &cvec_im);
348 
349  snprintf(dataset_name, name_length, "NRSurrogate_EIr_%d.dat", i_mode);
350  ret |= ReadHDF5RealMatrixDataset(file, dataset_name, &EI_re);
351 
352  snprintf(dataset_name, name_length, "NRSurrogate_EIi_%d.dat", i_mode);
353  ret |= ReadHDF5RealMatrixDataset(file, dataset_name, &EI_im);
354 
355  free(dataset_name);
356  return(ret);
357 }
358 
359 // Setup B-spline basis functions for given points
360 static void SplineData5d_Init(
362  int *nc, // Number of coefficients per dimension
363  double *x0, // Parameter grid values
364  double *x1,
365  double *x2,
366  double *x3,
367  double *x4
368 ) {
369  if(!splinedata) exit(1);
371 
372  (*splinedata)=XLALCalloc(1,sizeof(SplineData5d));
373 
374  // Set up B-spline basis for desired knots
375  const size_t nbreak_0 = nc[0]-2; // nbreak = ncoefs - 2 for cubic splines
376  const size_t nbreak_1 = nc[1]-2;
377  const size_t nbreak_2 = nc[2]-2;
378  const size_t nbreak_3 = nc[3]-2;
379  const size_t nbreak_4 = nc[4]-2;
380 
381  // Allocate a cubic bspline workspace (k = 4)
382  gsl_bspline_workspace *bw_x0 = gsl_bspline_alloc(4, nbreak_0);
383  gsl_bspline_workspace *bw_x1 = gsl_bspline_alloc(4, nbreak_1);
384  gsl_bspline_workspace *bw_x2 = gsl_bspline_alloc(4, nbreak_2);
385  gsl_bspline_workspace *bw_x3 = gsl_bspline_alloc(4, nbreak_3);
386  gsl_bspline_workspace *bw_x4 = gsl_bspline_alloc(4, nbreak_4);
387 
388  // Set breakpoints (and thus knots by hand)
389  gsl_vector *breakpts_0 = gsl_vector_alloc(nbreak_0);
390  gsl_vector *breakpts_1 = gsl_vector_alloc(nbreak_1);
391  gsl_vector *breakpts_2 = gsl_vector_alloc(nbreak_2);
392  gsl_vector *breakpts_3 = gsl_vector_alloc(nbreak_3);
393  gsl_vector *breakpts_4 = gsl_vector_alloc(nbreak_4);
394  for (UINT4 i=0; i<nbreak_0; i++)
395  gsl_vector_set(breakpts_0, i, x0[i]);
396  for (UINT4 i=0; i<nbreak_1; i++)
397  gsl_vector_set(breakpts_1, i, x1[i]);
398  for (UINT4 i=0; i<nbreak_2; i++)
399  gsl_vector_set(breakpts_2, i, x2[i]);
400  for (UINT4 i=0; i<nbreak_3; i++)
401  gsl_vector_set(breakpts_3, i, x3[i]);
402  for (UINT4 i=0; i<nbreak_4; i++)
403  gsl_vector_set(breakpts_4, i, x4[i]);
404 
405  // Calculate knots
406  gsl_bspline_knots(breakpts_0, bw_x0);
407  gsl_bspline_knots(breakpts_1, bw_x1);
408  gsl_bspline_knots(breakpts_2, bw_x2);
409  gsl_bspline_knots(breakpts_3, bw_x3);
410  gsl_bspline_knots(breakpts_4, bw_x4);
411 
412  gsl_vector_free(breakpts_0);
413  gsl_vector_free(breakpts_1);
414  gsl_vector_free(breakpts_2);
415  gsl_vector_free(breakpts_3);
416  gsl_vector_free(breakpts_4);
417 
418  (*splinedata)->bw_x0=bw_x0;
419  (*splinedata)->bw_x1=bw_x1;
420  (*splinedata)->bw_x2=bw_x2;
421  (*splinedata)->bw_x3=bw_x3;
422  (*splinedata)->bw_x4=bw_x4;
423 }
424 
426 {
427  if(!splinedata) return;
428  if(splinedata->bw_x0) gsl_bspline_free(splinedata->bw_x0);
429  if(splinedata->bw_x1) gsl_bspline_free(splinedata->bw_x1);
430  if(splinedata->bw_x2) gsl_bspline_free(splinedata->bw_x2);
431  if(splinedata->bw_x3) gsl_bspline_free(splinedata->bw_x3);
432  if(splinedata->bw_x4) gsl_bspline_free(splinedata->bw_x4);
433 
435 }
436 
437 // Interpolate empirical nodes over the parameter space.
438 // The multi-dimensional interpolation is carried out via a tensor product decomposition.
440  REAL8 x0, // Coordinates onto which we interpolate
441  REAL8 x1,
442  REAL8 x2,
443  REAL8 x3,
444  REAL8 x4,
445  int n_nodes, // Input: number of empirical nodes
446  int *nc, // Input: number of coefficients in each dimension
447  gsl_vector *cvec_re, // Input: flattened real spline coefficients
448  gsl_vector *cvec_im, // Input: flattened imag spline coefficients
449  SplineData5d *splinedata, // Input: Data associated with the tensor grid in parameter space
450  gsl_vector *nodes_re, // Output: interpolated real empirical nodes
451  gsl_vector *nodes_im // Output: interpolated imag empirical nodes
452 ) {
453 
454  // Store nonzero cubic (order k=4) B-spline basis functions in all directions.
455  gsl_vector *B0 = gsl_vector_calloc(4);
456  gsl_vector *B1 = gsl_vector_calloc(4);
457  gsl_vector *B2 = gsl_vector_calloc(4);
458  gsl_vector *B3 = gsl_vector_calloc(4);
459  gsl_vector *B4 = gsl_vector_calloc(4);
460 
461  size_t is0, is1, is2, is3, is4; // First non-zero basis spline
462  size_t ie0, ie1, ie2, ie3, ie4; // Last non-zero basis spline
463 
464  // Evaluate all potentially nonzero cubic B-spline basis functions and store them in the B vectors.
465  // Since the B-splines are of compact support we only need to store a small
466  // number of basis functions to avoid computing terms that would be zero anyway.
467  // https://www.gnu.org/software/gsl/manual/html_node/Overview-of-B_002dsplines.html#Overview-of-B_002dsplines
468  gsl_bspline_eval_nonzero(x0, B0, &is0, &ie0, splinedata->bw_x0);
469  gsl_bspline_eval_nonzero(x1, B1, &is1, &ie1, splinedata->bw_x1);
470  gsl_bspline_eval_nonzero(x2, B2, &is2, &ie2, splinedata->bw_x2);
471  gsl_bspline_eval_nonzero(x3, B3, &is3, &ie3, splinedata->bw_x3);
472  gsl_bspline_eval_nonzero(x4, B4, &is4, &ie4, splinedata->bw_x4);
473 
474  int N = nc[0]*nc[1]*nc[2]*nc[3]*nc[4]; // Size of the data matrix for one empirical node
475 
476  // Evaluate the TP spline for all empirical nodes
477  for (int k=0; k<n_nodes; k++) {
478  // Pick out the coefficient matrix corresponding to the k-th empirical node.
479  gsl_vector v_re = gsl_vector_subvector(cvec_re, k*N, N).vector;
480  gsl_vector v_im = gsl_vector_subvector(cvec_im, k*N, N).vector;
481 
482  REAL8 node_re = Interpolate_Coefficent_Tensor_5d(&v_re,
483  B0, B1, B2, B3, B4,
484  is0, is1, is2, is3, is4, nc);
485 
486  REAL8 node_im = Interpolate_Coefficent_Tensor_5d(&v_im,
487  B0, B1, B2, B3, B4,
488  is0, is1, is2, is3, is4, nc);
489  gsl_vector_set(nodes_re, k, node_re);
490  gsl_vector_set(nodes_im, k, node_im);
491  }
492 
493  gsl_vector_free(B0);
494  gsl_vector_free(B1);
495  gsl_vector_free(B2);
496  gsl_vector_free(B3);
497  gsl_vector_free(B4);
498 
499  return(0);
500 }
501 
502 /* Set up a new ROM submodel, using data contained in the NRSur4d2s.h5 h5 file */
504  NRSurrogateData_submodel **submodel,
505  LALH5File *file,
506  const int i_mode,
507  int n_nodes,
508  int n_freqs,
509  int *nc
510 ) {
511  int ret = XLAL_FAILURE;
512 
513  if(!submodel) exit(1);
514  /* Create storage for submodel structures */
515  if (!*submodel)
516  *submodel = XLALCalloc(1,sizeof(NRSurrogateData_submodel));
517  else
519 
520  int N = nc[0]*nc[1]*nc[2]*nc[3]*nc[4]; // Total number of spline coefficients for one empirical node
521 
522  // Initalize actual ROM data
523  (*submodel)->cvec_re = gsl_vector_calloc(N*n_nodes);
524  if ((*submodel)->cvec_re == NULL)
525  XLAL_ERROR(XLAL_ENOMEM, "gsl_vector_calloc(%d) failed", N*n_nodes);
526  (*submodel)->cvec_im = gsl_vector_calloc(N*n_nodes);
527  if ((*submodel)->cvec_im == NULL)
528  XLAL_ERROR(XLAL_ENOMEM, "gsl_vector_calloc(%d) failed", N*n_nodes);
529  (*submodel)->EI_re = gsl_matrix_calloc(n_nodes, n_freqs);
530  if ((*submodel)->EI_re == NULL)
531  XLAL_ERROR(XLAL_ENOMEM, "gsl_matrix_calloc(%d, %d) failed", n_nodes, n_freqs);
532  (*submodel)->EI_im = gsl_matrix_calloc(n_nodes, n_freqs);
533  if ((*submodel)->EI_im == NULL)
534  XLAL_ERROR(XLAL_ENOMEM, "gsl_matrix_calloc(%d, %d) failed", n_nodes, n_freqs);
535 
536  // Load ROM data for this submodel
537  printf("Loading mode %d...\n", i_mode);
538  ret=load_data_sub(i_mode, file, (*submodel)->cvec_re, (*submodel)->cvec_im, (*submodel)->EI_re, (*submodel)->EI_im);
539 
540  return ret;
541 }
542 
543 /* Deallocate contents of the given NRSurrogateData_submodel structure */
544 static void NRSurrogateData_Cleanup_submodel(NRSurrogateData_submodel *submodel) {
545  if(submodel->cvec_re) gsl_vector_free(submodel->cvec_re);
546  if(submodel->cvec_im) gsl_vector_free(submodel->cvec_im);
547  if(submodel->EI_re) gsl_matrix_free(submodel->EI_re);
548  if(submodel->EI_im) gsl_matrix_free(submodel->EI_im);
549 }
550 
551 /* Set up a new NRSurrogate model, using data contained in dir */
552 int NRSurrogateData_Init(NRSurrogateData *data, const char dir[]) {
553  int ret = XLAL_FAILURE;
554 
555  if(data->setup) {
556  XLALPrintError("WARNING: You tried to setup the NRSurrogate model that was already initialised. Ignoring\n");
557  return (XLAL_FAILURE);
558  }
559 
560  printf("Loading NRSur4d2s_FDROM data...\n");
561 
562  size_t size = strlen(dir) + strlen(NRSUR4D2S_DATAFILE) + 2;
563  char *filename = XLALMalloc(size);
564  snprintf(filename, size, "%s/%s", dir, NRSUR4D2S_DATAFILE);
565 
567  LALH5Dataset *dset;
568 
569  // Parse surrogate model parameters
570  int n_nodes, n_freqs, n_q, n_chi1, n_chi1theta, n_chi1phi, n_chi2;
571  INT8 tmp_param;
572  dset = XLALH5DatasetRead(file, "n_nodes");
573  ret = XLALH5DatasetQueryData(&tmp_param, dset);
574  n_nodes = (int) tmp_param;
575  data->n_nodes = n_nodes;
576  dset = XLALH5DatasetRead(file, "n_freqs");
577  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
578  n_freqs = (int) tmp_param;
579  data->n_freqs = n_freqs;
580  dset = XLALH5DatasetRead(file, "n_q");
581  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
582  n_q = (int) tmp_param;
583  dset = XLALH5DatasetRead(file, "n_chi1");
584  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
585  n_chi1 = (int) tmp_param;
586  dset = XLALH5DatasetRead(file, "n_chi1theta");
587  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
588  n_chi1theta = (int) tmp_param;
589  dset = XLALH5DatasetRead(file, "n_chi1phi");
590  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
591  n_chi1phi = (int) tmp_param;
592  dset = XLALH5DatasetRead(file, "n_chi2");
593  ret |= XLALH5DatasetQueryData(&tmp_param, dset);
594  n_chi2 = (int) tmp_param;
595 
596  data->nc = (int *) malloc(5*sizeof(double));
597  data->nc[0] = n_q+2;
598  data->nc[1] = n_chi1+2;
599  data->nc[2] = n_chi1theta+2;
600  data->nc[3] = n_chi1phi+2;
601  data->nc[4] = n_chi2+2;
602 
603  // Setup parameter vectors
604  int i;
605  double delta;
606 
607  // q
608  data->qvec = (double *)malloc(n_q*sizeof(double));
609  delta = (Q_MAX - Q_MIN)/(n_q - 1);
610  for(i=0; i<n_q; i++) data->qvec[i] = Q_MIN + i*delta;
611 
612  // chi1
613  data->chi1vec = (double *)malloc(n_chi1*sizeof(double));
614  delta = CHI1_MAG_MAX/(n_chi1 - 1);
615  for(i=0; i<n_chi1; i++) data->chi1vec[i] = i*delta;
616 
617  // chi1theta
618  data->chi1thetavec = (double *)malloc(n_chi1theta*sizeof(double));
619  delta = LAL_PI/(n_chi1theta - 1);
620  for(i=0; i<n_chi1theta; i++) data->chi1thetavec[i] = i*delta;
621 
622  // chi1phi
623  data->chi1phivec = (double *)malloc(n_chi1phi*sizeof(double));
624  delta = 2.0*LAL_PI/(n_chi1phi - 1);
625  for(i=0; i<n_chi1phi; i++) data->chi1phivec[i] = i*delta;
626 
627  // chi2
628  data->chi2vec = (double *)malloc(n_chi2*sizeof(double));
629  delta = (CHI2_MAX - CHI2_MIN)/(n_chi2 - 1);
630  for(i=0; i<n_chi2; i++) data->chi2vec[i] = CHI2_MIN + i*delta;
631 
632  // Setup modes
633  gsl_set_error_handler(&err_handler);
634 
636  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 0 loaded sucessfully.\n", __func__);
637 
639  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 1 loaded sucessfully.\n", __func__);
640 
642  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 2 loaded sucessfully.\n", __func__);
643 
645  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 3 loaded sucessfully.\n", __func__);
646 
648  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 4 loaded sucessfully.\n", __func__);
649 
651  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 5 loaded sucessfully.\n", __func__);
652 
654  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 6 loaded sucessfully.\n", __func__);
655 
657  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 7 loaded sucessfully.\n", __func__);
658 
660  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 8 loaded sucessfully.\n", __func__);
661 
663  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 9 loaded sucessfully.\n", __func__);
664 
666  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 10 loaded sucessfully.\n", __func__);
667 
669  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : Mode 11 loaded sucessfully.\n", __func__);
670 
671 
672  if (ret==XLAL_SUCCESS) printf("Successfully loaded all modes!\n");
673 
674  /* Load frequency samples */
675  data->fEI = gsl_vector_calloc(n_freqs);
676  ret |= ReadHDF5RealVectorDataset(file, "freqs", &(data->fEI));
677 
679 
680  /* setup splinedata */
681  SplineData5d *splinedata=NULL;
682  SplineData5d_Init(&splinedata, data->nc, data->qvec, data->chi1vec, data->chi1thetavec, data->chi1phivec, data->chi2vec);
683  data->splinedata = splinedata;
684 
685  if(XLAL_SUCCESS==ret)
686  data->setup=1;
687  else
689 
690  printf("Done setting up\n");
691  return (ret);
692 }
693 
694 /* Deallocate contents of the given NRSurrogate structure */
695 static void NRSurrogateData_Cleanup(NRSurrogateData *data) {
708  XLALFree((data)->mode_2m2);
709  XLALFree((data)->mode_2m1);
710  XLALFree((data)->mode_2p0);
711  XLALFree((data)->mode_2p1);
712  XLALFree((data)->mode_2p2);
713  XLALFree((data)->mode_3m3);
714  XLALFree((data)->mode_3m2);
715  XLALFree((data)->mode_3m1);
716  XLALFree((data)->mode_3p0);
717  XLALFree((data)->mode_3p1);
718  XLALFree((data)->mode_3p2);
719  XLALFree((data)->mode_3p3);
720  (data)->mode_2m2 = NULL;
721  (data)->mode_2m1 = NULL;
722  (data)->mode_2p0 = NULL;
723  (data)->mode_2p1 = NULL;
724  (data)->mode_2p2 = NULL;
725  (data)->mode_3p3 = NULL;
726  (data)->mode_3p2 = NULL;
727  (data)->mode_3p1 = NULL;
728  (data)->mode_3p0 = NULL;
729  (data)->mode_3m1 = NULL;
730  (data)->mode_3m2 = NULL;
731  (data)->mode_3m3 = NULL;
732  if(data->nc) free(data->nc);
733  if(data->fEI) gsl_vector_free(data->fEI);
734  if(data->qvec) free(data->qvec);
735  if(data->chi1vec) free(data->chi1vec);
736  if(data->chi1thetavec) free(data->chi1thetavec);
737  if(data->chi1phivec) free(data->chi1thetavec);
738  if(data->chi2vec) free(data->chi2vec);
739  if(data->splinedata) SplineData5d_Destroy(data->splinedata);
740  data->setup=0;
741 }
742 
743 //Add one spherical harmonic mode to the waveform h, weighted by the SWSH coefficient
745  double q, // Parameters at which we evaluate the surrogate mode
746  double chi1mag,
747  double chi1theta,
748  double chi1phi,
749  double chi2z,
750  double spheretheta, // The polar angle of the direction of GW propagation from the source
751  double spherephi, // The azimuthal angle of the direction of GW propagation from the source
752  int swsh_L, // The mode L
753  int swsh_m, // The mode m
754  int n_nodes, // Input: the number of empirical nodes
755  int *nc, // Input: the number of spline coefs per dimension
756  gsl_vector *h_re, // Gets modified - the real part of the waveform
757  gsl_vector *h_im, // Gets modified - the imag part of the waveform
758  NRSurrogateData_submodel *modeData, // The surrogate data for this mode
759  SplineData5d *splinedata, // Data associated with the tensor product grid in param space
760  gsl_vector *nodes_re, // Intermediate result - the real part of the empirical nodes for this mode
761  gsl_vector *nodes_im, // Intermediate result - the imag part of the empirical nodes for this mode
762  gsl_vector *mode_re, // Intermediate result - the real part of the evaluated mode
763  gsl_vector *mode_im // Intermediate result - the imag part of the evaluated mode
764 ){
765  //Interpolate nodes
766  TP_Spline_interpolation_5d(q, chi1mag, chi1theta, chi1phi, chi2z, n_nodes, nc, modeData->cvec_re, modeData->cvec_im,
767  splinedata, nodes_re, nodes_im);
768 
769  // Evaluate empirical interpolant
770  gsl_blas_dgemv(CblasTrans, 1.0, modeData->EI_re, nodes_re, 0., mode_re); // mode_re = EI_re*nodes_re
771  gsl_blas_dgemv(CblasTrans, -1., modeData->EI_im, nodes_im, 1., mode_re); // mode_re -= EI_im*nodes_im
772  gsl_blas_dgemv(CblasTrans, 1.0, modeData->EI_im, nodes_re, 0., mode_im); // mode_im = EI_im*nodes_re
773  gsl_blas_dgemv(CblasTrans, 1.0, modeData->EI_re, nodes_im, 1., mode_im); // mode_im += EI_re*nodes_im
774 
775  // Add (spin-weighted spherical harmonic coefficient)*mode to h
776  COMPLEX16 swsh_coef = XLALSpinWeightedSphericalHarmonic(spheretheta, spherephi, -2, swsh_L, swsh_m);
777  double c_re = creal(swsh_coef);
778  double c_im = cimag(swsh_coef);
779  gsl_blas_daxpy(c_re, mode_re, h_re); // h_re += c_re*mode_re
780  gsl_blas_daxpy(-1*c_im, mode_im, h_re); // h_re += -c_im*mode_im
781  gsl_blas_daxpy(c_re, mode_im, h_im); // h_im += c_re*mode_im
782  gsl_blas_daxpy(c_im, mode_re, h_im); // h_im += c_im*mode_re
783 }
784 
785 static int NRSurrogateCore(
786  COMPLEX16FrequencySeries **hptilde,
787  COMPLEX16FrequencySeries **hctilde,
788  double phiRef,
789  double distance,
790  double inclination,
791  double Mtot_sec,
792  double q,
793  double chi1mag,
794  double chi1theta,
795  double chi1phi,
796  double chi2z,
797  const REAL8Sequence *freqs /* Dimensionless frequency points at which to evaluate the waveform */
798 )
799 {
800  // Initialize waveform at empirical interpolant output frequencies (contains negative and positive frequency content)
802  gsl_vector *h_full_re = gsl_vector_calloc(n_freqs);
803  gsl_vector *h_full_im = gsl_vector_calloc(n_freqs);
804 
805  // Allocate memory for intermediate results
807  gsl_vector *nodes_re = gsl_vector_calloc(n_nodes);
808  gsl_vector *nodes_im = gsl_vector_calloc(n_nodes);
809  gsl_vector *mode_re = gsl_vector_calloc(n_freqs);
810  gsl_vector *mode_im = gsl_vector_calloc(n_freqs);
811 
812  // Add up all modes
813  int *nc = (&__lalsim_NRSurrogate_data)->nc;
814  double phi_sphere = 0.5*LAL_PI - phiRef;
815  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 2, -2, n_nodes, nc, h_full_re, h_full_im,
817  nodes_re, nodes_im, mode_re, mode_im);
818  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 2, -1, n_nodes, nc, h_full_re, h_full_im,
820  nodes_re, nodes_im, mode_re, mode_im);
821  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 2, 0, n_nodes, nc, h_full_re, h_full_im,
823  nodes_re, nodes_im, mode_re, mode_im);
824  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 2, 1, n_nodes, nc, h_full_re, h_full_im,
826  nodes_re, nodes_im, mode_re, mode_im);
827  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 2, 2, n_nodes, nc, h_full_re, h_full_im,
829  nodes_re, nodes_im, mode_re, mode_im);
830  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, -3, n_nodes, nc, h_full_re, h_full_im,
832  nodes_re, nodes_im, mode_re, mode_im);
833  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, -2, n_nodes, nc, h_full_re, h_full_im,
835  nodes_re, nodes_im, mode_re, mode_im);
836  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, -1, n_nodes, nc, h_full_re, h_full_im,
838  nodes_re, nodes_im, mode_re, mode_im);
839  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, 0, n_nodes, nc, h_full_re, h_full_im,
841  nodes_re, nodes_im, mode_re, mode_im);
842  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, 1, n_nodes, nc, h_full_re, h_full_im,
844  nodes_re, nodes_im, mode_re, mode_im);
845  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, 2, n_nodes, nc, h_full_re, h_full_im,
847  nodes_re, nodes_im, mode_re, mode_im);
848  AddModeContribution(q, chi1mag, chi1theta, chi1phi, chi2z, inclination, phi_sphere, 3, 3, n_nodes, nc, h_full_re, h_full_im,
850  nodes_re, nodes_im, mode_re, mode_im);
851 
852  gsl_vector_free(mode_re);
853  gsl_vector_free(mode_im);
854  gsl_vector_free(nodes_re);
855  gsl_vector_free(nodes_im);
856 
857  // We need h(f) for f > 0 and h(-f) for f < 0
858  int n = n_freqs/2;
859  int i0 = n_freqs - n_freqs/2;
860  gsl_vector h_negf_re = gsl_vector_subvector(h_full_re, 0, n).vector;
861  gsl_vector h_negf_im = gsl_vector_subvector(h_full_im, 0, n).vector;
862  gsl_vector h_posf_re = gsl_vector_subvector(h_full_re, i0, n).vector;
863  gsl_vector h_posf_im = gsl_vector_subvector(h_full_im, i0, n).vector;
864  gsl_vector_reverse(&h_negf_re);
865  gsl_vector_reverse(&h_negf_im);
866 
867  // TODO: There's probably a more memory efficient way to do do the previous step and this
868  // hp = 0.5*(h(f) + h(-f)*)
869  // hc = i*0.5*(h(f) - h(-f)*)
870  gsl_vector *hp_re = gsl_vector_alloc(n);
871  gsl_vector *hp_im = gsl_vector_alloc(n);
872  gsl_vector *hc_re = gsl_vector_alloc(n);
873  gsl_vector *hc_im = gsl_vector_alloc(n);
874 
875  gsl_vector_memcpy(hp_re, &h_posf_re); //hp_re = h_posf_re
876  gsl_blas_daxpy(1.0, &h_negf_re, hp_re); //hp_re = h_posf_re + h_negf_re
877  gsl_blas_dscal(0.5, hp_re); //hp_re = 0.5*(h_posf_re + h_negf_re)
878 
879  gsl_vector_memcpy(hp_im, &h_posf_im);
880  gsl_blas_daxpy(-1.0, &h_negf_im, hp_im);
881  gsl_blas_dscal(0.5, hp_im); //hp_im = 0.5*(h_posf_im - h_negf_im)
882 
883  gsl_vector_memcpy(hc_im, &h_posf_re);
884  gsl_blas_daxpy(-1.0, &h_negf_re, hc_im);
885  gsl_blas_dscal(0.5, hc_im); //hc_im = 0.5*(h_posf_re - h_negf_re)
886 
887  gsl_vector_memcpy(hc_re, &h_posf_im);
888  gsl_blas_daxpy(1.0, &h_negf_im, hc_re);
889  gsl_blas_dscal(-0.5, hc_re); //hp_re = -0.5*(h_posf_im + h_negf_im)
890 
891  // Setup interpolation of hp, hc onto hptilde, hctilde at freqs
892  gsl_vector fEI = gsl_vector_subvector((&__lalsim_NRSurrogate_data)->fEI, i0, n).vector;
893  const double *model_freqs = gsl_vector_const_ptr(&fEI, 0);
894  gsl_interp_accel *acc = gsl_interp_accel_alloc(); //All interpolations use the same grid -> use a single accelerator
895  gsl_spline *spl_hp_re = gsl_spline_alloc(gsl_interp_cspline, n);
896  gsl_spline *spl_hp_im = gsl_spline_alloc(gsl_interp_cspline, n);
897  gsl_spline *spl_hc_re = gsl_spline_alloc(gsl_interp_cspline, n);
898  gsl_spline *spl_hc_im = gsl_spline_alloc(gsl_interp_cspline, n);
899  gsl_spline_init(spl_hp_re, model_freqs, gsl_vector_const_ptr(hp_re, 0), n);
900  gsl_spline_init(spl_hp_im, model_freqs, gsl_vector_const_ptr(hp_im, 0), n);
901  gsl_spline_init(spl_hc_re, model_freqs, gsl_vector_const_ptr(hc_re, 0), n);
902  gsl_spline_init(spl_hc_im, model_freqs, gsl_vector_const_ptr(hc_im, 0), n);
903 
904  // Interpolate and dimensionalize the waveform
905  double a0 = Mtot_sec * Mtot_sec * LAL_C_SI / distance;
906  LIGOTimeGPS tC = {0, 0};
907  size_t npts = freqs->length;
908  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0, 1.0, &lalStrainUnit, npts);
909  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0, 1.0, &lalStrainUnit, npts);
910  memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
911  memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));
912  double f_min = model_freqs[0];
913  double f_max = model_freqs[n-1];
914 
915  for (UINT4 i=0; i < npts; i++) {
916  double f = freqs->data[i];
917  if (f > f_max || f < f_min) continue;
918  (*hptilde)->data->data[i] = a0*(gsl_spline_eval(spl_hp_re, f, acc) + I*gsl_spline_eval(spl_hp_im, f, acc));
919  (*hctilde)->data->data[i] = a0*(gsl_spline_eval(spl_hc_re, f, acc) + I*gsl_spline_eval(spl_hc_im, f, acc));
920  }
921 
922 
923  // Keep these around for the vector views until we don't need h_negf_re etc.
924  gsl_vector_free(h_full_re);
925  gsl_vector_free(h_full_im);
926 
927  gsl_vector_free(hp_re);
928  gsl_vector_free(hp_im);
929  gsl_vector_free(hc_re);
930  gsl_vector_free(hc_im);
931  gsl_spline_free(spl_hp_re);
932  gsl_spline_free(spl_hp_im);
933  gsl_spline_free(spl_hc_re);
934  gsl_spline_free(spl_hc_im);
935  gsl_interp_accel_free(acc);
936 
937  return XLAL_SUCCESS;
938 }
939 
941  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
942  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
943  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz), need to be strictly monotonically increasing */
944  REAL8 phiRef, /**< Orbital phase at reference frequency*/
945  REAL8 distance, /**< Distance of source (m) */
946  REAL8 inclination, /**< Inclination of source (rad) */
947  REAL8 m1SI, /**< Mass of companion 1 (kg) */
948  REAL8 m2SI, /**< Mass of companion 2 (kg) */
949  REAL8 S1x, /**< x-component of the dimensionless spin of companion 1 */
950  REAL8 S1y, /**< y-component of the dimensionless spin of companion 1 */
951  REAL8 S1z, /**< z-component of the dimensionless spin of companion 1 */
952  REAL8 S2x, /**< x-component of the dimensionless spin of companion 2 */
953  REAL8 S2y, /**< y-component of the dimensionless spin of companion 2 */
954  REAL8 S2z /**< z-component of the dimensionless spin of companion 2 */
955 ) {
956  /* Internally we need m1 > m2, so change around if this is not the case */
957  if (m1SI < m2SI) {
958  // Swap m1 and m2
959  double tmp = m1SI;
960  m1SI = m2SI;
961  m2SI = tmp;
962  tmp = S1x;
963  S1x = S2x;
964  S2x = tmp;
965  tmp = S1y;
966  S1y = S2y;
967  S2y = tmp;
968  tmp = S1z;
969  S1z = S2z;
970  S2z = tmp;
971  phiRef += LAL_PI;
972  }
973 
974  /* Get masses in terms of solar mass */
975  double mass1 = m1SI / LAL_MSUN_SI;
976  double mass2 = m2SI / LAL_MSUN_SI;
977  double Mtot = mass1+mass2;
978  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
979  double q = mass1/mass2; /* mass ratio (>= 1)*/
980  if (!freqs) XLAL_ERROR(XLAL_EFAULT);
981 
982  // Get model parameter spins
983  double chi1mag = sqrt(S1x*S1x + S1y*S1y + S1z*S1z);
984  double chi1theta = 0;
985  double chi1phi = 0;
986  if (chi1mag > 0.) chi1theta = acos(S1z/chi1mag);
987  if (fabs(S1y) + fabs(S1x) > 0.) chi1phi = atan2(S1y*cos(phiRef) - S1x*sin(phiRef), S1x*cos(phiRef) + S1y*sin(phiRef));
988  if (chi1phi < 0.) chi1phi += 2*LAL_PI;
989  double chi2z = S2z;
990 
991  // Load ROM data if not loaded already
992 #ifdef LAL_PTHREAD_LOCK
993  (void) pthread_once(&NRSur4d2s_is_initialized, NRSurrogate_Init_LALDATA);
994 #else
996 #endif
997 
998  if(!NRSurrogate_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up NRSur4d2s data - check your $LAL_DATA_PATH\n");
999 
1000  int retcode = NRSurrogateCore(hptilde, hctilde,
1001  phiRef, distance, inclination, Mtot_sec, q, chi1mag, chi1theta, chi1phi, chi2z, freqs);
1002 
1003  return(retcode);
1004 }
1005 
1006 
1007 
1008 /**
1009  * Compute waveform in LAL format for the NRSur4d2s_FDROM NR surrogate model.
1010  *
1011  * Described in:
1012  * https://journals.aps.org/prd/abstract/10.1103/PhysRevD.95.104023
1013  * https://arxiv.org/abs/1701.00550
1014  *
1015  * Returns the plus and cross polarizations as a complex frequency series with
1016  * equal spacing deltaF and contains zeros from zero frequency to the starting
1017  * frequency fLow and zeros beyond the cutoff frequency fHigh to the next power of 2 in
1018  * the size of the frequency series.
1019  */
1021  struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
1022  struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
1023  REAL8 phiRef, /**< Orbital phase at 4500M before peak amplitude.
1024  Note that usually this is TWICE the orb phase.*/
1025  REAL8 deltaF, /**< Sampling frequency (Hz) */
1026  REAL8 fLow, /**< Starting GW frequency (Hz) */
1027  REAL8 fHigh, /**< End frequency */
1028  REAL8 distance, /**< Distance of source (m) */
1029  REAL8 inclination, /**< Inclination of source (rad) */
1030  REAL8 m1SI, /**< Mass of companion 1 (kg) */
1031  REAL8 m2SI, /**< Mass of companion 2 (kg) */
1032  REAL8 S1x, /**< Spins are in the source frame, which is different from the alignment frame.
1033  See http://software.ligo.org/docs/lalsuite/lalsimulation/group__lalsimulation__inspiral.html
1034  In the alignment frame, the larger BH is on the positive x-axis. x-component of chi_1 */
1035  REAL8 S1y, /**< y-component of the dimensionless spin of companion 1 */
1036  REAL8 S1z, /**< z-component of the dimensionless spin of companion 1 */
1037  REAL8 S2x, /**< x-component of the dimensionless spin of companion 2 */
1038  REAL8 S2y, /**< y-component of the dimensionless spin of companion 2 */
1039  REAL8 S2z /**< z-component of the dimensionless spin of companion 2 */
1040 ) {
1041  /* Internally we need m1 > m2, so change around if this is not the case */
1042  if (m1SI < m2SI) {
1043  // Swap m1 and m2.
1044  double tmp = m1SI;
1045  m1SI = m2SI;
1046  m2SI = tmp;
1047  tmp = S1x;
1048  S1x = S2x;
1049  S2x = tmp;
1050  tmp = S1y;
1051  S1y = S2y;
1052  S2y = tmp;
1053  tmp = S1z;
1054  S1z = S2z;
1055  S2z = tmp;
1056  phiRef += LAL_PI;
1057  }
1058 
1059  /* Get mass ratio and dimensionful-constant */
1060  double mass1 = m1SI / LAL_MSUN_SI;
1061  double mass2 = m2SI / LAL_MSUN_SI;
1062  double Mtot = mass1+mass2;
1063  double Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
1064  double q = mass1/mass2; /* mass ratio (>= 1)*/
1065 
1066  // Get model parameter spins.
1067  double chi1mag = sqrt(S1x*S1x + S1y*S1y + S1z*S1z);
1068  double chi1theta = 0;
1069  double chi1phi = 0;
1070  if (chi1mag > 0.) chi1theta = acos(S1z/chi1mag);
1071  if (fabs(S1y) + fabs(S1x) > 0.) chi1phi = atan2(S1y*cos(phiRef) - S1x*sin(phiRef), S1x*cos(phiRef) + S1y*sin(phiRef));
1072  if (chi1phi < 0.) chi1phi += 2*LAL_PI;
1073  double chi2z = S2z;
1074  if (fabs(S2y) + fabs(S2x) > 0.) XLAL_ERROR(XLAL_FAILURE, "NRsurrogate does not support x or y spin components on the smaller BH\n");
1075 
1076  // Load data if not loaded already
1077 #ifdef LAL_PTHREAD_LOCK
1078  (void) pthread_once(&NRSur4d2s_is_initialized, NRSurrogate_Init_LALDATA);
1079 #else
1081 #endif
1082 
1083  if(!NRSurrogate_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up NRSurrogate data - check your $LAL_DATA_PATH\n");
1084 
1085  // Compute dimensionless frequency sequence
1086 
1087  if (fHigh == 0.) {
1088  // lal convention: secret flag to use max model frequency
1089  fHigh = gsl_vector_get((&__lalsim_NRSurrogate_data)->fEI, (&__lalsim_NRSurrogate_data)->n_freqs - 1)/Mtot_sec;
1090  }
1091 
1092  UINT4 nf = (UINT4) ceil(fHigh / deltaF);
1093  UINT4 i0 = (UINT4) ceil(fLow / deltaF);
1095  double deltaF_dimless = deltaF*Mtot_sec;
1096  UINT4 i;
1097  for (i=0; i<i0; i++) {
1098  // Ensure the waveform is zero below fLow
1099  freqs->data[i] = 0.0;
1100  }
1101  for (i=i0; i<nf; i++) {
1102  freqs->data[i] = i*deltaF_dimless;
1103  }
1104  int retcode = NRSurrogateCore(hptilde,hctilde,
1105  phiRef, distance, inclination, Mtot_sec, q, chi1mag, chi1theta, chi1phi, chi2z, freqs);
1106 
1107  XLALDestroyREAL8Sequence(freqs);
1108 
1109  return(retcode);
1110 }
1111 
1112 
1113 static void NRSurrogate_Init_LALDATA(void)
1114 {
1115  if (NRSurrogate_IsSetup()) return;
1116 
1118 
1119  if (path==NULL)
1120  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", NRSUR4D2S_DATAFILE);
1121  char *dir = dirname(path);
1122  int ret = NRSurrogate_Init(dir);
1123  XLALFree(path);
1124 
1125  if(ret!=XLAL_SUCCESS)
1126  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find NRSurrogateData data files in $LAL_DATA_PATH\n");
1127 }
struct tagLALH5File LALH5File
struct tagLALH5Dataset LALH5Dataset
static void AddModeContribution(double q, double chi1mag, double chi1theta, double chi1phi, double chi2z, double spheretheta, double spherephi, int swsh_L, int swsh_m, int n_nodes, int *nc, gsl_vector *h_re, gsl_vector *h_im, NRSurrogateData_submodel *modeData, SplineData5d *splinedata, gsl_vector *nodes_re, gsl_vector *nodes_im, gsl_vector *mode_re, gsl_vector *mode_im)
Evaluates one mode of the surrogate model and adds it to the waveform Real and imaginary parts used d...
static int NRSurrogateData_Init(NRSurrogateData *data, const char dir[])
static bool NRSurrogate_IsSetup(void)
Helper function to check if the NRSurrogate model has been initialised.
static NRSurrogateData __lalsim_NRSurrogate_data
static int NRSurrogateCore(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, double phiRef, double distance, double inclination, double Mtot_sec, double q, double chi1mag, double chi1theta, double chi1phi, double chi2z, const REAL8Sequence *freqs)
Core function for computing the ROM waveform.
int XLALSimNRSur4d2sFrequencySequence(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, REAL8 phiRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z)
static void err_handler(const char *reason, const char *file, int line, int gsl_errno)
static int TP_Spline_interpolation_5d(REAL8 x0, REAL8 x1, REAL8 x2, REAL8 x3, REAL8 x4, int n_nodes, int *nc, gsl_vector *cvec_re, gsl_vector *cvec_im, SplineData5d *splinedata, gsl_vector *nodes_re, gsl_vector *nodes_im)
static void NRSurrogateData_Cleanup(NRSurrogateData *data)
static const double CHI1_MAG_MAX
static void SplineData5d_Destroy(SplineData5d *splinedata)
static const double CHI2_MAX
static int NRSurrogateData_Init_submodel(NRSurrogateData_submodel **submodel, LALH5File *file, const int i_mode, int n_nodes, int n_freqs, int *nc)
static int NRSurrogate_Init(const char dir[])
Setup NRSurrogate model using data files installed in dir.
static REAL8 Interpolate_Coefficent_Tensor_5d(gsl_vector *v, gsl_vector *B0, gsl_vector *B1, gsl_vector *B2, gsl_vector *B3, gsl_vector *B4, size_t is0, size_t is1, size_t is2, size_t is3, size_t is4, int *nc)
static const double Q_MIN
static void NRSurrogate_Init_LALDATA(void)
int XLALSimNRSur4d2s(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z)
Compute waveform in LAL format for the NRSur4d2s_FDROM NR surrogate model.
static void NRSurrogateData_Cleanup_submodel(NRSurrogateData_submodel *submodel)
static const double Q_MAX
static const double CHI2_MIN
static int load_data_sub(const int i_mode, LALH5File *file, gsl_vector *cvec_re, gsl_vector *cvec_im, gsl_matrix *EI_re, gsl_matrix *EI_im)
static const char NRSUR4D2S_DATAFILE[]
static void SplineData5d_Init(SplineData5d **splinedata, int *nc, double *x1, double *x2, double *x3, double *x4, double *x5)
static double double delta
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
#define c
static REAL8 sum(REAL8 *arr1, REAL8 *arr2, int k)
double i
Definition: bh_ringdown.c:118
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 * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
LALH5Dataset * XLALH5DatasetRead(LALH5File UNUSED *file, const char UNUSED *name)
int XLALH5DatasetQueryData(void UNUSED *data, LALH5Dataset UNUSED *dset)
#define LAL_C_SI
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
double complex COMPLEX16
double REAL8
int64_t INT8
uint32_t UINT4
void * XLALCalloc(size_t m, size_t n)
void * XLALMalloc(size_t n)
void XLALFree(void *p)
static const INT4 q
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
COMPLEX16 XLALSpinWeightedSphericalHarmonic(REAL8 theta, REAL8 phi, int s, int l, int m)
const LALUnit lalStrainUnit
#define XLAL_ERROR_VOID(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EIO
XLAL_EFAILED
XLAL_FAILURE
path
filename
int N
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
REAL8 * data
gsl_bspline_workspace * bw_x4
gsl_bspline_workspace * bw_x0
gsl_bspline_workspace * bw_x3
gsl_bspline_workspace * bw_x2
gsl_bspline_workspace * bw_x1
NRSurrogateData_submodel * mode_2m2
NRSurrogateData_submodel * mode_3m1
NRSurrogateData_submodel * mode_3p1
NRSurrogateData_submodel * mode_3p0
NRSurrogateData_submodel * mode_3p2
NRSurrogateData_submodel * mode_3p3
NRSurrogateData_submodel * mode_3m2
NRSurrogateData_submodel * mode_2p1
NRSurrogateData_submodel * mode_3m3
NRSurrogateData_submodel * mode_2p0
NRSurrogateData_submodel * mode_2m1
NRSurrogateData_submodel * mode_2p2
SplineData5d * splinedata
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23