LALSimulation  5.4.0.1-fe68b98
LALSimIMREOBNRv2HMROM.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Sylvain Marsat
3  * Reduced Order Model for EOBNRv2HM
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with with program; see the file COPYING. If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  */
20 
21 /**
22  * \author Sylvain Marsat
23  *
24  * \file
25  *
26  * \brief C code for EOBNRv2HM reduced order model (non-spinning version).
27  * See CQG 31 195010, 2014, arXiv:1402.4146 for details on the reduced order method.
28  * See arXiv:1106.1021 for the EOBNRv2HM model.
29  *
30  * Borrows from the SEOBNR ROM LAL code written by Michael Puerrer and John Veitch.
31  *
32  * The binary data files are available at [TBD].
33  * Put the untared data into a location in your LAL_DATA_PATH.
34  *
35  * Parameter ranges:
36  * q = 1-11.98
37  * No spin
38  * Mtot >= 8Msun for fstart=10Hz
39  *
40  */
41 
42 #ifdef __GNUC__
43 #define UNUSED __attribute__ ((unused))
44 #else
45 #define UNUSED
46 #endif
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <math.h>
51 #include <complex.h>
52 #include <time.h>
53 #include <stdbool.h>
54 #include <alloca.h>
55 #include <string.h>
56 #include <libgen.h>
57 
58 #include <gsl/gsl_errno.h>
59 #include <gsl/gsl_bspline.h>
60 #include <gsl/gsl_blas.h>
61 #include <gsl/gsl_min.h>
62 #include <gsl/gsl_spline.h>
63 #include <gsl/gsl_poly.h>
64 #include <lal/Units.h>
65 #include <lal/SeqFactories.h>
66 #include <lal/LALConstants.h>
67 #include <lal/XLALError.h>
68 #include <lal/FrequencySeries.h>
69 #include <lal/Date.h>
70 #include <lal/StringInput.h>
71 #include <lal/Sequence.h>
72 #include <lal/LALStdio.h>
73 #include <lal/FileIO.h>
74 
75 #include <lal/LALSimInspiral.h>
76 #include <lal/LALSimIMR.h>
77 #include <lal/SphericalHarmonics.h>
78 
81 
82 
83 
84 /*****************************************************************************/
85 /**************************** General definitions ****************************/
86 
87 /* NOTE: some integer constants #define statements are in LALSimIMREOBNRv2HMROMUtilities.c */
88 
89 /* Number and list of modes to generate - to be modified ultimately to allow for a selection of the desired mode(s) */
90 /* By convention the first mode of the list, assumed to be the 22, is used to set phiRef */
91 #define EOBNRV2_ROM_NUM_MODES_MAX 5
93 static const INT4 listmode[EOBNRV2_ROM_NUM_MODES_MAX][2] = { {2,2}, {2,1}, {3,3}, {4,4}, {5,5} };
94 
95 /* Maximal mass ratio covered by the model - q=12 (almost) for now */
96 static const REAL8 q_max = 11.9894197212;
97 /* Minimal geometric frequency covered by the model - f=8Hz for M=10Msol for now */
98 static const REAL8 Mf_ROM_min = 0.0003940393857519091;
99 /* Maximal geometric frequency covered by the model - Mf=0.285 for the 55 mode - used as default */
100 static const REAL8 Mf_ROM_max = 0.285;
101 /* Total mass (in units of solar mass) used to generate the ROM - used to restore the correct amplitude (global factor M) when coming back to physical units */
102 static const REAL8 M_ROM = 10.;
103 
104 
105 /******************************************************************/
106 /********* Definitions for the persistent structures **************/
107 
108 /* SEOBNR-ROM structures are generalized to lists */
109 static ListmodesEOBNRHMROMdata* __lalsim_EOBNRv2HMROM_data_init = NULL; /* for initialization only */
111 static ListmodesEOBNRHMROMdata_interp* __lalsim_EOBNRv2HMROM_interp_init = NULL; /* for initialization only */
113 /* Tag indicating whether the data has been loaded and interpolated */
114 static INT4 __lalsim_EOBNRv2HMROM_setup = XLAL_FAILURE; /* To be set to XLAL_SUCCESS after initialization*/
115 
116 
117 /****************************************************************************/
118 /******************************** Prototypes ********************************/
119 
120 /* Functions to interpolate the data and to evaluate the interpolated data for a given q */
122  const REAL8 q, /* Input: q-value for which projection coefficients should be evaluated */
123  const EOBNRHMROMdata_interp* data_interp, /* Input: data in interpolated form */
124  EOBNRHMROMdata_coeff* data_coeff /* Output: vectors of projection coefficients and shifts in time and phase */
125 );
127  const EOBNRHMROMdata *data, /* Input: data in vector/matrix form to interpolate */
128  EOBNRHMROMdata_interp *data_interp /* Output: interpolated data */
129 );
130 
131 /* Functions to load and initalize ROM data */
132 static INT4 EOBNRv2HMROM_Init_LALDATA(void);
133 static INT4 EOBNRv2HMROM_Init(const char dir[]);
134 
135 /* Core functions for waveform reconstruction */
136 static INT4 EOBNRv2HMROMCore(
137  COMPLEX16FrequencySeries **hptilde,
138  COMPLEX16FrequencySeries **hctilde,
139  REAL8 phiRef,
140  REAL8 deltaF,
141  REAL8 fLow,
142  REAL8 fHigh,
143  REAL8 fRef,
144  REAL8 distance,
145  REAL8 inclination,
146  REAL8 Mtot_sec,
147  REAL8 q);
148 
149 
150 /************************************************************************************/
151 /******************************** Internal functions ********************************/
152 
153 /* Return the closest higher power of 2 */
154 static size_t NextPow2(const size_t n) {
155  return 1 << (size_t) ceil(log2(n));
156 }
157 
158 /* Arbitrary tuned q-dependent functions by which the frequencies for the 44 and 55 modes have been multiplied (to put the ringdowns at the same Mf). The frequencies stored in the data for the 44 and 55 modes are the rescaled ones, not the original ones. */
159 static REAL8 Scaling44(const REAL8 q) {
160  return 1.-1./4.*exp(-(q-1.)/5.);
161 }
162 static REAL8 Scaling55(const REAL8 q) {
163  return 1.-1./3.*exp(-(q-1.)/5.);
164 }
165 
166 /* Function evaluating eta as a function of q */
167 static REAL8 EtaOfq(const REAL8 q) {
168  return q/(1.+q)/(1.+q);
169 }
170 /* Function evaluating delta m/m = (m1-m2)/(m1+m2) as a function of q*/
171 static REAL8 DeltaOfq(const REAL8 q) {
172  return( (q-1.)/(q+1.) );
173 }
174 
175 /* Fit of the frequency of the 22 mode at the peak amplitude - from table III in the EOBNRv2HM paper, Pan&al 1106 */
176 static double omega22peakOfq(const double q) {
177  double eta = EtaOfq(q);
178  return 0.2733 + 0.2316*eta + 0.4463*eta*eta;
179 }
180 
181 /* Amplitude factors scaled out for each mode; this ddoes not include the global amplitude factor scaled out from all modes. */
182 static REAL8 ModeAmpFactor(const INT4 l, const INT4 m, const REAL8 q) {
183  REAL8 eta = EtaOfq(q);
184  if( l==2 && m==2 ) return(sqrt(eta));
185  else if( l==2 && m==1 ) return( sqrt(eta)*DeltaOfq(q) );
186  else if( l==3 && m==3 ) return( sqrt(eta)*DeltaOfq(q) );
187  else if( l==4 && m==4 ) return( sqrt(Scaling44(q))*sqrt(eta)*(1.-3.*eta) );
188  else if( l==5 && m==5 ) return( pow(Scaling55(q), 1./6)*sqrt(eta)*DeltaOfq(q)*(1.-2.*eta) );
189  else {
190  fprintf(stderr, "Unknown mode (%d,%d) for the amplitude factor.\n", l, m);
191  return(XLAL_FAILURE);
192  }
193 }
194 
195 /* Function interpolating the data in matrix/vector form produces an interpolated data in the form of SplineLists */
197 
198  SplineList* splinelist;
199  gsl_spline* spline;
200  gsl_interp_accel* accel;
201  gsl_vector* matrixline;
202  gsl_vector* vector;
203  INT4 j;
204 
205  /* Interpolating Camp */
206  splinelist = data_interp->Camp_interp;
207  for (j = 0; j<nk_amp; j++) {
208  matrixline = gsl_vector_alloc(nbwf);
209  gsl_matrix_get_row(matrixline, data->Camp, j);
210 
211  accel = gsl_interp_accel_alloc();
212  spline = gsl_spline_alloc(gsl_interp_cspline, nbwf);
213  gsl_spline_init(spline, gsl_vector_const_ptr(data->q, 0), gsl_vector_const_ptr(matrixline, 0), nbwf);
214 
215  splinelist = SplineList_AddElementNoCopy(splinelist, spline, accel, j);
216  gsl_vector_free(matrixline);
217  }
218  data_interp->Camp_interp = splinelist;
219 
220  /* Interpolating Cphi */
221  splinelist = data_interp->Cphi_interp;
222  for (j = 0; j<nk_phi; j++) {
223  matrixline = gsl_vector_alloc(nbwf);
224  gsl_matrix_get_row(matrixline, data->Cphi, j);
225 
226  accel = gsl_interp_accel_alloc();
227  spline = gsl_spline_alloc(gsl_interp_cspline, nbwf);
228  gsl_spline_init(spline, gsl_vector_const_ptr(data->q, 0), gsl_vector_const_ptr(matrixline, 0), nbwf);
229 
230  splinelist = SplineList_AddElementNoCopy(splinelist, spline, accel, j);
231  gsl_vector_free(matrixline);
232  }
233  data_interp->Cphi_interp = splinelist;
234 
235  /* Interpolating shifttime */
236  splinelist = data_interp->shifttime_interp;
237  vector = data->shifttime;
238 
239  accel = gsl_interp_accel_alloc();
240  spline = gsl_spline_alloc(gsl_interp_cspline, nbwf);
241  gsl_spline_init(spline, gsl_vector_const_ptr(data->q, 0), gsl_vector_const_ptr(vector, 0), nbwf);
242 
243  splinelist = SplineList_AddElementNoCopy(NULL, spline, accel, 0); /* This SplineList has only 1 element */
244  data_interp->shifttime_interp = splinelist;
245 
246  /* Interpolating shiftphase */
247  splinelist = data_interp->shiftphase_interp;
248  vector = data->shiftphase;
249 
250  accel = gsl_interp_accel_alloc();
251  spline = gsl_spline_alloc(gsl_interp_cspline, nbwf);
252  gsl_spline_init(spline, gsl_vector_const_ptr(data->q, 0), gsl_vector_const_ptr(vector, 0), nbwf);
253 
254  splinelist = SplineList_AddElementNoCopy(NULL, spline, accel, 0); /* This SplineList has only 1 element */
255  data_interp->shiftphase_interp = splinelist;
256 
257  return XLAL_SUCCESS;
258 }
259 
260 /* Function taking as input interpolated data in the form of SplineLists
261  * evaluates for a given q the projection coefficients and shifts in time and phase
262 */
263 static INT4 Evaluate_Spline_Data(const REAL8 q, const EOBNRHMROMdata_interp* data_interp, EOBNRHMROMdata_coeff* data_coeff){
264  INT4 j;
265  SplineList* splinelist;
266 
267  /* Evaluating the vector of projection coefficients for the amplitude */
268  for (j=0; j<nk_amp; j++) {
269  splinelist = SplineList_GetElement(data_interp->Camp_interp, j);
270  gsl_vector_set(data_coeff->Camp_coeff, j, gsl_spline_eval(splinelist->spline, q, splinelist->accel));
271  }
272  /* Evaluating the vector of projection coefficients for the phase */
273  for (j=0; j<nk_phi; j++) {
274  splinelist = SplineList_GetElement(data_interp->Cphi_interp, j);
275  gsl_vector_set(data_coeff->Cphi_coeff, j, gsl_spline_eval(splinelist->spline, q, splinelist->accel));
276  }
277  /* Evaluating the shift in time */
278  splinelist = SplineList_GetElement(data_interp->shifttime_interp, 0); /* This SplineList has only one element */
279  *(data_coeff->shifttime_coeff) = gsl_spline_eval(splinelist->spline, q, splinelist->accel);
280  /* Evaluating the shift in phase */
281  splinelist = SplineList_GetElement(data_interp->shiftphase_interp, 0); /* This SplineList has only one element */
282  *(data_coeff->shiftphase_coeff) = gsl_spline_eval(splinelist->spline, q, splinelist->accel);
283 
284  return XLAL_SUCCESS;
285 }
286 
287 /*
288  * Core function for computing the ROM waveform.
289  * Evaluates projection coefficients and shifts in time and phase at desired q.
290  * Construct 1D splines for amplitude and phase.
291  * Compute strain waveform from amplitude and phase.
292 */
294  COMPLEX16FrequencySeries **hptilde,
295  COMPLEX16FrequencySeries **hctilde,
296  REAL8 phiRef,
297  REAL8 deltaF,
298  REAL8 fLow,
299  REAL8 fHigh,
300  REAL8 fRef,
301  REAL8 distance,
302  REAL8 inclination,
303  REAL8 Mtot_sec,
304  REAL8 q)
305 {
306  INT4 ret = XLAL_SUCCESS;
307  INT4 i;
308  INT4 j;
309  double tpeak22estimate = 0.;
310  /* Check output arrays */
311  if(!hptilde || !hctilde) XLAL_ERROR(XLAL_EFAULT);
312  if(*hptilde || *hctilde)
313  {
314  XLALPrintError("(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p\n",(*hptilde),(*hctilde));
316  }
317 
318  /* Check if the data has been set up */
320  XLALPrintError("Error: the ROM data has not been set up\n");
322  }
323  /* Set the global pointers to data */
326 
327  /* Global amplitude prefactor - includes total mass scaling, Fourier scaling, distance scaling, and undoing an additional arbitrary scaling */
328  REAL8 Mtot_msol = Mtot_sec / LAL_MTSUN_SI; /* Mtot_msol and M_ROM in units of solar mass */
329  REAL8 amp0 = (Mtot_msol/M_ROM) * Mtot_sec * 1.E-16 * 1.E6 * LAL_PC_SI / distance;
330 
331  /* Highest allowed geometric frequency for the first mode of listmode in the ROM - used for fRef
332  * by convention, we use the first mode of listmode (presumably the 22) for phiref */
333  ListmodesEOBNRHMROMdata* listdata_ref = ListmodesEOBNRHMROMdata_GetMode(listdata, listmode[0][0], listmode[0][1]);
334  EOBNRHMROMdata* data_ref = listdata_ref->data;
335  REAL8 Mf_ROM_max_ref = gsl_vector_get(data_ref->freq, nbfreq-1);
336  /* Convert to geometric units for frequency */
337  REAL8 fLow_geom = fLow * Mtot_sec;
338  REAL8 fHigh_geom = fHigh * Mtot_sec;
339  REAL8 fRef_geom = fRef * Mtot_sec;
340  REAL8 deltaF_geom = deltaF * Mtot_sec;
341 
342  /* Enforce allowed geometric frequency range */
343  if (fLow_geom < Mf_ROM_min) { /* Enforce minimal frequency */
344  XLALPrintWarning("Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min);
345  fLow_geom = Mf_ROM_min;
346  }
347  /* Default highest frequency */
348  if (fHigh == 0)
349  fHigh_geom = Mf_ROM_max;
350  /* In case the user asks for a frequency higher than covered by the ROM, we keep it that way as we will just 0-pad the waveform (and do it anyway for some modes) */
351  if (fRef_geom > Mf_ROM_max_ref || fRef_geom == 0)
352  fRef_geom = Mf_ROM_max_ref; /* If fRef > fhigh or 0 we reset fRef to default value of cutoff frequency for the first mode of the list (presumably the 22 mode) */
353  if (0 < fRef_geom && fRef_geom < Mf_ROM_min) {
354  XLALPrintWarning("Reference frequency Mf_ref=%g is smaller than lowest frequency in ROM Mf=%g. Setting it to the lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min);
355  fRef_geom = Mf_ROM_min;
356  }
357  /* Set up output array with size closest power of 2 - fHigh is the upper frequency specified by the user */
358  size_t nbpt = NextPow2(fHigh_geom / deltaF_geom) + 1;
359 
360  /* Internal storage for the projection coefficients and shifts in time and phase */
361  /* Initialized only once, and reused for the different modes */
362  EOBNRHMROMdata_coeff *data_coeff = NULL;
363  EOBNRHMROMdata_coeff_Init(&data_coeff);
364  /* Create spherical harmonic frequency series that will contain the hlm's */
365  SphHarmFrequencySeries** hlmsphharmfreqseries = XLALMalloc(sizeof(SphHarmFrequencySeries));
366  *hlmsphharmfreqseries = NULL;
367 
368  /* GPS time definition - common to all modes */
369  LIGOTimeGPS tC;
370  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
371 
372  /* The phase change imposed by phiref, from the phase of the first mode in the list - to be set in the first step of the loop on the modes */
373  REAL8 phase_change_ref = 0;
374 
375  /* Main loop over the modes */
376  for( i=0; i<nbmode; i++ ){
377  UINT4 l = listmode[i][0];
378  INT4 m = listmode[i][1];
379 
380  /* Getting the relevant modes in the lists of data */
381  ListmodesEOBNRHMROMdata* listdata_mode = ListmodesEOBNRHMROMdata_GetMode(listdata, l, m);
382  ListmodesEOBNRHMROMdata_interp* listdata_interp_mode = ListmodesEOBNRHMROMdata_interp_GetMode(listdata_interp, l, m);
383 
384  /* Evaluating the projection coefficients and shift in time and phase */
385  ret |= Evaluate_Spline_Data(q, listdata_interp_mode->data_interp, data_coeff);
386 
387  /* Evaluating the unnormalized amplitude and unshifted phase vectors for the mode */
388  /* Notice a change in convention: B matrices are transposed with respect to the B matrices in SEOBNRROM */
389  /* amp_pts = Bamp . Camp_coeff */
390  /* phi_pts = Bphi . Cphi_coeff */
391  gsl_vector* amp_f = gsl_vector_alloc(nbfreq);
392  gsl_vector* phi_f = gsl_vector_alloc(nbfreq);
393  gsl_blas_dgemv(CblasNoTrans, 1.0, listdata_mode->data->Bamp, data_coeff->Camp_coeff, 0.0, amp_f);
394  gsl_blas_dgemv(CblasNoTrans, 1.0, listdata_mode->data->Bphi, data_coeff->Cphi_coeff, 0.0, phi_f);
395 
396  /* The downsampled frequencies for the mode - we undo the rescaling of the frequency for the 44 and 55 modes */
397  gsl_vector* freq_ds = gsl_vector_alloc(nbfreq);
398  gsl_vector_memcpy(freq_ds, listdata_mode->data->freq);
399  if ( l==4 && m==4) gsl_vector_scale( freq_ds, 1./Scaling44(q));
400  if ( l==5 && m==5) gsl_vector_scale( freq_ds, 1./Scaling55(q));
401 
402  /* Evaluating the shifts in time and phase - conditional scaling for the 44 and 55 modes */
403  /* Note: the stored values of 'shifttime' correspond actually to 2pi*Deltat */
404  SplineList* shifttime_splinelist = listdata_interp_mode->data_interp->shifttime_interp;
405  SplineList* shiftphase_splinelist = listdata_interp_mode->data_interp->shiftphase_interp;
406  REAL8 twopishifttime;
407  if( l==4 && m==4) {
408  twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel) * Scaling44(q);
409  }
410  else if( l==5 && m==5) {
411  twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel) * Scaling55(q);
412  }
413  else {
414  twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel);
415  }
416  REAL8 shiftphase = gsl_spline_eval(shiftphase_splinelist->spline, q, shiftphase_splinelist->accel);
417 
418  /* If first mode in the list, assumed to be the 22 mode, set totalshifttime and phase_change_ref */
419  if( i==0 ) {
420  if(l==2 && m==2) {
421  /* Setup 1d cubic spline for the phase of the 22 mode */
422  gsl_interp_accel* accel_phi22 = gsl_interp_accel_alloc();
423  gsl_spline* spline_phi22 = gsl_spline_alloc(gsl_interp_cspline, nbfreq);
424  gsl_spline_init(spline_phi22, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(phi_f,0), nbfreq);
425  /* Compute the shift in time needed to set the peak of the 22 mode roughly at t=0 */
426  /* We use the SPA formula tf = -(1/2pi)*dPsi/df to estimate the correspondence between frequency and time */
427  /* The frequency corresponding to the 22 peak is omega22peak/2pi, with omega22peak taken from the fit to NR in Pan&al 1106 EOBNRv2HM paper */
428  double f22peak = fmin(omega22peakOfq(q)/(2*LAL_PI), Mf_ROM_max_ref); /* We ensure we evaluate the spline within its range */
429  tpeak22estimate = -1./(2*LAL_PI) * gsl_spline_eval_deriv(spline_phi22, f22peak, accel_phi22);
430  /* Determine the change in phase (to be propagated to all modes) required to have phi22(fRef) = 2*phiRef */
431  phase_change_ref = 2*phiRef + (gsl_spline_eval(spline_phi22, fRef_geom, accel_phi22) - (twopishifttime - 2*LAL_PI*tpeak22estimate) * fRef_geom - shiftphase);
432 
433  gsl_spline_free(spline_phi22);
434  gsl_interp_accel_free(accel_phi22);
435  }
436  else {
437  XLALPrintError("Error: the first mode in listmode must be the 22 mode to set the changes in phase and time \n");
439  }
440  }
441  /* Total shift in time, and total change in phase for this mode */
442  double totaltwopishifttime = twopishifttime - 2*LAL_PI*tpeak22estimate;
443  double constphaseshift = (double) m/listmode[0][1] * phase_change_ref + shiftphase;
444 
445  /* Initialize the complex series for the mode - notice that metadata used here is useless, only the one for the final output will matter */
446  COMPLEX16FrequencySeries* mode = XLALCreateCOMPLEX16FrequencySeries("mode hlm", &tC, 0.0, deltaF, &lalStrainUnit, nbpt);
447  memset(mode->data->data, 0, nbpt * sizeof(COMPLEX16));
448  /* Setup 1d cubic spline for the phase and amplitude of the mode */
449  gsl_interp_accel* accel_phi = gsl_interp_accel_alloc();
450  gsl_interp_accel* accel_amp = gsl_interp_accel_alloc();
451  gsl_spline* spline_phi = gsl_spline_alloc(gsl_interp_cspline, nbfreq);
452  gsl_spline* spline_amp = gsl_spline_alloc(gsl_interp_cspline, nbfreq);
453  gsl_spline_init(spline_phi, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(phi_f,0), nbfreq);
454  gsl_spline_init(spline_amp, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(amp_f,0), nbfreq);
455  /* Interval in frequency covered by the ROM */
456  REAL8 fLow_geom_mode = gsl_vector_get(freq_ds, 0);
457  REAL8 fHigh_geom_mode = fmin(gsl_vector_get(freq_ds, nbfreq-1), fHigh_geom);
458  /* Initialize the loop - values outside this range in j are 0 by default */
459  INT4 jStart = (UINT4) ceil(fLow_geom_mode / deltaF_geom);
460  INT4 jStop = (UINT4) ceil(fHigh_geom_mode / deltaF_geom);
461  COMPLEX16 *modedata = mode->data->data;
462  /* Mode-dependent complete amplitude prefactor */
463  REAL8 amp_pre = amp0 * ModeAmpFactor( l, m, q);
464  /* Loop on the frequency samples chosen to evaluate the waveform */
465  /* We set apart the first and last step to avoid falling outside of the range of the splines by numerical errors */
466  REAL8 f, A, phase;
467 
468  f = fmax(fLow_geom_mode, jStart*deltaF_geom);
469  A = gsl_spline_eval(spline_amp, f, accel_amp);
470  phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */
471  modedata[jStart] = amp_pre * A * cexp(I*phase);
472 
473  for (j=jStart+1; j<jStop-1; j++) {
474  f = j*deltaF_geom;
475  A = gsl_spline_eval(spline_amp, f, accel_amp);
476  phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */
477  modedata[j] = amp_pre * A * cexp(I*phase);
478  }
479 
480  f = fmin(fHigh_geom_mode, (jStop-1)*deltaF_geom);
481  A = gsl_spline_eval(spline_amp, f, accel_amp);
482  phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */
483  modedata[jStop-1] = amp_pre * A * cexp(I*phase);
484 
485  /* Add the computed mode to the SphHarmFrequencySeries structure */
486  *hlmsphharmfreqseries = XLALSphHarmFrequencySeriesAddMode(*hlmsphharmfreqseries, mode, l, m);
487 
488  /* Cleanup for the mode */
489  gsl_spline_free(spline_amp);
490  gsl_spline_free(spline_phi);
491  gsl_interp_accel_free(accel_amp);
492  gsl_interp_accel_free(accel_phi);
493  gsl_vector_free(amp_f);
494  gsl_vector_free(phi_f);
495  gsl_vector_free(freq_ds);
497 
498  }
499  /* Cleanup of the coefficients data structure */
500  EOBNRHMROMdata_coeff_Cleanup(data_coeff);
501 
502  /* Combining the modes for a hplus, hcross output */
503  /* Initialize the complex series hplus, hcross */
504  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, nbpt);
505  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, nbpt);
506 
507  if (!(hptilde) || !(*hctilde)) XLAL_ERROR(XLAL_EFUNC);
508  memset((*hptilde)->data->data, 0, nbpt * sizeof(COMPLEX16));
509  memset((*hctilde)->data->data, 0, nbpt * sizeof(COMPLEX16));
510 
511  XLALUnitDivide(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
512  XLALUnitDivide(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
513 
514  /* Adding the modes to form hplus, hcross
515  * - use of a function that copies XLALSimAddMode but for Fourier domain structures */
516  INT4 sym; /* sym will decide whether to add the -m mode (when equatorial symmetry is present) */
517  for( i=0; i<nbmode; i++){
518  INT4 l = listmode[i][0];
519  INT4 m = listmode[i][1];
520  COMPLEX16FrequencySeries* mode = XLALSphHarmFrequencySeriesGetMode(*hlmsphharmfreqseries, l, m);
521  if ( m==0 ) sym = 0; /* We test for hypothetical m=0 modes */
522  else sym = 1;
523  FDAddMode( *hptilde, *hctilde, mode, inclination, 0., l, m, sym); /* The phase \Phi is set to 0 - assumes phiRef is defined as half the phase of the 22 mode h22 (or the first mode in the list), not for h = hplus-I hcross */
524  }
525 
526  /* Destroying the list of frequency series for the modes, including the COMPLEX16FrequencySeries that it contains */
527  XLALDestroySphHarmFrequencySeries(*hlmsphharmfreqseries);
528  XLALFree(hlmsphharmfreqseries);
529 
530  /* Additional complex conjugation of hptilde, hctilde - due to the difference in convention for the Fourier transform between LAL and the ROM internals */
531  COMPLEX16* datap = (*hptilde)->data->data;
532  COMPLEX16* datac = (*hctilde)->data->data;
533  for ( j = 0; j < (INT4) (*hptilde)->data->length; ++j ) {
534  datap[j] = conj(datap[j]);
535  }
536  for ( j = 0; j < (INT4) (*hctilde)->data->length; ++j ) {
537  datac[j] = conj(datac[j]);
538  }
539 
540  return(ret);
541 }
542 
543 /* Setup EOBNRv2HMROM model using data files installed in $LAL_DATA_PATH */
546 
547  INT4 ret=XLAL_FAILURE;
548  char *envpath=NULL;
549  char path[32768];
550  char *brkt,*word;
551  envpath=getenv("LAL_DATA_PATH");
552  if(!envpath) {
553  XLALPrintError("XLAL Error: the environment variable LAL_DATA_PATH, giving the path to the ROM data, seems undefined\n");
554  return(XLAL_FAILURE);
555  }
556  strncpy(path,envpath,sizeof(path)-1);
557 
558  for(word=strtok_r(path,":",&brkt); word; word=strtok_r(NULL,":",&brkt))
559  {
560  ret = EOBNRv2HMROM_Init(word);
561  if(ret == XLAL_SUCCESS) break;
562  }
563  if(ret!=XLAL_SUCCESS) {
564  XLALPrintError("Unable to find EOBNRv2HMROM data files in $LAL_DATA_PATH\n");
565  exit(XLAL_FAILURE);
566  }
568  return(ret);
569 }
570 
571 /* Setup EOBNRv2HMROM model using data files installed in dir */
572 static INT4 EOBNRv2HMROM_Init(const char dir[]) {
574  XLALPrintError("Error: EOBNRHMROMdata was already set up!");
576  }
577 
578  INT4 ret = XLAL_SUCCESS;
581 
582  for (UINT4 j=0; j<EOBNRV2_ROM_NUM_MODES_MAX; j++) {
583 
584  EOBNRHMROMdata* data = NULL;
586  ret |= Read_Data_Mode( dir, listmode[j], data);
587  if (!ret) {
588  listdata = ListmodesEOBNRHMROMdata_AddModeNoCopy( listdata, data, listmode[j][0], listmode[j][1]);
589 
590  EOBNRHMROMdata_interp* data_interp = NULL;
591  EOBNRHMROMdata_interp_Init(&data_interp);
592  ret |= Interpolate_Spline_Data(data, data_interp);
593  if (!ret) listdata_interp = ListmodesEOBNRHMROMdata_interp_AddModeNoCopy( listdata_interp, data_interp, listmode[j][0], listmode[j][1]);
594  }
595  }
596 
598  if (!ret) {
599  *__lalsim_EOBNRv2HMROM_data = listdata;
600  *__lalsim_EOBNRv2HMROM_interp = listdata_interp;
601  }
602  return(ret);
603 }
604 
605 
606 /******************************************************************************************/
607 /****************************** Waveform generation function ******************************/
608 
609 /* Compute waveform in LAL format */
611  struct tagCOMPLEX16FrequencySeries **hptilde, /* Output: Frequency-domain waveform h+ */
612  struct tagCOMPLEX16FrequencySeries **hctilde, /* Output: Frequency-domain waveform hx */
613  REAL8 phiRef, /* Half-phase of the 22 mode (~orbital phase) at reference frequency */
614  REAL8 deltaF, /* Sampling frequency (Hz) */
615  REAL8 fLow, /* Start frequency (Hz) - 0 defaults to the lowest Mf of the lowest m>=2 mode */
616  REAL8 fHigh, /* End frequency (Hz) - 0 defaults to the highest Mf of the highest m mode */
617  REAL8 fRef, /* Reference frequency (Hz); 0 defaults to fLow */
618  REAL8 distance, /* Distance of source (m) */
619  REAL8 inclination, /* Inclination of source (rad) */
620  REAL8 m1SI, /* Mass of companion 1 (kg) */
621  REAL8 m2SI, /* Mass of companion 2 (kg) */
622  const int higherModesFlag) /* flag to indicate use of higher modes */
623 {
624 
625  /* Set the number of modes depending on whether the user wants higher order modes */
626  if ( higherModesFlag == 0 )
627  {
628  nbmode = 1;
629  }
630  else if ( higherModesFlag == 1 )
631  {
633  }
634  else
635  {
636  XLALPrintError( "Higher mode flag appears to be uninitialised "
637  "(expected 0 or 1, but got %d\n)", higherModesFlag );
639  }
640 
641  /* Get masses in terms of solar mass */
642  REAL8 mass1 = m1SI / LAL_MSUN_SI;
643  REAL8 mass2 = m2SI / LAL_MSUN_SI;
644  REAL8 Mtot = mass1 + mass2;
645  REAL8 q = fmax(mass1/mass2, mass2/mass1); /* Mass-ratio >1 by convention*/
646  REAL8 Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
647 
648  if ( q > q_max ) {
649  XLALPrintError( "XLAL Error - %s: q out of range!\nEOBNRv2HMROM is only available for a mass ratio in the range q <= %g.\n", __func__, q_max);
651  }
652 
653  /* Set up (load and build interpolation) ROM data if not setup already */
655 
656  /* Call the Core function */
657  INT4 retcode = EOBNRv2HMROMCore(hptilde,hctilde,
658  phiRef, deltaF, fLow, fHigh, fRef, distance, inclination, Mtot_sec, q);
659 
660  return(retcode);
661 }
static ListmodesEOBNRHMROMdata **const __lalsim_EOBNRv2HMROM_data
static INT4 EOBNRv2HMROM_Init(const char dir[])
static REAL8 EtaOfq(const REAL8 q)
static const REAL8 q_max
static INT4 __lalsim_EOBNRv2HMROM_setup
static REAL8 DeltaOfq(const REAL8 q)
static double omega22peakOfq(const double q)
static INT4 Evaluate_Spline_Data(const REAL8 q, const EOBNRHMROMdata_interp *data_interp, EOBNRHMROMdata_coeff *data_coeff)
static const REAL8 Mf_ROM_max
static INT4 Interpolate_Spline_Data(const EOBNRHMROMdata *data, EOBNRHMROMdata_interp *data_interp)
static ListmodesEOBNRHMROMdata_interp **const __lalsim_EOBNRv2HMROM_interp
static const REAL8 M_ROM
static INT4 EOBNRv2HMROMCore(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 Mtot_sec, REAL8 q)
static const INT4 listmode[EOBNRV2_ROM_NUM_MODES_MAX][2]
static REAL8 Scaling55(const REAL8 q)
static ListmodesEOBNRHMROMdata_interp * __lalsim_EOBNRv2HMROM_interp_init
static INT4 nbmode
static REAL8 ModeAmpFactor(const INT4 l, const INT4 m, const REAL8 q)
#define EOBNRV2_ROM_NUM_MODES_MAX
static ListmodesEOBNRHMROMdata * __lalsim_EOBNRv2HMROM_data_init
static REAL8 Scaling44(const REAL8 q)
static size_t NextPow2(const size_t n)
static const REAL8 Mf_ROM_min
INT4 XLALSimIMREOBNRv2HMROM(struct tagCOMPLEX16FrequencySeries **hptilde, struct tagCOMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 m1SI, REAL8 m2SI, const int higherModesFlag)
static INT4 EOBNRv2HMROM_Init_LALDATA(void)
C code for structures EOBNRv2HM reduced order model (non-spinning version). See CQG 31 195010,...
static SplineList * SplineList_GetElement(SplineList *const splinelist, const UINT4 i)
static void EOBNRHMROMdata_coeff_Init(EOBNRHMROMdata_coeff **data_coeff)
static ListmodesEOBNRHMROMdata * ListmodesEOBNRHMROMdata_GetMode(ListmodesEOBNRHMROMdata *const list, UINT4 l, INT4 m)
static ListmodesEOBNRHMROMdata_interp * ListmodesEOBNRHMROMdata_interp_AddModeNoCopy(ListmodesEOBNRHMROMdata_interp *appended, EOBNRHMROMdata_interp *data, UINT4 l, INT4 m)
static INT4 FDAddMode(COMPLEX16FrequencySeries *hptilde, COMPLEX16FrequencySeries *hctilde, COMPLEX16FrequencySeries *hlmtilde, REAL8 theta, REAL8 phi, INT4 l, INT4 m, INT4 sym)
static ListmodesEOBNRHMROMdata_interp * ListmodesEOBNRHMROMdata_interp_GetMode(ListmodesEOBNRHMROMdata_interp *const list, UINT4 l, INT4 m)
static INT4 Read_Data_Mode(const char dir[], const INT4 mode[2], EOBNRHMROMdata *data)
static void EOBNRHMROMdata_interp_Init(EOBNRHMROMdata_interp **data_interp)
static void EOBNRHMROMdata_Init(EOBNRHMROMdata **data)
static SplineList * SplineList_AddElementNoCopy(SplineList *appended, gsl_spline *spline, gsl_interp_accel *accel, UINT4 i)
static void EOBNRHMROMdata_coeff_Cleanup(EOBNRHMROMdata_coeff *data_coeff)
static ListmodesEOBNRHMROMdata * ListmodesEOBNRHMROMdata_AddModeNoCopy(ListmodesEOBNRHMROMdata *appended, EOBNRHMROMdata *indata, UINT4 l, INT4 m)
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
#define fprintf
int l
Definition: bh_qnmode.c:135
double i
Definition: bh_ringdown.c:118
sigmaKerr data[0]
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_PC_SI
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
void XLALFree(void *p)
COMPLEX16FrequencySeries * XLALSphHarmFrequencySeriesGetMode(SphHarmFrequencySeries *ts, UINT4 l, INT4 m)
Get the time series of a waveform's (l,m) spherical harmonic mode from a SphHarmFrequencySeries linke...
SphHarmFrequencySeries * XLALSphHarmFrequencySeriesAddMode(SphHarmFrequencySeries *appended, const COMPLEX16FrequencySeries *inmode, UINT4 l, INT4 m)
Prepend a node to a linked list of SphHarmFrequencySeries, or create a new head.
void XLALDestroySphHarmFrequencySeries(SphHarmFrequencySeries *ts)
Delete list from current pointer to the end of the list.
static const INT4 m
static const INT4 q
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitDivide(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_ERROR(...)
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_EINVAL
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
path
COMPLEX16Sequence * data
COMPLEX16 * data
gsl_interp_accel * accel