LALSimulation  5.4.0.1-fe68b98
LALSimIMRSEOBNRv5HMROM.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) 2022 Lorenzo Pompili
4  * Copyright (C) 2019 Michael Puerrer, John Veitch, Roberto Cotesta, Sylvain Marsat
5  * Copyright (C) 2014, 2015, 2016 Michael Puerrer, John Veitch
6  * Reduced Order Model for SEOBNR
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with with program; see the file COPYING. If not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
22  */
23 
24 #ifdef __GNUC__
25 #define UNUSED __attribute__ ((unused))
26 #else
27 #define UNUSED
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <complex.h>
34 #include <time.h>
35 #include <stdbool.h>
36 #include <alloca.h>
37 #include <string.h>
38 #include <libgen.h>
39 
40 
41 #include <gsl/gsl_errno.h>
42 #include <gsl/gsl_bspline.h>
43 #include <gsl/gsl_blas.h>
44 #include <gsl/gsl_min.h>
45 #include <gsl/gsl_spline.h>
46 #include <gsl/gsl_poly.h>
47 #include <lal/Units.h>
48 #include <lal/SeqFactories.h>
49 #include <lal/LALConstants.h>
50 #include <lal/XLALError.h>
51 #include <lal/FrequencySeries.h>
52 #include <lal/Date.h>
53 #include <lal/StringInput.h>
54 #include <lal/Sequence.h>
55 #include <lal/LALStdio.h>
56 #include <lal/FileIO.h>
57 #include <lal/LALSimSphHarmMode.h>
58 #include <lal/LALDatatypes.h>
59 #include <lal/LALSimInspiral.h>
60 #include <lal/AVFactories.h>
61 #include <lal/SphericalHarmonics.h>
63 
64 #define NMODES 7
65 #define f_hyb_ini 0.003
66 #define f_hyb_end 0.004
67 
68 #ifdef LAL_HDF5_ENABLED
69 #include <lal/H5FileIO.h>
70 static const char ROMDataHDF5[] = "SEOBNRv5HMROM_v1.0.hdf5";
71 static const INT4 ROMDataHDF5_VERSION_MAJOR = 1;
72 static const INT4 ROMDataHDF5_VERSION_MINOR = 0;
73 static const INT4 ROMDataHDF5_VERSION_MICRO = 0;
74 static const char ROM22DataHDF5[] = "SEOBNRv5ROM_v1.0.hdf5";
75 static const INT4 ROM22DataHDF5_VERSION_MAJOR = 1;
76 static const INT4 ROM22DataHDF5_VERSION_MINOR = 0;
77 static const INT4 ROM22DataHDF5_VERSION_MICRO = 0;
78 #endif
79 
80 #include <lal/LALSimInspiral.h>
81 #include <lal/LALSimIMR.h>
82 
84 
85 #include <lal/LALConfig.h>
86 #ifdef LAL_PTHREAD_LOCK
87 #include <pthread.h>
88 #endif
89 
90 
91 
92 #ifdef LAL_PTHREAD_LOCK
93 static pthread_once_t SEOBNRv5HMROM_is_initialized = PTHREAD_ONCE_INIT;
94 static pthread_once_t SEOBNRv5ROM_is_initialized = PTHREAD_ONCE_INIT;
95 #endif
96 
97 
98 /*************** mode array definitions ******************/
99 
100 const char mode_array_v5hm[NMODES][3] =
101 {"22",
102 "33",
103 "21",
104 "44",
105 "55",
106 "32",
107 "43"};
108 
109 const UINT4 lmModes_v5hm[NMODES][2] = {{2, 2}, {3, 3}, {2, 1}, {4, 4}, {5, 5}, {3, 2}, {4, 3}};
110 
111 /*************** constant phase shifts ******************/
112 
113 // const REAL8 const_phaseshift_lm_v5hm[NMODES] = {0.,-LAL_PI/2.,LAL_PI/2.,LAL_PI,LAL_PI/2.,0.,-LAL_PI/2.};
114 const REAL8 const_phaseshift_lm_v5hm[NMODES] = {0.,0.,0.,0.,0.,0.,0.};
115 
116 /* This constant phaseshift is coming from the relations between the phase
117 * of the lm mode phi_lm and the orbital phase phi. At leading order phi_lm = -m*phi + c_lm
118 * where c_lm are these constant phaseshift. They can be derived from the PN expression of the modes
119 * see Blanchet, L. Living Rev. Relativ. (2014) 17: 2. https://doi.org/10.12942/lrr-2014-2 Eqs(327-329)
120 */
121 
122 /*************** constant factors used to define fmax for each mode ******************/
123 
124 const REAL8 const_fmax_lm_v5hm[NMODES] = {1.7, 1.55, 1.7, 1.35, 1.25, 1.7, 1.7};
125 
126 /*************** starting geometric frequency 22 mode non-hybridized ROM ***********************/
127 
128 #define Mf_low_22 0.0004925491025543576
129 #define Mf_low_33 (Mf_low_22 * (3.0/2.0))
130 #define Mf_low_21 (Mf_low_22 * (1.0/2.0))
131 #define Mf_low_44 (Mf_low_22 * (4.0/2.0))
132 #define Mf_low_55 (Mf_low_22 * (5.0/2.0))
133 #define Mf_low_32 (Mf_low_22)
134 #define Mf_low_43 (Mf_low_22 * (3.0/2.0))
136 
137 /*************** type definitions ******************/
138 
139 typedef struct tagSEOBNRROMdataDS_coeff
140 {
141  gsl_vector* c_real;
142  gsl_vector* c_imag;
143  gsl_vector* c_phase;
145 
147 {
148  gsl_vector* cvec_real; // Flattened Re(c-mode) projection coefficients
149  gsl_vector* cvec_imag; // Flattened Im(c-mode) projection coefficients
150  gsl_vector* cvec_phase; // Flattened orbital phase projection coefficients
151  gsl_matrix *Breal; // Reduced SVD basis for Re(c-mode)
152  gsl_matrix *Bimag; // Reduced SVD basis for Im(c-mode)
153  gsl_matrix *Bphase; // Reduced SVD basis for orbital phase
154  int nk_cmode; // Number frequency points for c-mode
155  int nk_phase; // Number of frequency points for orbital phase
156  gsl_vector *gCMode; // Sparse frequency points for c-mode
157  gsl_vector *gPhase; // Sparse frequency points for orbital phase
158  gsl_vector *qvec; // B-spline knots in q
159  gsl_vector *chi1vec; // B-spline knots in chi1
160  gsl_vector *chi2vec; // B-spline knots in chi2
161  int ncx, ncy, ncz; // Number of points in q, chi1, chi2
162  double q_bounds[2]; // [q_min, q_max]
163  double chi1_bounds[2]; // [chi1_min, chi1_max]
164  double chi2_bounds[2]; // [chi2_min, chi2_max]
165 };
166 typedef struct tagSEOBNRROMdataDS_submodel SEOBNRROMdataDS_submodel;
167 
168 struct tagSEOBNRROMdataDS
169 {
170  UINT4 setup;
171  SEOBNRROMdataDS_submodel* highf;
172  SEOBNRROMdataDS_submodel* lowf;
173 };
174 typedef struct tagSEOBNRROMdataDS SEOBNRROMdataDS;
175 
176 static SEOBNRROMdataDS __lalsim_SEOBNRv5HMROMDS_data[NMODES];
177 static SEOBNRROMdataDS __lalsim_SEOBNRv5ROMDS_data[1];
178 
179 typedef int (*load_dataPtr)(const char*, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *);
180 
181 typedef struct tagSplineData
182 {
183  gsl_bspline_workspace *bwx;
184  gsl_bspline_workspace *bwy;
185  gsl_bspline_workspace *bwz;
186 } SplineData;
187 
188 typedef struct tagAmpPhaseSplineData
189 {
190  gsl_spline *spline_amp;
191  gsl_spline *spline_phi;
192  gsl_interp_accel *acc_amp;
193  gsl_interp_accel *acc_phi;
194  gsl_vector *f;
196 
197 /**************** Internal functions **********************/
198 
199 UNUSED static bool SEOBNRv5HMROM_IsSetup(UINT4, SEOBNRROMdataDS *romdataset);
200 UNUSED static void SEOBNRv5HMROM_Init_LALDATA(void);
201 UNUSED static void SEOBNRv5ROM_Init_LALDATA(void);
202 UNUSED static int SEOBNRv5HMROM_Init(const char dir[],UINT4, bool, SEOBNRROMdataDS *romdataset);
203 UNUSED static int SEOBNRROMdataDS_Init(SEOBNRROMdataDS *romdata, const char dir[], UINT4, bool);
204 UNUSED static void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata);
205 
207  UNUSED SEOBNRROMdataDS_submodel **submodel,
208  UNUSED const char dir[],
209  UNUSED const char grp_name[],
210  UNUSED UINT4 index_mode,
211  UNUSED bool use_hm
212 );
213 UNUSED static void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel);
214 UNUSED static void SplineData_Destroy(SplineData *splinedata);
215 UNUSED static void SplineData_Init(
216  SplineData **splinedata,
217  int ncx, // Number of points in q + 2
218  int ncy, // Number of points in chi1 + 2
219  int ncz, // Number of points in chi2 + 2
220  const double *qvec, // B-spline knots in q
221  const double *chi1vec, // B-spline knots in chi1
222  const double *chi2vec // B-spline knots in chi2
223 );
224 UNUSED static void AmpPhaseSplineData_Init(
226  const int num_modes
227 );
228 UNUSED static void AmpPhaseSplineData_Destroy(AmpPhaseSplineData **data, const int num_modes);
229 
230 UNUSED static int TaylorF2Amplitude(
231  const double q, // Mass-ration m1/m2 >= 1
232  const double chi1, // Dimensionless aligned spin of body 1
233  const double chi2, // Dimensionless aligned spin of body 2
234  const int l, // First mode number l
235  const int m, // Second mode number m
236  gsl_vector *Mfs, // Input geometric frequencies
237  gsl_vector **PNamp // Output: TaylorF2 amplitude at frequencies Mfs
238 );
239 
240 UNUSED static int TaylorF2Phasing(
241  double Mtot, // Total mass in solar masses
242  double q, // Mass-ration m1/m2 >= 1
243  double chi1, // Dimensionless aligned spin of body 1
244  double chi2, // Dimensionless aligned spin of body 2
245  int l, // First mode number l
246  int m, // Second mode number m
247  gsl_vector *Mfs, // Input geometric frequencies
248  gsl_vector **PNphase // Output: TaylorF2 phase at frequencies Mfs
249 );
250 
251 UNUSED static double GetDeltaphilm(int l, int m);
252 UNUSED static double GetModeAmpFactor(double eta, double delta, double chi1, double chi2, int l, int m, double v);
253 
254 /* Build geom frequency grid suitable for waveform amp/phase interpolation */
255 UNUSED static int BuildInspiralGeomFrequencyGrid(
256  gsl_vector** Mfreq, /* Output: pointer to real vector */
257  const double Mfmin, /* Starting geometric frequency */
258  const double Mfmax, /* Ending geometric frequency */
259  const double q, /* Mass ratio */
260  const double acc); /* Desired phase interpolation error for inspiral */
261 
262 /**
263  * Core function for computing the ROM waveform.
264  * Interpolate projection coefficient data and evaluate coefficients at desired (q, chi).
265  * Construct 1D splines for amplitude and phase.
266  * Compute strain waveform from amplitude and phase.
267 */
268 UNUSED static int SEOBNRv5HMROMCoreModes(
269  SphHarmFrequencySeries **hlm_list, /**< Spherical modes frequency series for the waveform */
270  REAL8 phiRef, /**< Orbital phase at reference time */
271  REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
272  REAL8 distance, /**< Distance of source (m) */
273  REAL8 Mtot_sec, /**< Total mass in seconds **/
274  REAL8 q, /**< Mass ratio **/
275  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
276  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
277  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz) */
278  REAL8 deltaF,
279  /**< If deltaF > 0, the frequency points given in freqs are uniformly spaced with
280  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
281  * Then we will use deltaF = 0 to create the frequency series we return. */
282  INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 */
283  UINT4 nModes, /**< Number of modes to generate */
284  REAL8 sign_odd_modes, /**< Sign of the odd-m modes, used when swapping the two bodies */
285  SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
286 );
287 UNUSED static void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_cmode, int nk_phase);
288 UNUSED static void SEOBNRROMdataDS_coeff_Cleanup(SEOBNRROMdataDS_coeff *romdatacoeff);
289 
290 static size_t NextPow2(const size_t n);
291 static UINT8 Setup_EOBROM__std_mode_array_structure(LALValue *ModeArray, UINT4 nModes);
292 static INT8 Check_EOBROM_mode_array_structure(LALValue *ModeArray,UINT4 nModes);
295  *hplusFS, /**<< Output: frequency series for hplus, already created */
297  *hcrossFS, /**<< Output: frequency series for hplus, already created */
298  LALValue *ModeArray, /**<< Input: ModeArray structure with the modes to include */
300  *hlm, /**<< Input: list with frequency series for each mode hlm */
301  REAL8 inc, /**<< Input: inclination */
302  REAL8 phi /**<< Input: phase */
303 );
304 
305 static int TP_Spline_interpolation_3d(
306  REAL8 q, // Input: eta-value for which projection coefficients should be evaluated
307  REAL8 chi1, // Input: chi1-value for which projection coefficients should be evaluated
308  REAL8 chi2, // Input: chi2-value for which projection coefficients should be evaluated
309  gsl_vector *cvec, // Input: data for spline coefficients
310  int nk, // number of SVD-modes == number of basis functions
311  int nk_max, // truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1
312  int ncx, // Number of points in eta + 2
313  int ncy, // Number of points in chi1 + 2
314  int ncz, // Number of points in chi2 + 2
315  const double *qvec, // B-spline knots in eta
316  const double *chi1vec, // B-spline knots in chi1
317  const double *chi2vec, // B-spline knots in chi2
318  gsl_vector *c_out // Output: interpolated projection coefficients
319 );
320 UNUSED static UINT8 SEOBNRv5HMROM_Select_HF_patch(REAL8 q, REAL8 chi1);
321 UNUSED static UINT8 SEOBNRv5HMROM_phase_sparse_grid(gsl_vector* phase_f, REAL8 q, REAL8 chi1,REAL8 chi2, const char* freq_range, INT4 nk_max, SEOBNRROMdataDS *romdataset);
322 UNUSED static UINT8 SEOBNRv5HMROM_cmode_sparse_grid(gsl_vector* creal_f, gsl_vector* cimag_f, REAL8 q, REAL8 chi1,REAL8 chi2, const char* freq_range, UINT8 nMode,INT4 nk_max,SEOBNRROMdataDS *romdataset);
323 UNUSED static UINT8 SEOBNRv5HMROM_phase_sparse_grid_hybrid(gsl_vector* freq, gsl_vector* phase, gsl_vector* freq_lo, gsl_vector* freq_hi, REAL8 q, REAL8 chi1,REAL8 chi2,INT4 nk_max, SEOBNRROMdataDS *romdataset);
324 UNUSED static UINT8 SEOBNRv5HMROM_cmode_sparse_grid_hybrid(gsl_vector* freq, gsl_vector* cmode_real, gsl_vector* cmode_imag, gsl_vector* freq_lo, gsl_vector* freq_hi, REAL8 q, REAL8 chi1,REAL8 chi2, UINT8 nMode,INT8 nk_max,SEOBNRROMdataDS *romdataset);
325 UNUSED static UINT8 SEOBNRv5HMROM_freq_phase_sparse_grid_hybrid(UNUSED gsl_vector** freq, UNUSED gsl_vector** phase, REAL8 q, REAL8 chi1,REAL8 chi2,INT4 nk_max,SEOBNRROMdataDS *romdataset);
326 UNUSED static UINT8 SEOBNRv5HMROM_freq_cmode_sparse_grid_hybrid(gsl_vector** freq_cmode, gsl_vector** cmode_real, gsl_vector** cmode_imag, REAL8 q, REAL8 chi1,REAL8 chi2, UINT8 nMode,INT8 nk_max, SEOBNRROMdataDS *romdataset);
327 UNUSED static UINT8 SEOBNRv5HMROM_approx_phi_lm(gsl_vector* freq_mode_lm, gsl_vector* phase_approx_lm, gsl_vector* freq_carrier_hyb, gsl_vector* phase_carrier_hyb, UINT4 nMode);
328 
330  gsl_vector **freq, // Output: hybrid frequency array
331  gsl_vector **phase, // Output: hybrid phase
332  REAL8* Deltat_align, // Output: time alignment
333  REAL8* Deltaphi_align, // Output: phase alignment
334  gsl_vector *phase_lo, // low frequency phase
335  gsl_vector *phase_hi, // high frequency phase
336  gsl_vector *freq_lo, // frequency array for low frequency phase
337  gsl_vector *freq_hi, // frequency array for high frequency phase
338  double f_hyb_lo, // start frequency of hybridization window
339  double f_hyb_hi // end frequency of hybridization window
340 );
341 
343  gsl_vector **freq, // Output: hybrid frequency array
344  gsl_vector **phase, // Output: hybrid phase
345  gsl_vector *phase_lo, // low frequency phase
346  gsl_vector *phase_hi, // high frequency phase
347  gsl_vector *freq_lo, // frequency array for low frequency phase
348  gsl_vector *freq_hi, // frequency array for high frequency phase
349  double f_hyb_lo, // start frequency of hybridization window
350  double f_hyb_hi, // end frequency of hybridization window
351  REAL8 Deltat_22_align, // Input: 22 time alignment
352  REAL8 Deltaphi_22_align, // Input: 22 phase alignment
353  INT4 modeM // Input: m mode number
354 );
355 
357  gsl_vector **freq, // Output: hybrid frequency array
358  gsl_vector **amp, // Output: hybrid amplitude
359  gsl_vector *amp_lo, // low frequency amplitude
360  gsl_vector *amp_hi, // high frequency amplitude
361  gsl_vector *freq_lo, // frequency array for low frequency amplitude
362  gsl_vector *freq_hi, // frequency array for high frequency amplitude
363  double f_hyb_lo, // start frequency of hybridization window
364  double f_hyb_hi // end frequency of hybridization window
365 );
366 
367 UNUSED static int hybridize_ROM_with_PN_amplitude(
368  gsl_spline **hyb_spline, /**< Output: spline */
369  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
370  gsl_vector *PN_freq, /**< PN frequency */
371  gsl_vector *PN_amp, /**< PN amplitude */
372  double f_hyb_win_lo, /**< hybridization window start */
373  double f_hyb_win_hi /**< hybridization window end */
374 );
375 
377  gsl_spline **hyb_spline, /**< Output: spline */
378  REAL8* Deltat_align, /**< Output: time alignment */
379  REAL8* Deltaphi_align, /**< Output: phase alignment */
380  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
381  gsl_vector *PN_freq, /**< PN frequency */
382  gsl_vector *PN_phase, /**< PN phase */
383  double f_hyb_win_lo, /**< hybridization window start */
384  double f_hyb_win_hi /**< hybridization window end */
385 );
386 
388  gsl_spline **hyb_spline, /**< Output: spline */
389  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
390  gsl_vector *PN_freq, /**< PN frequency */
391  gsl_vector *PN_phase, /**< PN phase */
392  double f_hyb_win_lo, /**< hybridization window start */
393  double f_hyb_win_hi, /**< hybridization window end */
394  REAL8 Deltat_22_align, /**< Input: 22 time alignment */
395  REAL8 Deltaphi_22_align, /**< Input: 22 phase alignment */
396  INT4 modeM /**< Input: m mode number */
397 );
398 
399 UNUSED static int SEOBNRv5HMROMCoreModeAmpPhaseSplines(
400  UNUSED AmpPhaseSplineData **ampPhaseSplineData, /**<< Output: amplitude and phase splines for the modes */
401  UNUSED REAL8 q, /**< Mass ratio **/
402  UNUSED REAL8 chi1, /**< Dimensionless aligned component spin 1 */
403  UNUSED REAL8 chi2, /**< Dimensionless aligned component spin 2 */
404  UNUSED INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 (default). */
405  UNUSED UINT4 nModes, /**< Number of modes to generate */
406  UNUSED SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
407 );
408 
409 UNUSED static int SEOBNRv5HMROMCoreModesHybridized(
410  UNUSED SphHarmFrequencySeries **hlm_list, /**<< Output: Spherical modes frequency series for the waveform */
411  UNUSED REAL8 phiRef, /**<< orbital reference phase */
412  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
413  UNUSED REAL8 distance, /**< Distance of source (m) */
414  UNUSED REAL8 Mtot_sec, /**< Total mass in seconds **/
415  UNUSED REAL8 q, /**< Mass ratio **/
416  UNUSED REAL8 chi1, /**< Dimensionless aligned component spin 1 */
417  UNUSED REAL8 chi2, /**< Dimensionless aligned component spin 2 */
418  UNUSED const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */
419  UNUSED REAL8 deltaF, /**< Frequency points at which to evaluate the waveform (Hz) */
420  UNUSED INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1. We
421  *nk_max == -1 is the default setting */
422  UNUSED UINT4 nModes, /**< Number of modes to generate */
423  REAL8 sign_odd_modes, /**< Sign of the odd-m modes, used when swapping the two bodies */
424  UNUSED SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
425 );
426 
427 UNUSED static int SEOBNRv5ROMTimeFrequencySetup(
428  gsl_spline **spline_phi, // phase spline
429  gsl_interp_accel **acc_phi, // phase spline accelerator
430  REAL8 *Mf_final, // ringdown frequency in Mf
431  REAL8 *Mtot_sec, // total mass in seconds
432  REAL8 m1SI, // Mass of companion 1 (kg)
433  REAL8 m2SI, // Mass of companion 2 (kg)
434  REAL8 chi1, // Aligned spin of companion 1
435  REAL8 chi2, // Aligned spin of companion 2
436  REAL8 Mf_start, // Starting geometric frequency
437  REAL8 *Mf_ROM_min, // Lowest geometric frequency for ROM
438  REAL8 *Mf_ROM_max // Highest geometric frequency for ROM
439 );
440 
441 UNUSED static int spline_to_gsl_vectors(gsl_spline *s, gsl_vector **x, gsl_vector **y);
442 
443 /********************* Definitions begin here ********************/
444 
445 
446 UNUSED static int spline_to_gsl_vectors(gsl_spline *s, gsl_vector **x, gsl_vector **y) {
447  if ((*x) || (*y))
449 
450  *x = gsl_vector_alloc(s->size);
451  *y = gsl_vector_alloc(s->size);
452  for (size_t i=0; i < s->size; i++) {
453  gsl_vector_set(*x, i, s->x[i]);
454  gsl_vector_set(*y, i, s->y[i]);
455  }
456 
457  return(XLAL_SUCCESS);
458 }
459 
460 
461 /** Setup SEOBNRv5HMROM model using data files installed in $LAL_DATA_PATH
462  */
463 UNUSED static void SEOBNRv5HMROM_Init_LALDATA(void)
464 {
465  // Loop over all the available modes and check if they have already been initialized
466  for(int i = 0; i < NMODES; i++) {
468  }
469 
470  // Expect ROM datafile in a directory listed in LAL_DATA_PATH,
471 #ifdef LAL_HDF5_ENABLED
472 #define datafile ROMDataHDF5
473  char *path = XLAL_FILE_RESOLVE_PATH(datafile);
474  if (path==NULL){
475  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile);
476  }
477  char *dir = dirname(path);
478 
479  UINT4 ret = XLAL_SUCCESS;
480  bool use_hm = true;
481  for(int i = 0; i < NMODES; i++) {
483  if(ret != XLAL_SUCCESS)
484  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find SEOBNRv5HMROM data \
485  files in $LAL_DATA_PATH for the mode = %d\n", i);
486  }
487  XLALFree(path);
488 #else
489  XLAL_ERROR_VOID(XLAL_EFAILED, "SEOBNRv5HMROM requires HDF5 support which is not enabled\n");
490 #endif
491 }
492 
493 /** Setup SEOBNRv5ROM model using data files installed in $LAL_DATA_PATH
494  */
495 UNUSED static void SEOBNRv5ROM_Init_LALDATA(void)
496 {
497  // Loop over all the available modes and check if they have already been initialized
498  for(int i = 0; i < 1; i++) {
500  }
501 
502  // Expect ROM datafile in a directory listed in LAL_DATA_PATH,
503 #ifdef LAL_HDF5_ENABLED
504 #define datafile22 ROM22DataHDF5
505  char *path = XLAL_FILE_RESOLVE_PATH(datafile22);
506  if (path==NULL){
507  XLAL_ERROR_VOID(XLAL_EIO, "Unable to resolve data file %s in $LAL_DATA_PATH\n", datafile22);
508  }
509  char *dir = dirname(path);
510 
511  UINT4 ret = XLAL_SUCCESS;
512  bool use_hm = false;
513  for(int i = 0; i < 1; i++) {
514  ret = SEOBNRv5HMROM_Init(dir, i, use_hm, __lalsim_SEOBNRv5ROMDS_data);
515  if(ret != XLAL_SUCCESS)
516  XLAL_ERROR_VOID(XLAL_FAILURE, "Unable to find SEOBNRv5ROM data \
517  files in $LAL_DATA_PATH for the mode = %d\n", i);
518  }
519  XLALFree(path);
520 #else
521  XLAL_ERROR_VOID(XLAL_EFAILED, "SEOBNRv5ROM requires HDF5 support which is not enabled\n");
522 #endif
523 }
524 
525 /** Helper function to check if the SEOBNRv5HMROM model has been initialised */
526 static bool SEOBNRv5HMROM_IsSetup(UINT4 index_mode, SEOBNRROMdataDS *romdataset) {
527  if(romdataset[index_mode].setup){
528  return true;
529  }
530  else{
531  return false;
532  }
533 }
534 
535 // Setup B-spline basis functions for given points
536 static void SplineData_Init(
537  SplineData **splinedata,
538  int ncx, // Number of points in q + 2
539  int ncy, // Number of points in chi1 + 2
540  int ncz, // Number of points in chi2 + 2
541  const double *qvec, // B-spline knots in q
542  const double *chi1vec, // B-spline knots in chi1
543  const double *chi2vec // B-spline knots in chi2
544 )
545 {
546  if(!splinedata) exit(1);
547  if(*splinedata) SplineData_Destroy(*splinedata);
548 
549  (*splinedata)=XLALCalloc(1,sizeof(SplineData));
550 
551  // Set up B-spline basis for desired knots
552  const size_t nbreak_x = ncx-2; // must have nbreak = n-2 for cubic splines
553  const size_t nbreak_y = ncy-2; // must have nbreak = n-2 for cubic splines
554  const size_t nbreak_z = ncz-2; // must have nbreak = n-2 for cubic splines
555 
556  // Allocate a cubic bspline workspace (k = 4)
557  gsl_bspline_workspace *bwx = gsl_bspline_alloc(4, nbreak_x);
558  gsl_bspline_workspace *bwy = gsl_bspline_alloc(4, nbreak_y);
559  gsl_bspline_workspace *bwz = gsl_bspline_alloc(4, nbreak_z);
560 
561  // Set breakpoints (and thus knots by hand)
562  gsl_vector *breakpts_x = gsl_vector_alloc(nbreak_x);
563  gsl_vector *breakpts_y = gsl_vector_alloc(nbreak_y);
564  gsl_vector *breakpts_z = gsl_vector_alloc(nbreak_z);
565  for (UINT4 i=0; i<nbreak_x; i++)
566  gsl_vector_set(breakpts_x, i, qvec[i]);
567  for (UINT4 j=0; j<nbreak_y; j++)
568  gsl_vector_set(breakpts_y, j, chi1vec[j]);
569  for (UINT4 k=0; k<nbreak_z; k++)
570  gsl_vector_set(breakpts_z, k, chi2vec[k]);
571 
572  gsl_bspline_knots(breakpts_x, bwx);
573  gsl_bspline_knots(breakpts_y, bwy);
574  gsl_bspline_knots(breakpts_z, bwz);
575 
576  gsl_vector_free(breakpts_x);
577  gsl_vector_free(breakpts_y);
578  gsl_vector_free(breakpts_z);
579 
580  (*splinedata)->bwx=bwx;
581  (*splinedata)->bwy=bwy;
582  (*splinedata)->bwz=bwz;
583 }
584 
585 /* Destroy B-spline basis functions for given points */
586 static void SplineData_Destroy(SplineData *splinedata)
587 {
588  if(!splinedata) return;
589  if(splinedata->bwx) gsl_bspline_free(splinedata->bwx);
590  if(splinedata->bwy) gsl_bspline_free(splinedata->bwy);
591  if(splinedata->bwz) gsl_bspline_free(splinedata->bwz);
592  XLALFree(splinedata);
593 }
594 
595 // Allocate memory for an array of AmpPhaseSplineData structs to store all modes
597  AmpPhaseSplineData ***data_array,
598  const int num_modes
599 )
600 {
601  if(*data_array != NULL) AmpPhaseSplineData_Destroy(*data_array, num_modes);
602 
603  *data_array = XLALCalloc(num_modes, sizeof(AmpPhaseSplineData));
604 
605  for (int i=0; i<num_modes; i++) {
606  // The elements of the AmpPhaseSplineData structs will be allocated elsewhere.
607  (*data_array)[i] = XLALCalloc(1, sizeof(AmpPhaseSplineData));
608  }
609 }
610 
611 static void AmpPhaseSplineData_Destroy(AmpPhaseSplineData **data_array, const int num_modes)
612 {
613  if(!data_array) return;
614 
615  AmpPhaseSplineData* data = NULL;
616  for (int i=0; i<num_modes; i++) {
617  data = data_array[i];
618  if (!data)
619  continue;
620  else {
621  if (data->spline_amp) gsl_spline_free(data->spline_amp);
622  if (data->spline_phi) gsl_spline_free(data->spline_phi);
623  if (data->acc_amp) gsl_interp_accel_free(data->acc_amp);
624  if (data->acc_phi) gsl_interp_accel_free(data->acc_phi);
625  if (data->f) gsl_vector_free(data->f);
626  XLALFree(data);
627  }
628  }
629  XLALFree(data_array);
630 }
631 
632 
633 // Interpolate projection coefficients for either Re(c-mode), Im(c-mode) or orbital phase over the parameter space (q, chi).
634 // The multi-dimensional interpolation is carried out via a tensor product decomposition.
636  REAL8 q, // Input: eta-value for which projection coefficients should be evaluated
637  REAL8 chi1, // Input: chi1-value for which projection coefficients should be evaluated
638  REAL8 chi2, // Input: chi2-value for which projection coefficients should be evaluated
639  gsl_vector *cvec, // Input: data for spline coefficients
640  int nk, // number of SVD-modes == number of basis functions
641  int nk_max, // truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1
642  int ncx, // Number of points in eta + 2
643  int ncy, // Number of points in chi1 + 2
644  int ncz, // Number of points in chi2 + 2
645  const double *qvec, // B-spline knots in eta
646  const double *chi1vec, // B-spline knots in chi1
647  const double *chi2vec, // B-spline knots in chi2
648  gsl_vector *c_out // Output: interpolated projection coefficients
649  ) {
650  if (nk_max != -1) {
651  if (nk_max > nk)
652  XLAL_ERROR(XLAL_EDOM, "Truncation parameter nk_max %d must be smaller or equal to nk %d\n", nk_max, nk);
653  else { // truncate SVD modes
654  nk = nk_max;
655  }
656  }
657 
658  SplineData *splinedata=NULL;
659  SplineData_Init(&splinedata, ncx, ncy, ncz, qvec, chi1vec, chi2vec);
660 
661  gsl_bspline_workspace *bwx=splinedata->bwx;
662  gsl_bspline_workspace *bwy=splinedata->bwy;
663  gsl_bspline_workspace *bwz=splinedata->bwz;
664 
665  int N = ncx*ncy*ncz; // Size of the data matrix for one SVD-mode
666  // Evaluate the TP spline for all SVD modes - amplitude
667  for (int k=0; k<nk; k++) { // For each SVD mode
668  gsl_vector v = gsl_vector_subvector(cvec, k*N, N).vector; // Pick out the coefficient matrix corresponding to the k-th SVD mode.
669  REAL8 csum = Interpolate_Coefficent_Tensor(&v, q, chi1, chi2, ncy, ncz, bwx, bwy, bwz);
670  gsl_vector_set(c_out, k, csum);
671  }
672  SplineData_Destroy(splinedata);
673 
674  return(0);
675 }
676 
677 /** Setup SEOBNRv5HMROM mode using data files installed in dir
678  */
679 static int SEOBNRv5HMROM_Init(const char dir[],UINT4 index_mode, bool use_hm, SEOBNRROMdataDS *romdataset) {
680  if(romdataset[index_mode].setup) {
681  XLALPrintError("Error: SEOBNRv5HMROM data was already set up!");
683  }
684  SEOBNRROMdataDS_Init(&romdataset[index_mode], dir, index_mode, use_hm);
685 
686  if(romdataset[index_mode].setup) {
687  return(XLAL_SUCCESS);
688  }
689  else {
690  return(XLAL_EFAILED);
691  }
692  return(XLAL_SUCCESS);
693 }
694 
695 /* Set up a new ROM mode, using data contained in dir */
697  UNUSED SEOBNRROMdataDS *romdata,
698  UNUSED const char dir[],
699  UNUSED UINT4 index_mode,
700  UNUSED bool use_hm
701  )
702 {
703  int ret = XLAL_FAILURE;
704 
705  /* Create storage for structures */
706  if(romdata->setup) {
707  XLALPrintError("WARNING: You tried to setup the SEOBNRv5HMROM model that was already initialised. Ignoring\n");
708  return (XLAL_FAILURE);
709  }
710 
711 #ifdef LAL_HDF5_ENABLED
712  // First, check we got the correct version number
713  size_t size;
714  if (use_hm == true){
715  size = strlen(dir) + strlen(ROMDataHDF5) + 2;
716  }
717  else{
718  size = strlen(dir) + strlen(ROM22DataHDF5) + 2;
719  }
720  char *path = XLALMalloc(size);
721  if (use_hm == true){
722  snprintf(path, size, "%s/%s", dir, ROMDataHDF5);
723  }
724  else{
725  snprintf(path, size, "%s/%s", dir, ROM22DataHDF5);
726  }
728 
729  XLALPrintInfo("ROM metadata\n============\n");
730  if (use_hm == true){
731  PrintInfoStringAttribute(file, "Email");
732  PrintInfoStringAttribute(file, "Description");
733  ret = ROM_check_version_number(file, ROMDataHDF5_VERSION_MAJOR,
734  ROMDataHDF5_VERSION_MINOR,
735  ROMDataHDF5_VERSION_MICRO);
736  ret = ROM_check_canonical_file_basename(file,ROMDataHDF5,"CANONICAL_FILE_BASENAME");
737  }
738  else{
739  PrintInfoStringAttribute(file, "Email");
740  PrintInfoStringAttribute(file, "Description");
741  ret = ROM_check_version_number(file, ROM22DataHDF5_VERSION_MAJOR,
742  ROM22DataHDF5_VERSION_MINOR,
743  ROM22DataHDF5_VERSION_MICRO);
744  ret = ROM_check_canonical_file_basename(file,ROM22DataHDF5,"CANONICAL_FILE_BASENAME");
745  }
746 
747  ret |= SEOBNRROMdataDS_Init_submodel(&(romdata)->highf, dir, "highf",index_mode,use_hm);
748  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel high freqs loaded sucessfully.\n", __func__);
749 
750  ret |= SEOBNRROMdataDS_Init_submodel(&(romdata)->lowf, dir, "lowf",index_mode,use_hm);
751  if (ret==XLAL_SUCCESS) XLALPrintInfo("%s : submodel low freqs loaded sucessfully.\n", __func__);
752 
753 
754  if(XLAL_SUCCESS==ret){
755  romdata->setup=1;
756  }
757  else
758  SEOBNRROMdataDS_Cleanup(romdata);
759 
760  XLALFree(path);
762  ret = XLAL_SUCCESS;
763 
764 #else
765  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
766 #endif
767 
768  return (ret);
769 }
770 
771 /* Deallocate contents of the given SEOBNRROMdataDS structure */
772 static void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata) {
773  SEOBNRROMdataDS_Cleanup_submodel((romdata)->highf);
774  XLALFree((romdata)->highf);
775  (romdata)->highf = NULL;
776  SEOBNRROMdataDS_Cleanup_submodel((romdata)->lowf);
777  XLALFree((romdata)->lowf);
778  (romdata)->lowf = NULL;
779  romdata->setup=0;
780 }
781 
782 /* Deallocate contents of the given SEOBNRROMdataDS_submodel structure */
783 static void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel) {
784  if(submodel->cvec_real) gsl_vector_free(submodel->cvec_real);
785  if(submodel->cvec_imag) gsl_vector_free(submodel->cvec_imag);
786  if(submodel->cvec_phase) gsl_vector_free(submodel->cvec_phase);
787  if(submodel->Breal) gsl_matrix_free(submodel->Breal);
788  if(submodel->Bimag) gsl_matrix_free(submodel->Bimag);
789  if(submodel->Bphase) gsl_matrix_free(submodel->Bphase);
790  if(submodel->gCMode) gsl_vector_free(submodel->gCMode);
791  if(submodel->gPhase) gsl_vector_free(submodel->gPhase);
792  if(submodel->qvec) gsl_vector_free(submodel->qvec);
793  if(submodel->chi1vec) gsl_vector_free(submodel->chi1vec);
794  if(submodel->chi2vec) gsl_vector_free(submodel->chi2vec);
795 }
796 
797 /* Set up a new ROM submodel, using data contained in dir */
799  SEOBNRROMdataDS_submodel **submodel,
800  UNUSED const char dir[],
801  UNUSED const char grp_name[],
802  UNUSED UINT4 index_mode,
803  UNUSED bool use_hm
804 ) {
805  int ret = XLAL_FAILURE;
806  if(!submodel) exit(1);
807  /* Create storage for submodel structures */
808  if (!*submodel)
809  *submodel = XLALCalloc(1,sizeof(SEOBNRROMdataDS_submodel));
810  else
812 
813 #ifdef LAL_HDF5_ENABLED
814  size_t size;
815  if (use_hm == true){
816  size = strlen(dir) + strlen(ROMDataHDF5) + 2;
817  }
818  else{
819  size = strlen(dir) + strlen(ROM22DataHDF5) + 2;
820  }
821  char *path = XLALMalloc(size);
822  if (use_hm == true){
823  snprintf(path, size, "%s/%s", dir, ROMDataHDF5);
824  }
825  else{
826  snprintf(path, size, "%s/%s", dir, ROM22DataHDF5);
827  }
828 
830  LALH5File *sub = XLALH5GroupOpen(file, grp_name);
831 
832  // Read ROM coefficients
833 
834  //// c-modes coefficients
835  char* path_to_dataset = concatenate_strings(3,"CF_modes/",mode_array_v5hm[index_mode],"/coeff_re_flattened");
836  ReadHDF5RealVectorDataset(sub, path_to_dataset, & (*submodel)->cvec_real);
837  free(path_to_dataset);
838  path_to_dataset = concatenate_strings(3,"CF_modes/",mode_array_v5hm[index_mode],"/coeff_im_flattened");
839  ReadHDF5RealVectorDataset(sub, path_to_dataset, & (*submodel)->cvec_imag);
840  free(path_to_dataset);
841  //// orbital phase coefficients
842  //// They are used only in the 22 mode
843  if(index_mode == 0){
844  ReadHDF5RealVectorDataset(sub, "phase_carrier/coeff_flattened", & (*submodel)->cvec_phase);
845  }
846 
847 
848  // Read ROM basis functions
849 
850  //// c-modes basis
851  path_to_dataset = concatenate_strings(3,"CF_modes/",mode_array_v5hm[index_mode],"/basis_re");
852  ReadHDF5RealMatrixDataset(sub, path_to_dataset, & (*submodel)->Breal);
853  free(path_to_dataset);
854  path_to_dataset = concatenate_strings(3,"CF_modes/",mode_array_v5hm[index_mode],"/basis_im");
855  ReadHDF5RealMatrixDataset(sub, path_to_dataset, & (*submodel)->Bimag);
856  free(path_to_dataset);
857  //// orbital phase basis
858  //// Used only in the 22 mode
859  if(index_mode == 0){
860  ReadHDF5RealMatrixDataset(sub, "phase_carrier/basis", & (*submodel)->Bphase);
861  }
862  // Read sparse frequency points
863 
864  //// c-modes grid
865  path_to_dataset = concatenate_strings(3,"CF_modes/",mode_array_v5hm[index_mode],"/MF_grid");
866  ReadHDF5RealVectorDataset(sub, path_to_dataset, & (*submodel)->gCMode);
867  free(path_to_dataset);
868  //// orbital phase grid
869  //// Used only in the 22 mode
870  if(index_mode == 0){
871  ReadHDF5RealVectorDataset(sub, "phase_carrier/MF_grid", & (*submodel)->gPhase);
872  }
873  // Read parameter space nodes
874  ReadHDF5RealVectorDataset(sub, "qvec", & (*submodel)->qvec);
875  ReadHDF5RealVectorDataset(sub, "chi1vec", & (*submodel)->chi1vec);
876  ReadHDF5RealVectorDataset(sub, "chi2vec", & (*submodel)->chi2vec);
877 
878 
879  // Initialize other members
880  (*submodel)->nk_cmode = (*submodel)->gCMode->size;
881  //// Used only in the 22 mode
882  if(index_mode == 0){
883  (*submodel)->nk_phase = (*submodel)->gPhase->size;
884  }
885  (*submodel)->ncx = (*submodel)->qvec->size + 2;
886  (*submodel)->ncy = (*submodel)->chi1vec->size + 2;
887  (*submodel)->ncz = (*submodel)->chi2vec->size + 2;
888 
889  // Domain of definition of submodel
890  (*submodel)->q_bounds[0] = gsl_vector_get((*submodel)->qvec, 0);
891  (*submodel)->q_bounds[1] = gsl_vector_get((*submodel)->qvec, (*submodel)->qvec->size - 1);
892  (*submodel)->chi1_bounds[0] = gsl_vector_get((*submodel)->chi1vec, 0);
893  (*submodel)->chi1_bounds[1] = gsl_vector_get((*submodel)->chi1vec, (*submodel)->chi1vec->size - 1);
894  (*submodel)->chi2_bounds[0] = gsl_vector_get((*submodel)->chi2vec, 0);
895  (*submodel)->chi2_bounds[1] = gsl_vector_get((*submodel)->chi2vec, (*submodel)->chi2vec->size - 1);
896 
897  XLALFree(path);
899  XLALH5FileClose(sub);
900  ret = XLAL_SUCCESS;
901 #else
902  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
903 #endif
904 
905  return ret;
906 }
907 
908 /* Create structure for internal use to store coefficients for orbital phase and real/imaginary part of co-orbital modes */
909 static void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_cmode, int nk_phase) {
910  if(!romdatacoeff) exit(1);
911  /* Create storage for structures */
912  if(!*romdatacoeff)
913  *romdatacoeff=XLALCalloc(1,sizeof(SEOBNRROMdataDS_coeff));
914  else
915  SEOBNRROMdataDS_coeff_Cleanup(*romdatacoeff);
916 
917  (*romdatacoeff)->c_real = gsl_vector_alloc(nk_cmode);
918  (*romdatacoeff)->c_imag = gsl_vector_alloc(nk_cmode);
919  (*romdatacoeff)->c_phase = gsl_vector_alloc(nk_phase);
920 }
921 
922 /* Deallocate contents of the given SEOBNRROMdataDS_coeff structure */
924  if(romdatacoeff->c_real) gsl_vector_free(romdatacoeff->c_real);
925  if(romdatacoeff->c_imag) gsl_vector_free(romdatacoeff->c_imag);
926  if(romdatacoeff->c_phase) gsl_vector_free(romdatacoeff->c_phase);
927  XLALFree(romdatacoeff);
928 }
929 /* Return the closest higher power of 2 */
930 // Note: NextPow(2^k) = 2^k for integer values k.
931 static size_t NextPow2(const size_t n) {
932  return 1 << (size_t) ceil(log2(n));
933 }
934 /* This function returns the orbital phase in the sparse grid hybridized between LF and HF ROM */
935 UNUSED static UINT8 SEOBNRv5HMROM_phase_sparse_grid_hybrid(gsl_vector* freq, gsl_vector* phase, gsl_vector* freq_lo, gsl_vector* freq_hi, REAL8 q, REAL8 chi1,REAL8 chi2,INT4 nk_max, SEOBNRROMdataDS *romdataset){
936 
937  gsl_vector *phase_f_lo = gsl_vector_alloc(freq_lo->size);
938  gsl_vector *phase_f_hi = gsl_vector_alloc(freq_hi->size);
939 
940  /* Get LF and HF orbital phase */
941  UNUSED UINT8 retcode = SEOBNRv5HMROM_phase_sparse_grid(phase_f_lo,q,chi1,chi2, "LF",nk_max, romdataset);
942  retcode = SEOBNRv5HMROM_phase_sparse_grid(phase_f_hi,q,chi1,chi2, "HF",nk_max, romdataset);
943 
944  /* Align LF and HF orbital phase */
945  /* We will discard the constant and slope of the linear fit */
946  REAL8 constant = 0.;
947  REAL8 slope = 0.;
948  retcode = align_wfs_window(freq_lo, freq_hi, phase_f_lo, phase_f_hi, &constant, &slope, f_hyb_ini, f_hyb_end);
949 
950  /* Blend LF and HF orbital phase together */
951  retcode = blend_functions(freq,phase,freq_lo,phase_f_lo,freq_hi,phase_f_hi,f_hyb_ini, f_hyb_end);
952 
953  /* Cleanup */
954  gsl_vector_free(phase_f_lo);
955  gsl_vector_free(phase_f_hi);
956 
957  return XLAL_SUCCESS;
958 
959 }
960 
961 /* This function returns the frequency and orbital phase in a sparse grid. The frequency and orbital phase are hybridized between LF and HF ROM. */
962 UNUSED static UINT8 SEOBNRv5HMROM_freq_phase_sparse_grid_hybrid(UNUSED gsl_vector** freq, UNUSED gsl_vector** phase, REAL8 q, REAL8 chi1,REAL8 chi2, INT4 nk_max, SEOBNRROMdataDS *romdataset){
963 
964  /* We point to the data for computing the orbital phase. */
965  /* These data are stored in the structures for all modes */
966  /* We use the 22 mode (index 0) structure because the 22 mode will always be present */
967  SEOBNRROMdataDS *romdata=&romdataset[0];
968  if (!SEOBNRv5HMROM_IsSetup(0, romdataset)) {
970  "Error setting up SEOBNRv5ROM data - check your $LAL_DATA_PATH\n");
971  }
972 
973  UNUSED UINT4 retcode=0;
974 
975  //We always need to glue two submodels together for this ROM
976  SEOBNRROMdataDS_submodel *submodel_hi; // high frequency ROM
977  SEOBNRROMdataDS_submodel *submodel_lo; // low frequency ROM
978 
979  /* Select ROM patches */
980  //There is only one LF patch
981  submodel_lo = romdata->lowf;
982  //There is only one HF patch
983  submodel_hi = romdata->highf;
984 
985  /* Compute hybridized orbital phase */
986 
987  INT8 i_max_LF = 0;
988  INT8 i_min_HF = 0;
989 
990  // Get sparse frequency array for the LF orbital phase
991  gsl_vector* freq_lo = gsl_vector_alloc(submodel_lo->nk_phase);
992  for(unsigned int i = 0; i < freq_lo->size; i++){
993  freq_lo->data[i] = submodel_lo->gPhase->data[i];
994  }
995  gsl_vector* freq_hi = gsl_vector_alloc(submodel_hi->nk_phase);
996 
997  //Compute prefactor for rescaling the frequency.
998  //The HF ROM is build using freq/RD_freq, we need to compute RD_freq and undo the scaling
999 
1000  REAL8 omegaQNM = Get_omegaQNM_SEOBNRv5(q,chi1,chi2,2,2);
1001  REAL8 inv_scaling = 1. / (2*LAL_PI/omegaQNM);
1002  for(unsigned int i = 0; i < freq_hi->size; i++){
1003  freq_hi->data[i] = inv_scaling*submodel_hi->gPhase->data[i];
1004  }
1005 
1006  //Initialize arrays for hybridized phase
1007  // Compute length of hybridized frequency array
1008  retcode = compute_i_max_LF_i_min_HF(&i_max_LF, &i_min_HF,freq_lo,freq_hi,f_hyb_ini);
1009  *freq = gsl_vector_alloc(i_max_LF + freq_hi->size - i_min_HF + 1);
1010 
1011  //It's important to initialize this function to 0
1012  *phase = gsl_vector_calloc((*freq)->size);
1013 
1014  // Fill the hybridized frequency array
1015  for(unsigned int i = 0; i <= i_max_LF;i++){
1016  (*freq)->data[i] = freq_lo->data[i];
1017  };
1018  for(unsigned int i = i_min_HF; i < freq_hi->size;i++){
1019  (*freq)->data[i_max_LF+i-i_min_HF+1] = freq_hi->data[i];
1020  };
1021 
1022  /* Get the hybridized orbital phase */
1023 
1024  retcode = SEOBNRv5HMROM_phase_sparse_grid_hybrid(*freq,*phase,freq_lo, freq_hi,q,chi1,chi2,nk_max,romdataset);
1025 
1026  /* Cleanup */
1027  gsl_vector_free(freq_lo);
1028  gsl_vector_free(freq_hi);
1029 
1030 
1031  return XLAL_SUCCESS;
1032 
1033 }
1034 
1035 // Convention for alignment quantities:
1036 // phase_hi ~= phase_lo + Deltaphi_align + 2pi*f*Deltat_align
1038  gsl_vector **freq, // Output: hybrid frequency array
1039  gsl_vector **phase, // Output: hybrid phase
1040  REAL8* Deltat_align, // Output: time alignment
1041  REAL8* Deltaphi_align, // Output: phase alignment
1042  gsl_vector *phase_lo, // low frequency phase
1043  gsl_vector *phase_hi, // high frequency phase
1044  gsl_vector *freq_lo, // frequency array for low frequency phase
1045  gsl_vector *freq_hi, // frequency array for high frequency phase
1046  double f_hyb_lo, // start frequency of hybridization window
1047  double f_hyb_hi // end frequency of hybridization window
1048 ){
1049  INT8 i_max_LF = 0;
1050  INT8 i_min_HF = 0;
1051 
1052  // Initialize arrays for hybridized phase
1053 
1054  // Find indices of f_hyb_lo in freq_lo and freq_hi s. t.
1055  // freq_lo[i_max_LF] < f_hyb_lo
1056  // freq_hi[i_min_HF] >= f_hyb_lo
1057  UINT4 retcode = compute_i_max_LF_i_min_HF(&i_max_LF, &i_min_HF, freq_lo, freq_hi, f_hyb_lo);
1058  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1059 
1060  // Compute length of hybridized frequency array
1061  *freq = gsl_vector_alloc(i_max_LF + freq_hi->size - i_min_HF + 1);
1062 
1063  // Fill the hybridized frequency array
1064  for(unsigned int i=0; i <= i_max_LF; i++)
1065  (*freq)->data[i] = freq_lo->data[i];
1066  for(unsigned int i=i_min_HF; i < freq_hi->size; i++)
1067  (*freq)->data[i_max_LF+i-i_min_HF+1] = freq_hi->data[i];
1068 
1069  // Initialize phase array with zeros
1070  *phase = gsl_vector_calloc((*freq)->size);
1071 
1072  // Align low and high frequency phase over window [f_hyb_lo, f_hyb_hi]
1073  // Save phase and time shift from the linear fit of phase_hi - phase_lo
1074  REAL8 Deltat = 0.;
1075  REAL8 Deltaphi = 0.;
1076  retcode = align_wfs_window(freq_lo, freq_hi, phase_lo, phase_hi, &Deltat, &Deltaphi, f_hyb_lo, f_hyb_hi);
1077  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1078 
1079  // Blend low and high frequency phase together
1080  retcode = blend_functions(*freq, *phase, freq_lo, phase_lo, freq_hi, phase_hi, f_hyb_lo, f_hyb_hi);
1081  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1082 
1083  // We output the constant phase shift and time shift for phase_hi - phase_lo
1084  // Convention for alignment quantities:
1085  // phase_hi ~= phase_lo + Deltaphi_align + 2pi*f*Deltat_align
1086  *Deltat_align = Deltat;
1087  *Deltaphi_align = Deltaphi;
1088 
1089  return XLAL_SUCCESS;
1090 }
1091 
1092 // This is a general purpose function that hybridizes two phase arrays over frequency.
1094  gsl_vector **freq, // Output: hybrid frequency array
1095  gsl_vector **phase, // Output: hybrid phase
1096  gsl_vector *phase_lo, // low frequency phase
1097  gsl_vector *phase_hi, // high frequency phase
1098  gsl_vector *freq_lo, // frequency array for low frequency phase
1099  gsl_vector *freq_hi, // frequency array for high frequency phase
1100  double f_hyb_lo, // start frequency of hybridization window
1101  double f_hyb_hi, // end frequency of hybridization window
1102  REAL8 Deltat_22_align, // Input: 22 time alignment
1103  REAL8 Deltaphi_22_align, // Input: 22 phase alignment
1104  INT4 modeM // Input: m mode number
1105 ){
1106  INT8 i_max_LF = 0;
1107  INT8 i_min_HF = 0;
1108 
1109  // Initialize arrays for hybridized phase
1110 
1111  // Find indices of f_hyb_lo in freq_lo and freq_hi s. t.
1112  // freq_lo[i_max_LF] < f_hyb_lo
1113  // freq_hi[i_min_HF] >= f_hyb_lo
1114  UINT4 retcode = compute_i_max_LF_i_min_HF(&i_max_LF, &i_min_HF, freq_lo, freq_hi, f_hyb_lo);
1115  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1116 
1117  // Compute length of hybridized frequency array
1118  *freq = gsl_vector_alloc(i_max_LF + freq_hi->size - i_min_HF + 1);
1119 
1120  // Fill the hybridized frequency array
1121  for(unsigned int i=0; i <= i_max_LF; i++)
1122  (*freq)->data[i] = freq_lo->data[i];
1123  for(unsigned int i=i_min_HF; i < freq_hi->size; i++)
1124  (*freq)->data[i_max_LF+i-i_min_HF+1] = freq_hi->data[i];
1125 
1126  // Initialize phase array with zeros
1127  *phase = gsl_vector_calloc((*freq)->size);
1128 
1129  // Align low and high frequency phase over window [f_hyb_lo, f_hyb_hi]
1130  retcode = align_wfs_window_from_22(freq_lo, freq_hi, phase_lo, phase_hi, f_hyb_lo, f_hyb_hi, Deltat_22_align, Deltaphi_22_align, modeM);
1131  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1132 
1133  // Blend low and high frequency phase together
1134  retcode = blend_functions(*freq, *phase, freq_lo, phase_lo, freq_hi, phase_hi, f_hyb_lo, f_hyb_hi);
1135  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1136 
1137  return XLAL_SUCCESS;
1138 }
1139 
1140 // This is a general purpose function that hybridizes two amplitude arrays over frequency.
1142  gsl_vector **freq, // Output: hybrid frequency array
1143  gsl_vector **amp, // Output: hybrid amplitude
1144  gsl_vector *amp_lo, // low frequency amplitude
1145  gsl_vector *amp_hi, // high frequency amplitude
1146  gsl_vector *freq_lo, // frequency array for low frequency amplitude
1147  gsl_vector *freq_hi, // frequency array for high frequency amplitude
1148  double f_hyb_lo, // start frequency of hybridization window
1149  double f_hyb_hi // end frequency of hybridization window
1150 ){
1151  INT8 i_max_LF = 0;
1152  INT8 i_min_HF = 0;
1153 
1154  // Initialize arrays for hybridized phase
1155  // Find indices of f_hyb_lo in freq_lo and freq_hi s. t.
1156  // freq_lo[i_max_LF] < f_hyb_lo
1157  // freq_hi[i_min_HF] >= f_hyb_lo
1158  UINT4 retcode = compute_i_max_LF_i_min_HF(&i_max_LF, &i_min_HF, freq_lo, freq_hi, f_hyb_lo);
1159  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1160 
1161  // Compute length of hybridized frequency array
1162  *freq = gsl_vector_alloc(i_max_LF + freq_hi->size - i_min_HF + 1);
1163 
1164  // Fill the hybridized frequency array
1165  for(unsigned int i=0; i <= i_max_LF; i++)
1166  (*freq)->data[i] = freq_lo->data[i];
1167  for(unsigned int i=i_min_HF; i < freq_hi->size; i++)
1168  (*freq)->data[i_max_LF+i-i_min_HF+1] = freq_hi->data[i];
1169 
1170  // Initialize phase array with zeros
1171  *amp = gsl_vector_calloc((*freq)->size);
1172 
1173  // Blend low and high frequency phase together
1174  retcode = blend_functions(*freq, *amp, freq_lo, amp_lo, freq_hi, amp_hi, f_hyb_lo, f_hyb_hi);
1175  if (retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1176 
1177  return XLAL_SUCCESS;
1178 }
1179 
1180 
1181 /* This function returns the frequency and approximate phase of nMode in a sparse grid hybridized between LF and HF ROM. */
1182 /* Here we linearly extend the phase outside the regime where we have data */
1183 /* The derivation of this approximate phase is in https://git.ligo.org/waveforms/reviews/SEOBNRv5HM_ROM/blob/master/documents/notes.pdf */
1184 /* In this document this phase is the argument of the exponential in Eq.(22) */
1185 UNUSED static UINT8 SEOBNRv5HMROM_approx_phi_lm(gsl_vector* freq_mode_lm, gsl_vector* phase_approx_lm, gsl_vector* freq_carrier_hyb, gsl_vector* phase_carrier_hyb, UINT4 nMode){
1186 
1187  UINT8 modeM = lmModes_v5hm[nMode][1];
1188 
1189  REAL8 f_max_carrier = freq_carrier_hyb->data[freq_carrier_hyb->size -1];
1190  REAL8 phase_carrier_at_f_max = phase_carrier_hyb->data[phase_carrier_hyb->size -1];
1191 
1192  gsl_interp_accel *acc = gsl_interp_accel_alloc ();
1193  gsl_spline *spline = gsl_spline_alloc (gsl_interp_cspline, phase_carrier_hyb->size);
1194 
1195  gsl_spline_init (spline, freq_carrier_hyb->data, phase_carrier_hyb->data, phase_carrier_hyb->size);
1196  REAL8 der_phase_carrier_at_f_max = gsl_spline_eval_deriv(spline, f_max_carrier, acc);
1197 
1198  /* Constant shift between modes */
1199  REAL8 const_phase_shift = const_phaseshift_lm_v5hm[nMode] + (1.-(REAL8)modeM)*LAL_PI/4.;
1200 
1201  for(unsigned int i = 0; i < freq_mode_lm->size; i++){
1202  if(freq_mode_lm->data[i]/(REAL8)modeM < f_max_carrier){
1203  /* Compute the approximate phase of lm mode from the carrier phase */
1204  phase_approx_lm->data[i] = (REAL8)modeM*gsl_spline_eval (spline, freq_mode_lm->data[i]/(REAL8)modeM, acc) + const_phase_shift;
1205  }
1206  else{
1207  /* Linear extrapolation for frequency at which we don't have data for the orbital phase */
1208  phase_approx_lm->data[i] = modeM*(phase_carrier_at_f_max + der_phase_carrier_at_f_max*(freq_mode_lm->data[i]/modeM-f_max_carrier)) + const_phase_shift;
1209  }
1210  }
1211 
1212  /* Cleanup */
1213  gsl_spline_free(spline);
1214  gsl_interp_accel_free(acc);
1215 
1216  return XLAL_SUCCESS;
1217 }
1218 
1219 /* This function returns the Re/Im part of c-modes in a sparse grid. Re/Im of c-modes are hybridized between LF and HF ROM. */
1220 /* The derivation of the c-modes is in https://git.ligo.org/waveforms/reviews/SEOBNRv5HM_ROM/blob/master/documents/notes.pdf Eq. (22)*/
1221 UNUSED static UINT8 SEOBNRv5HMROM_cmode_sparse_grid_hybrid(gsl_vector* freq, gsl_vector* cmode_real, gsl_vector* cmode_imag, gsl_vector* freq_lo, gsl_vector* freq_hi, REAL8 q, REAL8 chi1,REAL8 chi2, UINT8 nMode,INT8 nk_max,SEOBNRROMdataDS *romdataset){
1222 
1223  gsl_vector* real_f_lo = gsl_vector_alloc(freq_lo->size);
1224  gsl_vector* imag_f_lo = gsl_vector_alloc(freq_lo->size);
1225  gsl_vector* real_f_hi = gsl_vector_alloc(freq_hi->size);
1226  gsl_vector* imag_f_hi = gsl_vector_alloc(freq_hi->size);
1227 
1228  /* Generate LF and HF cmode */
1229  UNUSED UINT8 retcode = SEOBNRv5HMROM_cmode_sparse_grid(real_f_lo, imag_f_lo,q,chi1,chi2,"LF",nMode,nk_max,romdataset);
1230  retcode = SEOBNRv5HMROM_cmode_sparse_grid(real_f_hi, imag_f_hi,q,chi1,chi2,"HF",nMode,nk_max,romdataset);
1231 
1232  UINT8 modeM = lmModes_v5hm[nMode][1];
1233 
1234  /* Blend LF and HF cmode together */
1235  retcode = blend_functions(freq,cmode_real,freq_lo,real_f_lo,freq_hi,real_f_hi,f_hyb_ini*(REAL8)modeM,f_hyb_end*(REAL8)modeM);
1236  retcode = blend_functions(freq,cmode_imag,freq_lo,imag_f_lo,freq_hi,imag_f_hi,f_hyb_ini*(REAL8)modeM,f_hyb_end*(REAL8)modeM);
1237 
1238  /* Cleanup */
1239  gsl_vector_free(real_f_lo);
1240  gsl_vector_free(imag_f_lo);
1241  gsl_vector_free(real_f_hi);
1242  gsl_vector_free(imag_f_hi);
1243 
1244  return XLAL_SUCCESS;
1245 
1246 }
1247 
1248 /* This function returns the frequency and Re/Im part of c-modes in a sparse grid. The frequency and Re/Im of c-modes are hybridized between LF and HF ROM. */
1249 UNUSED static UINT8 SEOBNRv5HMROM_freq_cmode_sparse_grid_hybrid(gsl_vector** freq_cmode, gsl_vector** cmode_real, gsl_vector** cmode_imag, REAL8 q, REAL8 chi1,REAL8 chi2, UINT8 nMode,INT8 nk_max, SEOBNRROMdataDS *romdataset){
1250 
1251  UINT8 modeL = lmModes_v5hm[nMode][0];
1252  UINT8 modeM = lmModes_v5hm[nMode][1];
1253 
1254  /* We point to the data for computing the cmode. */
1255  SEOBNRROMdataDS *romdata=&romdataset[nMode];
1256  if (!SEOBNRv5HMROM_IsSetup(nMode,romdataset)) {
1258  "Error setting up SEOBNRv5ROM data - check your $LAL_DATA_PATH\n");
1259  }
1260 
1261  UNUSED UINT4 retcode=0;
1262 
1263  /* We always need to glue two submodels together for this ROM */
1264  SEOBNRROMdataDS_submodel *submodel_hi; // high frequency ROM
1265  SEOBNRROMdataDS_submodel *submodel_lo; // low frequency ROM
1266 
1267  /* Select ROM patches */
1268  //There is only one LF patch
1269  submodel_lo = romdata->lowf;
1270  //There is only one HF patch
1271  submodel_hi = romdata->highf;
1272 
1273  /* Compute hybridized Re/Im part c-mode */
1274 
1275  INT8 i_max_LF = 0;
1276  INT8 i_min_HF = 0;
1277 
1278  // Get sparse frequency array for the LF orbital phase
1279  gsl_vector* freq_lo = gsl_vector_alloc(submodel_lo->nk_cmode);
1280  gsl_vector* freq_hi = gsl_vector_alloc(submodel_hi->nk_cmode);
1281 
1282  for(unsigned int i = 0; i < freq_lo->size; i++){
1283  freq_lo->data[i] = submodel_lo->gCMode->data[i];
1284  }
1285 
1286  //Compute prefactor for rescaling the frequency.
1287  //The HF ROM is build using freq/RD_freq, we need to compute RD_freq and undo the scaling
1288  REAL8 omegaQNM = Get_omegaQNM_SEOBNRv5(q,chi1,chi2,modeL,modeM);
1289  REAL8 inv_scaling = 1. / (2*LAL_PI/omegaQNM);
1290  for(unsigned int i = 0; i < freq_hi->size; i++){
1291  freq_hi->data[i] = inv_scaling*submodel_hi->gCMode->data[i];
1292  }
1293 
1294  //Initialize arrays for Re/Im part c-mode
1295  // Compute length of hybridized frequency array
1296  retcode = compute_i_max_LF_i_min_HF(&i_max_LF, &i_min_HF,freq_lo,freq_hi,f_hyb_ini*(REAL8)modeM);
1297 
1298  *freq_cmode = gsl_vector_alloc(i_max_LF + freq_hi->size - i_min_HF + 1);
1299  // It's important to initialize this function to 0
1300 
1301  for(unsigned int i = 0; i <= i_max_LF;i++){
1302  (*freq_cmode)->data[i] = freq_lo->data[i];
1303  };
1304  for(unsigned int i = i_min_HF; i < freq_hi->size;i++){
1305  (*freq_cmode)->data[i_max_LF+i-i_min_HF+1] = freq_hi->data[i];
1306  };
1307 
1308  *cmode_real = gsl_vector_calloc((*freq_cmode)->size);
1309  *cmode_imag = gsl_vector_calloc((*freq_cmode)->size);
1310 
1311 
1312  // Generate the hybridized Re/Im part of c-mode
1313 
1314  retcode = SEOBNRv5HMROM_cmode_sparse_grid_hybrid(*freq_cmode,*cmode_real,*cmode_imag,freq_lo, freq_hi,q,chi1,chi2,nMode,nk_max,romdataset);
1315 
1316 
1317  /* Cleanup */
1318  gsl_vector_free(freq_lo);
1319  gsl_vector_free(freq_hi);
1320 
1321  return XLAL_SUCCESS;
1322 }
1323 
1324 
1325 
1326 /* This function returns the orbital phase in a sparse grid */
1327 UNUSED static UINT8 SEOBNRv5HMROM_phase_sparse_grid(gsl_vector* phase_f, REAL8 q, REAL8 chi1,REAL8 chi2, const char* freq_range,INT4 nk_max, SEOBNRROMdataDS *romdataset){
1328 
1329  /* Loading the data for the 22 mode, the informations about orbital phase are stored here */
1330  SEOBNRROMdataDS *romdata=&romdataset[0];
1331  if (!SEOBNRv5HMROM_IsSetup(0,romdataset)) {
1333  "Error setting up SEOBNRv5ROM data - check your $LAL_DATA_PATH\n");
1334  }
1335  /* Check whether you are asking for the LF or the HF ROM */
1336  SEOBNRROMdataDS_submodel *submodel;
1337  if(strcmp("LF",freq_range) == 0){
1338  // In the case of LF there is only one patch
1339  submodel = romdata->lowf;
1340  }
1341  else{
1342  submodel = romdata->highf;
1343  }
1344  /* Create and initialize the structure for interpolating the orbital phase */
1345  SEOBNRROMdataDS_coeff *romdata_coeff=NULL;
1346  SEOBNRROMdataDS_coeff_Init(&romdata_coeff, submodel->nk_cmode, submodel->nk_phase);
1347 
1348  /* Interpolating projection coefficients for orbital phase */
1350  q, // Input: q-value for which projection coefficients should be evaluated
1351  chi1, // Input: chi1-value for which projection coefficients should be evaluated
1352  chi2, // Input: chi2-value for which projection coefficients should be evaluated
1353  submodel->cvec_phase, // Input: data for spline coefficients for amplitude
1354  submodel->nk_phase, // number of SVD-modes == number of basis functions for amplitude
1355  nk_max, // truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1
1356  submodel->ncx, // Number of points in q + 2
1357  submodel->ncy, // Number of points in chi1 + 2
1358  submodel->ncz, // Number of points in chi2 + 2
1359  gsl_vector_const_ptr(submodel->qvec, 0), // B-spline knots in q
1360  gsl_vector_const_ptr(submodel->chi1vec, 0), // B-spline knots in chi1
1361  gsl_vector_const_ptr(submodel->chi2vec, 0), // B-spline knots in chi2
1362  romdata_coeff->c_phase // Output: interpolated projection coefficients for orbital phase
1363  );
1364 
1365  if(retcode!=0) {
1366  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1367  XLAL_ERROR(retcode);
1368  }
1369 
1370  /* Project interpolation coefficients onto the basis */
1371  /* phase_pts = B_A^T . c_A */
1372  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Bphase, romdata_coeff->c_phase, 0.0, phase_f);
1373 
1374  /* Cleanup */
1375  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1376 
1377  return XLAL_SUCCESS;
1378 }
1379 
1380 /* This function returns the Re/Im part of c-modes in a sparse grid. */
1381 UNUSED static UINT8 SEOBNRv5HMROM_cmode_sparse_grid(gsl_vector* creal_f, gsl_vector* cimag_f, REAL8 q, REAL8 chi1,REAL8 chi2, const char* freq_range,UINT8 nMode,INT4 nk_max, SEOBNRROMdataDS *romdataset){
1382 
1383  /* Loading the data for the lm mode */
1384  SEOBNRROMdataDS *romdata=&romdataset[nMode];
1385  if (!SEOBNRv5HMROM_IsSetup(nMode,romdataset)) {
1387  "Error setting up SEOBNRv5ROM data - check your $LAL_DATA_PATH\n");
1388  }
1389  /* Check whether you are asking for the LF or the HF ROM */
1390  SEOBNRROMdataDS_submodel *submodel;
1391  if(strcmp("LF",freq_range) == 0){
1392  /* In the case of LF there is only one patch */
1393  submodel = romdata->lowf;
1394  }
1395  else{
1396  /* In the case of HF there is only one patch */
1397  submodel = romdata->highf;
1398  }
1399  /* Create and initialize the structure for interpolating the coorbital mode */
1400  SEOBNRROMdataDS_coeff *romdata_coeff=NULL;
1401  SEOBNRROMdataDS_coeff_Init(&romdata_coeff, submodel->nk_cmode, submodel->nk_cmode);
1402 
1403  /* Interpolating projection coefficients for Re(cmode) */
1405  q, // Input: eta-value for which projection coefficients should be evaluated
1406  chi1, // Input: chi1-value for which projection coefficients should be evaluated
1407  chi2, // Input: chi2-value for which projection coefficients should be evaluated
1408  submodel->cvec_real, // Input: data for spline coefficients for amplitude
1409  submodel->nk_cmode, // number of SVD-modes == number of basis functions for amplitude
1410  nk_max, // truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1
1411  submodel->ncx, // Number of points in q + 2
1412  submodel->ncy, // Number of points in chi1 + 2
1413  submodel->ncz, // Number of points in chi2 + 2
1414  gsl_vector_const_ptr(submodel->qvec, 0), // B-spline knots in eta
1415  gsl_vector_const_ptr(submodel->chi1vec, 0), // B-spline knots in chi1
1416  gsl_vector_const_ptr(submodel->chi2vec, 0), // B-spline knots in chi2
1417  romdata_coeff->c_real // Output: interpolated projection coefficients for Re(c-mode)
1418  );
1419 
1420  /* Interpolating projection coefficients for Im(cmode) */
1422  q, // Input: eta-value for which projection coefficients should be evaluated
1423  chi1, // Input: chi1-value for which projection coefficients should be evaluated
1424  chi2, // Input: chi2-value for which projection coefficients should be evaluated
1425  submodel->cvec_imag, // Input: data for spline coefficients for amplitude
1426  submodel->nk_cmode, // number of SVD-modes == number of basis functions for amplitude
1427  nk_max, // truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1
1428  submodel->ncx, // Number of points in q + 2
1429  submodel->ncy, // Number of points in chi1 + 2
1430  submodel->ncz, // Number of points in chi2 + 2
1431  gsl_vector_const_ptr(submodel->qvec, 0), // B-spline knots in eta
1432  gsl_vector_const_ptr(submodel->chi1vec, 0), // B-spline knots in chi1
1433  gsl_vector_const_ptr(submodel->chi2vec, 0), // B-spline knots in chi2
1434  romdata_coeff->c_imag // Output: interpolated projection coefficients for Im(c-mode)
1435  );
1436 
1437  if(retcode!=0) {
1438  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1439  XLAL_ERROR(retcode);
1440  }
1441 
1442  /* Project interpolation coefficients onto the basis */
1443  /* creal_pts = B_A^T . c_A */
1444  /* cimag_pts = B_A^T . c_A */
1445  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Breal, romdata_coeff->c_real, 0.0, creal_f);
1446  gsl_blas_dgemv(CblasTrans, 1.0, submodel->Bimag, romdata_coeff->c_imag, 0.0, cimag_f);
1447 
1448  /* Cleanup */
1449  SEOBNRROMdataDS_coeff_Cleanup(romdata_coeff);
1450 
1451  return XLAL_SUCCESS;
1452 }
1453 
1454 
1455 /* Select high frequency ROM submodel */
1457  if ((q> 3.) && (chi1<=0.8)){
1458  return 0;
1459  }
1460  else if ((q> 3.) && (chi1>0.8)){
1461  return 1;
1462  }
1463  else if ((q<= 3.) && (chi1<=0.8)){
1464  return 2;
1465  }
1466  else if ((q<= 3.) && (chi1>0.8)){
1467  return 3;
1468  }
1469  else{
1470  XLAL_ERROR( XLAL_EDOM );
1471  XLALPrintError("XLAL Error - %s: SEOBNRv5HM not currently available in this region!\n",
1472  __func__);
1473  }
1474 }
1475 
1476 
1477 /* Internal function to compute amplitudes and phases for each mode of the ROM and return these as gsl splines. */
1479  UNUSED AmpPhaseSplineData **ampPhaseSplineData, /**<< Output: amplitude and phase splines for the modes */
1480  UNUSED REAL8 q, /**< Mass ratio **/
1481  UNUSED REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1482  UNUSED REAL8 chi2, /**< Dimensionless aligned component spin 2 */
1483  UNUSED INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 (default). */
1484  UNUSED UINT4 nModes, /**< Number of modes to generate */
1485  UNUSED SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
1486 )
1487 {
1488  /* Check output structure */
1489  if(!ampPhaseSplineData)
1491 
1492  /* 'Nudge' parameter values to allowed boundary values if close by */
1493  if (q < 1.0) nudge(&q, 1.0, 1e-6);
1494  if (q > 100.0) nudge(&q, 100.0, 1e-6);
1495 
1496  if ( chi1 < -0.998 - 1e-6 || chi2 < -0.998 - 1e-6 || chi1 > 0.998 + 1e-6|| chi2 > 0.998 + 1e-6) {
1497  XLALPrintError("XLAL Error - %s: chi1 or chi2 smaller than -0.998 or larger than 0.998!\n"
1498  "SEOBNRv5HMROM is only available for spins in the range -0.998 <= a/M <= 0.998.\n",
1499  __func__);
1500  XLAL_ERROR( XLAL_EDOM );
1501  }
1502 
1503  if (q<1.0 || q > 100.0) {
1504  XLALPrintError("XLAL Error - %s: q (%f) bigger than 100.0 or unphysical!\n"
1505  "SEOBNRv5HMROM is only available for q in the range 1 <= q <= 100.\n",
1506  __func__, q);
1507  XLAL_ERROR( XLAL_EDOM );
1508  }
1509 
1510  gsl_vector *freq_carrier_hyb = NULL;
1511  gsl_vector *phase_carrier_hyb = NULL;
1512 
1513  /* Compute the orbital phase, this is the same for every mode. */
1514  /* For this reason it's outside the for loop over modes below. */
1515  UNUSED int retcode = SEOBNRv5HMROM_freq_phase_sparse_grid_hybrid(
1516  &freq_carrier_hyb, &phase_carrier_hyb, q, chi1, chi2, nk_max,romdataset);
1517  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1518 
1519  /* Put the phase into the right convention */
1520  for(unsigned int i=0; i < phase_carrier_hyb->size; i++) {
1521  phase_carrier_hyb->data[i] = -phase_carrier_hyb->data[i];
1522  }
1523 
1524  /* Looping over modes: compute complex mode and from that amplitude and phase */
1525  for(unsigned int nMode=0; nMode < nModes; nMode++){
1526 
1527  gsl_vector *freq_cmode_hyb = NULL;
1528  gsl_vector *cmode_real_hyb = NULL;
1529  gsl_vector *cmode_imag_hyb = NULL;
1530 
1531  UNUSED UINT4 modeL = lmModes_v5hm[nMode][0];
1532  UNUSED UINT4 modeM = lmModes_v5hm[nMode][1];
1533 
1534  /* Compute Re and Im c-modes */
1536  &freq_cmode_hyb, &cmode_real_hyb, &cmode_imag_hyb,
1537  q, chi1, chi2, nMode, nk_max, romdataset);
1538 
1539  gsl_vector *phase_approx_lm = gsl_vector_alloc(freq_cmode_hyb->size);
1540  /* Compute approximated phase from orbital phase */
1541  retcode = SEOBNRv5HMROM_approx_phi_lm(freq_cmode_hyb, phase_approx_lm,
1542  freq_carrier_hyb, phase_carrier_hyb, nMode);
1543 
1544  /* Compute the phase contribution coming from the cmode and unwrap it */
1545  COMPLEX16 complex_mode;
1546  gsl_vector *phase_cmode = gsl_vector_alloc(freq_cmode_hyb->size);
1547  for(unsigned int i=0; i < freq_cmode_hyb->size; i++) {
1548  complex_mode = cmode_real_hyb->data[i] + I*cmode_imag_hyb->data[i];
1549  phase_cmode->data[i] = carg(complex_mode);
1550  }
1551 
1552  /* Unwrap the phase contribution from the cmode */
1553  gsl_vector *unwrapped_phase_cmode = gsl_vector_alloc(freq_cmode_hyb->size);
1554  retcode = unwrap_phase(unwrapped_phase_cmode,phase_cmode);
1555 
1556  /* Reconstruct amplitude and phase */
1557  gsl_vector *reconstructed_phase = gsl_vector_alloc(freq_cmode_hyb->size);
1558  gsl_vector *reconstructed_amplitude = gsl_vector_alloc(freq_cmode_hyb->size);
1559  for(unsigned int i=0; i < freq_cmode_hyb->size; i++) {
1560  complex_mode = cmode_real_hyb->data[i] + I*cmode_imag_hyb->data[i];
1561  reconstructed_amplitude->data[i] = cabs(complex_mode);
1562  reconstructed_phase->data[i] = unwrapped_phase_cmode->data[i] - phase_approx_lm->data[i];
1563  }
1564 
1565  // Build amplitude and phase splines
1566  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
1567  gsl_spline *spline_amp = gsl_spline_alloc (gsl_interp_cspline, reconstructed_amplitude->size);
1568  gsl_spline_init(spline_amp, freq_cmode_hyb->data, reconstructed_amplitude->data, reconstructed_amplitude->size);
1569 
1570  gsl_interp_accel *acc_phase = gsl_interp_accel_alloc();
1571  gsl_spline *spline_phase = gsl_spline_alloc (gsl_interp_cspline, reconstructed_phase->size);
1572  gsl_spline_init(spline_phase, freq_cmode_hyb->data, reconstructed_phase->data, reconstructed_phase->size);
1573 
1574  // Store amplitude and phase spline data for this mode.
1575  // We return this information. The caller is responsible for freeing it.
1576  ampPhaseSplineData[nMode]->spline_amp = spline_amp;
1577  ampPhaseSplineData[nMode]->spline_phi = spline_phase;
1578  ampPhaseSplineData[nMode]->acc_amp = acc_amp;
1579  ampPhaseSplineData[nMode]->acc_phi = acc_phase;
1580  ampPhaseSplineData[nMode]->f = freq_cmode_hyb;
1581 
1582  /* Cleanup inside of loop over modes */
1583  gsl_vector_free(cmode_real_hyb);
1584  gsl_vector_free(cmode_imag_hyb);
1585  gsl_vector_free(phase_approx_lm);
1586  gsl_vector_free(phase_cmode);
1587  gsl_vector_free(unwrapped_phase_cmode);
1588  gsl_vector_free(reconstructed_amplitude);
1589  gsl_vector_free(reconstructed_phase);
1590  }
1591 
1592  /* Cleanup outside of loop over modes */
1593  gsl_vector_free(freq_carrier_hyb);
1594  gsl_vector_free(phase_carrier_hyb);
1595 
1596  return(XLAL_SUCCESS);
1597 }
1598 
1599 
1600 /**
1601 * Core function for computing the ROM modes.
1602 * It rebuilds the modes starting from "orbital phase" and co-orbital modes.
1603 * This function returns SphHarmFrequencySeries
1604 */
1605 UNUSED static int SEOBNRv5HMROMCoreModes(
1606  UNUSED SphHarmFrequencySeries **hlm_list, /**<< Spherical modes frequency series for the waveform */
1607  UNUSED REAL8 phiRef, /**<< orbital reference phase */
1608  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
1609  UNUSED REAL8 distance, /**< Distance of source (m) */
1610  UNUSED REAL8 Mtot_sec, /**< Total mass in seconds **/
1611  UNUSED REAL8 q, /**< Mass ratio **/
1612  UNUSED REAL8 chi1, /**< Dimensionless aligned component spin 1 */
1613  UNUSED REAL8 chi2, /**< Dimensionless aligned component spin 2 */
1614  UNUSED const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */
1615  UNUSED REAL8 deltaF, /**< Frequency points at which to evaluate the waveform (Hz) */
1616  UNUSED INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1. We
1617  *nk_max == -1 is the default setting */
1618  UNUSED UINT4 nModes, /**< Number of modes to generate */
1619  REAL8 sign_odd_modes, /**< Sign of the odd-m modes, used when swapping the two bodies */
1620  UNUSED SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
1621  )
1622 {
1623  /* Check output structure */
1624  if(!hlm_list)
1626 
1627  /* 'Nudge' parameter values to allowed boundary values if close by */
1628  if (q < 1.0) nudge(&q, 1.0, 1e-6);
1629  if (q > 100.0) nudge(&q, 100.0, 1e-6);
1630 
1631  if ( chi1 < -0.998 || chi2 < -0.998 || chi1 > 0.998 || chi2 > 0.998) {
1632  XLALPrintError("XLAL Error - %s: chi1 or chi2 smaller than -0.998 or larger than 0.998!\n"
1633  "SEOBNRv5HMROM is only available for spins in the range -0.998 <= a/M <= 0.998.\n",
1634  __func__);
1635  XLAL_ERROR( XLAL_EDOM );
1636  }
1637 
1638  if (q<1.0 || q > 100.0) {
1639  XLALPrintError("XLAL Error - %s: q (%f) bigger than 100.0 or unphysical!\n"
1640  "SEOBNRv5HMROM is only available for q in the range 1 <= q <= 100.\n",
1641  __func__, q);
1642  XLAL_ERROR( XLAL_EDOM );
1643  }
1644 
1645 
1646  // Get the splines for the amplitude and phase of the modes
1647  AmpPhaseSplineData **ampPhaseSplineData = NULL;
1648  AmpPhaseSplineData_Init(&ampPhaseSplineData, nModes);
1649  UNUSED int retcode = SEOBNRv5HMROMCoreModeAmpPhaseSplines(
1650  ampPhaseSplineData, q, chi1, chi2, nk_max, nModes,romdataset);
1651  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
1652 
1653 
1654  /* Find frequency bounds */
1655  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
1656  REAL8 fLow = freqs_in->data[0];
1657  REAL8 fHigh = freqs_in->data[freqs_in->length - 1];
1658 
1659  UNUSED REAL8 fLow_geom = fLow * Mtot_sec;
1660  REAL8 fHigh_geom = fHigh * Mtot_sec;
1661  REAL8 deltaF_geom = deltaF * Mtot_sec;
1662  // The maximum available frequency is the one associated with the 55 mode
1663  REAL8 Mf_ROM_max = const_fmax_lm_v5hm[4] * Get_omegaQNM_SEOBNRv5(q, chi1, chi2, 5, 5) / (2.*LAL_PI);
1664 
1665  // Enforce allowed geometric frequency range
1666  if (fHigh_geom == 0)
1667  fHigh_geom = Mf_ROM_max;
1668  if (fLow_geom < Mf_low_22)
1669  XLAL_ERROR(XLAL_EDOM, "Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g.\n", fLow_geom, Mf_low_22);
1670  if (fHigh_geom < Mf_low_22)
1671  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than ROM starting frequency %g!\n", fHigh_geom, Mf_low_22);
1672  if (fHigh_geom <= fLow_geom)
1673  XLAL_ERROR(XLAL_EDOM, "End frequency %g is smaller than (or equal to) starting frequency %g!\n", fHigh_geom, fLow_geom);
1674 
1675  /* Looping over cmodes */
1676  for(unsigned int nMode=0; nMode < nModes; nMode++){
1677  UNUSED UINT4 modeL = lmModes_v5hm[nMode][0];
1678  UNUSED UINT4 modeM = lmModes_v5hm[nMode][1];
1679 
1680  size_t npts = 0;
1681  LIGOTimeGPS tC = {0, 0};
1682  UINT4 offset = 0; // Index shift between freqs and the frequency series
1683  REAL8Sequence *freqs = NULL;
1684  // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
1685  // I removed the if statement for the time being
1686  /* Set up output array with size closest power of 2 */
1687  npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
1688  if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
1689  npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;
1690 
1691  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
1692  COMPLEX16FrequencySeries *hlmtilde = XLALCreateCOMPLEX16FrequencySeries("hlmtilde: FD mode", &tC, 0.0, deltaF, &lalStrainUnit, npts);
1693 
1694 
1695  // Recreate freqs using only the lower and upper bounds
1696  // Use fLow, fHigh and deltaF rather than geometric frequencies for numerical accuracy
1697  double fHigh_temp = fHigh_geom / Mtot_sec;
1698  UINT4 iStart = (UINT4) ceil(fLow / deltaF);
1699  UINT4 iStop = (UINT4) ceil(fHigh_temp / deltaF);
1700  freqs = XLALCreateREAL8Sequence(iStop - iStart);
1701  if (!freqs) XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
1702  for (UINT4 i=iStart; i<iStop; i++)
1703  freqs->data[i-iStart] = i*deltaF_geom;
1704 
1705  offset = iStart;
1706 
1707 
1708  if (!hlmtilde) {
1709  XLALDestroyREAL8Sequence(freqs);
1711  }
1712 
1713  memset(hlmtilde->data->data, 0, npts * sizeof(COMPLEX16));
1714  XLALUnitMultiply(&(hlmtilde->sampleUnits), &(hlmtilde->sampleUnits), &lalSecondUnit);
1715  COMPLEX16 *hlmdata=hlmtilde->data->data;
1716 
1717  REAL8 Mtot = Mtot_sec / LAL_MTSUN_SI;
1718  // Correct overall amplitude to undo mass-dependent scaling used in ROM
1719  REAL8 amp0 = Mtot * Mtot_sec * LAL_MRSUN_SI / (distance);
1720 
1721  // ROM was build with t = 0 at t_peak^22 -1000. To agree with LAL convention, we undo this shift to get t_peak^22 = 0
1722  REAL8 t_corr = 1000.;
1723 
1724  // Shorthands for amplitude and phase splines for this mode
1725  gsl_spline *spline_amp = ampPhaseSplineData[nMode]->spline_amp;
1726  gsl_spline *spline_phase = ampPhaseSplineData[nMode]->spline_phi;
1727  gsl_interp_accel *acc_amp = ampPhaseSplineData[nMode]->acc_amp;
1728  gsl_interp_accel *acc_phase = ampPhaseSplineData[nMode]->acc_phi;
1729  // gsl_vector *freq_cmode_hyb = ampPhaseSplineData[nMode]->f;
1730 
1731  // Maximum frequency at which we have data for the ROM
1732  REAL8 Mf_max_mode = const_fmax_lm_v5hm[nMode] * Get_omegaQNM_SEOBNRv5(q, chi1, chi2, modeL, modeM) / (2.*LAL_PI);
1733 
1734  // Assemble modes from amplitude and phase
1735  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
1736  REAL8 f = freqs->data[i];
1737  if (f > Mf_max_mode) continue; // We're beyond the highest allowed frequency; since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
1738  if (f <= Mf_low_22 * modeM/2.) continue; // We're above the lowest allowed frequency; since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
1739  int j = i + offset; // shift index for frequency series if needed
1740  REAL8 A = gsl_spline_eval(spline_amp, f, acc_amp);
1741  REAL8 phase = gsl_spline_eval(spline_phase, f, acc_phase);
1742  hlmdata[j] = amp0*A * (cos(phase) + I*sin(phase));//cexp(I*phase);
1743  REAL8 phase_factor = -2.*LAL_PI*f*t_corr;
1744  COMPLEX16 t_factor = cos(phase_factor) + I*sin(phase_factor);
1745  hlmdata[j] *= t_factor;
1746  // We now return the (l,-m) mode that in the LAL convention has support for f > 0
1747  // We use the equation h(l,-m)(f) = (-1)^l h(l,m)*(-f) with f > 0
1748  hlmdata[j] = pow(-1.,modeL)*conj(hlmdata[j]);
1749  if(modeM%2 != 0){
1750  // This is changing the sign of the odd-m modes in the case m1 < m2,
1751  // if m1>m2 sign_odd_modes = 1 and nothing changes.
1752  hlmdata[j] = hlmdata[j]*sign_odd_modes;
1753  }
1754  }
1755  /* Save the mode (l,-m) in the SphHarmFrequencySeries structure */
1756  *hlm_list = XLALSphHarmFrequencySeriesAddMode(*hlm_list, hlmtilde, modeL, -modeM);
1757 
1758  /* Cleanup inside of loop over modes */
1759  XLALDestroyREAL8Sequence(freqs);
1761  }
1762 
1763  AmpPhaseSplineData_Destroy(ampPhaseSplineData, nModes);
1764 
1765  return(XLAL_SUCCESS);
1766 }
1767 
1768 
1769 /**
1770  * ModeArray is a structure which allows to select the modes to include
1771  * in the waveform.
1772  * This function will create a structure with the default modes for every model
1773  */
1775  LALValue *ModeArray, UINT4 nModes)
1776 {
1777 
1778  /* setup ModeArray */
1779 
1780  if (nModes == 7) {
1781  /* Adding all the modes of SEOBNRv5HM
1782  * i.e. [(2,2),(2,1),(3,3),(4,4),(5,5),(3,2),(4,3)]
1783  the relative -m modes are added automatically*/
1784  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
1785  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -1);
1786  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -3);
1787  XLALSimInspiralModeArrayActivateMode(ModeArray, 4, -4);
1788  XLALSimInspiralModeArrayActivateMode(ModeArray, 5, -5);
1789  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -2);
1790  XLALSimInspiralModeArrayActivateMode(ModeArray, 4, -3);
1791  }
1792  else{
1793  /*All the other spin aligned model so far only have the 22 mode
1794  */
1795  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
1796  }
1797 
1798 
1799  return XLAL_SUCCESS;
1800 }
1801 
1802 /**
1803  * ModeArray is a structure which allows to select the modes to include
1804  * in the waveform.
1805  * This function check if the selected modes are available
1806  */
1808  LALValue *ModeArray, UINT4 nModes)
1809 {
1810  INT4 flagTrue = 0;
1811  UINT4 modeL;
1812  INT4 modeM;
1813  const char *model_name;
1814  if (nModes == 1){
1815  model_name="SEOBNRv5_ROM";
1816  }
1817  else{
1818  model_name="SEOBNRv5HM_ROM";
1819  }
1820  /*Loop over all the possible modes
1821  *we only check -m modes, in the waveform both + and - m
1822  *modes will be included
1823  */
1824  for (UINT4 ELL = 2; ELL <= LAL_SIM_L_MAX_MODE_ARRAY; ELL++) {
1825  for (INT4 EMM = -ELL; EMM <= (INT4)ELL; EMM++) {
1826  if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ELL, EMM) == 1) {
1827  for (UINT4 k = 0; k < nModes; k++) {
1828  modeL = lmModes_v5hm[k][0];
1829  //lmModes_v5hm includes the modes in EOB convention for which hlm(f) is non 0 for f>0
1830  //for this reason we need the - sign here
1831  modeM = -lmModes_v5hm[k][1];
1832  if ((modeL == ELL)&&(modeM == EMM)) {
1833  flagTrue=1;
1834  }
1835  if ((modeL == ELL)&&(modeM == -EMM)) {
1836  flagTrue=2;
1837  }
1838  }
1839  /*For each active mode check if is available for the selected model
1840  */
1841  if (flagTrue == 0) {
1842  XLALPrintError ("Mode (%d,%d) is not available by the model %s\n", ELL,
1843  EMM, model_name);
1844  return XLAL_FAILURE;
1845  }
1846  if (flagTrue == 2) {
1847  XLALPrintError ("Mode (%d,%d) is not available by the model %s.\n"
1848  "In this function you can only select (l,-|m|) modes that are directly modeled in the ROM.\n"
1849  "The (l,+|m|) mode will be automatically added to the waveform using symmetry arguments.\n", ELL,
1850  EMM, model_name);
1851  return XLAL_FAILURE;
1852  }
1853  flagTrue = 0;
1854  }
1855  }
1856  }
1857 
1858  return XLAL_SUCCESS;
1859 }
1860 
1861 /**
1862  * This function combines the modes hlm frequencyseries with the sYlm to produce the
1863  * polarizations hplus, hcross.
1864  */
1865 // NOTE: azimuthal angle of the observer entering the -2Ylm is pi/2-phi according to LAL conventions
1868  *hplusFS, /**<< Output: frequency series for hplus, already created */
1870  *hcrossFS, /**<< Output: frequency series for hplus, already created */
1871  LALValue *ModeArray, /**<< Input: ModeArray structure with the modes to include */
1873  *hlm, /**<< Input: list with frequency series for each mode hlm */
1874  REAL8 inc, /**<< Input: inclination */
1875  UNUSED REAL8 phi /**<< Input: phase */
1876 ) {
1877  /* Loop over modes */
1878  SphHarmFrequencySeries *hlms_temp = hlm;
1879  while ( hlms_temp ) {
1880  if (XLALSimInspiralModeArrayIsModeActive(ModeArray, hlms_temp->l, hlms_temp->m) == 1) {
1881  /* Here we check if the mode generated is in the ModeArray structure */
1882  XLALSimAddModeFD(hplusFS, hcrossFS, hlms_temp->mode, inc, LAL_PI/2. - phi,
1883  hlms_temp->l, hlms_temp->m, 1);
1884  }
1885  hlms_temp = hlms_temp->next;
1886  }
1887 
1888  return XLAL_SUCCESS;
1889 }
1890 
1891 /*
1892  * Auxiliary function for TF2 phasing HM: phase constants for different modes
1893  */
1894 static double GetDeltaphilm(int l, int m)
1895 {
1896  if (l==2 && m==2) return 0.;
1897  else if (l==2 && m==1) return LAL_PI/2;
1898  else if (l==3 && m==3) return -LAL_PI/2;
1899  else if (l==4 && m==4) return LAL_PI;
1900  else if (l==5 && m==5) return LAL_PI/2;
1901  else if (l==3 && m==2) return 0;
1902  else if (l==4 && m==3) return -LAL_PI/2;
1903  else XLAL_ERROR(XLAL_EINVAL, "Mode indices (l,m) not recognized.");
1904 }
1905 /*
1906  * Auxiliary function for TF2 amplitude HM: mode amplitude factors
1907  * Leading Newtonian order + 0.5PN relative spin terms for 21
1908  * Here only the 21 has a 0.5PN spin contribution (important for 0-crossings)
1909  * The leading +-1 or +-i factor is supposed to be treated as a phase
1910  * (see GetDeltaphilm)
1911  * Reference: Eqs (4.17) of arXiv:0810.5336 [Phys.Rev.D79:104023,2009]
1912  * (reference for precessing modes, take iota=0)
1913  */
1914 static double GetModeAmpFactor(double eta, double delta, double chi1, double chi2, int l, int m, double v)
1915 {
1916  double chis = 1./2 * (chi1 + chi2);
1917  double chia = 1./2 * (chi1 - chi2);
1918  if (l==2 && m==2) return 1.;
1919  else if (l==2 && m==1) return v * (delta/3 - 1./2*v*(chia + delta*chis));
1920  else if (l==3 && m==3) return v * 3./4 * sqrt(15./14) * delta;
1921  else if (l==4 && m==4) return v*v * 8*sqrt(35.)/63 * (1 - 3*eta);
1922  else if (l==5 && m==5) return v*v*v * 625*sqrt(66.)/6336 * delta * (1 - 2*eta);
1923  else if (l==3 && m==2) return v*v * 9./8 *sqrt(5./7) * (8./27 * (-1 + 3*eta));
1924  else if (l==4 && m==3) return v*v*v * 8./9*sqrt(10./7)*81./320 * delta * (-1 + 2*eta);
1925  // LP: look at hybridized 32 and 43 modes to double check
1926  else XLAL_ERROR(XLAL_EINVAL, "Mode indices (l,m) not recognized.");
1927 }
1928 
1929 /*
1930  * Function computing the TaylorF2 phasing for the mode (l,m)
1931  * Arbitrary (set to 0) time and phase constants
1932  * The relative alignment between modes is consistent
1933  * We should evaluate XLALSimInspiralTaylorF2AlignedPhasing once for all modes;
1934  * however, this is presumably negligible for performance.
1935  * Reference for SPA scaling between modes:
1936  * Section III A 2) of arxiv:2003.12079 [Phys. Rev. D 101, 124040 (2020)]
1937  */
1938 static int TaylorF2Phasing(
1939  double Mtot, // Total mass in solar masses
1940  double q, // Mass-ration m1/m2 >= 1
1941  double chi1, // Dimensionless aligned spin of body 1
1942  double chi2, // Dimensionless aligned spin of body 2
1943  int l, // First mode number l
1944  int m, // Second mode number m
1945  gsl_vector *Mfs, // Input geometric frequencies
1946  gsl_vector **PNphase // Output: TaylorF2 phase at frequencies Mfs
1947 ) {
1948  XLAL_CHECK(PNphase != NULL, XLAL_EFAULT);
1949  XLAL_CHECK(*PNphase == NULL, XLAL_EFAULT);
1950  *PNphase = gsl_vector_alloc(Mfs->size);
1951 
1952  PNPhasingSeries *pn = NULL;
1953  LALDict *extraParams = XLALCreateDict();
1954  // Should we go for max order or set it explicitly?
1956 
1957  double m1OverM = q / (1.0+q);
1958  double m2OverM = 1.0 / (1.0+q);
1959  double m1 = Mtot * m1OverM * LAL_MSUN_SI;
1960  double m2 = Mtot * m2OverM * LAL_MSUN_SI;
1961  // This function is a thin wrapper around XLALSimInspiralPNPhasing_F2
1962  XLALSimInspiralTaylorF2AlignedPhasing(&pn, m1, m2, chi1, chi2, extraParams);
1963 
1964  /* Constant phase for the mode (l,m) */
1965  double Deltaphilm = GetDeltaphilm(l, m);
1966 
1967  /* Note: we rescale the frequency (and v) according to the mode number m */
1968  for (size_t i=0; i < Mfs->size; i++) {
1969  const double Mf = gsl_vector_get(Mfs, i);
1970  const double Mf_m = 2./m * Mf;
1971  const double v = cbrt(LAL_PI * Mf_m);
1972  const double logv = log(v);
1973  const double v2 = v * v;
1974  const double v3 = v * v2;
1975  const double v4 = v * v3;
1976  const double v5 = v * v4;
1977  const double v6 = v * v5;
1978  const double v7 = v * v6;
1979  double phasing = 0.0;
1980 
1981  phasing += pn->v[7] * v7;
1982  phasing += (pn->v[6] + pn->vlogv[6] * logv) * v6;
1983  phasing += (pn->v[5] + pn->vlogv[5] * logv) * v5;
1984  phasing += pn->v[4] * v4;
1985  phasing += pn->v[3] * v3;
1986  phasing += pn->v[2] * v2;
1987  phasing += pn->v[1] * v;
1988  phasing += pn->v[0];
1989 
1990  /* Leading prefactor v^-5 */
1991  phasing /= v5;
1992 
1993  /* Rescaling by m/2 going from the 22 mode to the lm mode */
1994  phasing *= m/2.;
1995 
1996  /* Constant phase for the mode (l,m), and pi/4 from the SPA formula */
1997  phasing += Deltaphilm - LAL_PI/4.;
1998 
1999  gsl_vector_set(*PNphase, i, phasing);
2000  }
2001 
2002  XLALDestroyDict(extraParams);
2003  XLALFree(pn);
2004 
2005  return XLAL_SUCCESS;
2006 }
2007 
2008 /*
2009  * Function computing the TaylorF2 amplitude for the mode (l,m)
2010  * In geometric units.
2011  * Reference for SPA scaling between modes:
2012  * Section III A 2) of arxiv:2003.12079 [Phys. Rev. D 101, 124040 (2020)]
2013  */
2015  const double q, // Mass-ration m1/m2 >= 1
2016  const double chi1, // Dimensionless aligned spin of body 1
2017  const double chi2, // Dimensionless aligned spin of body 2
2018  const int l, // First mode number l
2019  const int m, // Second mode number m
2020  gsl_vector *Mfs, // Input geometric frequencies
2021  gsl_vector **PNamp // Output: TaylorF2 amplitude at frequencies Mfs
2022 ) {
2023 
2024  XLAL_CHECK(PNamp != NULL, XLAL_EFAULT);
2025  XLAL_CHECK(*PNamp == NULL, XLAL_EFAULT);
2026  *PNamp = gsl_vector_alloc(Mfs->size);
2027  double eta = q / ((1.+q)*(1.+q));
2028  // Modify delta to be tiny but nonzero for q=1 to avoid problems when hybridizing
2029  // with the ROM modes which do not vanish at q=1. This will make the modes
2030  // which should vanish exactly at q=1 about 15 orders of magnitude smaller than the (2,2) mode.
2031  double delta = (q-1. + DBL_EPSILON) / (1.+q);
2032  /* Prefactor of the Newtonian amplitude FD: A_N = G^2 M^2/r/c^5 pi sqrt(2nu/3) v^(-7/2) */
2033  /* Here in geometric units, simply pi sqrt(2nu/3) */
2034  double ampN = LAL_PI * sqrt(2*eta/3.);
2035 
2036  /* Note: we rescale the frequency (and v) according to the mode number m */
2037  for (size_t i=0; i < Mfs->size; i++) {
2038  const double Mf = gsl_vector_get(Mfs, i);
2039  const double Mf_m = 2./m * Mf;
2040  const double v = cbrt(LAL_PI * Mf_m);
2041  const double vm72 = pow(v, -7./2);
2042 
2043  /* Take into account 0.5PN (1PN for 22) amplitude of different modes */
2044  double mode_amp_factor = GetModeAmpFactor(eta, delta, chi1, chi2, l, m, v);
2045  double amp = ampN * vm72 * sqrt(2./m) * mode_amp_factor;
2046  gsl_vector_set(*PNamp, i, amp);
2047  }
2048 
2049  return XLAL_SUCCESS;
2050 }
2051 
2052 /* Build geom frequency grid suitable for waveform amp/phase interpolation */
2053 /* Based on cubic spline error bound for leading-order power-law phase */
2054 /* Reference: Section (5.1) of arXiv:1402.4146 [CQG 31 195010, 2014] */
2056  gsl_vector** Mfreq, /* Output: pointer to real vector */
2057  const double Mfmin, /* Starting geometric frequency */
2058  const double Mfmax, /* Ending geometric frequency */
2059  const double q, /* Mass ratio */
2060  const double acc) /* Desired phase interpolation error for inspiral */
2061 {
2062  /* Checks */
2063  if (*Mfreq != NULL)
2064  XLAL_ERROR(XLAL_EFAULT, "Input pointer for frequencies is not NULL.");
2065  if (!(Mfmin < Mfmax))
2066  XLAL_ERROR(XLAL_EINVAL, "Input Mf limits do not verify Mfmin < Mfmax.");
2067 
2068  double eta = q / ((1.+q) * (1.+q));
2069 
2070  /* Inspiral sampling */
2071  /* Dimensionless number so that DeltaMf = Lambda * Mf^(17/12) */
2072  /* Factor 3.8 tuned empirically */
2073  double Lambda = 3.8 * pow(acc * eta, 1./4) * pow(LAL_PI, 5./12);
2074 
2075  /* Number of samples with inspiral sampling */
2076  int N = 0;
2077  double Lambdatilde = 0.;
2078  N = 1 + ceil(12./5/Lambda * (pow(Mfmin, -5./12) - pow(Mfmax, -5./12)));
2079  /* Adjust a bit Lambda so that the last point at N_insp-1 is Mfmax */
2080  Lambdatilde = 12./5/(N-1) * (pow(Mfmin, -5./12) - pow(Mfmax, -5./12));
2081 
2082  /* Allocate output */
2083  *Mfreq = gsl_vector_alloc(N);
2084 
2085  /* Fill in values */
2086  double Mfmin_m512 = pow(Mfmin, -5./12);
2087  for (int i=0; i<N; i++) { /* includes Mfmin and Mfmax, will be readjusted */
2088  (*Mfreq)->data[i] = pow(Mfmin_m512 - 5./12*Lambdatilde*i, -12./5);
2089  }
2090 
2091  /* Eliminate rounding errors at both ends */
2092  (*Mfreq)->data[0] = Mfmin;
2093  (*Mfreq)->data[N-1] = Mfmax;
2094 
2095  return XLAL_SUCCESS;
2096 }
2097 
2099  gsl_spline **hyb_spline, /**< Output: spline */
2100  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
2101  gsl_vector *PN_freq, /**< PN frequency */
2102  gsl_vector *PN_amp, /**< PN amplitude */
2103  double f_hyb_win_lo, /**< hybridization window start */
2104  double f_hyb_win_hi /**< hybridization window end */
2105 )
2106 {
2107  gsl_vector *ROM_amp_f = NULL;
2108  gsl_vector *ROM_amp = NULL;
2109  spline_to_gsl_vectors(ampPhaseSplineData_for_mode->spline_amp, &ROM_amp_f, &ROM_amp);
2110 
2111  // Sanity checks
2112  if ( (gsl_vector_get(PN_freq, 0) > f_hyb_win_lo)
2113  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_lo)
2114  || (gsl_vector_get(PN_freq, 0) > f_hyb_win_hi)
2115  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_hi) )
2116  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for amplitude is not contained in PN frequencies.");
2117  if ( (gsl_vector_get(ROM_amp_f, 0) > f_hyb_win_lo)
2118  || (gsl_vector_get(ROM_amp_f, ROM_amp_f->size - 1) < f_hyb_win_lo)
2119  || (gsl_vector_get(ROM_amp_f, 0) > f_hyb_win_hi)
2120  || (gsl_vector_get(ROM_amp_f, ROM_amp_f->size - 1) < f_hyb_win_hi) )
2121  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for amplitude is not contained in ROM frequencies.");
2122 
2123  // Scale PN amplitude to match ROM amplitude
2124  gsl_spline *PN_amp_spline = gsl_spline_alloc(gsl_interp_cspline, PN_amp->size);
2125  gsl_spline_init(PN_amp_spline, PN_freq->data, PN_amp->data, PN_amp->size);
2126  gsl_interp_accel *acc_PN = gsl_interp_accel_alloc();
2127  gsl_interp_accel *acc_ROM = gsl_interp_accel_alloc();
2128  double PN_amp_i = gsl_spline_eval(PN_amp_spline, f_hyb_win_lo, acc_PN);
2129  double ROM_amp_i = gsl_spline_eval(ampPhaseSplineData_for_mode->spline_amp, f_hyb_win_lo, acc_ROM);
2130  double fac = ROM_amp_i / PN_amp_i;
2131  for (size_t i=0; i < PN_amp->size; i++) {
2132  double A = gsl_vector_get(PN_amp, i);
2133  gsl_vector_set(PN_amp, i, A * fac);
2134  }
2135  gsl_spline_free(PN_amp_spline);
2136  gsl_interp_accel_free(acc_PN);
2137  gsl_interp_accel_free(acc_ROM);
2138 
2139  gsl_vector *hyb_freq = NULL;
2140  gsl_vector *hyb_amp = NULL;
2142  &hyb_freq, &hyb_amp,
2143  PN_amp, ROM_amp,
2144  PN_freq, ROM_amp_f,
2145  f_hyb_win_lo, f_hyb_win_hi
2146  );
2147  // Make a spline from the hybridized data
2148  *hyb_spline = gsl_spline_alloc(gsl_interp_cspline, hyb_amp->size);
2149  gsl_spline_init(*hyb_spline, hyb_freq->data, hyb_amp->data, hyb_amp->size);
2150 
2151  gsl_vector_free(ROM_amp_f);
2152  gsl_vector_free(ROM_amp);
2153  gsl_vector_free(hyb_freq);
2154  gsl_vector_free(hyb_amp);
2155 
2156  return XLAL_SUCCESS;
2157 }
2158 
2160  gsl_spline **hyb_spline, /**< Output: spline */
2161  REAL8* Deltat_align, /**< Output: time alignment */
2162  REAL8* Deltaphi_align, /**< Output: phase alignment */
2163  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
2164  gsl_vector *PN_freq, /**< PN frequency */
2165  gsl_vector *PN_phase, /**< PN phase */
2166  double f_hyb_win_lo, /**< hybridization window start */
2167  double f_hyb_win_hi /**< hybridization window end */
2168 )
2169 {
2170  gsl_vector *ROM_phi_f = NULL;
2171  gsl_vector *ROM_phi = NULL;
2172  spline_to_gsl_vectors(ampPhaseSplineData_for_mode->spline_phi, &ROM_phi_f, &ROM_phi);
2173 
2174  // Sanity checks
2175  if ( (gsl_vector_get(PN_freq, 0) > f_hyb_win_lo)
2176  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_lo)
2177  || (gsl_vector_get(PN_freq, 0) > f_hyb_win_hi)
2178  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_hi) )
2179  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for phase is not contained in PN frequencies.");
2180  if ( (gsl_vector_get(ROM_phi_f, 0) > f_hyb_win_lo)
2181  || (gsl_vector_get(ROM_phi_f, ROM_phi_f->size - 1) < f_hyb_win_lo)
2182  || (gsl_vector_get(ROM_phi_f, 0) > f_hyb_win_hi)
2183  || (gsl_vector_get(ROM_phi_f, ROM_phi_f->size - 1) < f_hyb_win_hi) )
2184  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for phase is not contained in ROM frequencies.");
2185 
2186  gsl_vector *hyb_freq = NULL;
2187  gsl_vector *hyb_phase = NULL;
2189  &hyb_freq, &hyb_phase, Deltat_align, Deltaphi_align,
2190  PN_phase, ROM_phi,
2191  PN_freq, ROM_phi_f,
2192  f_hyb_win_lo, f_hyb_win_hi
2193  );
2194 
2195  // Make a spline from the hybridized data
2196  *hyb_spline = gsl_spline_alloc(gsl_interp_cspline, hyb_phase->size);
2197  gsl_spline_init(*hyb_spline, hyb_freq->data, hyb_phase->data, hyb_phase->size);
2198 
2199  gsl_vector_free(ROM_phi_f);
2200  gsl_vector_free(ROM_phi);
2201  gsl_vector_free(hyb_freq);
2202  gsl_vector_free(hyb_phase);
2203 
2204  return XLAL_SUCCESS;
2205 }
2206 
2208  gsl_spline **hyb_spline, /**< Output: spline */
2209  AmpPhaseSplineData *ampPhaseSplineData_for_mode, /**< ROM spline data */
2210  gsl_vector *PN_freq, /**< PN frequency */
2211  gsl_vector *PN_phase, /**< PN phase */
2212  double f_hyb_win_lo, /**< hybridization window start */
2213  double f_hyb_win_hi, /**< hybridization window end */
2214  REAL8 Deltat_22_align, /**< Input: 22 time alignment */
2215  REAL8 Deltaphi_22_align, /**< Input: 22 phase alignment */
2216  INT4 modeM /**< Input: m mode number */
2217 )
2218 {
2219  gsl_vector *ROM_phi_f = NULL;
2220  gsl_vector *ROM_phi = NULL;
2221  spline_to_gsl_vectors(ampPhaseSplineData_for_mode->spline_phi, &ROM_phi_f, &ROM_phi);
2222 
2223  // Sanity checks
2224  if ( (gsl_vector_get(PN_freq, 0) > f_hyb_win_lo)
2225  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_lo)
2226  || (gsl_vector_get(PN_freq, 0) > f_hyb_win_hi)
2227  || (gsl_vector_get(PN_freq, PN_freq->size - 1) < f_hyb_win_hi) )
2228  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for phase is not contained in PN frequencies.");
2229  if ( (gsl_vector_get(ROM_phi_f, 0) > f_hyb_win_lo)
2230  || (gsl_vector_get(ROM_phi_f, ROM_phi_f->size - 1) < f_hyb_win_lo)
2231  || (gsl_vector_get(ROM_phi_f, 0) > f_hyb_win_hi)
2232  || (gsl_vector_get(ROM_phi_f, ROM_phi_f->size - 1) < f_hyb_win_hi) )
2233  XLAL_ERROR(XLAL_EFUNC, "Hybridization window for phase is not contained in ROM frequencies.");
2234 
2235  gsl_vector *hyb_freq = NULL;
2236  gsl_vector *hyb_phase = NULL;
2238  &hyb_freq, &hyb_phase,
2239  PN_phase, ROM_phi,
2240  PN_freq, ROM_phi_f,
2241  f_hyb_win_lo, f_hyb_win_hi,
2242  Deltat_22_align, Deltaphi_22_align, modeM
2243  );
2244 
2245  // Make a spline from the hybridized data
2246  *hyb_spline = gsl_spline_alloc(gsl_interp_cspline, hyb_phase->size);
2247  gsl_spline_init(*hyb_spline, hyb_freq->data, hyb_phase->data, hyb_phase->size);
2248 
2249  gsl_vector_free(ROM_phi_f);
2250  gsl_vector_free(ROM_phi);
2251  gsl_vector_free(hyb_freq);
2252  gsl_vector_free(hyb_phase);
2253 
2254  return XLAL_SUCCESS;
2255 }
2256 
2257 
2258 // Compute spherical harmonic modes similar to SEOBNRv5HMROMCoreModes() but here the ROM modes
2259 // are hybridized with PN in the early inspiral.
2261  UNUSED SphHarmFrequencySeries **hlm_list, /**<< Output: Spherical modes frequency series for the waveform */
2262  UNUSED REAL8 phiRef, /**<< orbital reference phase */
2263  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
2264  UNUSED REAL8 distance, /**< Distance of source (m) */
2265  UNUSED REAL8 Mtot_sec, /**< Total mass in seconds **/
2266  UNUSED REAL8 q, /**< Mass ratio **/
2267  UNUSED REAL8 chi1, /**< Dimensionless aligned component spin 1 */
2268  UNUSED REAL8 chi2, /**< Dimensionless aligned component spin 2 */
2269  UNUSED const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */
2270  UNUSED REAL8 deltaF, /**< Sampling frequency (Hz).
2271  * If deltaF > 0, the frequency points given in freqs are uniformly spaced with
2272  * spacing deltaF. Otherwise, the frequency points can be spaced non-uniformly.
2273  * Then we will use deltaF = 0 to create the frequency series we return. */
2274  UNUSED INT4 nk_max, /**< truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1. We
2275  *nk_max == -1 is the default setting */
2276  UNUSED UINT4 nModes, /**< Number of modes to generate */
2277  REAL8 sign_odd_modes, /**< Sign of the odd-m modes, used when swapping the two bodies */
2278  UNUSED SEOBNRROMdataDS *romdataset /**< Dataset for the 22 or HM ROM */
2279 )
2280 {
2281  /* Find frequency bounds */
2282  if (!freqs_in) XLAL_ERROR(XLAL_EFAULT);
2283  REAL8 fLow = freqs_in->data[0];
2284  REAL8 fHigh = freqs_in->data[freqs_in->length - 1];
2285 
2286  REAL8 fLow_geom = fLow * Mtot_sec;
2287  REAL8 fHigh_geom = fHigh * Mtot_sec;
2288  REAL8 deltaF_geom = deltaF * Mtot_sec;
2289 
2290  // The maximum available frequency is the one associated with the 55 mode
2291  REAL8 Mf_ROM_max = const_fmax_lm_v5hm[4] * Get_omegaQNM_SEOBNRv5(q, chi1, chi2, 5, 5) / (2.*LAL_PI);
2292 
2293  if (fHigh_geom == 0)
2294  fHigh_geom = Mf_ROM_max;
2295  // Enforce allowed geometric frequency range
2296  // ROM starting frequency
2297  // Note: Mf_low_55 is 5/2 times Mf_low_22 and about 1e-3; this is the shortest mode
2298  // (Could make a distinction of whether we just want the 22 mode or all the modes.)
2299  if (fLow_geom <= Mf_low_22)
2300  XLAL_PRINT_INFO("Starting frequency %g is smaller than (or equal to) ROM starting frequency for (2,2) mode %g!\nUsing hybridization with TaylorF2.\n", fLow_geom, Mf_low_22);
2301  if (fLow_geom <= Mf_low_55)
2302  XLAL_PRINT_INFO("Starting frequency %g is smaller than (or equal to) ROM starting frequency for (5,5) mode %g!\nUsing hybridization with TaylorF2.\n", fLow_geom, Mf_low_55);
2303  if (fLow_geom <= 0.0) {
2304  XLALPrintError("XLAL Error - %s: Starting frequency in REAL8Sequence must be positive.\n", __func__);
2306  }
2307  // Get the splines for the amplitude and phase of the modes
2308  AmpPhaseSplineData **ampPhaseSplineData = NULL;
2309  AmpPhaseSplineData_Init(&ampPhaseSplineData, nModes);
2310  UNUSED int retcode = SEOBNRv5HMROMCoreModeAmpPhaseSplines(
2311  ampPhaseSplineData, q, chi1, chi2, nk_max, nModes,romdataset);
2312  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2313 
2314  // Safety factors for defining the hybridization window
2315  // See the definition of f_hyb_win_lo and f_hyb_win_hi below.
2316  const double f_hyb_win_lo_fac = 1.01; // Slightly above 1, so that f_hyb_win_lo will be slightly above Mf_low_lm_v5hm[k] to avoid issues with floating point comparisons
2317  const double f_hyb_win_hi_fac = 2.0;
2318  // Empirically this factor of 2 is a good choice for the length of the hybridization window with PN.
2319  // If the window is too short then there may be an abrupt change in the slope of the phase.
2320  // If the window is too wide then the linear fit will be thrown off by nonlinear contributions.
2321  // For hybridization we need the PN frequencies to contain [Mf_low_21 * f_hyb_win_lo_fac, Mf_low_55 * f_hyb_win_hi_fac] to be safe for all modes.
2322 
2323  /* Generate PN amplitudes and phases */
2324  double Mtot = Mtot_sec / LAL_MTSUN_SI;
2325 
2326  double PN_Mf_low = fmin(fLow_geom / 2.0, Mf_low_21); // Start at half of the starting frequency to avoid gsl interpolation errors in the (2,1) mode; at least starting frequency of the 22 mode.
2327  double PN_Mf_high = 1.1 * f_hyb_win_hi_fac * Mf_low_55; // to have some overlap with the shortest ROM mode
2328 
2329  gsl_vector *Mfs = NULL;
2330  const double acc = 1e-4; // Hardcoded spline interpolation accuracy target
2331  retcode = BuildInspiralGeomFrequencyGrid(&Mfs, PN_Mf_low, PN_Mf_high, q, acc);
2332  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2333 
2334  // Arrays for storing amplitude and phase splines for each mode
2335  gsl_spline *hybrid_spline_amp[nModes];
2336  gsl_spline *hybrid_spline_phi[nModes];
2337  for (UINT4 i=0; i < nModes; i++) {
2338  hybrid_spline_amp[i] = NULL;
2339  hybrid_spline_phi[i] = NULL;
2340  }
2341 
2342  // Alignment constants, time and phase shift
2343  // Computed once for (2,-2), then propagated to other modes (with possible pi)
2344  REAL8 Deltat_22_align = 0.;
2345  REAL8 Deltaphi_22_align = 0.;
2346 
2347  // Loop over all modes, hybridize, and compute modes
2348  // For the amplitude hybridize_ROM_with_PN_amplitude() will make them continuous, but the slope will be wrong
2349  for (UINT4 k=0; k < nModes; k++) {
2350  double f_hyb_win_lo = Mf_low_lm_v5hm[k] * f_hyb_win_lo_fac;
2351  double f_hyb_win_hi = Mf_low_lm_v5hm[k] * f_hyb_win_hi_fac;
2352  if (k==0)
2353  XLALPrintInfo("%s : SEOBNRv5HM_ROM hybridization window for (2,2) mode: Mf in [%g, %g]\n",
2354  __func__, f_hyb_win_lo, f_hyb_win_hi);
2355  int modeL = lmModes_v5hm[k][0];
2356  int modeM = lmModes_v5hm[k][1];
2357 
2358  gsl_vector *PNamp = NULL;
2359  gsl_vector *PNphase = NULL;
2360 
2361  // We get q >= 1 which is consistent with the TF2 wrapper functions
2362  retcode |= TaylorF2Amplitude(q, chi1, chi2, modeL, modeM, Mfs, &PNamp);
2363  retcode |= TaylorF2Phasing(Mtot, q, chi1, chi2, modeL, modeM, Mfs, &PNphase);
2364  if(retcode != 0) {
2365  gsl_vector_free(PNamp);
2366  gsl_vector_free(PNphase);
2367  gsl_vector_free(Mfs);
2368  XLAL_ERROR(retcode);
2369  }
2370 
2371  // Hybridize phase
2372  // Distinguish (2,2) (time and phase alignment output) from others (input)
2373  // NOTE: sensitive to the ordering of the modes ! We check k=0 is (2,-2)
2374  // NOTE: convention in error message, (2,2) or (2,-2) ?
2375  if (k==0) {
2376  if (!(modeL==2 && modeM==2)) {
2377  XLALPrintError ("The first mode in the loop must be (2,2).\n");
2379  }
2380  // Hybridize (2,-2) and output time and phase shift
2382  &hybrid_spline_phi[k],
2383  &Deltat_22_align,
2384  &Deltaphi_22_align,
2385  ampPhaseSplineData[k],
2386  Mfs, PNphase,
2387  f_hyb_win_lo, f_hyb_win_hi
2388  );
2389  }
2390  else {
2391  // Hybridize with time and phase shift determined from (2,-2) as input
2393  &hybrid_spline_phi[k],
2394  ampPhaseSplineData[k],
2395  Mfs, PNphase,
2396  f_hyb_win_lo, f_hyb_win_hi,
2397  Deltat_22_align, Deltaphi_22_align, modeM
2398  );
2399  }
2400 
2401  // Hybridize amplitude
2403  &hybrid_spline_amp[k],
2404  ampPhaseSplineData[k],
2405  Mfs, PNamp,
2406  f_hyb_win_lo, f_hyb_win_hi
2407  );
2408 
2409  // Set up accelerators for spline evaluation in the loop below
2410  gsl_interp_accel *acc_amp = gsl_interp_accel_alloc();
2411  gsl_interp_accel *acc_phase = gsl_interp_accel_alloc();
2412 
2413  // Set up data structure for current mode for Nyquist or user specified frequency grids
2414  size_t npts = 0;
2415  LIGOTimeGPS tC = {0, 0};
2416  UINT4 offset = 0; // Index shift between freqs and the frequency series
2417  REAL8Sequence *freqs = NULL;
2418  COMPLEX16FrequencySeries *hlmtilde = NULL;
2419 
2420  if (deltaF > 0) {
2421  // uniform frequency grid with spacing deltaF; we start at frequency 0
2422 
2423  npts = NextPow2(fHigh_geom / deltaF_geom) + 1;
2424  if (fHigh_geom < fHigh * Mtot_sec) /* Resize waveform if user wants f_max larger than cutoff frequency */
2425  npts = NextPow2(fHigh * Mtot_sec / deltaF_geom) + 1;
2426  XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */
2427 
2428  // Allocate space for the current mode
2430  "hlmtilde: FD mode", &tC, 0.0, deltaF, &lalStrainUnit, npts);
2431 
2432  // Recreate freqs using only the lower and upper bounds
2433  // Use fLow, fHigh and deltaF rather than geometric frequencies for numerical accuracy
2434  double fHigh_temp = fHigh_geom / Mtot_sec;
2435  UINT4 iStart = (UINT4) ceil(fLow / deltaF);
2436  UINT4 iStop = (UINT4) ceil(fHigh_temp / deltaF);
2437  freqs = XLALCreateREAL8Sequence(iStop - iStart);
2438  if (!freqs) XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
2439  for (UINT4 i=iStart; i<iStop; i++)
2440  freqs->data[i-iStart] = i*deltaF_geom;
2441 
2442  offset = iStart;
2443  } else {
2444  // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
2445  npts = freqs_in->length;
2446 
2447  // Allocate space for the current mode
2449  "hlmtilde: FD mode", &tC, fLow, deltaF, &lalStrainUnit, npts);
2450 
2451  freqs = XLALCreateREAL8Sequence(freqs_in->length);
2452  if (!freqs) XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
2453  for (UINT4 i=0; i<freqs_in->length; i++)
2454  freqs->data[i] = freqs_in->data[i] * Mtot_sec;
2455 
2456  offset = 0;
2457  }
2458 
2459  memset(hlmtilde->data->data, 0, npts * sizeof(COMPLEX16));
2460  COMPLEX16 *hlmdata=hlmtilde->data->data;
2461 
2462  // Correct overall amplitude to undo mass-dependent scaling used in ROM
2463  double amp0 = Mtot * Mtot_sec * LAL_MRSUN_SI / (distance);
2464 
2465  // The ROM was build with t = 0 at t_peak^22 -1000.
2466  // To agree with the LAL convention, we undo this shift to get t_peak^22 = 0.
2467  double t_corr = 1000.0;
2468 
2469  // Maximum frequency at which we have data for the ROM
2470  double Mf_max_mode = const_fmax_lm_v5hm[k] * Get_omegaQNM_SEOBNRv5(
2471  q, chi1, chi2, modeL, modeM) / (2.0*LAL_PI);
2472 
2473  // Loop over frequency points in sequence
2474  for (UINT4 i=0; i < freqs->length; i++) {
2475  double f = freqs->data[i];
2476  if (f > Mf_max_mode) continue; // We're beyond the highest allowed frequency; since freqs may not be ordered, we'll just skip the current frequency and leave zero in the buffer
2477  int j = i + offset; // shift index for frequency series if needed
2478 
2479  // Assemble mode from amplitude and phase
2480  REAL8 A = gsl_spline_eval(hybrid_spline_amp[k], f, acc_amp);
2481  REAL8 phase = gsl_spline_eval(hybrid_spline_phi[k], f, acc_phase);
2482  hlmdata[j] = amp0*A * (cos(phase) + I*sin(phase));
2483  REAL8 phase_factor = -2.0*LAL_PI * f * t_corr;
2484  COMPLEX16 t_factor = cos(phase_factor) + I*sin(phase_factor);
2485  hlmdata[j] *= t_factor;
2486  // We now return the (l,-m) mode that in the LAL convention has support for f > 0
2487  // We use the equation h(l,-m)(f) = (-1)^l h(l,m)*(-f) with f > 0
2488  hlmdata[j] = pow(-1.0, modeL) * conj(hlmdata[j]);
2489  if(modeM%2 != 0){
2490  // This is changing the sign of the odd-m modes in the case m1 < m2.
2491  // If m1>m2 sign_odd_modes = 1 and nothing changes
2492  hlmdata[j] = hlmdata[j] * sign_odd_modes;
2493  }
2494  }
2495  /* Save the mode (l,-m) in the SphHarmFrequencySeries structure */
2496  *hlm_list = XLALSphHarmFrequencySeriesAddMode(*hlm_list, hlmtilde, modeL, -modeM);
2497 
2498  // Cleanup
2500  gsl_interp_accel_free(acc_amp);
2501  gsl_interp_accel_free(acc_phase);
2502  gsl_vector_free(PNamp);
2503  gsl_vector_free(PNphase);
2504  XLALDestroyREAL8Sequence(freqs);
2505  }
2506 
2507  // Cleanup outside of loop
2508  gsl_vector_free(Mfs);
2509  AmpPhaseSplineData_Destroy(ampPhaseSplineData, nModes);
2510 
2511  for (UINT4 k=0; k < nModes; k++) {
2512  gsl_spline_free(hybrid_spline_amp[k]);
2513  gsl_spline_free(hybrid_spline_phi[k]);
2514  }
2515  return(XLAL_SUCCESS);
2516 }
2517 
2518 /**
2519  * @addtogroup LALSimIMRSEOBNRv5HMROM_c
2520  *
2521  * \author Lorenzo Pompili, Roberto Cotesta, Sylvain Marsat, Michael Puerrer
2522  *
2523  * \brief C code for SEOBNRv5HM reduced order model *
2524  *
2525  * This is a frequency domain model that approximates the time domain SEOBNRv5HM model described in ...
2526  *
2527  * The binary data HDF5 file (SEOBNRv5ROM_v1.0.hdf5) is available on the lalsuite-extra repository https://git.ligo.org/lscsoft/lalsuite-extra
2528  * Make sure the files are in your LAL_DATA_PATH.
2529  *
2530  * @note Parameter ranges:
2531  * * 1 <= q <= 100
2532  * * -0.998 <= chi_i <= 0.998
2533  * * no limitations on f_low as the mode is hybridized with Taylor F2 at low frequencies
2534  *
2535  * Aligned component spins chi1, chi2.
2536  * Mass-ratio q = m1/m2 >= 1
2537  *
2538  *
2539  * @{
2540  */
2541 /**
2542  * Compute waveform in LAL format for the SEOBNRv5HM_ROM model.
2543  *
2544  * Returns the plus and cross polarizations as a complex frequency series with
2545  * equal spacing deltaF and contains zeros from zero frequency to the starting
2546  * frequency fLow and zeros beyond the cutoff frequency in the ringdown.
2547  */
2549  UNUSED struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
2550  UNUSED struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
2551  UNUSED REAL8 phiRef, /**< Phase at reference time */
2552  UNUSED REAL8 deltaF, /**< Sampling frequency (Hz) */
2553  REAL8 fLow, /**< Starting GW frequency (Hz) */
2554  UNUSED REAL8 fHigh, /**< End frequency */
2555  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
2556  UNUSED REAL8 distance, /**< Distance of source (m) */
2557  UNUSED REAL8 inclination, /**< Inclination of source (rad) */
2558  REAL8 m1SI, /**< Mass of companion 1 (kg) */
2559  REAL8 m2SI, /**< Mass of companion 2 (kg) */
2560  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
2561  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
2562  UNUSED INT4 nk_max, /**< Truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 */
2563  UNUSED UINT4 nModes, /**< Number of modes to use. This should be 1 for SEOBNRv5_ROM and 7 for SEOBNRv5HM_ROM */
2564  bool use_hybridization, /**< Whether the ROM should be hybridized */
2565  LALDict *LALParams /**<< Dictionary of additional wf parameters, here is used to pass ModeArray */
2566 )
2567 {
2568  REAL8 sign_odd_modes = 1.;
2569  /* Internally we need m1 > m2, so change around if this is not the case */
2570  if (m1SI < m2SI) {
2571  // Swap m1 and m2
2572  REAL8 m1temp = m1SI;
2573  REAL8 chi1temp = chi1;
2574  m1SI = m2SI;
2575  chi1 = chi2;
2576  m2SI = m1temp;
2577  chi2 = chi1temp;
2578  sign_odd_modes = -1.; // When we swap m1 with m2 odd-m modes should get - sign because they depend on dm
2579  }
2580 
2581  /* Get masses in terms of solar mass */
2582  REAL8 mass1 = m1SI / LAL_MSUN_SI;
2583  REAL8 mass2 = m2SI / LAL_MSUN_SI;
2584  REAL8 Mtot = mass1+mass2;
2585  REAL8 q = mass1/mass2;
2586  UNUSED REAL8 Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
2587 
2588  /* Select modes to include in the waveform */
2589  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(LALParams);
2590  //ModeArray includes the modes chosen by the user
2591  if (ModeArray == NULL) {
2592  //If the user doesn't choose the modes, use the standard modes
2593  ModeArray = XLALSimInspiralCreateModeArray();
2595  }
2596  //Check that the modes chosen are available for the model
2598  XLALPrintError ("Not available mode chosen.\n");
2600  }
2601 
2602  // Use fLow, fHigh, deltaF to compute freqs sequence
2603  // Instead of building a full sequency we only transfer the boundaries and let
2604  // the internal core function do the rest (and properly take care of corner cases).
2606  freqs->data[0] = fLow;
2607  freqs->data[1] = fHigh;
2608 
2609  SEOBNRROMdataDS *romdataset;
2610 
2611  /* Load ROM data if not loaded already */
2612 #ifdef LAL_PTHREAD_LOCK
2613  if (nModes == 1){
2614  romdataset=__lalsim_SEOBNRv5ROMDS_data;
2615  (void) pthread_once(&SEOBNRv5ROM_is_initialized, SEOBNRv5ROM_Init_LALDATA);
2616  }
2617  else{
2618  romdataset=__lalsim_SEOBNRv5HMROMDS_data;
2619  (void) pthread_once(&SEOBNRv5HMROM_is_initialized, SEOBNRv5HMROM_Init_LALDATA);
2620  }
2621 #else
2622  if (nModes == 1){
2624  }
2625  else{
2627  }
2628 #endif
2629  SphHarmFrequencySeries *hlm = NULL;
2630 
2631  /* Generate modes */
2632  UINT8 retcode = 0;
2633  if (use_hybridization) {
2634  retcode = SEOBNRv5HMROMCoreModesHybridized(&hlm,
2635  phiRef, fRef, distance, Mtot_sec, q, chi1, chi2, freqs, deltaF, nk_max,
2636  nModes, sign_odd_modes, romdataset);
2637  }
2638  else {
2639  retcode = SEOBNRv5HMROMCoreModes(&hlm,
2640  phiRef, fRef, distance, Mtot_sec, q, chi1, chi2, freqs, deltaF, nk_max,
2641  nModes, sign_odd_modes, romdataset);
2642  }
2643  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2644 
2645 
2646  /* GPS time for output frequency series and modes */
2648  LIGOTimeGPS tGPS = hlm_for_hphc->epoch;
2649  size_t npts = hlm_for_hphc->data->length;
2650 
2651  /* Create output frequencyseries for hplus, hcross */
2652  UNUSED COMPLEX16FrequencySeries *hPlustilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tGPS, 0.0, deltaF,&lalStrainUnit, npts);
2653  UNUSED COMPLEX16FrequencySeries *hCrosstilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tGPS, 0.0, deltaF,&lalStrainUnit, npts);
2654  memset(hPlustilde->data->data, 0, npts * sizeof(COMPLEX16));
2655  memset(hCrosstilde->data->data, 0, npts * sizeof(COMPLEX16));
2656  XLALUnitMultiply(&hPlustilde->sampleUnits, &hPlustilde->sampleUnits, &lalSecondUnit);
2657  XLALUnitMultiply(&hCrosstilde->sampleUnits, &hCrosstilde->sampleUnits, &lalSecondUnit);
2658  retcode = SEOBROMComputehplushcrossFromhlm(hPlustilde,hCrosstilde,ModeArray,hlm,inclination,phiRef);
2659  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2660 
2661  /* Point the output pointers to the relevant time series and return */
2662  (*hptilde) = hPlustilde;
2663  (*hctilde) = hCrosstilde;
2664 
2665  XLALDestroyREAL8Sequence(freqs);
2667  XLALDestroyValue(ModeArray);
2668 
2669  // This is a debug enviromental variable, when activated is deleting the ROM dataset from memory
2670  const char* s = getenv("FREE_MEMORY_SEOBNRv5HMROM");
2671  if (s!=NULL){
2672  for(unsigned int index_mode = 0; index_mode < nModes;index_mode++){
2673  SEOBNRROMdataDS_Cleanup(&romdataset[index_mode]);
2674  }
2675  }
2676 
2677  return(XLAL_SUCCESS);
2678 }
2679 
2680 /**
2681 * Compute waveform polarizations at user specified frequencies for the SEOBNRv5HM_ROM model
2682 *
2683 * This function is designed as an entry point for reduced order quadratures.
2684 * Since ROQs are most effective for long waveforms the hybridized ROM is used.
2685 *
2686 */
2688  UNUSED struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */
2689  UNUSED struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */
2690  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz) */
2691  UNUSED REAL8 phiRef, /**< Phase at reference time */
2692  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
2693  UNUSED REAL8 distance, /**< Distance of source (m) */
2694  UNUSED REAL8 inclination, /**< Inclination of source (rad) */
2695  REAL8 m1SI, /**< Mass of companion 1 (kg) */
2696  REAL8 m2SI, /**< Mass of companion 2 (kg) */
2697  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
2698  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
2699  UNUSED INT4 nk_max, /**< Truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 */
2700  UNUSED UINT4 nModes, /**< Number of modes to use. This should be 1 for SEOBNRv5_ROM and 7 for SEOBNRv5HM_ROM */
2701  LALDict *LALParams /**<< Dictionary of additional wf parameters, here is used to pass ModeArray */
2702 )
2703 {
2704  REAL8 sign_odd_modes = 1.;
2705  /* Internally we need m1 > m2, so change around if this is not the case */
2706  if (m1SI < m2SI) {
2707  // Swap m1 and m2
2708  REAL8 m1temp = m1SI;
2709  REAL8 chi1temp = chi1;
2710  m1SI = m2SI;
2711  chi1 = chi2;
2712  m2SI = m1temp;
2713  chi2 = chi1temp;
2714  sign_odd_modes = -1.; // When we swap m1 with m2 odd-m modes should get - sign because they depend on dm
2715  }
2716 
2717  /* Get masses in terms of solar mass */
2718  REAL8 mass1 = m1SI / LAL_MSUN_SI;
2719  REAL8 mass2 = m2SI / LAL_MSUN_SI;
2720  REAL8 Mtot = mass1+mass2;
2721  REAL8 q = mass1/mass2;
2722  UNUSED REAL8 Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
2723 
2724  /* Select modes to include in the waveform */
2725  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(LALParams);
2726  //ModeArray includes the modes chosen by the user
2727  if (ModeArray == NULL) {
2728  //If the user doesn't choose the modes, use the standard modes
2729  ModeArray = XLALSimInspiralCreateModeArray();
2731  }
2732  //Check that the modes chosen are available for the model
2734  XLALPrintError ("Not available mode chosen.\n");
2736  }
2737 
2738  SEOBNRROMdataDS *romdataset;
2739 
2740  /* Load ROM data if not loaded already */
2741 #ifdef LAL_PTHREAD_LOCK
2742  if (nModes == 1){
2743  romdataset=__lalsim_SEOBNRv5ROMDS_data;
2744  (void) pthread_once(&SEOBNRv5ROM_is_initialized, SEOBNRv5ROM_Init_LALDATA);
2745  }
2746  else{
2747  romdataset=__lalsim_SEOBNRv5HMROMDS_data;
2748  (void) pthread_once(&SEOBNRv5HMROM_is_initialized, SEOBNRv5HMROM_Init_LALDATA);
2749  }
2750 #else
2751  if (nModes == 1){
2753  }
2754  else{
2756  }
2757 #endif
2758  SphHarmFrequencySeries *hlm = NULL;
2759 
2760  // Call the internal core function with deltaF = 0 to indicate that freqs is non-uniformly
2761  // spaced and we want the strain only at these frequencies
2762  // The FS interface is only implemented for the hybridized ROM
2763  double deltaF = 0.0;
2764 
2765  /* Generate modes */
2766  UINT8 retcode = 0;
2767  retcode = SEOBNRv5HMROMCoreModesHybridized(&hlm,
2768  phiRef, fRef, distance, Mtot_sec, q, chi1, chi2, freqs, deltaF, nk_max,
2769  nModes, sign_odd_modes, romdataset);
2770  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2771 
2772 
2773  /* GPS time for output frequency series and modes */
2775  LIGOTimeGPS tGPS = hlm_for_hphc->epoch;
2776  size_t npts = hlm_for_hphc->data->length;
2777 
2778  double fLow = freqs->data[0];
2779  /* Create output frequencyseries for hplus, hcross */
2781  "hptilde: FD waveform", &tGPS, fLow, deltaF, &lalStrainUnit, npts);
2783  "hctilde: FD waveform", &tGPS, fLow, deltaF, &lalStrainUnit, npts);
2784  memset(hPlustilde->data->data, 0, npts * sizeof(COMPLEX16));
2785  memset(hCrosstilde->data->data, 0, npts * sizeof(COMPLEX16));
2786  XLALUnitDivide(&hPlustilde->sampleUnits, &hPlustilde->sampleUnits, &lalSecondUnit);
2787  XLALUnitDivide(&hCrosstilde->sampleUnits, &hCrosstilde->sampleUnits, &lalSecondUnit);
2788  retcode = SEOBROMComputehplushcrossFromhlm(hPlustilde, hCrosstilde, ModeArray, hlm, inclination, phiRef);
2789  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
2790 
2791  /* Point the output pointers to the relevant time series and return */
2792  (*hptilde) = hPlustilde;
2793  (*hctilde) = hCrosstilde;
2794 
2796  XLALDestroyValue(ModeArray);
2797 
2798  // This is a debug enviromental variable; when activated it deletes the ROM dataset from memory.
2799  const char* s = getenv("FREE_MEMORY_SEOBNRv5HMROM");
2800  if (s!=NULL){
2801  for(unsigned int index_mode = 0; index_mode < nModes;index_mode++){
2802  SEOBNRROMdataDS_Cleanup(&romdataset[index_mode]);
2803  }
2804  }
2805 
2806  return(XLAL_SUCCESS);
2807 }
2808 
2809 /**
2810  * Compute modes in LAL format for the SEOBNRv5HM_ROM model.
2811  *
2812  * Returns hlm modes as a SphHarmFrequencySeries with
2813  * equal spacing deltaF and contains zeros from zero frequency to the starting
2814  * frequency fLow and zeros beyond the cutoff frequency in the ringdown.
2815  */
2817  SphHarmFrequencySeries **hlm, /**< Output: Frequency-domain hlm */
2818  UNUSED REAL8 phiRef, /**< Phase at reference time */
2819  UNUSED REAL8 deltaF, /**< Sampling frequency (Hz) */
2820  REAL8 fLow, /**< Starting GW frequency (Hz) */
2821  UNUSED REAL8 fHigh, /**< End frequency; 0 defaults to Mf=0.14 */
2822  REAL8 fRef, /**< Reference frequency unused here */
2823  REAL8 distance, /**< Reference frequency (Hz); 0 defaults to fLow */
2824  REAL8 m1SI, /**< Mass of companion 1 (kg) */
2825  REAL8 m2SI, /**< Mass of companion 2 (kg) */
2826  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
2827  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
2828  UNUSED INT4 nk_max, /**< Truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 */
2829  UNUSED UINT4 nModes, /**< Number of modes to use. This should be 1 for SEOBNRv5_ROM and 7 for SEOBNRv5HM_ROM */
2830  bool use_hybridization /**< Whether the ROM should be hybridized */
2831 )
2832 {
2833  REAL8 sign_odd_modes = 1.;
2834  /* Internally we need m1 > m2, so change around if this is not the case */
2835  if (m1SI < m2SI) {
2836  // Swap m1 and m2
2837  REAL8 m1temp = m1SI;
2838  REAL8 chi1temp = chi1;
2839  m1SI = m2SI;
2840  chi1 = chi2;
2841  m2SI = m1temp;
2842  chi2 = chi1temp;
2843  sign_odd_modes = -1.; // When we swap m1 with m2 odd-m modes should get - sign because they depend on dm
2844  }
2845  /* Check if the number of modes makes sense */
2846 
2847  if(nModes >7){
2848  XLAL_PRINT_ERROR("Requested number of modes not available. Set nModes = 0 to get all the available modes.\n");
2850  }
2851 
2852  /* Get masses in terms of solar mass */
2853  REAL8 mass1 = m1SI / LAL_MSUN_SI;
2854  REAL8 mass2 = m2SI / LAL_MSUN_SI;
2855  REAL8 Mtot = mass1+mass2;
2856  REAL8 q = mass1/mass2;
2857  UNUSED REAL8 Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
2858 
2859  if(fRef==0.0)
2860  fRef=fLow;
2861 
2862  // Use fLow, fHigh, deltaF to compute freqs sequence
2863  // Instead of building a full sequency we only transfer the boundaries and let
2864  // the internal core function do the rest (and properly take care of corner cases).
2866  freqs->data[0] = fLow;
2867  freqs->data[1] = fHigh;
2868 
2869  SEOBNRROMdataDS *romdataset;
2870 
2871  /* Load ROM data if not loaded already */
2872 #ifdef LAL_PTHREAD_LOCK
2873  if (nModes == 1){
2874  romdataset=__lalsim_SEOBNRv5ROMDS_data;
2875  (void) pthread_once(&SEOBNRv5ROM_is_initialized, SEOBNRv5ROM_Init_LALDATA);
2876  }
2877  else{
2878  romdataset=__lalsim_SEOBNRv5HMROMDS_data;
2879  (void) pthread_once(&SEOBNRv5HMROM_is_initialized, SEOBNRv5HMROM_Init_LALDATA);
2880  }
2881 #else
2882  if (nModes == 1){
2884  }
2885  else{
2887  }
2888 #endif
2889 
2890  /* Generate modes */
2891  UNUSED UINT8 retcode;
2892 
2893  if (use_hybridization) {
2894  if(nModes == 0) // Return all modes by default
2895  retcode = SEOBNRv5HMROMCoreModesHybridized(hlm, phiRef, fRef, distance,
2896  Mtot_sec, q, chi1, chi2, freqs,
2897  deltaF, nk_max, 7, sign_odd_modes, romdataset);
2898  else
2899  retcode = SEOBNRv5HMROMCoreModesHybridized(hlm, phiRef, fRef, distance,
2900  Mtot_sec, q, chi1, chi2, freqs,
2901  deltaF, nk_max, nModes, sign_odd_modes, romdataset);
2902  }
2903  else { // No hybridization
2904  if(nModes == 0) // Return all modes by default
2905  retcode = SEOBNRv5HMROMCoreModes(hlm, phiRef, fRef, distance,
2906  Mtot_sec, q, chi1, chi2, freqs,
2907  deltaF, nk_max, 7, sign_odd_modes, romdataset);
2908  else
2909  retcode = SEOBNRv5HMROMCoreModes(hlm, phiRef, fRef, distance,
2910  Mtot_sec, q, chi1, chi2, freqs,
2911  deltaF, nk_max, nModes, sign_odd_modes, romdataset);
2912 }
2913 
2914  XLALDestroyREAL8Sequence(freqs);
2915 
2916  return(XLAL_SUCCESS);
2917 }
2918 
2919 /**
2920 * Compute waveform modes at user specified frequencies for the SEOBNRv5HM_ROM model
2921 *
2922 * This is a convenience function. It uses the hybridized ROM.
2923 *
2924 */
2926  SphHarmFrequencySeries **hlm, /**< Output: Frequency-domain hlm */
2927  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz) */
2928  UNUSED REAL8 phiRef, /**< Phase at reference time */
2929  UNUSED REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */
2930  UNUSED REAL8 distance, /**< Distance of source (m) */
2931  UNUSED REAL8 inclination, /**< Inclination of source (rad) */
2932  REAL8 m1SI, /**< Mass of companion 1 (kg) */
2933  REAL8 m2SI, /**< Mass of companion 2 (kg) */
2934  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
2935  REAL8 chi2, /**< Dimensionless aligned component spin 2 */
2936  UNUSED INT4 nk_max, /**< Truncate interpolants at SVD mode nk_max; don't truncate if nk_max == -1 */
2937  UNUSED UINT4 nModes, /**< Number of modes to use. This should be 1 for SEOBNRv5_ROM and 7 for SEOBNRv5HM_ROM */
2938  LALDict *LALParams /**<< Dictionary of additional wf parameters, here is used to pass ModeArray */
2939 )
2940 {
2941  REAL8 sign_odd_modes = 1.;
2942  /* Internally we need m1 > m2, so change around if this is not the case */
2943  if (m1SI < m2SI) {
2944  // Swap m1 and m2
2945  REAL8 m1temp = m1SI;
2946  REAL8 chi1temp = chi1;
2947  m1SI = m2SI;
2948  chi1 = chi2;
2949  m2SI = m1temp;
2950  chi2 = chi1temp;
2951  sign_odd_modes = -1.; // When we swap m1 with m2 odd-m modes should get - sign because they depend on dm
2952  }
2953 
2954  /* Get masses in terms of solar mass */
2955  REAL8 mass1 = m1SI / LAL_MSUN_SI;
2956  REAL8 mass2 = m2SI / LAL_MSUN_SI;
2957  REAL8 Mtot = mass1+mass2;
2958  REAL8 q = mass1/mass2;
2959  UNUSED REAL8 Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
2960 
2961  /* Select modes to include in the waveform */
2962  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(LALParams);
2963  //ModeArray includes the modes chosen by the user
2964  if (ModeArray == NULL) {
2965  //If the user doesn't choose the modes, use the standard modes
2966  ModeArray = XLALSimInspiralCreateModeArray();
2968  }
2969  //Check that the modes chosen are available for the model
2971  XLALPrintError ("Not available mode chosen.\n");
2973  }
2974 
2975  SEOBNRROMdataDS *romdataset;
2976 
2977  /* Load ROM data if not loaded already */
2978 #ifdef LAL_PTHREAD_LOCK
2979  if (nModes == 1){
2980  romdataset=__lalsim_SEOBNRv5ROMDS_data;
2981  (void) pthread_once(&SEOBNRv5ROM_is_initialized, SEOBNRv5ROM_Init_LALDATA);
2982  }
2983  else{
2984  romdataset=__lalsim_SEOBNRv5HMROMDS_data;
2985  (void) pthread_once(&SEOBNRv5HMROM_is_initialized, SEOBNRv5HMROM_Init_LALDATA);
2986  }
2987 #else
2988  if (nModes == 1){
2990  }
2991  else{
2993  }
2994 #endif
2995 
2996  // Call the internal core function with deltaF = 0 to indicate that freqs is non-uniformly
2997  // spaced and we want the modes only at these frequencies
2998  // The FS interface is only implemented for the hybridized ROM
2999  double deltaF = 0.0;
3000 
3001  /* Generate modes */
3002  UINT8 retcode = 0;
3003  retcode = SEOBNRv5HMROMCoreModesHybridized(hlm,
3004  phiRef, fRef, distance, Mtot_sec, q, chi1, chi2, freqs, deltaF, nk_max,
3005  nModes, sign_odd_modes, romdataset);
3006  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
3007 
3008  XLALDestroyValue(ModeArray);
3009 
3010  // This is a debug enviromental variable; when activated it deletes the ROM dataset from memory.
3011  const char* s = getenv("FREE_MEMORY_SEOBNRv5HMROM");
3012  if (s!=NULL){
3013  for(unsigned int index_mode = 0; index_mode < nModes;index_mode++){
3014  SEOBNRROMdataDS_Cleanup(&romdataset[index_mode]);
3015  }
3016  }
3017 
3018  return(retcode);
3019 }
3020 
3021 // Auxiliary function to perform setup of phase spline for t(f) and f(t) functions
3023  gsl_spline **spline_phi, // phase spline
3024  gsl_interp_accel **acc_phi, // phase spline accelerator
3025  REAL8 *Mf_final, // ringdown frequency in Mf
3026  REAL8 *Mtot_sec, // total mass in seconds
3027  REAL8 m1SI, // Mass of companion 1 (kg)
3028  REAL8 m2SI, // Mass of companion 2 (kg)
3029  REAL8 chi1, // Aligned spin of companion 1
3030  REAL8 chi2, // Aligned spin of companion 2
3031  REAL8 Mf_start, // Starting geometric frequency
3032  REAL8 *Mf_ROM_min, // Lowest geometric frequency for ROM
3033  REAL8 *Mf_ROM_max // Highest geometric frequency for ROM
3034 )
3035 {
3036  /* Get masses in terms of solar mass */
3037  double mass1 = m1SI / LAL_MSUN_SI;
3038  double mass2 = m2SI / LAL_MSUN_SI;
3039  double Mtot = mass1 + mass2;
3040  double q = mass1 / mass2;
3041  double eta = mass1 * mass2 / (Mtot*Mtot); /* Symmetric mass-ratio */
3042  *Mtot_sec = Mtot * LAL_MTSUN_SI; /* Total mass in seconds */
3043 
3044  /* 'Nudge' parameter values to allowed boundary values if close by */
3045  if (q < 1.0) nudge(&q, 1.0, 1e-6);
3046  if (q > 100.0) nudge(&q, 100.0, 1e-6);
3047 
3048  if ( chi1 < -0.998 || chi2 < -0.998 || chi1 > 0.998 || chi2 > 0.998) {
3049  XLALPrintError("XLAL Error - %s: chi1 or chi2 smaller than -0.998 or larger than 0.998!\n"
3050  "SEOBNRv5HMROM is only available for spins in the range -0.998 <= a/M <= 0.998.\n",
3051  __func__);
3052  XLAL_ERROR( XLAL_EDOM );
3053  }
3054 
3055  if (q<1.0 || q > 100.0) {
3056  XLALPrintError("XLAL Error - %s: q (%f) bigger than 100.0 or unphysical!\n"
3057  "SEOBNRv5HMROM is only available for q in the range 1 <= q <= 100.\n",
3058  __func__, q);
3059  XLAL_ERROR( XLAL_EDOM );
3060  }
3061 
3062  SEOBNRROMdataDS *romdataset;
3063 
3064  /* Load ROM data if not loaded already */
3065 #ifdef LAL_PTHREAD_LOCK
3066  romdataset=__lalsim_SEOBNRv5ROMDS_data;
3067  (void) pthread_once(&SEOBNRv5ROM_is_initialized, SEOBNRv5ROM_Init_LALDATA);
3068 #else
3070 #endif
3071 
3072  UINT4 nModes = 1; /* 22 mode only */
3073  UINT4 nk_max = -1; /* Default value */
3074  // Get the splines for the amplitude and phase of the modes
3075  AmpPhaseSplineData **ampPhaseSplineData = NULL;
3076  AmpPhaseSplineData_Init(&ampPhaseSplineData, nModes);
3077  UNUSED int retcode = SEOBNRv5HMROMCoreModeAmpPhaseSplines(
3078  ampPhaseSplineData, q, chi1, chi2, nk_max, nModes,romdataset);
3079  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
3080 
3081  // Setup hybridized phase splines as in SEOBNRv5HMROMCoreModesHybridized
3082 
3083  // Safety factors for defining the hybridization window
3084  const double f_hyb_win_lo_fac = 1.01;
3085  const double f_hyb_win_hi_fac = 2.0;
3086 
3087  /* Generate PN phases */
3088  double PN_Mf_low = fmin(Mf_start / 2.0, Mf_low_21); // Start at half of the starting frequency to avoid gsl interpolation errors in the (2,1) mode; at least starting frequency of the 22 mode.
3089  double PN_Mf_high = 1.1 * f_hyb_win_hi_fac * Mf_low_55; // to have some overlap with the shortest ROM mode
3090 
3091  gsl_vector *Mfs = NULL;
3092  const double acc = 1e-4; // Hardcoded spline interpolation accuracy target
3093  retcode = BuildInspiralGeomFrequencyGrid(&Mfs, PN_Mf_low, PN_Mf_high, q, acc);
3094  if(retcode != XLAL_SUCCESS) XLAL_ERROR(retcode);
3095 
3096  // Arrays for storing phase spline for each mode
3097  gsl_spline *hybrid_spline_phi[nModes];
3098  for (UINT4 i=0; i < nModes; i++) {
3099  hybrid_spline_phi[i] = NULL;
3100  }
3101 
3102  // Alignment constants, time and phase shift
3103  // Computed once for (2,-2), then propagated to other modes (with possible pi)
3104  REAL8 Deltat_22_align = 0.;
3105  REAL8 Deltaphi_22_align = 0.;
3106 
3107  // Loop over all modes and hybridize
3108  for (UINT4 k=0; k < nModes; k++) {
3109  double f_hyb_win_lo = Mf_low_lm_v5hm[k] * f_hyb_win_lo_fac;
3110  double f_hyb_win_hi = Mf_low_lm_v5hm[k] * f_hyb_win_hi_fac;
3111  if (k==0)
3112  XLALPrintInfo("%s : SEOBNRv5HM_ROM hybridization window for (2,2) mode: Mf in [%g, %g]\n",
3113  __func__, f_hyb_win_lo, f_hyb_win_hi);
3114  int modeL = lmModes_v5hm[k][0];
3115  int modeM = lmModes_v5hm[k][1];
3116 
3117  gsl_vector *PNphase = NULL;
3118 
3119  // We get q >= 1 which is consistent with the TF2 wrapper functions
3120  retcode |= TaylorF2Phasing(Mtot, q, chi1, chi2, modeL, modeM, Mfs, &PNphase);
3121  if(retcode != 0) {
3122  gsl_vector_free(PNphase);
3123  gsl_vector_free(Mfs);
3124  XLAL_ERROR(retcode);
3125  }
3126 
3127  // Hybridize phase
3128  if (!(modeL==2 && modeM==2)) {
3129  XLALPrintError ("Only the (2,2) mode is used.\n");
3131  }
3132  // Hybridize (2,-2) and output time and phase shift
3134  &hybrid_spline_phi[k],
3135  &Deltat_22_align,
3136  &Deltaphi_22_align,
3137  ampPhaseSplineData[k],
3138  Mfs, PNphase,
3139  f_hyb_win_lo, f_hyb_win_hi
3140  );
3141  }
3142 
3143  *spline_phi = hybrid_spline_phi[0];
3144  *acc_phi = ampPhaseSplineData[0]->acc_phi;
3145 
3146  // lowest allowed geometric frequency for ROM
3147  *Mf_ROM_min = Mf_low_22;
3148  // highest allowed geometric frequency for ROM is the one associated with the 55 mode
3149  *Mf_ROM_max = const_fmax_lm_v5hm[4] * Get_omegaQNM_SEOBNRv5(q, chi1, chi2, 5, 5) / (2.*LAL_PI);
3150 
3151  // Get SEOBNRv5_ROM ringdown frequency for 22 mode
3152  *Mf_final = SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(*Mtot_sec, eta, chi1, chi2,
3153  SEOBNRv5_ROM);
3154 
3155  return(XLAL_SUCCESS);
3156 }
3157 
3158 /**
3159  * Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
3160  * Analogous of XLALSimIMRSEOBNRv4ROMTimeOfFrequency from LALSimIMRSEOBNRv4ROM.c
3161  *
3162  * The notion of elapsed 'time' (in seconds) is defined here as the difference of the
3163  * frequency derivative of the frequency domain phase between the ringdown frequency
3164  * and the starting frequency ('frequency' argument). This notion of time is similar to the
3165  * chirp time, but it includes both the inspiral and the merger ringdown part of SEOBNRv5_ROM.
3166  *
3167  * The SEOBNRv5_ROM ringdown frequency can be obtained by calling XLALSimInspiralGetFinalFreq().
3168  *
3169  */
3171  REAL8 *t, /**< Output: time (s) elapsed from starting frequency to ringdown */
3172  REAL8 frequency, /**< Starting frequency (Hz) */
3173  REAL8 m1SI, /**< Mass of companion 1 (kg) */
3174  REAL8 m2SI, /**< Mass of companion 2 (kg) */
3175  REAL8 chi1, /**< Dimensionless aligned component spin 1 */
3176  REAL8 chi2 /**< Dimensionless aligned component spin 2 */
3177 )
3178 {
3179  /* Internally we need m1 > m2, so change around if this is not the case */
3180  if (m1SI < m2SI) {
3181  // Swap m1 and m2
3182  double m1temp = m1SI;
3183  double chi1temp = chi1;
3184  m1SI = m2SI;
3185  chi1 = chi2;
3186  m2SI = m1temp;
3187  chi2 = chi1temp;
3188  }
3189 
3190  // Set up phase spline
3191  gsl_spline *spline_phi;
3192  gsl_interp_accel *acc_phi;
3193  double Mf_final, Mtot_sec;
3194  double Mf_ROM_min, Mf_ROM_max;
3195  double Mf = frequency * (m1SI + m2SI) * LAL_MTSUN_SI / LAL_MSUN_SI;
3196 
3197  int ret = SEOBNRv5ROMTimeFrequencySetup(&spline_phi, &acc_phi, &Mf_final,
3198  &Mtot_sec, m1SI, m2SI, chi1, chi2, Mf,
3199  &Mf_ROM_min, &Mf_ROM_max);
3200  if(ret != 0)
3201  XLAL_ERROR(ret);
3202 
3203  // Time correction is t(f_final) = 1/(2pi) dphi/df (f_final)
3204  double t_corr = gsl_spline_eval_deriv(spline_phi, Mf_final, acc_phi) / (2*LAL_PI); // t_corr / M
3205  //XLAL_PRINT_INFO("t_corr[s] = %g\n", t_corr * Mtot_sec);
3206 
3207  if (Mf > Mf_ROM_max || Mf > Mf_final) {
3208  gsl_spline_free(spline_phi);
3209  gsl_interp_accel_free(acc_phi);
3210  XLAL_ERROR(XLAL_EDOM, "Frequency %g Hz (Mf=%g) is outside allowed range.\n"
3211  "Min / max / final Mf values are %g, %g, %g\n", frequency, Mf, Mf_ROM_min, Mf_ROM_max, Mf_final);
3212  }
3213 
3214  // Compute time relative to origin at merger
3215  double time_M = gsl_spline_eval_deriv(spline_phi, frequency * Mtot_sec, acc_phi) / (2*LAL_PI) - t_corr;
3216  // Add a minus factor to match SEOBNRv4_ROM conventions
3217  *t = -1. * time_M * Mtot_sec;
3218 
3219  gsl_spline_free(spline_phi);
3220  gsl_interp_accel_free(acc_phi);
3221 
3222  return(XLAL_SUCCESS);
3223 }
3224 
3225 /** @} */
struct tagLALH5File LALH5File
void XLALDestroyDict(LALDict *dict)
LALDict * XLALCreateDict(void)
static const REAL8 Mf_ROM_max
static const REAL8 Mf_ROM_min
#define nModes
static void nudge(REAL8 *x, REAL8 X, REAL8 epsilon)
static double double delta
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
static UNUSED UINT4 align_wfs_window_from_22(gsl_vector *f_array_1, gsl_vector *f_array_2, gsl_vector *phase_1, gsl_vector *phase_2, REAL8 f_align_start, REAL8 f_align_end, REAL8 Deltat22, REAL8 Deltaphi22, INT4 modeM)
static UNUSED REAL8 Get_omegaQNM_SEOBNRv5(REAL8 q, REAL8 chi1z, REAL8 chi2z, UINT4 l, UINT4 m)
static UNUSED UINT4 compute_i_max_LF_i_min_HF(INT8 *i_max_LF, INT8 *i_min_LF, gsl_vector *freqs_in_1, gsl_vector *freqs_in_2, REAL8 freq_1)
static UNUSED REAL8 Interpolate_Coefficent_Tensor(gsl_vector *v, REAL8 eta, REAL8 chi1, REAL8 chi2, int ncy, int ncz, gsl_bspline_workspace *bwx, gsl_bspline_workspace *bwy, gsl_bspline_workspace *bwz)
static UNUSED UINT4 unwrap_phase(gsl_vector *phaseout, gsl_vector *phasein)
static UNUSED UINT4 align_wfs_window(gsl_vector *f_array_1, gsl_vector *f_array_2, gsl_vector *phase_1, gsl_vector *phase_2, REAL8 *Deltat, REAL8 *Deltaphi, REAL8 f_align_start, REAL8 f_align_end)
static UNUSED double SEOBNRROM_Ringdown_Mf_From_Mtot_Eta(const double Mtot_sec, const double eta, const double chi1, const double chi2, Approximant apx)
static UNUSED char * concatenate_strings(int count,...)
static UNUSED UINT4 blend_functions(gsl_vector *freqs_out, gsl_vector *out_fun, gsl_vector *freq_in_1, gsl_vector *fun_in_1, gsl_vector *freq_in_2, gsl_vector *fun_in_2, REAL8 freq_1, REAL8 freq_2)
const REAL8 const_fmax_lm_v5hm[NMODES]
static UNUSED UINT8 SEOBNRv5HMROM_Select_HF_patch(REAL8 q, REAL8 chi1)
static UNUSED void AmpPhaseSplineData_Destroy(AmpPhaseSplineData **data, const int num_modes)
static SEOBNRROMdataDS __lalsim_SEOBNRv5ROMDS_data[1]
static UNUSED UINT8 SEOBNRv5HMROM_freq_phase_sparse_grid_hybrid(UNUSED gsl_vector **freq, UNUSED gsl_vector **phase, REAL8 q, REAL8 chi1, REAL8 chi2, INT4 nk_max, SEOBNRROMdataDS *romdataset)
static INT8 Check_EOBROM_mode_array_structure(LALValue *ModeArray, UINT4 nModes)
ModeArray is a structure which allows to select the modes to include in the waveform.
static UNUSED UINT8 SEOBNRv5HMROM_cmode_sparse_grid(gsl_vector *creal_f, gsl_vector *cimag_f, REAL8 q, REAL8 chi1, REAL8 chi2, const char *freq_range, UINT8 nMode, INT4 nk_max, SEOBNRROMdataDS *romdataset)
static UNUSED int SEOBNRROMdataDS_Init(SEOBNRROMdataDS *romdata, const char dir[], UINT4, bool)
static UNUSED void SEOBNRv5ROM_Init_LALDATA(void)
Setup SEOBNRv5ROM model using data files installed in $LAL_DATA_PATH.
static UNUSED int TaylorF2Phasing(double Mtot, double q, double chi1, double chi2, int l, int m, gsl_vector *Mfs, gsl_vector **PNphase)
int(* load_dataPtr)(const char *, gsl_vector *, gsl_vector *, gsl_matrix *, gsl_matrix *, gsl_vector *)
static UNUSED double GetDeltaphilm(int l, int m)
static UNUSED void SplineData_Init(SplineData **splinedata, int ncx, int ncy, int ncz, const double *qvec, const double *chi1vec, const double *chi2vec)
static UNUSED int hybridize_ROM_with_PN_phase_output_align(gsl_spline **hyb_spline, REAL8 *Deltat_align, REAL8 *Deltaphi_align, AmpPhaseSplineData *ampPhaseSplineData_for_mode, gsl_vector *PN_freq, gsl_vector *PN_phase, double f_hyb_win_lo, double f_hyb_win_hi)
static UNUSED int SEOBNRv5HMROM_Init(const char dir[], UINT4, bool, SEOBNRROMdataDS *romdataset)
Setup SEOBNRv5HMROM mode using data files installed in dir.
const REAL8 Mf_low_lm_v5hm[NMODES]
static UNUSED void SplineData_Destroy(SplineData *splinedata)
#define Mf_low_43
#define f_hyb_ini
static UNUSED UINT8 SEOBNRv5HMROM_phase_sparse_grid_hybrid_output_align(gsl_vector **freq, gsl_vector **phase, REAL8 *Deltat_align, REAL8 *Deltaphi_align, gsl_vector *phase_lo, gsl_vector *phase_hi, gsl_vector *freq_lo, gsl_vector *freq_hi, double f_hyb_lo, double f_hyb_hi)
static UNUSED bool SEOBNRv5HMROM_IsSetup(UINT4, SEOBNRROMdataDS *romdataset)
Helper function to check if the SEOBNRv5HMROM model has been initialised.
static UNUSED void SEOBNRROMdataDS_coeff_Init(SEOBNRROMdataDS_coeff **romdatacoeff, int nk_cmode, int nk_phase)
static SEOBNRROMdataDS __lalsim_SEOBNRv5HMROMDS_data[NMODES]
static UNUSED int TaylorF2Amplitude(const double q, const double chi1, const double chi2, const int l, const int m, gsl_vector *Mfs, gsl_vector **PNamp)
static UNUSED int SEOBNRv5HMROMCoreModes(SphHarmFrequencySeries **hlm_list, REAL8 phiRef, REAL8 fRef, REAL8 distance, REAL8 Mtot_sec, REAL8 q, REAL8 chi1, REAL8 chi2, const REAL8Sequence *freqs, REAL8 deltaF, INT4 nk_max, UINT4 nModes, REAL8 sign_odd_modes, SEOBNRROMdataDS *romdataset)
Core function for computing the ROM waveform.
const REAL8 const_phaseshift_lm_v5hm[NMODES]
static int SEOBROMComputehplushcrossFromhlm(COMPLEX16FrequencySeries *hplusFS, COMPLEX16FrequencySeries *hcrossFS, LALValue *ModeArray, SphHarmFrequencySeries *hlm, REAL8 inc, REAL8 phi)
static UNUSED int SEOBNRROMdataDS_Init_submodel(UNUSED SEOBNRROMdataDS_submodel **submodel, UNUSED const char dir[], UNUSED const char grp_name[], UNUSED UINT4 index_mode, UNUSED bool use_hm)
static UNUSED void SEOBNRROMdataDS_Cleanup_submodel(SEOBNRROMdataDS_submodel *submodel)
#define Mf_low_33
static UNUSED void AmpPhaseSplineData_Init(AmpPhaseSplineData ***data, const int num_modes)
static UNUSED void SEOBNRv5HMROM_Init_LALDATA(void)
Setup SEOBNRv5HMROM model using data files installed in $LAL_DATA_PATH.
static UNUSED UINT8 SEOBNRv5HMROM_phase_sparse_grid(gsl_vector *phase_f, REAL8 q, REAL8 chi1, REAL8 chi2, const char *freq_range, INT4 nk_max, SEOBNRROMdataDS *romdataset)
static UNUSED int SEOBNRv5HMROMCoreModesHybridized(UNUSED SphHarmFrequencySeries **hlm_list, UNUSED REAL8 phiRef, UNUSED REAL8 fRef, UNUSED REAL8 distance, UNUSED REAL8 Mtot_sec, UNUSED REAL8 q, UNUSED REAL8 chi1, UNUSED REAL8 chi2, UNUSED const REAL8Sequence *freqs_in, UNUSED REAL8 deltaF, UNUSED INT4 nk_max, UNUSED UINT4 nModes, REAL8 sign_odd_modes, UNUSED SEOBNRROMdataDS *romdataset)
static UNUSED void SEOBNRROMdataDS_coeff_Cleanup(SEOBNRROMdataDS_coeff *romdatacoeff)
const char mode_array_v5hm[NMODES][3]
#define Mf_low_22
static UNUSED UINT8 SEOBNRv5HMROM_cmode_sparse_grid_hybrid(gsl_vector *freq, gsl_vector *cmode_real, gsl_vector *cmode_imag, gsl_vector *freq_lo, gsl_vector *freq_hi, REAL8 q, REAL8 chi1, REAL8 chi2, UINT8 nMode, INT8 nk_max, SEOBNRROMdataDS *romdataset)
#define Mf_low_21
static UNUSED UINT8 SEOBNRv5HMROM_approx_phi_lm(gsl_vector *freq_mode_lm, gsl_vector *phase_approx_lm, gsl_vector *freq_carrier_hyb, gsl_vector *phase_carrier_hyb, UINT4 nMode)
#define NMODES
#define f_hyb_end
static UNUSED UINT8 SEOBNRv5HMROM_phase_sparse_grid_hybrid(gsl_vector *freq, gsl_vector *phase, gsl_vector *freq_lo, gsl_vector *freq_hi, REAL8 q, REAL8 chi1, REAL8 chi2, INT4 nk_max, SEOBNRROMdataDS *romdataset)
static UNUSED void SEOBNRROMdataDS_Cleanup(SEOBNRROMdataDS *romdata)
#define Mf_low_44
static UNUSED int hybridize_ROM_with_PN_amplitude(gsl_spline **hyb_spline, AmpPhaseSplineData *ampPhaseSplineData_for_mode, gsl_vector *PN_freq, gsl_vector *PN_amp, double f_hyb_win_lo, double f_hyb_win_hi)
static UNUSED double GetModeAmpFactor(double eta, double delta, double chi1, double chi2, int l, int m, double v)
static UNUSED UINT8 SEOBNRv5HMROM_freq_cmode_sparse_grid_hybrid(gsl_vector **freq_cmode, gsl_vector **cmode_real, gsl_vector **cmode_imag, REAL8 q, REAL8 chi1, REAL8 chi2, UINT8 nMode, INT8 nk_max, SEOBNRROMdataDS *romdataset)
static size_t NextPow2(const size_t n)
static UNUSED int BuildInspiralGeomFrequencyGrid(gsl_vector **Mfreq, const double Mfmin, const double Mfmax, const double q, const double acc)
static int TP_Spline_interpolation_3d(REAL8 q, REAL8 chi1, REAL8 chi2, gsl_vector *cvec, int nk, int nk_max, int ncx, int ncy, int ncz, const double *qvec, const double *chi1vec, const double *chi2vec, gsl_vector *c_out)
static UNUSED UINT8 SEOBNRv5HMROM_amplitude_sparse_grid_hybrid_general(gsl_vector **freq, gsl_vector **amp, gsl_vector *amp_lo, gsl_vector *amp_hi, gsl_vector *freq_lo, gsl_vector *freq_hi, double f_hyb_lo, double f_hyb_hi)
static UNUSED UINT8 SEOBNRv5HMROM_phase_sparse_grid_hybrid_input_align(gsl_vector **freq, gsl_vector **phase, gsl_vector *phase_lo, gsl_vector *phase_hi, gsl_vector *freq_lo, gsl_vector *freq_hi, double f_hyb_lo, double f_hyb_hi, REAL8 Deltat_22_align, REAL8 Deltaphi_22_align, INT4 modeM)
#define Mf_low_32
#define Mf_low_55
static UNUSED int hybridize_ROM_with_PN_phase_input_align(gsl_spline **hyb_spline, AmpPhaseSplineData *ampPhaseSplineData_for_mode, gsl_vector *PN_freq, gsl_vector *PN_phase, double f_hyb_win_lo, double f_hyb_win_hi, REAL8 Deltat_22_align, REAL8 Deltaphi_22_align, INT4 modeM)
const UINT4 lmModes_v5hm[NMODES][2]
static UNUSED int SEOBNRv5HMROMCoreModeAmpPhaseSplines(UNUSED AmpPhaseSplineData **ampPhaseSplineData, UNUSED REAL8 q, UNUSED REAL8 chi1, UNUSED REAL8 chi2, UNUSED INT4 nk_max, UNUSED UINT4 nModes, UNUSED SEOBNRROMdataDS *romdataset)
static UINT8 Setup_EOBROM__std_mode_array_structure(LALValue *ModeArray, UINT4 nModes)
ModeArray is a structure which allows to select the modes to include in the waveform.
static UNUSED int spline_to_gsl_vectors(gsl_spline *s, gsl_vector **x, gsl_vector **y)
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
int XLALSimInspiralWaveformParamsInsertPNSpinOrder(LALDict *params, INT4 value)
void XLALDestroyValue(LALValue *value)
int s
Definition: bh_qnmode.c:137
int l
Definition: bh_qnmode.c:135
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
const double pn
sigmaKerr data[0]
const double Lambda
#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 XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
void XLALH5FileClose(LALH5File UNUSED *file)
LALH5File * XLALH5GroupOpen(LALH5File UNUSED *file, const char UNUSED *name)
LALH5File * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
uint64_t UINT8
double complex COMPLEX16
double REAL8
int64_t INT8
uint32_t UINT4
int32_t INT4
void * XLALCalloc(size_t m, size_t n)
void * XLALMalloc(size_t n)
void XLALFree(void *p)
static UNUSED int SEOBNRv5ROMTimeFrequencySetup(gsl_spline **spline_phi, gsl_interp_accel **acc_phi, REAL8 *Mf_final, REAL8 *Mtot_sec, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, REAL8 Mf_start, REAL8 *Mf_ROM_min, REAL8 *Mf_ROM_max)
int XLALSimIMRSEOBNRv5HMROM_Modes(SphHarmFrequencySeries **hlm, UNUSED REAL8 phiRef, UNUSED REAL8 deltaF, REAL8 fLow, UNUSED REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, UNUSED INT4 nk_max, UNUSED UINT4 nModes, bool use_hybridization)
Compute modes in LAL format for the SEOBNRv5HM_ROM model.
int XLALSimIMRSEOBNRv5HMROMFrequencySequence(UNUSED struct tagCOMPLEX16FrequencySeries **hptilde, UNUSED struct tagCOMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, UNUSED REAL8 phiRef, UNUSED REAL8 fRef, UNUSED REAL8 distance, UNUSED REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, UNUSED INT4 nk_max, UNUSED UINT4 nModes, LALDict *LALParams)
Compute waveform polarizations at user specified frequencies for the SEOBNRv5HM_ROM model.
int XLALSimIMRSEOBNRv5HMROMFrequencySequence_Modes(SphHarmFrequencySeries **hlm, const REAL8Sequence *freqs, UNUSED REAL8 phiRef, UNUSED REAL8 fRef, UNUSED REAL8 distance, UNUSED REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, UNUSED INT4 nk_max, UNUSED UINT4 nModes, LALDict *LALParams)
Compute waveform modes at user specified frequencies for the SEOBNRv5HM_ROM model.
int XLALSimIMRSEOBNRv5ROMTimeOfFrequency(REAL8 *t, REAL8 frequency, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
int XLALSimIMRSEOBNRv5HMROM(UNUSED struct tagCOMPLEX16FrequencySeries **hptilde, UNUSED struct tagCOMPLEX16FrequencySeries **hctilde, UNUSED REAL8 phiRef, UNUSED REAL8 deltaF, REAL8 fLow, UNUSED REAL8 fHigh, UNUSED REAL8 fRef, UNUSED REAL8 distance, UNUSED REAL8 inclination, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2, UNUSED INT4 nk_max, UNUSED UINT4 nModes, bool use_hybridization, LALDict *LALParams)
Compute waveform in LAL format for the SEOBNRv5HM_ROM model.
#define LAL_SIM_L_MAX_MODE_ARRAY
Maximum L spherical harmonic mode that is supported in Mode Array.
@ LAL_SIM_INSPIRAL_SPIN_ORDER_35PN
@ SEOBNRv5_ROM
Time domain, precessing phenomenological IMR waveform model with subdominant modes ([arXiv: 20XY....
int XLALSimInspiralTaylorF2AlignedPhasing(PNPhasingSeries **pfa, const REAL8 m1, const REAL8 m2, const REAL8 chi1, const REAL8 chi2, LALDict *extraPars)
Returns structure containing TaylorF2 phasing coefficients for given physical parameters.
LALValue * XLALSimInspiralCreateModeArray(void)
Create a LALValue pointer to store the mode array.
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralModeArrayActivateMode(LALValue *modes, unsigned l, int m)
int XLALSimAddModeFD(COMPLEX16FrequencySeries *hptilde, COMPLEX16FrequencySeries *hctilde, COMPLEX16FrequencySeries *hlmtilde, REAL8 theta, REAL8 phi, INT4 l, INT4 m, INT4 sym)
Helper function to add a mode to hplus, hcross in Fourier domain copies the function XLALSimAddMode,...
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
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitDivide(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_ERROR_VOID(...)
#define XLAL_PRINT_INFO(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_PRINT_ERROR(...)
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EINVAL
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))
gsl_interp_accel * acc_amp
gsl_interp_accel * acc_phi
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8 * data
struct tagSphHarmFrequencySeries * next
next pointer
COMPLEX16FrequencySeries * mode
The sequences of sampled data.
gsl_bspline_workspace * bwx
gsl_bspline_workspace * bwz
gsl_bspline_workspace * bwy
SEOBNRROMdataDS_submodel * lowf
SEOBNRROMdataDS_submodel * highf