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