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