LALSimulation  5.4.0.1-fe68b98
LALSimInspiralTEOBResumROM.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Jeroen Meidam, Benjamin Lackey.
3  * Reduced Order Model for a nonspinning Tidal EOB model with l=2,3,4
4  * tidal interactions (arXiv:1610.04742). Based on SEOBNRv2ROM code.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21 
22 #ifdef __GNUC__
23 #define UNUSED __attribute__ ((unused))
24 #else
25 #define UNUSED
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <complex.h>
32 #include <time.h>
33 #include <stdbool.h>
34 #include <alloca.h>
35 #include <string.h>
36 #include <libgen.h>
37 
38 
39 #include <gsl/gsl_errno.h>
40 #include <gsl/gsl_chebyshev.h>
41 
42 #include <lal/Units.h>
43 #include <lal/SeqFactories.h>
44 #include <lal/LALConstants.h>
45 #include <lal/XLALError.h>
46 #include <lal/FrequencySeries.h>
47 #include <lal/Date.h>
48 #include <lal/StringInput.h>
49 #include <lal/Sequence.h>
50 #include <lal/LALStdio.h>
51 #include <lal/FileIO.h>
52 
53 #include <lal/LALSimInspiral.h>
54 #include <lal/LALSimIMR.h>
55 
56 #include <gsl/gsl_bspline.h>
57 #include <gsl/gsl_spline.h>
58 //needed for read_vector and nudge
60 
61 #include <lal/LALConfig.h>
62 #ifdef LAL_PTHREAD_LOCK
63 #include <pthread.h>
64 #endif
65 
66 
67 /************** Model parameters **************/
68 
69 //Prepending G to make clear it is a global variable
70 #define Gntimes 73624 //
71 #define Gnamp 12
72 #define Gnphase 7
73 #define Gnq 16
74 #define Gnlambda1 16
75 #define Gnlambda2 16
76 
77 #ifdef LAL_PTHREAD_LOCK
78 static pthread_once_t TEOBResumROM_is_initialized = PTHREAD_ONCE_INIT;
79 #endif
80 
81 static const double Gparams_min[] = {0.5,50.,50.}; //qmin,lambda1min,lambda2min
82 static const double Gparams_max[] = {1.0,5000.,5000.}; //qmax,lambda1max,lambda2max
83 
84 /*************** type definitions ******************/
85 
86 typedef struct tagTEOBResumROMdataDS_coeff
87 {
88  gsl_vector* c_amp;
89  gsl_vector* c_phi;
91 
93 {
94  gsl_vector* cvec_amp; // amplitude projection coefficients
95  gsl_vector* cvec_phi; // phase projection coefficients
96  gsl_matrix *Bamp; // Reduced SVD basis for amplitude
97  gsl_matrix *Bphi; // Reduced SVD basis for phase
98  gsl_vector* times; // AMplitude prefactor coefficient
99  const double *params_min;
100  const double *params_max;
101  int n_amp; // Number frequency points for amplitude
102  int n_phi; // Number of frequency points for phase
103  int nq, nl1, nl2, ntimes; // Number of points in eta, chi1, chi2
104 };
105 typedef struct tagTEOBResumROMdataDS_submodel TEOBResumROMdataDS_submodel;
106 
108 {
110  TEOBResumROMdataDS_submodel* sub1;
111  TEOBResumROMdataDS_submodel* sub2;
112  TEOBResumROMdataDS_submodel* sub3;
113 };
114 typedef struct tagTEOBResumROMdataDS TEOBResumROMdataDS;
115 
116 static TEOBResumROMdataDS __lalsim_TEOBResumROMDS_data;
117 
118 typedef int (*load_dataPtr)(const char*, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *);
119 
120 /**************** Internal functions **********************/
121 
122 static void TEOBResumROM_Init_LALDATA(void);
123 static int TEOBResumROM_Init(const char dir[]);
124 static bool TEOBResumROM_IsSetup(void);
125 
126 static int TEOBResumROMdataDS_Init(TEOBResumROMdataDS *romdata, const char dir[]);
127 static void TEOBResumROMdataDS_Cleanup(TEOBResumROMdataDS *romdata);
128 
130  TEOBResumROMdataDS_submodel **submodel,
131  const int n_amp,
132  const int n_phi,
133  const int nq,
134  const int nl1,
135  const int nl2,
136  const int ntimes,
137  const double *params_min,
138  const double *params_max,
139  const char dir[],
141 );
142 
143 
144 static double gsl_cheb_evaluate_polynomial(int n, double x);
145 static double gsl_cheb_eval_3d(gsl_vector *c_ijk, int nx, int ny, int nz, double x, double y, double z);
146 // static double chebev_3d(gsl_vector *c_ijk, int nx, int ny, int nz, double x, double y, double z, const double xyz_min[], const double xyz_max[]);
147 static int chebyshev_interpolation3d(
148  double q,
149  double lambda1,
150  double lambda2,
151  int nx, int ny, int nz,
152  gsl_vector *cvec_amp,
153  gsl_vector *cvec_phi,
154  int nk_amp,
155  int nk_phi,
156  const double xyz_min[],
157  const double xyz_max[],
158  gsl_vector *interp_amp,
159  gsl_vector *interp_phi);
160 
161 static void TEOBResumROMdataDS_Cleanup_submodel(TEOBResumROMdataDS_submodel *submodel);
162 
163 static int TEOBResumROMCore(
164  REAL8TimeSeries **hPlus,
165  REAL8TimeSeries **hCross,
166  double phiRef,
167  double deltaT,
168  double fLow,
169  double distance,
170  double inclination,
171  double Mtot_sec,
172  double eta,
173  double lambda1,
174  double lambda2
175 );
176 
177 static int load_data_romeos(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *times);
178 
179 /********************* Definitions begin here ********************/
180 
181 /** Setup SEOBNRv2ROMDoubleSpin model using data files installed in dir
182  */
183 static int TEOBResumROM_Init(const char dir[]) {
184  if(__lalsim_TEOBResumROMDS_data.setup) {
185  XLALPrintError("Error: DSTEOBResumROMdata was already set up!");
187  }
188 
190 
191  if(__lalsim_TEOBResumROMDS_data.setup) {
192  return(XLAL_SUCCESS);
193  }
194  else {
195  return(XLAL_EFAILED);
196  }
197 }
198 
199 /** Helper function to check if the SEOBNRv2ROMDoubleSpin model has been initialised
200 */
201 static bool TEOBResumROM_IsSetup(void) {
203  return true;
204  else
205  return false;
206 }
207 
208 // Read binary ROM data for basis functions and coefficients for submodel 1
209 static int load_data_romeos(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *times) {
210  int ret = XLAL_SUCCESS;
211  ret |= read_vector(dir, "TEOBResumROM_Amp_ciall.dat", cvec_amp);
212  ret |= read_vector(dir, "TEOBResumROM_Phase_ciall.dat", cvec_phi);
213  ret |= read_matrix(dir, "TEOBResumROM_Bamp_matrix.dat", Bamp);
214  ret |= read_matrix(dir, "TEOBResumROM_Bphase_matrix.dat", Bphi);
215  ret |= read_vector(dir, "TEOBResumROM_times.dat", times);
216  return(ret);
217 }
218 
219 /* Set up a new ROM submodel, using data contained in dir */
221  TEOBResumROMdataDS_submodel **submodel,
222  const int n_amp,
223  const int n_phi,
224  const int nq,
225  const int nl1,
226  const int nl2,
227  const int ntimes,
228  const double *params_min,
229  const double *params_max,
230  const char dir[],
232 ) {
233  int ret = XLAL_FAILURE;
234 
235  if(!submodel) exit(1);
236  /* Create storage for submodel structures */
237  if (!*submodel)
238  *submodel = XLALCalloc(1,sizeof(TEOBResumROMdataDS_submodel));
239  else
241 
242  int N = nq*nl1*nl2;
243 
244  // Initalize actual ROM data
245  (*submodel)->cvec_amp = gsl_vector_alloc(N*n_amp);
246  (*submodel)->cvec_phi = gsl_vector_alloc(N*n_phi);
247  (*submodel)->Bamp = gsl_matrix_alloc(n_amp, ntimes);
248  (*submodel)->Bphi = gsl_matrix_alloc(n_phi, ntimes);
249  (*submodel)->times = gsl_vector_alloc(ntimes);
250 
251  // Load ROM data for this submodel
252  ret=load_data(dir, (*submodel)->cvec_amp, (*submodel)->cvec_phi, (*submodel)->Bamp, (*submodel)->Bphi, (*submodel)->times);
253 
254  // Initialize other members
255  (*submodel)->n_amp = n_amp;
256  (*submodel)->n_phi = n_phi;
257  (*submodel)->nq = nq;
258  (*submodel)->nl1 = nl1;
259  (*submodel)->nl2 = nl2;
260  (*submodel)->ntimes = ntimes;
261 
262  (*submodel)->params_min = params_min;
263  (*submodel)->params_max = params_max;
264 
265  return ret;
266 }
267 
268 /* Deallocate contents of the given TEOBResumROMdataDS_submodel structure */
269 static void TEOBResumROMdataDS_Cleanup_submodel(TEOBResumROMdataDS_submodel *submodel) {
270  if(submodel->cvec_amp) gsl_vector_free(submodel->cvec_amp);
271  if(submodel->cvec_phi) gsl_vector_free(submodel->cvec_phi);
272  if(submodel->Bamp) gsl_matrix_free(submodel->Bamp);
273  if(submodel->Bphi) gsl_matrix_free(submodel->Bphi);
274  if(submodel->times) gsl_vector_free(submodel->times);
275 }
276 
277 /* Set up a new ROM model, using data contained in dir */
278 int TEOBResumROMdataDS_Init(TEOBResumROMdataDS *romdata, const char dir[]) {
279  int ret = XLAL_FAILURE;
280 
281  /* Create storage for structures */
282  if(romdata->setup) {
283  XLALPrintError("WARNING: You tried to setup the TEOBResumROM model that was already initialised. Ignoring\n");
284  return (XLAL_FAILURE);
285  }
286 
287  //gsl_set_error_handler(&err_handler);
288 
291  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel 1 loaded sucessfully.\n", __func__);
292 
293  if(XLAL_SUCCESS==ret)
294  romdata->setup=1;
295  else
297 
298  return (ret);
299 }
300 
301 /* Deallocate contents of the given TEOBResumROMdataDS structure */
302 static void TEOBResumROMdataDS_Cleanup(TEOBResumROMdataDS *romdata) {
304  XLALFree((romdata)->sub1);
305  (romdata)->sub1 = NULL;
306  romdata->setup=0;
307 }
308 
309 
310 /* NOTE: this function does not give correct results yet */
311 /* Wrapper function to evaluate 3d chebyshev polynomial.
312  * p(x,y,z) = \sum_{i,j,k} c_{ijk} T_i(x) T_j(y) T_k(z)
313  * This is done by expressing the sum as follows:
314  * f(x;y,z) = \sum_i h_i(y;z) T_i(x)
315  * = \sum_i [ \sum_j g_ij(z) T_j(y) ] T_i(x)
316  * = \sum_i \sum_j [ \sum_k c_ijk T_k(z) ] T_j(y) T_i(x)
317  * The inner sum is evaluated with a custom implementation of Clenshaw's Recurrence to
318  * avoid having to create the 1d coefficient vector for each ij. This implementation
319  * picks out the coefficients from the 3d coefficient vector c_ijk.
320  * The following sums are evaluated with gsl_cheb_eval at no additional cost.
321  */
322 // static double chebev_3d(gsl_vector *c_ijk, int nx, int ny, int nz, double x, double y, double z, const double xyz_min[], const double xyz_max[]){
323 //
324 // int i,j,k;
325 // int index=0;
326 // int Nyz = ny*nz ;
327 //
328 // double gij_z,hi_y,f_xyz;
329 // double d1=0.0,d2=0.0,sv,G,G2 ;
330 //
331 // double a=xyz_min[2];
332 // double b=xyz_max[2];
333 // gsl_cheb_series *coeffs_1 = gsl_cheb_alloc(ny-1); //GSL assumes coeffs from c[0] to and including c[order]. So N = order+1
334 // coeffs_1->a = xyz_min[1] ;
335 // coeffs_1->b = xyz_max[1] ;
336 // gsl_cheb_series *coeffs_2 = gsl_cheb_alloc(nx-1);
337 // coeffs_2->a = xyz_min[0] ;
338 // coeffs_2->b = xyz_max[0] ;
339 //
340 // for (i=0;i<nx;i++){
341 //
342 // for (j=0;j<ny;j++){
343 //
344 // G = (2.0*z-a-b)/(b-a); //Change of variable
345 // G2 = 2.0*G;
346 // for (k=nz-1 ; k>=1 ; k--) { //Clenshaw's recurrence
347 // sv = d1;
348 // index = (i%Nyz)*Nyz + j*nz + k%nz ; //select coefficient corresponding to current ijk
349 // d1 = G2*d1 - d2 + gsl_vector_get(c_ijk,index);
350 // d2 = sv;
351 // }
352 // index = (i%Nyz)*Nyz + j*nz ; //c_ij0
353 //
354 // //evaluate g_{ij}(z), which will be the coefficients for evaluation of h_i(y;z)
355 // gij_z = G*d1 - d2 + gsl_vector_get(c_ijk,index); //NOTE: gsl returns G*d1 - d2 + 0.5 * cs->c[0]
356 // coeffs_1->c[j] = gij_z ;
357 // }
358 //
359 // //evaluate h_i(y;z), which will be the coefficients for evaluation of f(x;y,z)
360 // hi_y = gsl_cheb_eval(coeffs_1, y) + 0.5*coeffs_1->c[0] ;
361 // coeffs_2->c[i] = hi_y ;
362 // }
363 //
364 // //evaluate f(x;y,z)
365 // f_xyz = gsl_cheb_eval(coeffs_2, x) + 0.5*coeffs_2->c[0] ;
366 //
367 // gsl_cheb_free(coeffs_1);
368 // gsl_cheb_free(coeffs_2);
369 //
370 // return f_xyz ;
371 //
372 // }
373 
374 /* Evaluate the n-th Chebyshev polynomial at value x i.e. this is only T_n(x) without any coefficients or summing */
375 static double gsl_cheb_evaluate_polynomial(int n, double x){
376 
377  double Tnx = 0.0 ;
378  //T_0(x)
379  if (n==0){
380  Tnx = 1.0 ;
381  }
382  //T_1(x)
383  else if (n==1){
384  Tnx = x ;
385  }
386  //T_2(x)
387  else if (n==2){
388  Tnx = 2.0*x*x - 1.0 ;
389  }
390  //T_n(x)
391  else {
392  double d1=0.0,d2=0.0,sv ;
393  int k=0;
394 
395  sv = d1;
396  d1 = 2.0*x*d1 - d2 + 1.0 ; //last coefficient is 1.0
397  d2 = sv ;
398  for (k=n-1 ; k>=1 ; k--) { //Clenshaw's recurrence
399  sv = d1;
400  d1 = 2.0*x*d1 - d2 ; //all coefficients except the last one are 0.0
401  d2 = sv;
402  }
403  Tnx = x*d1 - d2 ; //c[0] is also 0.0
404  }
405 
406  return Tnx ;
407 
408 }
409 
410 /* Temporary function that is about 5 times slower compared to the commented out chebev_3d. */
411 static double gsl_cheb_eval_3d(gsl_vector *c_ijk, int nx, int ny, int nz, double x, double y, double z){
412 
413  double sum=0.0;
414  int i,j,k;
415  int index=0;
416  double Tix=0.,Tjy=0.,Tkz=0.;
417 
418  for (i=0;i<nx;i++){
420  for (j=0;j<ny;j++){
422  for (k=0;k<nz;k++){
424  sum+=gsl_vector_get(c_ijk,index)*Tix*Tjy*Tkz;
425  index+=1;
426  }
427  }
428  }
429 
430  return sum ;
431 
432 }
433 
434 
435 /* Evaluate the chebyshev polinomials for amplitude and phase at node T_j
436  */
438  double q,
439  double lambda1,
440  double lambda2,
441  int nx, int ny, int nz,
442  gsl_vector *cvec_amp,
443  gsl_vector *cvec_phi,
444  int nk_amp,
445  int nk_phi,
446  const double xyz_min[],
447  const double xyz_max[],
448  gsl_vector *interp_amp, //return: A(T_j;q,lambda1,lambda2) <=> p_j(q,lambda1,lambda2)
449  gsl_vector *interp_phi) //return: \Phi(T_j;q,lambda1,lambda2) <=> p_j(q,lambda1,lambda2)
450 {
451 
452  double sum = 0.0;
453  int k = 0;
454  int N=nx*ny*nz ;
455 
456  double xrescale = (q-0.5*(xyz_max[0]+xyz_min[0])) / (0.5*(xyz_max[0]-xyz_min[0]));
457  double yrescale = (lambda1-0.5*(xyz_max[1]+xyz_min[1])) / (0.5*(xyz_max[1]-xyz_min[1]));
458  double zrescale = (lambda2-0.5*(xyz_max[2]+xyz_min[2])) / (0.5*(xyz_max[2]-xyz_min[2]));
459 
460  /*-- Calculate interp_amp --*/
461  for (k=0; k<nk_amp; k++) { // For each empirical node
462  gsl_vector v = gsl_vector_subvector(cvec_amp, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th node.
463 // sum = chebev_3d(&v, nx, ny, nz, q, lambda1, lambda2, xyz_min, xyz_max) ;
464  sum = gsl_cheb_eval_3d(&v, nx, ny, nz, xrescale, yrescale, zrescale) ;
465  gsl_vector_set(interp_amp, k, sum); //write p_k(x,y,z)
466  }
467 
468  /*-- Calculate interp_phi --*/
469  for (k=0; k<nk_phi; k++) { // For each empirical node
470  gsl_vector v = gsl_vector_subvector(cvec_phi, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th node.
471 // sum = chebev_3d(&v, nx, ny, nz, q, lambda1, lambda2, xyz_min, xyz_max) ;
472  sum = gsl_cheb_eval_3d(&v, nx, ny, nz, xrescale, yrescale, zrescale) ;
473  gsl_vector_set(interp_phi, k, sum); //write p_k(x,y,z)
474  }
475 
476  return 0;
477 }
478 
479 
480 static int TEOBResumROMCore(
481  REAL8TimeSeries **hPlus,
482  REAL8TimeSeries **hCross,
483  double phiRef, // orbital reference phase NOTE: unused
484  double deltaT,
485  double fLow,
486  double distance,
487  double inclination,
488  double Mtot, // in Msol
489  double eta,
490  double lambda1, //in range 50 - 5000
491  double lambda2 //in range 50 - 5000
492 )
493 {
494 
495  //NOTE: silly
496  inclination = inclination + phiRef - phiRef ;
497 
498  /* Check output arrays */
499  if(!hPlus || !hCross)
501  TEOBResumROMdataDS *romdata=&__lalsim_TEOBResumROMDS_data;
502  if(*hPlus || *hCross)
503  {
504  XLALPrintError("(*hPlus) and (*hCross) are supposed to be NULL, but got %p and %p",(*hPlus),(*hCross));
506  }
507  int retcode=0;
508 
509  REAL8TimeSeries *hp;
510  REAL8TimeSeries *hc;
511 
512  /* Select ROM submodel */
513  TEOBResumROMdataDS_submodel *submodel;
514  submodel = romdata->sub1;
515 
516  double x = sqrt(1.0-4.0*eta) ;
517  double q = (1-x)/(1+x);
518 
519  //Allocate space for the nodes
520  gsl_vector *amp_at_nodes = gsl_vector_alloc(submodel->times->size);
521  gsl_vector *phi_at_nodes = gsl_vector_alloc(submodel->times->size);
522 
523  double *amp_interp = calloc(Gntimes,sizeof(double));
524  double *phi_interp = calloc(Gntimes,sizeof(double));
525  double *freqs = calloc(Gntimes,sizeof(double));
526  double *physical_times = calloc(Gntimes,sizeof(double));
527 
528  //calculate chebyshev interpolants (A(T_j),Phi(T_j))
529  retcode = chebyshev_interpolation3d(q,lambda1,lambda2,
531  submodel->cvec_amp,submodel->cvec_phi,
533  amp_at_nodes,phi_at_nodes);
534 
535  //calculate A(T_j) and Phi(T_j) at nodes
536  double BjAmp_tn=0.0;
537  double BjPhi_tn=0.0;
538  int n,j;
539  double c3 = LAL_C_SI*LAL_C_SI*LAL_C_SI ;
540  double time_to_phys = LAL_G_SI*Mtot*LAL_MSUN_SI/c3 ;
541  for (n=0;n<Gntimes;n++){
542  BjAmp_tn=0.0 ;
543  BjPhi_tn=0.0 ;
544  for (j=0;j<Gnamp;j++){
545  BjAmp_tn+=gsl_vector_get(amp_at_nodes,j)*gsl_matrix_get(submodel->Bamp,j,n);
546  }
547  for (j=0;j<Gnphase;j++){
548  BjPhi_tn+=gsl_vector_get(phi_at_nodes,j)*gsl_matrix_get(submodel->Bphi,j,n);
549  }
550  //convert times in to seconds
551  physical_times[n]=gsl_vector_get(submodel->times,n)*time_to_phys;
552  amp_interp[n]=BjAmp_tn;
553  phi_interp[n]=BjPhi_tn;
554  }
555 
556 
557 
558  //Resampling A(t) and Phi(t) to arbitrary deltaT ---\n");
559  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
560  gsl_interp_accel *acc_phi = gsl_interp_accel_alloc();
561  gsl_interp_accel *acc_fot = gsl_interp_accel_alloc();
562  gsl_spline *ampoft_spline = gsl_spline_alloc (gsl_interp_cspline, Gntimes);
563  gsl_spline *phioft_spline = gsl_spline_alloc (gsl_interp_cspline, Gntimes);
564 
565  //initializing splines
566  gsl_spline_init(ampoft_spline, physical_times, amp_interp, Gntimes);
567  gsl_spline_init(phioft_spline, physical_times, phi_interp, Gntimes);
568 
569  double der ;
570  //calculate frequencies at nodes (derivative of phi(t)/2pi)
571  int i_end_mono = Gntimes;
572  for (n=0;n<Gntimes;n++) {
573  der = gsl_spline_eval_deriv (phioft_spline, physical_times[n], acc_phi);
574  freqs[n] = 0.5*der/LAL_PI;//omegaoft(time_phys)/(2*np.pi)
575  //determine up to where f is monotonically increasing
576  if (n > 0 && i_end_mono == Gntimes) {
577  if (freqs[n] < freqs[n-1]) i_end_mono = n ;
578  }
579  }
580 
581  //create t(f) spline
582  double physical_times_end = physical_times[Gntimes-1];//save the last element before resizing
583  //Resize freqs and physical_times to include only monotonically increasing values
584  if ( (freqs = XLALRealloc ( freqs, i_end_mono*sizeof( *freqs ) )) == NULL ) {
585  XLALPrintError ("%s: XLALRealloc(%d) failed!\n", __func__, i_end_mono );
587  }
588  if ( (physical_times = XLALRealloc ( physical_times, i_end_mono*sizeof( *physical_times ) )) == NULL ) {
589  XLALPrintError ("%s: XLALRealloc(%d) failed!\n", __func__, i_end_mono );
591  }
592  //interpolate to get t(f)
593  gsl_spline *toffreq_spline = gsl_spline_alloc (gsl_interp_cspline, i_end_mono);
594  gsl_spline_init(toffreq_spline, freqs, physical_times, i_end_mono);
595 
596  //calculate parameters to resample with even spacing
597  double tstart = gsl_spline_eval(toffreq_spline, fLow, acc_fot);
598  int Ntimes_res = (int) ceil((physical_times_end-tstart)/deltaT);
599  double *times_res = calloc(Ntimes_res,sizeof(double));
600  double *amp_res = calloc(Ntimes_res,sizeof(double));
601  double *phi_res = calloc(Ntimes_res,sizeof(double));
602  double t=tstart;
603  // fprintf(stdout,"tstart=%.2f\n",tstart);
604  //fprintf(stdout,"Ntimes=%d\n",Ntimes_res);
605 
606  //for scaling the amplitude
607  double h22_to_h = 4.0*eta*sqrt(5.0/LAL_PI)/8.0;
608  double amp_units = LAL_G_SI*Mtot*LAL_MSUN_SI/(LAL_C_SI*LAL_C_SI*distance) ;
609 
610  //Adjust for inclination angle [0,pi]
611  double cosi = cos(inclination);
612  double inc_plus = (1.0+cosi*cosi)/2.0;
613  double inc_cross = cosi;
614 
615 
616  //Generate h+(t) and hx(t)
617 
618  //XLALGPSAdd(&tC, -1 / deltaF); /* coalesce at t=0 */
620  XLALGPSAdd(&tC, tstart);
621  //XLALGPSAdd(&tC, -1.0*j*deltaT);
622  /* Allocate hplus and hcross */
623  hp = XLALCreateREAL8TimeSeries("hplus: TD waveform", &tC, 0.0, deltaT, &lalStrainUnit, Ntimes_res);
624  if (!hp) XLAL_ERROR(XLAL_EFUNC);
625  memset(hp->data->data, 0, Ntimes_res * sizeof(REAL8));
626 
627  hc = XLALCreateREAL8TimeSeries("hcross: TD waveform", &tC, 0.0, deltaT, &lalStrainUnit, Ntimes_res);
628  if (!hc) XLAL_ERROR(XLAL_EFUNC);
629  memset(hc->data->data, 0, Ntimes_res * sizeof(REAL8));
630 
631  times_res[0] = t ;
632  amp_res[0] = gsl_spline_eval(ampoft_spline, t, acc_amp)*amp_units*h22_to_h;
633  double phi0 = gsl_spline_eval(phioft_spline, t, acc_phi);
634  phi_res[0] = 0.0;
635  hp->data->data[0] = inc_plus*amp_res[0]*cos(phi_res[0]);
636  hc->data->data[0] = inc_cross*amp_res[0]*sin(phi_res[0]);
637  t+=deltaT;
638  for (n=1;n<Ntimes_res;n++) {
639  times_res[n] = t;
640  amp_res[n] = gsl_spline_eval(ampoft_spline, t, acc_amp)*amp_units*h22_to_h;
641  //Zero the phase at the beginning (-phi0)
642  phi_res[n] = gsl_spline_eval(phioft_spline, t, acc_phi)-phi0;
643 
644  hp->data->data[n] = inc_plus*amp_res[n]*cos(phi_res[n]);
645  hc->data->data[n] = inc_cross*amp_res[n]*sin(phi_res[n]);
646 
647  t+=deltaT;
648  }
649 
650  *hPlus = hp;
651  *hCross = hc;
652 
653  gsl_spline_free (ampoft_spline);
654  gsl_spline_free (phioft_spline);
655  gsl_spline_free (toffreq_spline);
656  gsl_interp_accel_free (acc_amp);
657  gsl_interp_accel_free (acc_phi);
658  gsl_interp_accel_free (acc_fot);
659 
660  gsl_vector_free(amp_at_nodes);
661  gsl_vector_free(phi_at_nodes);
662 
663  free(amp_interp);
664  free(phi_interp);
665  free(freqs);
666  free(physical_times);
667  free(times_res);
668  free(amp_res);
669  free(phi_res);
670 
671  if (retcode==0){
672  return(XLAL_SUCCESS);
673  } else {
674  return(retcode);
675  }
676 
677 }
678 
679 /**
680  * @addtogroup LALSimInspiralTEOBResumROM_c
681  *
682  * @name TEOBResum Reduced Order Model (Tidal effects)
683  *
684  * @author Jeroen Meidam, ... (Based on SEOBNRv2ROM code written by Michael Puerrer and John Veitch)
685  *
686  * @brief C code for TEOBResum reduced order model which includes tidal effects.
687  * See ... for the basic approach.
688  * Further details in ...
689  *
690  * This is a time domain model that approximates the time domain EOB model with tidal effects.
691  *
692  * The binary data files are available at https://github.com/benjaminlackey/cbcrom/tree/master/data.
693  * Put the *.dat files into a location in your LAL_DATA_PATH.
694  * They must have the names
695  * - TEOBResumROM_Amp_ciall.dat
696  * - TEOBResumROM_Phase_ciall.dat
697  * - TEOBResumROM_Bamp_matrix.dat
698  * - TEOBResumROM_Bphase_matrix.dat
699  * - TEOBResumROM_times.dat
700  *
701  * @note Approximant name is TEOBResum_ROM
702  *
703  * @note Parameter ranges:
704  * 0.5 <= q <= 1.0
705  * 50 <= lambda_i <= 5000
706  *
707  * @{
708  */
709 
710 
711 //Function to test data reading
713  REAL8TimeSeries **hPlus, /**< Output: Frequency-domain waveform h+ */
714  REAL8TimeSeries **hCross, /**< Output: Frequency-domain waveform hx */
715  REAL8 phiRef, /**< Orbital phase at reference frequency*/
716  REAL8 deltaT, /**< Sampling frequency (Hz) */
717  REAL8 fLow, /**< Starting GW frequency (Hz) */
718  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
719  REAL8 distance, /**< Distance of source (m) */
720  REAL8 inclination, /**< Inclination of source (rad) */
721  REAL8 m1SI, /**< Mass of companion 1 (kg) */
722  REAL8 m2SI, /**< Mass of companion 2 (kg) */
723  REAL8 lambda1, /**< dimensionless tidal deformability of body 1 */
724  REAL8 lambda2) /**< dimensionless tidal deformability of body 1 */
725 {
726  /* Internally we need m1 > m2, so change around if this is not the case */
727  if (m1SI < m2SI) {
728  // Swap m1 and m2
729  double m1temp = m1SI;
730  double l1temp = lambda1;
731  m1SI = m2SI;
732  lambda1 = lambda2;
733  m2SI = m1temp;
734  lambda2 = l1temp;
735  }
736 
737  /* Get masses in terms of solar mass */
738  double mass1 = m1SI / LAL_MSUN_SI;
739  double mass2 = m2SI / LAL_MSUN_SI;
740  double Mtot = mass1+mass2;
741  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
742 
743  double x = sqrt(1.0-4.0*eta) ;
744  double q = (1-x)/(1+x);
745 
746  // 'Nudge' q to allowed boundary values if close by (q could be e.g. 0.499999)
747  if (q > Gparams_max[0]) nudge(&q, Gparams_max[0], 1e-6);
748  if (q < Gparams_min[0]) nudge(&q, Gparams_min[0], 1e-6);
749 
750  /* Check that parameters are within the limits for this model */
751  if ( q<Gparams_min[0] || q>Gparams_max[0] ) {
752  fprintf(stderr,"Error: q not in range (%.2f not in [%.2f,%.2f])\n",q,Gparams_min[0],Gparams_max[0]);
753  return(XLAL_EDOM);
754  }
755  if ( lambda1<Gparams_min[1] || lambda1>Gparams_max[1] ) {
756  fprintf(stderr,"Error: lambda1 not in range (%.2f not in [%.2f,%.2f])\n",lambda1,Gparams_min[1],Gparams_max[1]);
757  return(XLAL_EDOM);
758  }
759  if ( lambda2<Gparams_min[2] || lambda2>Gparams_max[2] ) {
760  fprintf(stderr,"Error: lambda2 not in range (%.2f not in [%.2f,%.2f])\n",lambda2,Gparams_min[2],Gparams_max[2]);
761  return(XLAL_EDOM);
762  }
763 
764  // if (fRef!=0.0) fprintf(stdout,"WARNING: fREf != 0.0 -> TEOBResum_ROM does not do anything with fRef. It will be evaluated from fLow.\n");
765  //fRef = 0.0;
766 
767  // Load ROM data if not loaded already
768  // fprintf(stdout,"initializing with TEOBResumROM_Init_LALDATA()\n");
769  #ifdef LAL_PTHREAD_LOCK
770  (void) pthread_once(&TEOBResumROM_is_initialized, TEOBResumROM_Init_LALDATA);
771  #else
773  #endif
774 
775  if(!TEOBResumROM_IsSetup()) XLAL_ERROR(XLAL_EFAILED,"Error setting up TEOBResumROM data - check your $LAL_DATA_PATH\n");
776 
777  int retcode = TEOBResumROMCore(hPlus,hCross, phiRef, deltaT, fLow, distance, inclination, Mtot, eta, lambda1, lambda2);
778 
779  return(retcode);
780 }
781 
782 /** @} */
783 
784 /** Setup TEOBResum_ROM model using data files installed in $LAL_DATA_PATH
785  */
786 static void TEOBResumROM_Init_LALDATA(void)
787 {
788  if (TEOBResumROM_IsSetup()) return;
789 
790  // If we find one ROM datafile in a directory listed in LAL_DATA_PATH,
791  // then we expect the remaining datafiles to also be there.
792  char datafile[] = "TEOBResumROM_Phase_ciall.dat";
793 
794  char *path = XLAL_FILE_RESOLVE_PATH(datafile);
795  if (path==NULL)
796  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile);
797  char *dir = dirname(path);
798  int ret = TEOBResumROM_Init(dir);
799  XLALFree(path);
800 
801  if(ret!=XLAL_SUCCESS)
802  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find TEOBResumROM data files in $LAL_DATA_PATH\n");
803 }
static void nudge(REAL8 *x, REAL8 X, REAL8 epsilon)
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
static UNUSED int read_vector(const char dir[], const char fname[], gsl_vector *v)
static UNUSED int read_matrix(const char dir[], const char fname[], gsl_matrix *m)
static int load_data(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *cvec_amp_pre)
static int chebyshev_interpolation3d(double q, double lambda1, double lambda2, int nx, int ny, int nz, gsl_vector *cvec_amp, gsl_vector *cvec_phi, int nk_amp, int nk_phi, const double xyz_min[], const double xyz_max[], gsl_vector *interp_amp, gsl_vector *interp_phi)
static double gsl_cheb_evaluate_polynomial(int n, double x)
#define Gntimes
#define Gnlambda1
int(* load_dataPtr)(const char *, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *)
static int TEOBResumROMdataDS_Init_submodel(TEOBResumROMdataDS_submodel **submodel, const int n_amp, const int n_phi, const int nq, const int nl1, const int nl2, const int ntimes, const double *params_min, const double *params_max, const char dir[], load_dataPtr load_data)
static void TEOBResumROM_Init_LALDATA(void)
Setup TEOBResum_ROM model using data files installed in $LAL_DATA_PATH.
static double gsl_cheb_eval_3d(gsl_vector *c_ijk, int nx, int ny, int nz, double x, double y, double z)
static int TEOBResumROMdataDS_Init(TEOBResumROMdataDS *romdata, const char dir[])
static const double Gparams_max[]
static const double Gparams_min[]
static int TEOBResumROM_Init(const char dir[])
Setup SEOBNRv2ROMDoubleSpin model using data files installed in dir.
#define Gnphase
#define Gnq
static int TEOBResumROMCore(REAL8TimeSeries **hPlus, REAL8TimeSeries **hCross, double phiRef, double deltaT, double fLow, double distance, double inclination, double Mtot_sec, double eta, double lambda1, double lambda2)
static int load_data_romeos(const char dir[], gsl_vector *cvec_amp, gsl_vector *cvec_phi, gsl_matrix *Bamp, gsl_matrix *Bphi, gsl_vector *times)
static void TEOBResumROMdataDS_Cleanup(TEOBResumROMdataDS *romdata)
#define Gnamp
#define Gnlambda2
static TEOBResumROMdataDS __lalsim_TEOBResumROMDS_data
static bool TEOBResumROM_IsSetup(void)
Helper function to check if the SEOBNRv2ROMDoubleSpin model has been initialised.
int XLALSimInspiralTEOBResumROM(REAL8TimeSeries **hPlus, REAL8TimeSeries **hCross, REAL8 phiRef, REAL8 deltaT, REAL8 fLow, UNUSED REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 lambda1, REAL8 lambda2)
static void TEOBResumROMdataDS_Cleanup_submodel(TEOBResumROMdataDS_submodel *submodel)
static REAL8 sum(REAL8 *arr1, REAL8 *arr2, int k)
#define fprintf
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
LIGOTimeGPS tstart
const double sv
const double ny
const double nz
const double nx
#define XLAL_FILE_RESOLVE_PATH(fname)
#define LAL_C_SI
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_G_SI
#define LIGOTIMEGPSZERO
double REAL8
uint32_t UINT4
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
static const INT4 q
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
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_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list x
list y
path
int N
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
REAL8Sequence * data
REAL8 * data
TEOBResumROMdataDS_submodel * sub1
TEOBResumROMdataDS_submodel * sub2
TEOBResumROMdataDS_submodel * sub3
double deltaT
Definition: unicorn.c:24