Loading [MathJax]/extensions/TeX/AMSmath.js
LALSimulation 6.2.0.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRTEOBResumS.c
Go to the documentation of this file.
1
2/**
3 * Copyright (C) 2017-2018 Alessandro Nagar, Sebastiano Bernuzzi,
4 * Sarp Ackay, Gregorio Carullo, Walter Del Pozzo, Ka Wa Tsang, Michalis Agathos
5 * LALSimulation implementation by Michalis Agathos
6 *
7 * This file is part of the LALSimulation version of TEOBResumS.
8 * The review of this implementation of the TEOBResumS waveform approximant
9 * can be found at https://git.ligo.org/waveforms/reviews/teobresums/wikis/
10 */
11
12/**
13 * TEOBResumS is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * TEOBResumS is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see http://www.gnu.org/licenses/.
25 *
26 */
27
28#ifdef __GNUC__
29#define UNUSED __attribute__ ((unused))
30#else
31#define UNUSED
32#endif
33
34//#ifndef _OPENMP
35//#define omp ignore
36//#endif
37
38#include <complex.h>
39#include <math.h>
40
41#include <gsl/gsl_const.h>
42#include <gsl/gsl_errno.h>
43#include <gsl/gsl_math.h>
44#include <gsl/gsl_odeiv.h>
45
46#include "LALSimTEOBResumS.h"
47
48#define ODE_ABSTOL (1e-13)
49#define ODE_RELTOL (1e-11)
50#define INTERP_UNIFORM_GRID 1
51
52/**
53 * GSL routines for ODE integration
54 * https://www.gnu.org/software/gsl/doc/html/ode-initval.html
55 * http://www.csse.uwa.edu.au/programming/gsl-1.0/gsl-ref_24.html
56 */
57
58/** Global vars, defined as external in header */
60 2,2,
61 3,3,3,
62 4,4,4,4,
63 5,5,5,5,5,
64 6,6,6,6,6,6,
65 7,7,7,7,7,7,7,
66 8,8,8,8,8,8,8,8};
67
69 1,2,
70 1,2,3,
71 1,2,3,4,
72 1,2,3,4,5,
73 1,2,3,4,5,6,
74 1,2,3,4,5,6,7,
75 1,2,3,4,5,6,7,8};
76
77/**
78 * @addtogroup LALSimIMRTEOBResumS_c
79 * @brief Routines to generate time-domain effective-one-body gravitational waveforms for coalescing compact binaries with non-precessing spins, tides and self-spin effects.
80 * inspiral-merger-ringdown waveforms.
81 *
82 * See:
83 * A. Nagar et al, TEOBResumS, arXiv:1806.01772, PRD, 98, 104052, (2018) - TEOBResumS main paper
84 * A. Nagar et al, arXiv:1805.03891, PRD, 99, 021501, (2019) - post-Adiabatic approximation
85 * A. Nagar et al, arXiv:1812.07923, PRD, 99, 044007, (2019) - Nonlinear-in-spin effects.
86 * S. Ackay et al, arXiv:1812.02744, PRD, 99, 044051, (2019) - Effective-one-body multipolar waveform for tidally interacting binary neutron stars up to merger
87 *
88 * @review by Geraint Pratten, Gunnar Riemenschneider, Piero Rettegno, Rachael Huxford, Rossella Gamba
89 * Combined review wiki:
90 * https://git.ligo.org/waveforms/reviews/teobresums/-/wikis/home
91 *
92 *
93 */
94
95 /**
96 * @addtogroup LALSimIMRTEOBResumS_c
97 * @{
98 *
99 * @name Routines for TEOBResumS
100 * @{
101 *
102 * @author Alessandro Nagar, Sebastiano Bernuzzi, Sarp Ackay, Gregorio Carullo, Walter Del Pozzo, Ka Wa Tsang, Michalis Agathos (LALSimulation implementation by Michalis Agathos)
103 *
104 * @brief C code for TEOBResumS.
105 *
106 * This is an aligned-spin time-domain model for coalescing compact binaries. The model contains only the 22-mode for BBHs but (optional) inspiral-only higher multipoles (l<8) for BNS and NSBH systems.
107 * The model contains equation-of-state specific self-spin interactions (monopole-quadrupole) that are incorporated at leading-order PN. Gravitoelectric tides up to NNLO are modelled and
108 * gravitomagnetic tides up to NLO.
109 *
110 * See:
111 * - A. Nagar et al, TEOBResumS, arXiv:1806.01772, PRD, 98, 104052, (2018) - TEOBResumS main paper
112 * - A. Nagar et al, arXiv:1805.03891, PRD, 99, 021501, (2019) - post-Adiabatic approximation
113 * - A. Nagar et al, arXiv:1812.07923, PRD, 99, 044007, (2019) - Nonlinear-in-spin effects.
114 * - S. Ackay et al, arXiv:1812.02744, PRD, 99, 044051, (2019) - Effective-one-body multipolar waveform for tidally interacting binary neutron stars up to merger
115 *
116 * @note The model was calibrated to NR simulations at mass-ratios 1 to 20.
117 *
118 * @attention The model is usable outside this parameter range,
119 * and in tests to date gives sensible physical results up to mass ratios ~ 30 and spins ~ 0.99.
120 * For higher mass ratios and very negative spins memory allocation errors were found.
121 * These occur for \f$\eta < 0.073\f$ and \f$S < -0.8\f$. An approximate fit of the region to exclude was found to be: \f$\chi_1\f$ = -51.2 * \f$\eta^2\f$ +2.2456 * \f$\eta\f$ - 0.8804.
122 * For more information, see the review wiki https://git.ligo.org/waveforms/reviews/teobresums/-/wikis/home
123 *
124 *
125 */
126
127
128/**
129 * Driver routine to calculate a TEOBResumS
130 * inspiral-merger-ringdown waveform model
131 * in the time domain.
132 *
133 * All input parameters should be in SI units. Angles should be in radians.
134 *
135 * Returns the plus and cross polarizations as a complex time series.
136 *
137 */
138int XLALSimIMRTEOBResumS(REAL8TimeSeries **hplus, /**< +-polarization waveform */
139 REAL8TimeSeries **hcross, /**< x-polarization waveform */
140 const REAL8 phiRef, /**< reference orbital phase (rad) */
141 const REAL8 deltaT, /**< sampling interval (s) */
142 const REAL8 m1, /**< mass of companion 1 (kg) */
143 const REAL8 m2, /**< mass of companion 2 (kg) */
144 const REAL8 S1x, /**< x-component of the dimensionless spin of object 1 */
145 const REAL8 S1y, /**< y-component of the dimensionless spin of object 1 */
146 const REAL8 S1z, /**< z-component of the dimensionless spin of object 1 */
147 const REAL8 S2x, /**< x-component of the dimensionless spin of object 2 */
148 const REAL8 S2y, /**< y-component of the dimensionless spin of object 2 */
149 const REAL8 S2z, /**< z-component of the dimensionless spin of object 2 */
150 const REAL8 lambda1, /**< (tidal deformation of body 1)/(mass of body 1)^5 */
151 const REAL8 lambda2, /**< (tidal deformation of body 2)/(mass of body 2)^5 */
152 const REAL8 distance, /**< distance of source (m) */
153 const REAL8 inclination, /**< inclination of source (rad) */
154 const REAL8 UNUSED longAscNodes, /**< longitude of ascending nodes, degenerate with the polarization angle, Omega in documentation */
155 LALDict *LALparams, /**< LAL dictionary containing option parameters */
156 const REAL8 UNUSED eccentricity, /**< eccentrocity at reference epoch */
157 const REAL8 UNUSED meanPerAno, /**< mean anomaly of periastron */
158 const REAL8 f_min, /**< starting GW frequency (Hz) */
159 const REAL8 UNUSED f_ref /**< reference GW frequency (Hz) */
160)
161{
162 /* DOMAIN CHECKS */
163 XLAL_CHECK(hplus, XLAL_EFAULT, "hplus points to NULL");
164 XLAL_CHECK(hcross, XLAL_EFAULT, "hcross points to NULL");
165 XLAL_CHECK(*hplus == NULL, XLAL_EFAULT, "*hplus is not empty.\n");
166 XLAL_CHECK(*hcross == NULL, XLAL_EFAULT, "*hcross is not empty.\n");
167
168 XLAL_CHECK(deltaT >= 0.0, XLAL_EDOM, "deltaT cannot take negative values.\n");
169 XLAL_CHECK((m1>0.0) && (m2>0.0), XLAL_EDOM, "Masses need to be positive.\n");
170 XLAL_CHECK(f_ref >= 0.0, XLAL_EDOM, "Reference frequency f_ref cannot be negative.\n");
171 XLAL_CHECK(distance > 0.0, XLAL_EDOM, "Distance needs to be positive");
172
173 /* check for the presence of in-plane spins */
174 XLAL_CHECK(((S1x==0)&&(S1y==0)&&(S2x==0)&&(S2y==0)), XLAL_EDOM, "ERROR! Non-aligned spins not supported (yet)! Aborting.\n");
175
176
177 /* *****************************************
178 * Init
179 * *****************************************
180 */
181
182 REAL8 m1_SI, m2_SI, LambdaAl2, LambdaAl3, LambdaAl4, LambdaBl2, LambdaBl3, LambdaBl4;
183
184 m1_SI = m1;
185 m2_SI = m2;
186 REAL8 spin1x, spin1y, spin1z, spin2x, spin2y, spin2z;
187 spin1x = S1x;
188 spin1y = S1y;
189 spin1z = S1z;
190 spin2x = S2x;
191 spin2y = S2y;
192 spin2z = S2z;
193
194 /* Tidal polarizability parameters: l=2 are nudged to zero */
195 LambdaAl2 = fabs(lambda1) > TEOB_LAMBDA_TOL ? lambda1 : 0.0;
196 LambdaAl3 = 0.0;
197 LambdaAl4 = 0.0;
198 LambdaBl2 = fabs(lambda2) > TEOB_LAMBDA_TOL ? lambda2 : 0.0;
199 LambdaBl3 = 0.0;
200 LambdaBl4 = 0.0;
201
202 /* l=3,4 tidal parameters are read from LALDict if present */
203 if(XLALDictContains(LALparams, "TidalOctupolarLambda1"))
205 if(XLALDictContains(LALparams, "TidalOctupolarLambda2"))
207 if(XLALDictContains(LALparams, "TidalHexadecapolarLambda1"))
209 if(XLALDictContains(LALparams, "TidalHexadecapolarLambda2"))
211
212
213 /* Swap parameters if mass convention m1>m2 is not respected */
214 if (m2 > m1)
215 {
216 SWAPTRS(m1_SI, m2_SI);
217 SWAPTRS(spin1x, spin2x);
218 SWAPTRS(spin1y, spin2y);
219 SWAPTRS(spin1z, spin2z);
220 SWAPTRS(LambdaAl2, LambdaBl2);
221 SWAPTRS(LambdaAl3, LambdaBl3);
222 SWAPTRS(LambdaAl4, LambdaBl4);
223 }
224
225 /* Switch to mass-rescaled geometric units */
226 REAL8 M = (m1_SI + m2_SI) / LAL_MSUN_SI; /* total mass in Msun */
227 REAL8 time_unit_fact = time_units_factor(M);
228
229 /* Set useful pars/vars */
230 REAL8 q = m1_SI/m2_SI;
231 REAL8 nu = q_to_nu(q);
232
233 /* HARDCODED 0.5 in geom units */
234 const REAL8 dt = 0.5;
235
236 /* Initialize list of modes */
237 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(LALparams);
238
239 /* *****************************************
240 * Set Memory & do preliminary computations
241 * *****************************************
242 */
243
244 /* Alloc memory for dynamics and multipolar waveform */
246 SphHarmPolarTimeSeries *hlm, *this_hlm;
247 REAL8Sequence *tdata;
250 SphHarmPolarTimeSeries *hlm_nqc=NULL;
251
252 SphHarmPolarTimeSeries *hlm_mrg=NULL; /* merger chunk */
253 LALTEOBResumSDynamics *dyn_mrg=NULL;
254
255 const INT4 chunk = 500;
256 INT4 size = chunk; /* note: size can vary */
257
258 INT4 store_dynamics = 0;
259
260 INT4 use_postadiab_dyn = 1;
261 INT4 rush_only = 0;
262
263 /* Parse usage flags for postadiabatic (rush) speed-up */
264 if (XLALDictContains(LALparams, "TEOB_use_postadiabatic"))
265 {
266 switch (XLALDictLookupINT4Value(LALparams, "TEOB_use_postadiabatic"))
267 {
268 case TEOB_PA_ON:
269 break;
270 case TEOB_PA_OFF:
271 use_postadiab_dyn = 0;
272 break;
273 case TEOB_PA_ONLY:
274 rush_only = 1;
275 break;
276 default: XLAL_ERROR(XLAL_EINVAL, "Postadiabatic usage option not recognized.");
277 }
278 }
279
280 /* Define lower radius limit for PA */
283
284 /* Compute initial radius (NOTE: this may change) */
285 const REAL8 f0M = f_min/time_unit_fact;
286 REAL8 r0byM = eob_dyn_r0_Kepler(f0M);
287 //REAL8 r0byM = eob_dyn_r0_eob(f0M, dyn); /* Radius from EOB equations. This is what should be used. */
288 // if (DEBUG) fprintf(stdout, "r0 = %f\n", r0byM);
289
290 /* If f_min is too high fall back to a minimum acceptable initial radius */
291 if (r0byM < TEOB_R0_THRESHOLD) {
292 r0byM = TEOB_R0_THRESHOLD;
293 }
294
295 size = floor((r0byM - pa_rmin)/POSTADIABATIC_DR) + 1;
296
297 /* If initial radius is too close to PA limit then skip PA and go directly to ODE */
298 if (size - 1 < POSTADIABATIC_NSTEP_MIN) {
299 size = chunk;
300 use_postadiab_dyn = 0;
301 }
302
303 /*
304 XLAL_CHECK(size>1, XLAL_EINVAL, "Start of waveform at r < %f. Exiting...\n", pa_rmin);
305 if (DEBUG)
306 {
307 fprintf(stdout, "size = %d\n", size);
308 fprintf(stdout, "r0 = %f\n", r0byM);
309 }
310 */
311
312 /* Initialize dynamics structure */
313 XLALTEOBDynamicsInit(&dyn, size, "dyn");
314
315 /* Set quick-access parameters dyn (be careful here) */
316 XLALTEOBDynamicsSetParams(dyn, &ModeArray, m1_SI, m2_SI, spin1x, spin1y, spin1z, spin2x, spin2y, spin2z, dt, LambdaAl2, LambdaBl2, LambdaAl3, LambdaBl3, LambdaAl4, LambdaBl4, LALparams);
317 dyn->store = dyn->noflux = 0; /* Default: do not store vars, flux on */
318
319 /* Set some flags (to be later controlled by LALDict) */
320 INT4 use_tidal, use_spins;
321 INT4 merger_interp = 0;
322 use_spins = dyn->use_spins;
323 use_tidal = dyn->use_tidal;
324 INT4 interp_uniform_grid = INTERP_UNIFORM_GRID_DEFAULT;
325
326 /* Use rk45 by default for ODE */
327 INT4 use_rk45 = 1;
328
329 /* Parse interpolation scheme flag from LALDict */
330 if (XLALDictContains(LALparams, "TEOB_interp_scheme"))
331 {
332 interp_uniform_grid = XLALDictLookupINT4Value(LALparams, "TEOB_interp_scheme");
333 }
334
335 /* Parse ODE integrator flag from LALDict */
336 if (XLALDictContains(LALparams, "TEOB_use_rk45"))
337 {
338 use_rk45 = XLALDictLookupINT4Value(LALparams, "TEOB_use_rk45");
339 }
340
341 const INT4 ode_tstep = dyn->ode_timestep;
342 REAL8 t_peak = 0.0;
343
344 store_dynamics = (use_postadiab_dyn || !use_tidal);
345
346 /* Amplitude and phase TimeSeries */
347 REAL8TimeSeries *Alm_adt, *philm_adt;
349
350 Alm_adt = XLALCreateREAL8TimeSeries("A_lm", &gpst0, 0, deltaT, &lalStrainUnit, (size_t) size);
351 philm_adt = XLALCreateREAL8TimeSeries("phi_lm", &gpst0, 0, deltaT, &lalDimensionlessUnit, (size_t) size);
352 XLAL_CHECK (Alm_adt && philm_adt, XLAL_ENOMEM, "Could not allocate memory for hlm data.\n");
353
354 /* Time series sequence */
355 tdata = XLALCreateREAL8Sequence(size);
356 XLAL_CHECK (tdata, XLAL_ENOMEM, "Could not allocate memory for time data.\n");
357
358 /* Populate the mode list with head pointing at l=2, m=1 mode */
359 hlm = NULL;
360 for (int k=KMAX-1; k>=0; k--)
361 {
362 hlm = XLALSphHarmPolarTimeSeriesAddMode(hlm, Alm_adt, philm_adt, TEOB_LINDEX[k], TEOB_MINDEX[k]);
363 XLAL_CHECK(hlm, XLAL_ENOMEM, "Could not allocate hlm mode.\n");
364 }
365 XLALSphHarmPolarTimeSeriesSetTData(hlm, tdata); // MA: tdata still needs to be filled in
366 Waveform_lm_t_alloc (&hlm_t);
369
370 /* Set r.h.s. fun pointer */
371 int (*p_eob_dyn_rhs)(REAL8, const REAL8*, REAL8*, void*);
372 if (use_spins) p_eob_dyn_rhs = &eob_dyn_rhs_s;
373 else p_eob_dyn_rhs = &eob_dyn_rhs;
374
375 /* Iteration index */
376 INT4 iter = 0;
377
378 if (use_postadiab_dyn)
379 {
380 /* *****************************************
381 * Post-adiabatic dynamics
382 * *****************************************
383 */
384
385 /* Calculate dynamics */
386 eob_dyn_Npostadiabatic(dyn, r0byM);
387
388 /* Calculate waveform */
389 for (int i = 0; i < size; i++) tdata->data[i] = dyn->time[i];
390
391 dyn->store = dyn->noflux = 1;
392
393 for (int i = 0; i < size; i++)
394 {
395 dyn->y[TEOB_EVOLVE_RAD] = dyn->data[TEOB_RAD][i];
396 dyn->y[TEOB_EVOLVE_PHI] = dyn->data[TEOB_PHI][i];
397 dyn->y[TEOB_EVOLVE_PRSTAR] = dyn->data[TEOB_PRSTAR][i];
398 dyn->y[TEOB_EVOLVE_PPHI] = dyn->data[TEOB_PPHI][i];
399 p_eob_dyn_rhs(dyn->t, dyn->y, dyn->dy, dyn);
400 eob_wav_hlm(dyn, hlm_t);
401
402 this_hlm = hlm;
403 for (int k = 0; k < KMAX; k++)
404 {
405 if (DEBUG)
406 {
407 XLAL_CHECK(((int) this_hlm->l == TEOB_LINDEX[k]) && ((int) this_hlm->m == TEOB_MINDEX[k]), XLAL_EDATA, "Mode numbers do not match\n");
408 }
409 XLAL_CHECK(this_hlm, XLAL_EFAULT, "Missing modes.\n");
410 this_hlm->ampl->data->data[i] = hlm_t->ampli[k];
411 this_hlm->phase->data->data[i] = hlm_t->phase[k];
412 this_hlm = this_hlm->next;
413 }
414 XLAL_CHECK(this_hlm==NULL, XLAL_EFAULT, "More modes present than expected.\n");
415 }
416
417 dyn->store = dyn->noflux = 0;
418 if (rush_only)
419 {
420 /* SKIP ODE EVOLUTION */
421 goto END_ODE_EVOLUTION;
422 }
423
424 /* Prepare for evolution */
425
426 /* start counting from here */
427 iter = size-1;
428 dyn->dt = 0.5*(dyn->time[iter]-dyn->time[iter-1]);
429
430 /* Set arrays with initial conditions
431 Note current time is already set in dyn->t */
432 dyn->y0[TEOB_ID_RAD] = dyn->r;
433 dyn->y0[TEOB_ID_PHI] = dyn->phi;
434 dyn->y0[TEOB_ID_PPHI] = dyn->pphi;
435 dyn->y0[TEOB_ID_OMGJ] = dyn->Omg;
436 dyn->y0[TEOB_ID_PRSTAR] = dyn->prstar;
437 dyn->y[TEOB_EVOLVE_RAD] = dyn->r;
438 dyn->y[TEOB_EVOLVE_PHI] = dyn->phi;
439 dyn->y[TEOB_EVOLVE_PRSTAR] = dyn->prstar;
440 dyn->y[TEOB_EVOLVE_PPHI] = dyn->pphi;
441
442 }
443 else
444 {
445 /* *****************************************
446 * Initial conditions for the evolution
447 * *****************************************
448 */
449
450 /* Compute the initial conditions */
451 if (use_spins) eob_dyn_ic_s(r0byM, dyn, dyn->y0);
452 else eob_dyn_ic(r0byM, dyn, dyn->y0);
453
454 /* Se arrays with initial conditions */
455 dyn->t = 0.;
456 dyn->r = dyn->y0[TEOB_ID_RAD];
457 dyn->phi = 0.;
458 dyn->pphi = dyn->y0[TEOB_ID_PPHI];
459 dyn->Omg = dyn->y0[TEOB_ID_OMGJ];
460 dyn->ddotr = 0.;
461 dyn->prstar = dyn->y0[TEOB_ID_PRSTAR];
462 dyn->Omg_orb = 0.; //FIXME
463 dyn->y[TEOB_EVOLVE_RAD] = dyn->r;
464 dyn->y[TEOB_EVOLVE_PHI] = dyn->phi;
465 dyn->y[TEOB_EVOLVE_PRSTAR] = dyn->prstar;
466 dyn->y[TEOB_EVOLVE_PPHI] = dyn->pphi;
467 if (store_dynamics)
468 {
469 dyn->time[0] = dyn->t;
470 dyn->data[TEOB_RAD][0] = dyn->r;
471 dyn->data[TEOB_PHI][0] = dyn->phi;
472 dyn->data[TEOB_PPHI][0] = dyn->pphi;
473 dyn->data[TEOB_MOMG][0] = dyn->Omg;
474 dyn->data[TEOB_DDOTR][0] = dyn->ddotr;
475 dyn->data[TEOB_PRSTAR][0] = dyn->prstar;
476 dyn->data[TEOB_OMGORB][0] = dyn->Omg_orb;
477 dyn->data[TEOB_E0][0] = dyn->E;
478 }
479
480 /* Waveform computation at t = 0
481 Needs a r.h.s. evaluation for some vars (no flux) */
482 dyn->store = dyn->noflux = 1;
483 p_eob_dyn_rhs(dyn->t, dyn->y, dyn->dy, dyn);
484 dyn->store = dyn->noflux = 0;
485 eob_wav_hlm(dyn, hlm_t);
486
487 /* Append waveform to mode list */
488 this_hlm = hlm;
489 hlm->tdata->data[0] = 0.;
490 for (int k = 0; k < KMAX; k++)
491 {
492 if ( (DEBUG) && (this_hlm->l -TEOB_LINDEX[k] != 0 || this_hlm->m != TEOB_MINDEX[k]) )
493 {
494 XLAL_ERROR(XLAL_EDATA, "Mode numbers do not match!");
495 }
496 XLAL_CHECK(this_hlm, XLAL_EFAULT, "Missing modes.\n");
497 this_hlm->ampl->data->data[0] = hlm_t->ampli[k];
498 this_hlm->phase->data->data[0] = hlm_t->phase[k];
499 this_hlm = this_hlm->next;
500 }
501 XLAL_CHECK(this_hlm==NULL, XLAL_EFAULT, "More modes present than expected.\n");
502
503 /* Prepare for evolution */
504 dyn->dt = dt;
505
506 }
507
508
509 /* *****************************************
510 * ODE Evolution
511 * *****************************************
512 */
513
514 /* Initialize ODE system solver */
515 dyn->ode_stop = false;
516 dyn->ode_stop_MOmgpeak = false;
517 dyn->ode_stop_radius = false;
518
519 // Currently hardcoded to 1.0
520 const REAL8 rstop = dyn->r_stop;
521 if (rstop>0.)
522 {
523 dyn->ode_stop_radius = true;
524 }
525
526 /* GSL integrator memory */
527 gsl_odeiv2_system sys = {p_eob_dyn_rhs, NULL , TEOB_EVOLVE_NVARS, dyn};
528 const gsl_odeiv2_step_type * T;
529 gsl_odeiv2_driver * d;
530
531 if (use_rk45)
532 {
533 T = gsl_odeiv2_step_rkf45;
534 d = gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rkf45, (double) dyn->dt, ODE_ABSTOL, ODE_RELTOL);
535 }
536 else
537 {
538 // If we prefer rk8:
539 T = gsl_odeiv2_step_rk8pd;
540 d = gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd, dyn->dt, ODE_ABSTOL, ODE_RELTOL);
541 }
542
543 gsl_odeiv2_step * s = gsl_odeiv2_step_alloc (T, TEOB_EVOLVE_NVARS);
544 gsl_odeiv2_control * c = gsl_odeiv2_control_y_new (ODE_ABSTOL, ODE_RELTOL);
545 gsl_odeiv2_evolve * e = gsl_odeiv2_evolve_alloc (TEOB_EVOLVE_NVARS);
546
547 /* Set optimized dt around merger */
548 const double dt_tuned_mrg = get_mrg_timestep(q, dyn->chi1, dyn->chi2);
549
550 /* Solve ODE */
551 int STATUS = 0;
552 while (!(dyn->ode_stop))
553 {
554 iter++;
555
556 switch (ode_tstep)
557 {
559 {
560 /* Uniform timestepping */
561 dyn->ti = dyn->t + dyn->dt;
562 STATUS = gsl_odeiv2_driver_apply (d, &dyn->t, (double) dyn->ti, dyn->y);
563 break;
564 }
566 {
567 /* Adaptive timestepping */
568 if ( dyn->ode_stop_MOmgpeak == true )
569 /* if we are after the peak, slow down and fix the last steps ! */
570 STATUS = gsl_odeiv2_evolve_apply_fixed_step (e, c, s, &sys, &dyn->t, dyn->dt, dyn->y);
571 else
572 STATUS = gsl_odeiv2_evolve_apply (e, c, s, &sys, &dyn->t, (double) dyn->t_stop, &dyn->dt, dyn->y);
573 break;
574 }
576 {
577 /* Adaptive timestepping until LSO ... */
578 if (dyn->r > dyn->rLSO)
579 {
580 STATUS = gsl_odeiv2_evolve_apply (e, c, s, &sys, &dyn->t, (double) dyn->t_stop, &dyn->dt, dyn->y);
581 }
582 else
583 {
584 /* ... uniform afterwards */
585 dyn->dt = dt_tuned_mrg;
586 dyn->ti = dyn->t + dyn->dt;
587 STATUS = gsl_odeiv2_evolve_apply_fixed_step (e, c, s, &sys, &dyn->t, dyn->dt, dyn->y);
588 }
589 break;
590 }
591 default: XLAL_ERROR(XLAL_EINVAL, "Unknown ODE time step method. Aborting\n");
592 }
593
594 /* Check for failures */
595
596 if (dyn->ode_stop_MOmgpeak == true)
597 {
598 /* ...if after the Omega_orb peak, stop integration */
599 if ( (STATUS != GSL_SUCCESS) || (!isfinite(dyn->y[TEOB_EVOLVE_RAD])) )
600 {
601 iter--; /* do count this iter! */
602 dyn->ode_stop = true;
603 break; /* (while) stop */
604 }
605 }
606
607 XLAL_CHECK(STATUS == GSL_SUCCESS, XLAL_EFAULT | STATUS, "GSL ODE solver failed. Error = %d\n", STATUS);
608
609 /* Checking whether the dynamics produces NaN values this can happen if radius r becomes too small */
610 XLAL_CHECK(isfinite(dyn->r), XLAL_ESING, "ODE solver returned NaN radius.\n");
611
612 /* Unpack data */
613 dyn->r = dyn->y[TEOB_EVOLVE_RAD];
614 dyn->phi = dyn->y[TEOB_EVOLVE_PHI];
615 dyn->prstar = dyn->y[TEOB_EVOLVE_PRSTAR];
616 dyn->pphi = dyn->y[TEOB_EVOLVE_PPHI];
617
618 /* Waveform computation
619 Needs a r.h.s. evaluation for some vars (but no flux) */
620 dyn->store = dyn->noflux = 1;
621 p_eob_dyn_rhs(dyn->t, dyn->y, dyn->dy, dyn);
622 dyn->store = dyn->noflux = 0;
623 eob_wav_hlm(dyn, hlm_t);
624
625 /* Update size and push arrays (if needed) */
626 if (iter==size)
627 {
628 size += chunk;
629 /* Resize time sequence, padding with 0s */
630 XLALResizeREAL8Sequence(tdata, 0, size);
631
632 /* Resize mode series and dynamics */
634 XLALTEOBDynamicsPush(&dyn, size);
635
636 XLAL_CHECK(tdata && hlm && dyn, XLAL_ENOMEM, "Could not resize waveform structures.\n");
637 }
638
639 /* Append waveform and dynamics to mode list */
640 tdata->data[iter] = hlm_t->time;
641 this_hlm = hlm;
642 for (int k = 0; k < KMAX; k++)
643 {
644 if ( (DEBUG) && (this_hlm->l - TEOB_LINDEX[k] != 0 || this_hlm->m != TEOB_MINDEX[k]) )
645 {
646 XLAL_ERROR(XLAL_EDATA, "Mode numbers do not match!");
647 }
648 XLAL_CHECK(this_hlm, XLAL_EFAULT, "Missing modes.\n");
649 this_hlm->ampl->data->data[iter] = hlm_t->ampli[k];
650 this_hlm->phase->data->data[iter] = hlm_t->phase[k];
651 this_hlm = this_hlm->next;
652 }
653 XLAL_CHECK(this_hlm==NULL, XLAL_EFAULT, "More modes present than expected.\n");
654
655 if (store_dynamics)
656 {
657 dyn->time[iter] = dyn->t;
658 dyn->data[TEOB_RAD][iter] = dyn->r;
659 dyn->data[TEOB_PHI][iter] = dyn->phi;
660 dyn->data[TEOB_PPHI][iter] = dyn->pphi;
661 dyn->data[TEOB_MOMG][iter] = dyn->Omg;
662 dyn->data[TEOB_DDOTR][iter] = dyn->ddotr;
663 dyn->data[TEOB_PRSTAR][iter] = dyn->prstar;
664 dyn->data[TEOB_OMGORB][iter] = dyn->Omg_orb;
665 dyn->data[TEOB_E0][iter] = dyn->E;
666 }
667
668 /* Stop integration if reached max time */
669 if (dyn->t >= dyn->t_stop) dyn->ode_stop = true;
670
671 /* Stop integration at given radius (if rstop >= 0) */
672 if ((dyn->ode_stop_radius) && (dyn->r < rstop) ) dyn->ode_stop = true;
673
674 /* Check when to break the computation
675 find peak of omega curve and continue for 2M */
676 dyn->MOmg = use_spins ? dyn->Omg_orb : dyn->Omg;
677
678 if (dyn->ode_stop_MOmgpeak == false)
679 {
680 /* Before the Omega_orb peak */
681 if (dyn->MOmg < dyn->MOmg_prev)
682 /* This is the first step after the peak
683 Set things for uniform tstep evolution */
684 {
685 dyn->tMOmgpeak = dyn->t; // = dyn->t-0.5*dyn->dt;
686 dyn->ode_stop_MOmgpeak = true;
687 dyn->dt = MIN(dyn->dt, dt_tuned_mrg);
688 // dyn->t_stop = dyn->t + nstep_stop*dyn->dt; // continue for nstep_stop iters
689 dyn->t_stop = dyn->t + 2.;
690 t_peak = dyn->t;
691 }
692 else
693 {
694 /* Peak not reached, update the max */
695 dyn->MOmg_prev = dyn->MOmg;
696 }
697 }
698 else
699 {
700 if (dyn->t >= dyn->t_stop) dyn->ode_stop = true;
701 }
702
703 }
704 /* end time iteration */
705
706 /* Free ODE system solver */
707 gsl_odeiv2_evolve_free (e);
708 gsl_odeiv2_control_free (c);
709 gsl_odeiv2_step_free (s);
710 gsl_odeiv2_driver_free (d);
711
712 /* Update waveform and dynamics size
713 resize to actual size */
714 size = iter+1;
715
716 /* Size down mode series and time sequence */
718 XLALResizeREAL8Sequence(hlm->tdata, 0, size);
719
720 /* Size down dynamics */
721 XLALTEOBDynamicsPush(&dyn, size);
722
723END_ODE_EVOLUTION:;
724
725 if (!(use_tidal) && !(rush_only))
726 {
727
728 /* *****************************************
729 * Following is for BBH : NQC & Ringdown
730 * *****************************************
731 */
732
733 /*
734 This is a BBH run. NQC and ringdown attachment currently assume uniform grids.
735 Do we need to interpolate ?
736 */
737
738 /* In general, yes interpolate... */
739 merger_interp = 1;
740
741 /* HARDCODED default value */
742 REAL8 dt_merger_interp = 0.5;
743
744 /* ... except if merger is covered by uniform tstep, then we do NOT interpolate */
745 if (ode_tstep != ODE_TSTEP_ADAPTIVE) merger_interp = 0;
746
747 if (merger_interp)
748 {
749 /* NQC and ringdown attachment is done around merger
750 using auxiliary variables defined around [tmin,tmax]
751 Recall that parameters are NOT stored into these auxiliary vars */
752
753 const REAL8 tmin = hlm->tdata->data[size-1] - 20; /* Use last 20M points */
754 const REAL8 tmax = hlm->tdata->data[size-1] + 2*dt; /* Make sure to use or get last point */
755
756 /* Find indexes of closest elements to (to, tn) */
757 INT4 imin = 0;
758 INT4 imax = hlm->tdata->length - 1;
759 /* Check limits first */
760 XLAL_CHECK((tmin<tmax) && (tmin < hlm->tdata->data[imax]) && (tmax > hlm->tdata->data[imin]), XLAL_EDOM, "Bad choice of times.");
761
762 if (tmin > hlm->tdata->data[0])
763 imin = find_point_bisection(tmin, hlm->tdata->length, hlm->tdata->data, 1);
764 if (tmax < hlm->tdata->data[imax])
765 imax = find_point_bisection(tmax, hlm->tdata->length, hlm->tdata->data, 0);
766
767 /* Create a new mode list and dynamics by extracting a part of the original */
768 hlm_mrg = XLALCutSphHarmPolarTimeSeries(hlm, imin, (size_t) imax - imin);
769 XLALTEOBDynamicsExtract (dyn, tmin, tmax, &dyn_mrg, "dyn_mrg");
770
771 /* Interpolate mrg on uniform grid */
772
773 /* Build uniform grid of width dt and alloc tmp memory */
774 //dt_merger_interp = MIN(dt_merger_interp, (dyn->time[size-1] - dyn->tMOmgpeak)/4 ); /* Make sure to have always 3 points */
775 dt_merger_interp = MIN(dt_merger_interp, dyn->dt);
776
777 const INT4 size_mrg = get_uniform_size(hlm_mrg->tdata->data[hlm_mrg->tdata->length-1], hlm_mrg->tdata->data[0], dt_merger_interp);
778
779 /* Fill new time array */
780 REAL8Sequence *mrgtime_interp;
781 mrgtime_interp = XLALCreateREAL8Sequence(size_mrg);
782 for (int i = 0; i < size_mrg; i++)
783 mrgtime_interp->data[i] = i*dt_merger_interp + hlm_mrg->tdata->data[0];
784
785 /* Interp Waveform */
786
787 REAL8TimeSeries *Alm_mrg, *philm_mrg;
788 this_hlm = hlm_mrg;
789 while (this_hlm)
790 {
791 /* Interpolate mode amplitude and replace */
792 Alm_mrg = XLALCreateREAL8TimeSeries(this_hlm->ampl->name, &epoch0, 0, dt_merger_interp, &(lalStrainUnit), (size_t) size_mrg);
793 interp_spline(this_hlm->tdata->data, this_hlm->ampl->data->data, this_hlm->ampl->data->length, mrgtime_interp->data, size_mrg, Alm_mrg->data->data);
795 this_hlm->ampl = Alm_mrg;
796
797 /* Interpolate mode phase and replace */
798 philm_mrg = XLALCreateREAL8TimeSeries(this_hlm->phase->name, &epoch0, 0, dt_merger_interp, &(lalDimensionlessUnit), (size_t) size_mrg);
799 interp_spline(this_hlm->tdata->data, this_hlm->phase->data->data, this_hlm->phase->data->length, mrgtime_interp->data, size_mrg, philm_mrg->data->data);
801 this_hlm->phase = philm_mrg;
802
803 Alm_mrg = NULL;
804 philm_mrg = NULL;
805 this_hlm = this_hlm->next;
806 }
807
808 /* Replace time sequence */
809 if (hlm_mrg->tdata) XLALDestroyREAL8Sequence(hlm_mrg->tdata);
810 XLALSphHarmPolarTimeSeriesSetTData(hlm_mrg, mrgtime_interp);
811 mrgtime_interp = NULL;
812 LALFree(mrgtime_interp);
813
814 /* Interp Dynamics */
815 XLALTEOBDynamicsInterp (dyn_mrg, size_mrg, dyn_mrg->time[0], dt_merger_interp, "dyn_mrg_interp");
816
817 } /* End of merger interp */
818
819 if (dyn->nqc_coeffs_hlm == NQC_COMPUTE) {
820
821 /* BBH : compute and add NQC */
822
823 UINT4 size_nqc = merger_interp ? hlm_mrg->tdata->length : (UINT4) size;
824
825 /* Populate NQC mode list */
826 for (int k=KMAX-1; k>=0; k--)
827 {
828 REAL8TimeSeries *Alm, *philm;
829 Alm = XLALCreateREAL8TimeSeries("A_nqc", &epoch0, 0, deltaT, &(lalStrainUnit), (size_t) size_nqc);
830 philm = XLALCreateREAL8TimeSeries("phi_nqc", &epoch0, 0, deltaT, &(lalDimensionlessUnit), (size_t) size_nqc);
831 hlm_nqc = XLALSphHarmPolarTimeSeriesAddMode(hlm_nqc, Alm, philm, TEOB_LINDEX[k], TEOB_MINDEX[k]);
832 XLAL_CHECK(hlm_nqc, XLAL_ENOMEM, "Could not allocate hlm_nqc mode.\n");
835 }
836
837
838 if (merger_interp) {
839
840 /* Compute NQC only around merger,
841 add to both merger and full waveform */
842 XLALSphHarmPolarTimeSeriesSetTData(hlm_nqc, hlm_mrg->tdata);
843 eob_wav_hlmNQC_find_a1a2a3_mrg(dyn_mrg, hlm_mrg, hlm_nqc, dyn, hlm);
844 this_hlm = hlm_mrg;
845 while (this_hlm) {
846 strcat(this_hlm->ampl->name,"_nqc");
847 strcat(this_hlm->phase->name,"_nqc");
848 this_hlm = this_hlm->next;
849 }
850
851 /* Join merger to full waveform */
852 XLALSphHarmPolarJoin(hlm, hlm_mrg, hlm_mrg->tdata->data[0]);
853 XLALTEOBDynamicsJoin (dyn, dyn_mrg, dyn_mrg->time[0]);
854 size = hlm->tdata->length;
855
856 }
857 else
858 {
859
860 /* Compute NQC and add them to full waveform */
862 eob_wav_hlmNQC_find_a1a2a3(dyn, hlm, hlm_nqc);
863
864 }
865 /* Suffix to hlm name */
866 this_hlm = hlm;
867 while (this_hlm)
868 {
869 strcat(this_hlm->ampl->name,"_nqc");
870 strcat(this_hlm->phase->name,"_nqc");
871 this_hlm = this_hlm->next;
872 }
873
874 }
875
876 /* BBH : add Ringdown */
877
878 /* Extend arrays */
879 const UINT4 size_ringdown = RINGDOWN_EXTEND_ARRAY;
880 REAL8 dt_rngdn = dt;
881
882 /* If ODE does not finish with uniform timestep, then match merger interp timestep */
883 if (merger_interp)
884 dt_rngdn = dt_merger_interp;
885
886 /* Resize waveform and time array */
887
888 XLALResizeSphHarmPolarTimeSeries(hlm, 0, (size+size_ringdown));
889 XLALResizeREAL8Sequence(tdata, 0, (size+size_ringdown));
890 for (UINT4 i = size; i < (size+size_ringdown); i++)
891 {
892 hlm->tdata->data[i] = hlm->tdata->data[i-1] + dt_rngdn;
893 }
894 size += size_ringdown;
895
896 /* Ringdown attachment */
897 eob_wav_ringdown(dyn, hlm);
898 strcat(hlm->ampl->name,"_ringdown");
899 strcat(hlm->phase->name,"_ringdown");
900 } /* End of BBH section */
901
902
903 /* *****************************************
904 * Compute h+, hx
905 * *****************************************
906 */
907
908 /* Scale to physical units (if necessary) */
909 REAL8 amplitude_prefactor = nu * M * LAL_MRSUN_SI / distance;
910
911 /* Azimuthal angle phi follows LAL convention of LIGO-T1800226 for master,
912 * where the polarization basis is defined with \f$\Omega=\pi/2\f$ and
913 * \f$Z = \sin{\iota}\sin{\Phi}x + \sin{\iota}\cos{\Phi}y + \cos{\iota}z\f$
914 */
915 const REAL8 phi = LAL_PI_2 - phiRef;
916 const REAL8 iota = inclination;
917
918 /* Time to use as the epoch of the returned time series.
919 * Time of merger is centered at zero.
920 * If ODE did not integrate up to peak then defaults to 0.
921 */
923 XLALGPSAdd(&epoch, -t_peak/time_unit_fact);
924
925
926 /*
927 * Interpolate on uniform grid
928 */
929
930 /* Auxiliary Structures */
931 REAL8Sequence *utime=NULL;
932
933 /* Build uniform grid of width dt and alloc tmp memory */
934 const UINT4 size_out = get_uniform_size(tdata->data[size-1], tdata->data[0], deltaT*time_unit_fact);
935
936 /* Waveform */
937
938 /* Create a new mode list to store uniform time data */
939 utime = XLALCreateREAL8Sequence(size_out);
940 XLAL_CHECK (utime, XLAL_ENOMEM, "Could not allocate memory for time data.\n");
941
942 for (UINT4 i = 0; i < size_out; i++) utime->data[i] = i*deltaT*time_unit_fact;
943
944 /* Interp to uniform grid the multipoles before hpc computation if
945 *INTERP_UNIFORM_GRID_HLM scheme is used
946 */
947 if (interp_uniform_grid == INTERP_UNIFORM_GRID_HLM)
948 {
949 //#pragma omp parallel
950 //{
951 /* Interpolate ampl and phase */
952 //#pragma omp single private(this_hlm)
953 //{
954 this_hlm = hlm;
955 while (this_hlm)
956 {
957 //#pragma omp task
958 //{
959 //fprintf(stderr, "In thread%d/%d\n", omp_get_thread_num(), omp_get_num_threads());
960 REAL8TimeSeries *A_ut=NULL;
961 REAL8TimeSeries *phi_ut=NULL;
962 /* Interpolate mode amplitude and replace */
963 A_ut = XLALCreateREAL8TimeSeries(this_hlm->ampl->name, &epoch, 0, deltaT, &(lalStrainUnit), (size_t) size_out);
964 // XLAL_CHECK (A_ut, XLAL_ENOMEM, "Could not allocate memory for hlm amplitude data.\n");
965 interp_spline(tdata->data, this_hlm->ampl->data->data, size, utime->data,
966 size_out, A_ut->data->data);
968 this_hlm->ampl = A_ut;
969
970 /* Interpolate mode phase and replace */
971 phi_ut = XLALCreateREAL8TimeSeries(this_hlm->phase->name, &epoch, 0, deltaT, &(lalDimensionlessUnit), (size_t) size_out);
972 // XLAL_CHECK (phi_ut, XLAL_ENOMEM, "Could not allocate memory for hlm phase data.\n");
973 interp_spline(tdata->data, this_hlm->phase->data->data, size, utime->data,
974 size_out, phi_ut->data->data);
976 this_hlm->phase = phi_ut;
977
978 A_ut = NULL;
979 phi_ut = NULL;
982 //}
983 this_hlm = this_hlm->next;
984 }
985 //}
986 //}
987
988 /* Replace time sequence */
989 size = size_out;
991 }
992
993 /* Computation of (h+,hx) */
994
995 /* Allocate hplus and hcross */
996 *hplus = XLALCreateREAL8TimeSeries( "h_plus", &epoch, 0.0, deltaT, &lalStrainUnit, size_out);
997 XLAL_CHECK(*hplus, XLAL_EFAULT, "ERROR allocating hplus.\n");
998
999 *hcross = XLALCreateREAL8TimeSeries( "h_cross", &epoch, 0.0, deltaT, &lalStrainUnit, size_out);
1000 XLAL_CHECK(*hcross, XLAL_EFAULT, "ERROR allocating hplus.\n");
1001
1002 memset ((*hplus)->data->data, 0, (*hplus)->data->length*sizeof(*(*hplus)->data->data));
1003 memset ((*hcross)->data->data, 0, (*hcross)->data->length*sizeof(*(*hcross)->data->data));
1004
1005 /* Spherical harmonics projection **/
1006 /* construct hplus and hcross **/
1007 /* h22 = 1/R * (nu*M)*G/c^2 h_code_output */
1008
1009 /* Computation of (h+,hx) */
1010 // NOTE that we set the phase angle for the m mode equal to zero by definition and to be consistent with the PA approximation
1011 if (interp_uniform_grid == INTERP_UNIFORM_GRID_HLM)
1012 {
1013 XLALSimIMRComputePolarisationsPolar((*hplus)->data, (*hcross)->data, hlm, ModeArray, amplitude_prefactor, iota, phi);
1014 }
1015 else if (interp_uniform_grid == INTERP_UNIFORM_GRID_HPC)
1016 {
1017
1018 /* TEMPORARY ERROR MESSAGE */
1019 XLAL_ERROR(XLAL_EINVAL, "Only HLM interpolation scheme is available. HPC is under reconstruction! Exiting...\n");
1020
1021 /* Interpolate (h+,hx) if INTERP_UNIFORM_GRID_HPC scheme is used
1022 * This is much faster in the current implementation but may smear
1023 * out higher-mode features.
1024 */
1025
1026 /* Allocate non-uniform hplus and hcross */
1028 XLAL_CHECK(hp, XLAL_EFAULT, "ERROR allocating hplus.\n");
1029
1031 XLAL_CHECK(hc, XLAL_EFAULT, "ERROR allocating hcross.\n");
1032
1033 memset (hp->data, 0, hp->length*sizeof(REAL8));
1034 memset (hc->data, 0, hc->length*sizeof(REAL8));
1035
1036 XLALSimIMRComputePolarisationsPolar(hp, hc, hlm, ModeArray, 1.0, iota, phi);
1037
1038 REAL8 *Apc, *A_interp;
1039 REAL8 *phipc, *phi_interp;
1040
1041 Apc = malloc(size * sizeof(REAL8));
1042 phipc = malloc(size * sizeof(REAL8));
1043 A_interp = malloc(size_out * sizeof(REAL8));
1044 phi_interp = malloc(size_out * sizeof(REAL8));
1045
1046 for (int i=0; i<size; i++) {
1047 Apc[i] = sqrt( SQ(hp->data[i]) + SQ(hc->data[i]) );
1048 phipc[i] = - atan2(hc->data[i], hp->data[i]);
1049 }
1050 unwrap_proxy(phipc, hlm->next->phase->data->data, size, 0); /* ... but use phi22 as unwrap proxy */
1051
1052
1053 /* Interp to uniform grid after AP computation */
1054
1055 /* Interpolate amplitude and phase */
1056 // FIXME: this is wrong, amplitude interpolation gives unphyiscal modulation when not perfectly face-on!
1057 interp_spline(tdata->data, Apc, size, utime->data,
1058 size_out, A_interp);
1059 interp_spline(tdata->data, phipc, size, utime->data,
1060 size_out, phi_interp);
1061
1062 // FIXME: this is currently wrong, always gives circular polarization
1063 for (UINT4 i=0; i<size_out; i++)
1064 {
1065 (*hplus)->data->data[i] = amplitude_prefactor * A_interp[i] * cos(phi_interp[i]);
1066 (*hcross)->data->data[i] = amplitude_prefactor * A_interp[i] * sin(phi_interp[i]);
1067 }
1068
1071 free(Apc);
1072 free(phipc);
1073 free(A_interp);
1074 free(phi_interp);
1075
1076 } else XLAL_ERROR(XLAL_EINVAL, "Only HLM and HPC interpolation schemes are available.");
1077
1078
1079 /* Free memory */
1082
1084 if (merger_interp)
1085 {
1086 XLALFreeTEOBDynamics(dyn_mrg);
1088 }
1089
1092
1093 /* tdata of NQC mode list used to point to hlm->tdata or hlm_mrg->tdata which is now destroyed */
1096
1097 Waveform_lm_t_free(hlm_t);
1098
1099 XLALDestroyValue(ModeArray);
1100
1101 return XLAL_SUCCESS;
1102}
1103
1104/** @} */
1105/** @} */
int XLALDictContains(const LALDict *dict, const char *key)
INT4 XLALDictLookupINT4Value(const LALDict *dict, const char *key)
#define LALFree(p)
#define MIN(a, b)
#define DEBUG
const INT4 TEOB_MINDEX[KMAX]
#define ODE_ABSTOL
const INT4 TEOB_LINDEX[KMAX]
GSL routines for ODE integration https://www.gnu.org/software/gsl/doc/html/ode-initval....
#define ODE_RELTOL
void eob_wav_hlm(LALTEOBResumSDynamics *dyn, LALTEOBResumSWaveformModeSingleTime *hlm)
int eob_dyn_Npostadiabatic(LALTEOBResumSDynamics *dyn, const REAL8 r0)
void eob_dyn_ic_s(REAL8 r0, LALTEOBResumSDynamics *dyn, REAL8 y_init[])
int eob_dyn_rhs(REAL8 t, const REAL8 y[], REAL8 dy[], void *d)
void eob_wav_hlmNQC_find_a1a2a3_mrg(LALTEOBResumSDynamics *dyn_mrg, SphHarmPolarTimeSeries *hlm_mrg, SphHarmPolarTimeSeries *hnqc, LALTEOBResumSDynamics *dyn, SphHarmPolarTimeSeries *hlm)
void eob_wav_ringdown(LALTEOBResumSDynamics *dyn, SphHarmPolarTimeSeries *hlm)
void eob_wav_hlmNQC_find_a1a2a3(LALTEOBResumSDynamics *dyn, SphHarmPolarTimeSeries *h, SphHarmPolarTimeSeries *hnqc)
int eob_dyn_rhs_s(REAL8 t, const REAL8 y[], REAL8 dy[], void *d)
REAL8 eob_dyn_r0_Kepler(REAL8 f0)
void eob_dyn_ic(REAL8 r0, LALTEOBResumSDynamics *dyn, REAL8 y_init[])
INT4 find_point_bisection(REAL8 x, INT4 n, REAL8 *xp, INT4 o)
void interp_spline(double *t, double *y, int n, double *ti, int ni, REAL8 *yi)
void XLALTEOBDynamicsPush(LALTEOBResumSDynamics **dyn, INT4 size)
void Waveform_lm_t_free(LALTEOBResumSWaveformModeSingleTime *wav)
void XLALTEOBDynamicsInit(LALTEOBResumSDynamics **dyn, INT4 size, const char *name)
void XLALFreeTEOBDynamics(LALTEOBResumSDynamics *dyn)
void XLALTEOBDynamicsSetParams(LALTEOBResumSDynamics *dyn, UNUSED LALValue **pModeArray, const REAL8 m1, const REAL8 m2, const REAL8 UNUSED S1x, const REAL8 UNUSED S1y, const REAL8 S1z, const REAL8 UNUSED S2x, const REAL8 UNUSED S2y, const REAL8 S2z, const REAL8 dt, const REAL8 lambda1, const REAL8 lambda2, const REAL8 lambda1oct, const REAL8 lambda2oct, const REAL8 lambda1hex, const REAL8 lambda2hex, LALDict *LALparams)
REAL8 time_units_factor(REAL8 M)
void XLALSimIMRComputePolarisationsPolar(REAL8Sequence *hplus_out, REAL8Sequence *hcross_out, SphHarmPolarTimeSeries *hlm, LALValue *modeArray, REAL8 amplitude_prefactor, REAL8 theta, REAL8 phi)
void XLALTEOBDynamicsInterp(LALTEOBResumSDynamics *dyn, const INT4 size, const REAL8 t0, const REAL8 dt, const char *name)
void XLALTEOBDynamicsExtract(LALTEOBResumSDynamics *dyna, const REAL8 to, const REAL8 tn, LALTEOBResumSDynamics **dynb, const char *name)
REAL8 get_mrg_timestep(REAL8 q, REAL8 chi1, REAL8 chi2)
void XLALTEOBDynamicsJoin(LALTEOBResumSDynamics *dyna, LALTEOBResumSDynamics *dynb, REAL8 to)
REAL8 q_to_nu(const REAL8 q)
void XLALSphHarmPolarJoin(SphHarmPolarTimeSeries *hlma, SphHarmPolarTimeSeries *hlmb, REAL8 to)
INT4 get_uniform_size(const REAL8 tN, const REAL8 t0, const REAL8 dt)
void unwrap_proxy(REAL8 *p, REAL8 *r, const INT4 size, const INT4 shift0)
void Waveform_lm_t_alloc(LALTEOBResumSWaveformModeSingleTime **wav)
Replaced by LAL COMPLEX16TimeSeries functions.
static vector d(const double L_norm, const double J_norm, const vector roots)
Internal function that returns the coefficients "d_0", "d_2" and "d_4" from 1703.03967 corresponding ...
#define c
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalHexadecapolarLambda1(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalHexadecapolarLambda2(LALDict *params)
INT4 XLALSimInspiralWaveformParamsLookupPNTidalOrder(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalOctupolarLambda1(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalOctupolarLambda2(LALDict *params)
This file is part of TEOBResumS.
#define POSTADIABATIC_RMIN_BBH
@ INTERP_UNIFORM_GRID_HPC
@ INTERP_UNIFORM_GRID_HLM
#define TEOB_LAMBDA_TOL
#define SWAPTRS(a, b)
#define POSTADIABATIC_DR
#define TEOB_R0_THRESHOLD
#define INTERP_UNIFORM_GRID_DEFAULT
#define KMAX
@ TEOB_EVOLVE_RAD
@ TEOB_EVOLVE_NVARS
@ TEOB_EVOLVE_PHI
@ TEOB_EVOLVE_PPHI
@ TEOB_EVOLVE_PRSTAR
#define POSTADIABATIC_RMIN_BNS
#define POSTADIABATIC_NSTEP_MIN
@ TEOB_PA_OFF
@ TEOB_PA_ONLY
@ TEOB_PA_ON
#define RINGDOWN_EXTEND_ARRAY
@ NQC_COMPUTE
@ TEOB_ID_PRSTAR
@ TEOB_ID_PHI
@ TEOB_ID_RAD
@ TEOB_ID_PPHI
@ TEOB_ID_OMGJ
@ ODE_TSTEP_UNIFORM
@ ODE_TSTEP_ADAPTIVE_UNIFORM_AFTER_LSO
@ ODE_TSTEP_ADAPTIVE
#define SQ(a)
@ TEOB_PRSTAR
@ TEOB_OMGORB
@ TEOB_DDOTR
@ TEOB_E0
@ TEOB_RAD
@ TEOB_MOMG
@ TEOB_PHI
@ TEOB_PPHI
void XLALDestroyValue(LALValue *value)
int s
Definition: bh_qnmode.c:137
REAL8 M
Definition: bh_qnmode.c:133
double dt
Definition: bh_ringdown.c:113
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
#define LAL_PI_2
#define LAL_MSUN_SI
#define LAL_MRSUN_SI
#define LIGOTIMEGPSZERO
double REAL8
uint32_t UINT4
int32_t INT4
int XLALSimIMRTEOBResumS(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, const REAL8 phiRef, const REAL8 deltaT, const REAL8 m1, const REAL8 m2, const REAL8 S1x, const REAL8 S1y, const REAL8 S1z, const REAL8 S2x, const REAL8 S2y, const REAL8 S2z, const REAL8 lambda1, const REAL8 lambda2, const REAL8 distance, const REAL8 inclination, const REAL8 UNUSED longAscNodes, LALDict *LALparams, const REAL8 UNUSED eccentricity, const REAL8 UNUSED meanPerAno, const REAL8 f_min, const REAL8 UNUSED f_ref)
Driver routine to calculate a TEOBResumS inspiral-merger-ringdown waveform model in the time domain.
LALSimInspiralTidalOrder
Enumeration of allowed PN orders of tidal effects.
@ LAL_SIM_INSPIRAL_TIDAL_ORDER_0PN
SphHarmPolarTimeSeries * XLALResizeSphHarmPolarTimeSeries(SphHarmPolarTimeSeries *ts, int first, size_t length)
For every (l,m) node in the SphHarmPolarTimeSeries linked list, call XLALResizeREAL8TimeSeries(ts->am...
SphHarmPolarTimeSeries * XLALSphHarmPolarTimeSeriesAddMode(SphHarmPolarTimeSeries *appended, const REAL8TimeSeries *inAmpl, const REAL8TimeSeries *inphase, UINT4 l, INT4 m)
Prepend a node to a linked list of SphHarmPolarTimeSeries, or create a new head.
void XLALDestroySphHarmPolarTimeSeries(SphHarmPolarTimeSeries *ts)
Delete list from current pointer to the end of the list.
SphHarmPolarTimeSeries * XLALCutSphHarmPolarTimeSeries(SphHarmPolarTimeSeries *ts, int first, size_t length)
Create a new SphHarmPolarTimeSeries linked listby extracting a section of an existing SphHarmPolarTim...
void XLALSphHarmPolarTimeSeriesSetTData(SphHarmPolarTimeSeries *ts, REAL8Sequence *tdata)
Set the tdata member for all nodes in the list.
static const INT4 q
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALResizeREAL8Sequence(REAL8Sequence *sequence, int first, size_t length)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
const LALUnit lalStrainUnit
const LALUnit lalDimensionlessUnit
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
XLAL_ESING
XLAL_ENOMEM
XLAL_EDATA
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EDOM
XLAL_EINVAL
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
Dynamics data type.
REAL8 y[TEOB_EVOLVE_NVARS]
REAL8 y0[TEOB_ID_NVARS]
REAL8 * data[TEOB_DYNAMICS_NVARS]
REAL8 dy[TEOB_EVOLVE_NVARS]
Multipolar waveform at given time, comes at handy.
REAL8Sequence * data
CHAR name[LALNameLength]
REAL8 * data
REAL8TimeSeries * ampl
The sequences of mode amplitude.
REAL8TimeSeries * phase
The sequences of mode phase (not modulo 2Pi).
struct tagSphHarmPolarTimeSeries * next
next pointer
REAL8Sequence * tdata
Timestamp values.
LIGOTimeGPS epoch
Definition: unicorn.c:20
double f_min
Definition: unicorn.c:22
double deltaT
Definition: unicorn.c:24