LALSimulation  5.4.0.1-fe68b98
LALSimIMREOBNRv2.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Stas Babak, David Churches, Duncan Brown, David Chin, Jolien Creighton,
3 * B.S. Sathyaprakash, Craig Robinson , Thomas Cokelaer, Evan Ochsner
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with with program; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20 
21 #include <complex.h>
22 #include <lal/Units.h>
23 #include <lal/LALAdaptiveRungeKuttaIntegrator.h>
24 #include <lal/FindRoot.h>
25 #include <lal/SeqFactories.h>
26 #include <lal/LALSimInspiral.h>
27 #include <lal/LALSimIMR.h>
28 #include <lal/Date.h>
29 #include <lal/TimeSeries.h>
30 #include <lal/LALSimSphHarmMode.h>
31 #include <lal/LALSimBlackHoleRingdown.h>
32 #include <gsl/gsl_sf_gamma.h>
33 #include "LALSimIMREOBNRv2.h"
34 
35 /* Include all the static function files we need */
42 
43 /**
44  * The maximum number of modes available to us in this model
45  */
46 static const int EOBNRV2_NUM_MODES_MAX = 5;
47 
48 /**
49  * The following declarations are so that the compiler quits. It appears that they are here because
50  * some of these functions are called before their definitions in the following code.
51  * Perhaps this can be made cleaner by just moving the definitions, but for now I'm keeping with what
52  * the original code did.
53  */
54 
55 static int
57  expnCoeffsdEnergyFlux *ak, /**<<PN expansion coefficients (only relevant fields will be populated)*/
58  REAL8 eta /**<< Symmetric mass ratio */
59  );
60 
61 static REAL8
63  const REAL8 r,
64  const REAL8 eta,
65  void *params);
66 
67 static
68 int LALHCapDerivativesP4PN( double t,
69  const double values[],
70  double dvalues[],
71  void *funcParams);
72 
73 static
75  REAL8 r,
76  REAL8 pr,
77  REAL8 pPhi,
78  EOBACoefficients *aCoeffs );
79 
80 static
82  const double values[],
83  double dvalues[],
84  void *funcParams);
85 
86 static
88  const double values[],
89  double dvalues[],
90  void *funcParams);
91 
92 static
94 
95 static
97  EOBACoefficients * restrict coeffs );
98 
99 static
101 
102 static
103 REAL8 XLALvrP4PN(const REAL8 r, const REAL8 omega, pr3In *params);
104 
105 static
106 size_t find_instant_freq(const REAL8TimeSeries *hp, const REAL8TimeSeries *hc, const REAL8 target, const size_t start, const int fsign);
107 
108 static
110  const REAL8 target, const size_t start);
111 
112 /*-------------------------------------------------------------------*/
113 /* pseudo-4PN functions */
114 /*-------------------------------------------------------------------*/
115 
116 /*
117  * Calculates the initial orbital momentum.
118  */
119 static REAL8
121  const REAL8 r, /**<< Initial orbital separation */
122  EOBACoefficients * restrict coeffs /**<< Pre-computed EOB A coefficients */
123  )
124 {
125  REAL8 u, u2, A, dA;
126 
127  u = 1. / r;
128  u2 = u*u;
129 
130  /* Comparing this expression with the old one, I *think* I will need to multiply */
131  /* dA by - r^2. TODO: Check that this should be the case */
132 
133  A = XLALCalculateEOBA( r, coeffs );
134  dA = - r*r * XLALCalculateEOBdAdr( r, coeffs );
135  return sqrt(-dA/(2.*u*A + u2 * dA));
136 /* why is it called phase? This is initial j!? */
137 }
138 
139 
140 /*
141  * The name of this function is slightly misleading, as it does
142  * not computs the initial pr directly. It instead calculated
143  * dH/dpr - vr for the given values of vr and p. This function is
144  * then passed to a root finding function, which determines the
145  * value of pr which makes this function zero. That value is then
146  * the initial pr.
147  */
148 static REAL8
150  REAL8 p, /**<< The pr value we are currently testing */
151  void *params /**<< The pr3In structure containing necessary parameters */
152  )
153 {
154  REAL8 pr;
155  REAL8 u, u2, p2, p3, p4, A;
156  REAL8 onebyD, AbyD, Heff, HReal, etahH;
157  REAL8 eta, z3, r, vr, q;
158  pr3In *ak;
159 
160  /* TODO: Change this to use tortoise coord */
161 
162  ak = (pr3In *) params;
163 
164  eta = ak->eta;
165  vr = ak->vr;
166  r = ak->r;
167  q = ak->q;
168 
169  p2 = p*p;
170  p3 = p2*p;
171  p4 = p2*p2;
172  u = 1./ r;
173  u2 = u*u;
174  z3 = 2. * (4. - 3. * eta) * eta;
175 
176  A = XLALCalculateEOBA( r, ak->aCoeffs );
177  onebyD = 1. / XLALCalculateEOBD( r, eta );
178  AbyD = A * onebyD;
179 
180  Heff = sqrt(A*(1. + AbyD * p2 + q*q * u2 + z3 * p4 * u2));
181  HReal = sqrt(1. + 2.*eta*(Heff - 1.)) / eta;
182  etahH = eta*Heff*HReal;
183 
184 /* This sets pr = dH/dpr - vr, calls rootfinder,
185  gets value of pr s.t. dH/pr = vr */
186  pr = -vr + A*(AbyD*p + 2. * z3 * u2 * p3)/etahH;
187 
188  return pr;
189 }
190 
191 
192 /*-------------------------------------------------------------------*/
193 
194 /*
195  * This function calculates the initial omega for a given value of r.
196  */
197 static REAL8
199  const REAL8 r, /**<< Initial orbital separation (in units of total mass M */
200  const REAL8 eta, /**<< Symmetric mass ratio */
201  void *params /**<< The pre-computed A coefficients */
202  )
203 {
204  REAL8 u, u3, A, dA, omega;
205 
206  EOBACoefficients *coeffs;
207  coeffs = (EOBACoefficients *) params;
208 
209  u = 1./r;
210  u3 = u*u*u;
211 
212  A = XLALCalculateEOBA( r, coeffs );
213  dA = XLALCalculateEOBdAdr( r, coeffs );
214 
215  /* Comparing this expression with the old one, I *think* I will need to multiply */
216  /* dA by - r^2. TODO: Check that this should be the case */
217  dA = - r * r * dA;
218 
219  omega = sqrt(u3) * sqrt ( -0.5 * dA /(1. + 2.*eta * (A/sqrt(A+0.5 * u*dA)-1.)));
220  return omega;
221 }
222 
223 /*-------------------------------------------------------------------*/
224 
225 /*
226  * Function called within a root-finding algorithm used to determine
227  * the initial radius for a given value of omega.
228  */
229 static REAL8
231  REAL8 r, /**<< Test value of the initial radius */
232  void *params /**<< pr3In structure, containing useful parameters, including omega */
233  )
234 {
235  REAL8 omega1,omega2;
236  pr3In *pr3in;
237 
238  if ( !params )
240 
241  pr3in = (pr3In *) params;
242 
243  omega1 = pr3in->omega;
244  omega2 = omegaofrP4PN(r, pr3in->eta, pr3in->aCoeffs);
245  return ( -omega1 + omega2 );
246 }
247 
248 /*-------------------------------------------------------------------*/
249 
250 /*
251  * This function computes the derivatives of the EOB Hamiltonian w.r.t. the dynamical
252  * variables, and therefore the derivatives of the dynamical variables w.r.t. time.
253  * As such this gets called in the Runge-Kutta integration of the orbit.
254  */
255 static int
256 LALHCapDerivativesP4PN( double UNUSED t, /**<< Current time (GSL requires it to be a parameter, but it's irrelevant) */
257  const REAL8 values[], /**<< The dynamics r, phi, pr, pphi */
258  REAL8 dvalues[], /**<< The derivatives dr/dt, dphi/dt. dpr/dt and dpphi/dt */
259  void *funcParams /**<< Structure containing all the necessary parameters */
260  )
261 {
262 
263  EOBParams *params = NULL;
264 
265  /* Max l to sum up to in the factorized flux */
266  const INT4 lMax = 8;
267 
268  REAL8 eta, omega;
269 
270  double r, p, q;
271  REAL8 r2, p2, p4, q2;
272  REAL8 u, u2, u3;
273  REAL8 A, AoverSqrtD, dAdr, Heff, Hreal;
274  REAL8 HeffHreal;
275  REAL8 flux;
276  REAL8 z3;
277 
278  /* Factorized flux function takes a REAL8Vector */
279  /* We will wrap our current array for now */
280  REAL8Vector valuesVec;
281 
282  params = (EOBParams *) funcParams;
283 
284  valuesVec.length = 4;
285  memcpy( &(valuesVec.data), &(values), sizeof(REAL8 *) );
286 
287  eta = params->eta;
288 
289  z3 = 2. * ( 4. - 3. * eta ) * eta;
290 
291  r = values[0];
292  p = values[2];
293  q = values[3];
294 
295  u = 1.0 / r;
296  u2 = u * u;
297  u3 = u2 * u;
298  r2 = r * r;
299  p2 = p*p;
300  p4 = p2 * p2;
301  q2 = q * q;
302 
303  A = XLALCalculateEOBA(r, params->aCoeffs );
304  dAdr = XLALCalculateEOBdAdr(r, params->aCoeffs );
305  AoverSqrtD = A / sqrt( XLALCalculateEOBD(r, eta) );
306 
307  /* Note that Hreal as given here is missing a factor of 1/eta */
308  /* This is because it only enters into the derivatives in */
309  /* the combination eta*Hreal*Heff, so the eta would get */
310  /* cancelled out anyway. */
311 
312  Heff = XLALEffectiveHamiltonian( eta, r, p, q, params->aCoeffs );
313  Hreal = sqrt( 1. + 2.*eta*(Heff - 1.) );
314 
315  HeffHreal = Heff * Hreal;
316 
317  /* rDot */
318  dvalues[0] = AoverSqrtD * u2 * p * (r2 + 2. * p2 * z3 * A ) / HeffHreal;
319 
320  /* sDot */
321  dvalues[1] = omega = q * A * u2 / HeffHreal;
322 
323  /* Note that the only field of dvalues used in the flux is dvalues->data[1] */
324  /* which we have already calculated. */
325  flux = XLALSimIMREOBFactorizedFlux( &valuesVec, omega, params, lMax );
326 
327  /* pDot */
328  dvalues[2] = 0.5 * AoverSqrtD * u3 * ( 2.0 * ( q2 + p4 * z3) * A
329  - r * ( q2 + r2 + p4 * z3 ) * dAdr ) / HeffHreal
330  - (p / q) * (flux / (eta * omega));
331 
332  /* qDot */
333  dvalues[3] = - flux / (eta * omega);
334 
335  return GSL_SUCCESS;
336 }
337 
338 /*
339  * Function which calculates omega = dphi/dt
340  */
341 static
342 REAL8 XLALCalculateOmega( REAL8 eta, /**<< Symmetric mass ratio */
343  REAL8 r, /**<< Orbital separation (units of total mass M) */
344  REAL8 pr, /**<< Tortoise co-ordinate */
345  REAL8 pPhi, /**<< Momentum pphi */
346  EOBACoefficients *aCoeffs /**<< Pre-computed EOB A coefficients */
347  )
348 {
349 
350  REAL8 A, Heff, Hreal, HeffHreal;
351 
352  A = XLALCalculateEOBA( r, aCoeffs );
353  Heff = XLALEffectiveHamiltonian( eta, r, pr, pPhi, aCoeffs );
354  Hreal = sqrt( 1. + 2.*eta*(Heff - 1.) );
355 
356  HeffHreal = Heff * Hreal;
357  return pPhi * A / (HeffHreal*r*r);
358 }
359 
360 /*
361  * Function which will determine whether to stop the evolution for the initial,
362  * user-requested sample rate. We stop in this case when we have reached the peak
363  * orbital frequency.
364  */
365 static int
366 XLALFirstStoppingCondition(double UNUSED t, /**<< Current time (required by GSL) */
367  const double UNUSED values[], /**<< Current dynamics (required by GSL) */
368  double dvalues[], /**<< Derivatives of dynamics w.r.t. time */
369  void *funcParams /**<< Structure containing necessary parameters */
370  )
371 {
372 
373  EOBParams *params = (EOBParams *)funcParams;
374  double omega = dvalues[1];
375 
376  if ( omega < params->omega )
377  {
378  return 1;
379  }
380 
381  params->omega = omega;
382  return GSL_SUCCESS;
383 }
384 
385 /*
386  * Function which will determine whether to stop the evolution for the high sample rate.
387  * In this case, the data obtained will be used to attach the ringdown, so to make sure
388  * we won't be interpolating data too near the final points, we push this integration
389  * as far as is feasible.
390  */
391 static int
392 XLALHighSRStoppingCondition(double UNUSED t, /**<< Current time (required by GSL) */
393  const double values[], /**<< Current dynamics */
394  double dvalues[], /**<< Derivatives of dynamics w.r.t. time */
395  void UNUSED *funcParams /**<< Structure containing necessary parameters */
396  )
397 {
398  EOBParams *params = (EOBParams *)funcParams;
399  REAL8 rstop;
400  if ( params->eta > 0.1 )
401  {
402  rstop = 1.25 - params->eta;
403  }
404  else
405  {
406  rstop = 2.1 - 10.0 * params->eta;
407  }
408 
409  if ( values[0] <= rstop || isnan(dvalues[3]) || isnan (dvalues[2]) || isnan (dvalues[1]) || isnan (dvalues[0]) )
410  {
411  return 1;
412  }
413  return 0;
414 }
415 
416 /*-------------------------------------------------------------------*/
417 
418 /*
419  * Calculates the initial radial velocity
420  */
421 static REAL8 XLALvrP4PN( const REAL8 r, /**<< Orbital separation (in units of total mass M) */
422  const REAL8 omega, /**<< Orbital frequency (dimensionless: M*omega)*/
423  pr3In *params /**<< pr3In structure containing some necessary parameters */
424  )
425 {
426  REAL8 A, dAdr, d2Adr2, dA, d2A, NA, DA, dDA, dNA, d2DA, d2NA;
427  REAL8 r2, r3, r4, r5, u, u2, v, x1;
428  REAL8 eta, FDIS;
429  REAL8 twoUAPlusu2dA;
430 
432 
433  EOBACoefficients *aCoeffs = params->aCoeffs;
434 
435  eta = params->eta;
436  r2 = r*r;
437  r3 = r2*r;
438  r4 = r2*r2;
439  r5 = r2*r3;
440 
441  u = 1./ r;
442 
443  u2 = u*u;
444 
445  NA = r4 * aCoeffs->n4
446  + r5 * aCoeffs->n5;
447 
448  DA = aCoeffs->d0
449  + r * aCoeffs->d1
450  + r2 * aCoeffs->d2
451  + r3 * aCoeffs->d3
452  + r4 * aCoeffs->d4
453  + r5 * aCoeffs->d5;
454 
455  dNA = 4. * aCoeffs->n4 * r3
456  + 5. * aCoeffs->n5 * r4;
457 
458  dDA = aCoeffs->d1
459  + 2. * aCoeffs->d2 * r
460  + 3. * aCoeffs->d3 * r2
461  + 4. * aCoeffs->d4 * r3
462  + 5. * aCoeffs->d5 * r4;
463 
464  d2NA = 12. * aCoeffs->n4 * r2
465  + 20. * aCoeffs->n5 * r3;
466 
467  d2DA = 2. * aCoeffs->d2
468  + 6. * aCoeffs->d3 * r
469  + 12. * aCoeffs->d4 * r2
470  + 20. * aCoeffs->d5 * r3;
471 
472  A = NA/DA;
473  dAdr = ( dNA * DA - dDA * NA ) / (DA*DA);
474  d2Adr2 = (d2NA*DA - d2DA*NA - 2.*dDA*DA*dAdr)/(DA*DA);
475 
476  /* The next derivatives are with respect to u, not r */
477 
478  dA = - r2 * dAdr;
479  d2A = r4 * d2Adr2 + 2.*r3 * dAdr;
480 
481  v = cbrt(omega);
482 
483  XLALSimIMREOBNRv2SetupFlux( &ak, eta);
484 
485  FDIS = - XLALSimInspiralFp8PP(v, &ak)/(eta*omega);
486 
487  twoUAPlusu2dA = 2.* u * A + u2 * dA;
488  x1 = -r2 * sqrt (-dA * twoUAPlusu2dA * twoUAPlusu2dA * twoUAPlusu2dA )
489  / (2.* u * dA * dA + A*dA - u * A * d2A);
490  return (FDIS * x1);
491 }
492 
493 /*
494  * Calculates the time window over which the ringdown attachment takes
495  * place. These values were calibrated to numerical relativity simulations,
496  * and come from Pan et al, PRD84, 124052(2011).
497  * The time returned is in units of M.
498  */
499 static REAL8
501  INT4 l, /**<< Mode l */
502  INT4 m /**<< Mode m */
503  )
504 {
505 
506  switch ( l )
507  {
508  case 2:
509  switch ( m )
510  {
511  case 2:
512  return 5.;
513  break;
514  case 1:
515  return 8.;
516  break;
517  default:
519  break;
520  }
521  break;
522  case 3:
523  if ( m == 3 )
524  {
525  return 12.;
526  }
527  else
528  {
530  }
531  break;
532  case 4:
533  if ( m == 4 )
534  {
535  return 9.;
536  }
537  else
538  {
540  }
541  break;
542  case 5:
543  if ( m == 5 )
544  {
545  return 8.;
546  }
547  else
548  {
550  }
551  break;
552  default:
554  break;
555  }
556 
557  /* It should not be possible to get to this point */
558  /* Put an return path here to avoid compiler warning */
559  XLALPrintError( "We shouldn't ever reach this point!\n" );
561 
562 }
563 
564 /*
565  * Sets up the various PN coefficients which are needed to calculate
566  * the flux. This is only used in setting the initial conditions, as in
567  * the waveform evolution, the flux comes from the waveform itself.
568  * Some of these values are only really needed as intermediate steps on
569  * the way to getting the Pade coefficients, but since they are contained
570  * within the structure, we may as well set them.
571  */
572 static int
574  expnCoeffsdEnergyFlux *ak, /**<<PN expansion coefficients (only relevant fields will be populated)*/
575  REAL8 eta /**<< Symmetric mass ratio */
576  )
577 {
578 
579  REAL8 a1, a2, a3, a4, a5, a6, a7, a8;
580 
581  /* Powers of a */
582  REAL8 a12, a22, a32, a42, a52, a62, a72, a23, a33, a43, a53, a34, a44;
583 
584  REAL8 c1, c2, c3, c4, c5, c6, c7, c8;
585 
586  REAL8 vlso, vpole;
587 
588  memset( ak, 0, sizeof( *ak ) );
589 
590  /* Taylor coefficients of flux. */
591  ak->fPaN = ak->FTaN = 32.*eta*eta/5.;
592  ak->FTa1 = 0.;
593  ak->FTa2 = -1247./336.-35.*eta/12.;
594  ak->FTa3 = 4.*LAL_PI;
595  ak->FTa4 = -44711./9072.+9271.*eta/504.+65.*eta*eta/18.;
596  ak->FTa5 = -(8191./672.+583./24.*eta)*LAL_PI;
597  ak->FTl6 = -1712./105.;
598  ak->FTa6 = 6643739519./69854400. + 16.*LAL_PI*LAL_PI/3. + ak->FTl6 * log (4.L)
599  - 1712./105.*LAL_GAMMA + (-134543./7776. + 41.*LAL_PI*LAL_PI/48.)*eta
600  - 94403./3024. *eta*eta - 775./324. * eta*eta*eta;
601  ak->FTa7 = LAL_PI * (-16285./504. + 214745./1728.*eta
602  + 193385./3024.*eta*eta);
603  ak->FTa8 = - 117.5043907226773;
604  ak->FTl8 = 52.74308390022676;
605 
606  /* For the EOBPP model, vpole and vlso are tuned to NR */
607  vpole = ak->vpolePP = 0.85;
608  vlso = ak->vlsoPP = 1.0;
609 
610  /* Pade coefficients of f(v); assumes that a0=1 => c0=1 */
611  a1 = ak->FTa1 - 1./vpole;
612  a2 = ak->FTa2 - ak->FTa1/vpole;
613  a3 = ak->FTa3 - ak->FTa2/vpole;
614  a4 = ak->FTa4 - ak->FTa3/vpole;
615  a5 = ak->FTa5 - ak->FTa4/vpole;
616  a6 = ak->FTa6 - ak->FTa5/vpole + ak->FTl6*log(vlso);
617  a7 = ak->FTa7 - ( ak->FTa6 + ak->FTl6*log(vlso))/vpole;
618  a8 = ak->FTa8 - ak->FTa7/vpole + ak->FTl8*log(vlso);
619 
620  c1 = -a1;
621  c2 = -(c1*c1 - a2)/c1;
622  c3 = -(c1*pow(c2+c1,2.) + a3)/(c1*c2);
623  c4 = -(c1*pow(c2+c1,3.) + c1*c2*c3*(c3+2*c2+2*c1) - a4)/(c1*c2*c3);
624  c5 = -(c1*pow(pow(c1+c2,2.)+c2*c3,2.) + c1*c2*c3*pow(c1+c2+c3+c4,2.) + a5)
625  /(c1*c2*c3*c4);
626  c6 = -(c1*pow(c1+c2, 5.)
627  + c1*c2*c3*(pow(c1+c2+c3,3.) + 3.*pow(c1+c2,3.)
628  + 3.*c2*c3*(c1+c2) + c3*c3*(c2-c1))
629  + c1*c2*c3*c4*(pow(c1+c2+c3+c4,2.)
630  + 2.*pow(c1+c2+c3,2.) + c3*(c4-2.*c1))
631  + c1*c2*c3*c4*c5*(c5 + 2.*(c1+c2+c3+c4))
632  - a6)/(c1*c2*c3*c4*c5);
633 
634  a12 = a1*a1;
635  a22 = a2*a2;
636  a32 = a3*a3;
637  a42 = a4*a4;
638  a52 = a5*a5;
639  a62 = a6*a6;
640  a72 = a7*a7;
641  a23 = a22*a2;
642  a33 = a32*a3;
643  a43 = a42*a4;
644  a53 = a52*a5;
645  a34 = a33*a3;
646  a44 = a43*a4;
647 
648  c7 = ((a23 + a32 + a12*a4 - a2*(2*a1*a3 + a4)) *
649  (-a44 - a32*a52 + a1*a53 - a22*a62 + a33*a7
650  + a22*a5*a7 + a42*(3*a3*a5 + 2*a2*a6 + a1*a7)
651  + a3*(2*a2*a5*a6 + a1*a62 - a1*a5*a7)
652  - 2*a4*((a32 + a1*a5)*a6 + a2*(a52 + a3*a7))))/
653  ((a33 + a1*a42 + a22*a5 - a3*(2*a2*a4 + a1*a5))*
654  (a34 + a22*a42 - a43 - 2*a1*a2*a4*a5 + a12*a52
655  - a2*a52 - a23*a6 - a12*a4*a6 + a2*a4*a6
656  - a32*(3*a2*a4 + 2*a1*a5 + a6)
657  + 2*a3*((a22 + a4)*a5 + a1*(a42 + a2*a6))));
658 
659  c8 = -(((a33 + a1*a42 + a22*a5 - a3*(2*a2*a4 + a1*a5)) *
660  (pow(a4,5) + pow(a5,4) - 2*a33*a5*a6 + 2*a1*a3*a52*a6
661  + 2*a3*a5*a62 + a12*a62*a6 - 2*a3*a52*a7
662  + 2*a1*a32*a6*a7 - 2*a12*a5*a6*a7 + a32*a72
663  + pow(a3,4)*a8 - 2*a1*a32*a5*a8 + a12*a52*a8
664  - a32*a6*a8 - a43*(4*a3*a5 + 3*a2*a6 + 2*a1*a7 + a8)
665  + a42*(3*a2*a52 + 3*a32*a6 + 4*a1*a5*a6 + a62
666  + 4*a2*a3*a7 + 2*a5*a7 + a22*a8 + 2*a1*a3*a8)
667  + a22*(a52*a6 - 2*a3*a6*a7 + 2*a3*a5*a8)
668  + a22*a2*(a72 - a6*a8) - a4*(3*a52*a6 - 2*a22*a62 + 2*a33*a7
669  + 4*a22*a5*a7 + a2*a72 - a2*a6*a8 - 3*a32*(a52 - a2*a8)
670  + 2*a3*(a2*a5*a6 + 2*a1*a62 + a6*a7 - a5*a8)
671  + 2*a1*(a52*a5 - a2*a6*a7 + a2*a5*a8) + a12*(-a72 + a6*a8))
672  + a2*(-a62*a6 + 2*a5*a6*a7 + 2*a1*a5*(-a62 + a5*a7)
673  + a32*(a62 + 2*a5*a7) - a52*a8
674  - 2*a3*(a52*a5 + a1*(a72 - a6*a8)))))
675  / ((pow(a3,4) + a22*a42 - a43 - 2*a1*a2*a4*a5
676  + a12*a52 - a2*a52 - a22*a2*a6 - a12*a4*a6 + a2*a4*a6
677  - a32*(3*a2*a4 + 2*a1*a5 + a6)
678  + 2*a3*((a22 + a4)*a5 + a1*(a42 + a2*a6)))
679  * (-pow(a4,4) - a32*a52 + a1*a52*a5 - a22*a62 + a33*a7
680  + a22*a5*a7 + a42*(3*a3*a5 + 2*a2*a6 + a1*a7)
681  + a3*(2*a2*a5*a6 + a1*a62 - a1*a5*a7)
682  - 2*a4*((a32 + a1*a5)*a6 + a2*(a52 + a3*a7)))));
683 
684  ak->fPa1 = c1;
685  ak->fPa2 = c2;
686  ak->fPa3 = c3;
687  ak->fPa4 = c4;
688  ak->fPa5 = c5;
689  ak->fPa6 = c6;
690  ak->fPa7 = c7;
691  ak->fPa8 = c8;
692 
693  return XLAL_SUCCESS;
694 }
695 
696 /* return the index before the instantaneous frequency rises past target */
697 static size_t find_instant_freq(const REAL8TimeSeries *hp, const REAL8TimeSeries *hc, const REAL8 target, const size_t start, const int fsign) {
698  size_t k = start + 1;
699  const size_t n = hp->data->length - 1;
700 
701  /* Use second order differencing to find the instantaneous frequency as
702  * h = A e^(2 pi i f t) ==> f = d/dt(h) / (2*pi*h) */
703  for (; k < n; k++) {
704  const REAL8 hpDot = (hp->data->data[k+1] - hp->data->data[k-1]) / (2 * hp->deltaT);
705  const REAL8 hcDot = (hc->data->data[k+1] - hc->data->data[k-1]) / (2 * hc->deltaT);
706  REAL8 f = hcDot * hp->data->data[k] - hpDot * hc->data->data[k];
707  f /= LAL_TWOPI;
708  f /= hp->data->data[k] * hp->data->data[k] + hc->data->data[k] * hc->data->data[k];
709  if (fsign != 0) f = -f;
710 //printf("this f: %f\n",f);
711  if (f >= target) return k - 1;
712  }
713 //printf("target f: %f\n",target);
714  printf("Error: initial frequency too high, no waveform generated");
716 }
717 
719  const REAL8 target, const size_t start) {
720  size_t k = start + 1;
721  const size_t n = hlm->data->length - 1;
722  COMPLEX16 *dataPtr = hlm->data->data;
723  /* Use second order differencing to find the instantaneous frequency as
724  * h_lm = A e^(-2 pi i f t) ==> f = - d/dt(h_lm) / (2*pi*h_lm) */
725  for (; k < n; k++) {
726  const REAL8 hreDot = (creal(dataPtr[k+1]) - creal(dataPtr[k-1]))
727  / (2 * hlm->deltaT);
728  const REAL8 himDot = (cimag(dataPtr[k+1]) - cimag(dataPtr[k-1]))
729  / (2 * hlm->deltaT);
730  REAL8 f = hreDot * cimag(dataPtr[k]) - himDot * creal(dataPtr[k]);
731  f /= LAL_TWOPI;
732  f /= creal(dataPtr[k]) * creal(dataPtr[k])
733  + cimag(dataPtr[k]) * cimag(dataPtr[k]);
734  if (f >= target) return k - 1;
735  }
736  printf("Error: initial frequency too high, no waveform generated");
738 }
739 
740 /* Engine function of EOBNRv2 */
741 static int
743  REAL8TimeSeries **hplus,
744  REAL8TimeSeries **hcross,
745  SphHarmTimeSeries **h_lms,
746  const REAL8 phiC,
747  const REAL8 deltaT,
748  const REAL8 m1SI,
749  const REAL8 m2SI,
750  const REAL8 fLower,
751  const REAL8 distance,
752  const REAL8 inclination,
753  const int higherModeFlag
754  )
755 {
756  UINT4 count, nn=4, hiSRndx=0;
757  UINT4 flag_fLower_extend = 0;
758  size_t cut_ind = 0.;
759 
760  /* Vector containing the current signal mode */
761  COMPLEX16TimeSeries *sigMode = NULL;
762 
763  REAL8Vector rVec, phiVec, prVec, pPhiVec;
764  REAL8Vector rVecHi, phiVecHi, prVecHi, pPhiVecHi, tVecHi;
765 
766  /* Masses in solar masses */
767  REAL8 mass1, mass2, totalMass;
768  REAL8 eta, m, r, s, p, q, dt, t, v, omega, f, ampl0;
769  REAL8 omegaOld;
770 
771  REAL8Vector *values, *dvalues;
772 
773  /* Time to use as the epoch of the returned time series */
775 
776  /* Variables for the integrator */
777  LALAdaptiveRungeKuttaIntegrator *integrator = NULL;
778  REAL8Array *dynamics = NULL;
779  REAL8Array *dynamicsHi = NULL;
780  INT4 retLen;
781  REAL8 tMax;
782 
783  pr3In pr3in;
784 
785  /* Stuff for pre-computed EOB values */
786  EOBParams eobParams;
787  EOBACoefficients aCoeffs;
788  FacWaveformCoeffs hCoeffs;
789  NewtonMultipolePrefixes prefixes;
790 
791  /* Variables to allow the waveform to be generated */
792  /* from a specific fLower */
793  REAL8 sSub = 0.0; /* Initial phase, and phase to subtract */
794 
795  REAL8 rmin = 20; /* Smallest value of r at which to generate the waveform */
796  COMPLEX16 hLM; /* Factorized waveform */
797  COMPLEX16 hNQC; /* Non-quasicircular correction */
798  UINT4 i, j, modeL;
799  INT4 modeM;
800  INT4 nModes; /* number of modes required */
801 
802  /* Used for EOBNR */
803  COMPLEX16Vector *modefreqs;
804  UINT4 resampFac;
805  UINT4 resampPwr; /* Power of 2 for resampling */
806  REAL8 resampEstimate;
807 
808  /* For checking XLAL return codes */
809  INT4 xlalStatus;
810 
811  /* Accuracy of root finding algorithms */
812  const REAL8 xacc = 1.0e-12;
813 
814  /* Min and max rInit and prInit to consider in root finding */
815  const REAL8 rInitMin = 3.;
816  const REAL8 rInitMax = 1000.;
817 
818  const REAL8 prInitMin = -10.;
819  const REAL8 prInitMax = 5.;
820 
821  /* Accuracies of adaptive Runge-Kutta integrator */
822  const REAL8 EPS_ABS = 1.0e-12;
823  const REAL8 EPS_REL = 1.0e-10;
824 
825  REAL8 tStepBack; /* We need to step back 20M to attach ringdown */
826  UINT4 nStepBack; /* Num points to step back */
827 
828  /* Stuff at higher sample rate */
829  /* Note that real and imaginary parts of signal mode are in separate vectors */
830  /* This is necessary for the ringdown attachment code */
831  REAL8Vector *sigReHi, *sigImHi;
832  REAL8Vector *phseHi, *omegaHi;
833  UINT4 lengthHiSR;
834 
835  /* Used in the calculation of the non-quasicircular correctlon */
836  REAL8Vector *ampNQC, *q1, *q2, *q3, *p1, *p2;
837  EOBNonQCCoeffs nqcCoeffs;
838 
839  /* Inidices of the ringdown matching points */
840  /* peakIdx is the index where omega is a maximum */
841  /* finalIdx is the index of the last point before the */
842  /* integration breaks */
843  /* startIdx is the index at which the waveform crosses fLower */
844  REAL8Vector *rdMatchPoint;
845  UINT4 peakIdx = 0;
846  UINT4 finalIdx = 0;
847  UINT4 startIdx = 0;
848  /* Counter used in unwrapping the waveform phase for NQC correction */
849  INT4 phaseCounter;
850 
851  /* The list of available modes */
852  const INT4 lmModes[5][2] = {{2, 2},
853  {2, 1},
854  {3, 3},
855  {4, 4},
856  {5, 5}};
857 
858  INT4 currentMode;
859 
860  /* Checks on input */
861  if ( (!hplus || !hcross) && !h_lms )
862  {
864  }
865 
866  if ( hplus && hcross ) // If given polarization double pointers **hp, **hc...
867  {
868  if ( *hplus || *hcross ) // ...Make sure *hp, *hc are NULL
869  {
870  XLALPrintError( "(*hplus) and (*hcross) are expected to be NULL; got %p and %p\n",
871  *hplus, *hcross);
873  }
874  }
875  if ( h_lms ) // If given Sph. Harm. double pointer **h_lms...
876  {
877  if ( *h_lms ) // ...Make sure *h_lms is NULL
878  {
879  XLALPrintError( "(*h_lms) is expected to be NULL; got %p\n",
880  *h_lms);
882  }
883  }
884 
885  if ( distance <= 0.0 )
886  {
887  XLALPrintError( "Distance must be > 0.\n" );
889  }
890 
891  if ( m1SI <= 0. || m2SI <= 0. )
892  {
893  XLALPrintError( "Component masses must be > zero!\n" );
895  }
896 
897  /* Allocate some memory */
898  values = XLALCreateREAL8Vector( nn );
899  dvalues = XLALCreateREAL8Vector( nn );
900 
901  if ( !values || !dvalues )
902  {
903  XLALDestroyREAL8Vector( values );
904  XLALDestroyREAL8Vector( dvalues );
906  }
907 
908  /* From this point on, we will want to use masses in solar masses */
909  mass1 = m1SI / LAL_MSUN_SI;
910  mass2 = m2SI / LAL_MSUN_SI;
911 
912  totalMass = mass1 + mass2;
913 
914  eta = mass1 * mass2 / (totalMass*totalMass);
915 
916  /* We will also need the total mass in units of seconds */
917  m = totalMass * LAL_MTSUN_SI;
918 
919  dt = deltaT;
920 
921  /* The Runge-Kutta integrator needs an estimate of the length of the waveform */
922  /* It doesn't really matter, as the length will be determined by the stopping condition */
923  tMax = 5.;
924 
925  /* Set the amplitude depending on whether the distance is given */
926  ampl0 = totalMass * LAL_MRSUN_SI/ distance;
927 
928  /* Check we get a sensible answer */
929  if ( ampl0 == 0.0 )
930  {
931  XLALPrintWarning( "Generating waveform of zero amplitude!!\n" );
932  }
933 
934  /* Set the number of modes depending on whether the user wants higher order modes */
935  if ( higherModeFlag == 0 )
936  {
937  nModes = 1;
938  }
939  else if ( higherModeFlag == 1 )
940  {
942  }
943  else
944  {
945  XLALPrintError( "Higher mode flag appears to be uninitialised "
946  "(expected 0 or 1, but got %d\n)", higherModeFlag );
948  }
949 
950  /* Check that the (l,m,0) QNM freq. is less than the Nyquist freq. */
951  modefreqs = XLALCreateCOMPLEX16Vector( 3 );
952  for ( currentMode = 0; currentMode < nModes; currentMode++ )
953  {
954  count = 0;
955 
956  modeL = lmModes[currentMode][0];
957  modeM = lmModes[currentMode][1];
958  /* Get QNM frequencies */
959  xlalStatus = XLALSimIMREOBGenerateQNMFreqV2( modefreqs, mass1, mass2, NULL, NULL, modeL, modeM, 3, EOBNRv2);
960  if ( xlalStatus != XLAL_SUCCESS )
961  {
962  XLALDestroyCOMPLEX16Vector( modefreqs );
963  XLALDestroyREAL8Vector( values );
964  XLALDestroyREAL8Vector( dvalues );
966  }
967  /* If Nyquist freq. < (l,m,0) QNM freq., exit */
968  /* Note that we cancelled a factor of 2 occuring on both sides */
969  if ( LAL_PI / creal(modefreqs->data[0]) < dt )
970  {
971  XLALDestroyCOMPLEX16Vector( modefreqs );
972  XLALDestroyREAL8Vector( values );
973  XLALDestroyREAL8Vector( dvalues );
974  XLALPrintError( "(%d,%d) mode ringdown freq greater than Nyquist freq. "
975  "Increase sample rate or consider using EOB approximant.\n",modeL,modeM );
977  }
978  }
979 
980  /* Calculate the time we will need to step back for ringdown */
981  tStepBack = 20.0 * m;
982  nStepBack = ceil( tStepBack / dt );
983 
984  /* Set up structures for pre-computed EOB coefficients */
985  memset( &eobParams, 0, sizeof(eobParams) );
986  eobParams.eta = eta;
987  eobParams.m1 = mass1;
988  eobParams.m2 = mass2;
989  eobParams.aCoeffs = &aCoeffs;
990  eobParams.hCoeffs = &hCoeffs;
991  eobParams.nqcCoeffs = &nqcCoeffs;
992  eobParams.prefixes = &prefixes;
993 
994  if ( XLALCalculateEOBACoefficients( &aCoeffs, eta ) == XLAL_FAILURE
996  || XLALSimIMREOBComputeNewtonMultipolePrefixes( &prefixes, eobParams.m1, eobParams.m2 )
997  == XLAL_FAILURE )
998  {
999  XLALDestroyCOMPLEX16Vector( modefreqs );
1000  XLALDestroyREAL8Vector( values );
1001  XLALDestroyREAL8Vector( dvalues );
1003  }
1004 
1005  /* For the dynamics, we need to use preliminary calculated versions */
1006  /*of the NQC coefficients for the (2,2) mode. We calculate them here. */
1007  if ( XLALSimIMREOBGetCalibratedNQCCoeffs( &nqcCoeffs, 2, 2, eta ) == XLAL_FAILURE )
1008  {
1009  XLALDestroyCOMPLEX16Vector( modefreqs );
1010  XLALDestroyREAL8Vector( values );
1011  XLALDestroyREAL8Vector( dvalues );
1013  }
1014 
1015  /* Calculate the resample factor for attaching the ringdown */
1016  /* We want it to be a power of 2 */
1017  /* Of course, we only want to do this if the required SR > current SR... */
1018  /* The form chosen for the resampleEstimate will essentially set */
1019  /* deltaT = M / 20. ( or less taking into account the power of 2 stuff */
1020  resampEstimate = 20.* dt / m;
1021  resampFac = 1;
1022 
1023  if ( resampEstimate > 1 )
1024  {
1025  resampPwr = (UINT4)ceil(log2(resampEstimate));
1026  while ( resampPwr-- )
1027  {
1028  resampFac *= 2u;
1029  }
1030  }
1031 
1032  /* The length of the vectors at the higher sample rate will be */
1033  /* the step back time plus the ringdown */
1034  lengthHiSR = ( nStepBack + (UINT4)(2. * EOB_RD_EFOLDS / cimag(modefreqs->data[0]) / dt) ) * resampFac;
1035 
1036  /* Double it for good measure */
1037  lengthHiSR *= 2;
1038 
1039  /* We are now done with the ringdown modes - destroy them here */
1040  XLALDestroyCOMPLEX16Vector( modefreqs );
1041  modefreqs = NULL;
1042 
1043  /* Find the initial velocity given the lower frequency */
1044  f = fLower;
1045  omega = f * LAL_PI * m;
1046  v = cbrt( omega );
1047 
1048  /* initial r as a function of omega - where to start evolution */
1049  pr3in.eta = eta;
1050  pr3in.aCoeffs = &aCoeffs;
1051 
1052  /* We will be changing the starting r if it is less than rmin */
1053  /* Therefore, we should reset pr3in.omega later if necessary. */
1054  /* For now we need it so that we can see what the initial r is. */
1055 
1056  pr3in.omega = omega;
1057 
1058  /* if ( XLALrOfOmegaP4PN(rInitMin, &pr3in) < 0.)
1059  {
1060  XLALPrintError( "Initial orbital frequency too high. The corresponding initial radius < %fM\n", rInitMin);
1061  XLALDestroyREAL8Vector( values );
1062  XLALDestroyREAL8Vector( dvalues );
1063  XLAL_ERROR( XLAL_EFUNC );
1064  } */
1065  /* If initial frequency too high and initial r < 10M, start at r = 10M, set flag and remove low freq waveform at the end */
1066  if ( XLALrOfOmegaP4PN(10., &pr3in) < 0.)
1067  {
1068  flag_fLower_extend = 1;
1069  omega = pow(10., -1.5);
1070  pr3in.omega = omega;
1071  v = cbrt( omega );
1072  f = omega / LAL_PI / m;
1073  }
1074  if ( XLALrOfOmegaP4PN(rInitMax, &pr3in) > 0.)
1075  {
1076  XLALPrintError( "Initial orbital frequency too low. The corresponding initial radius > %fM\n", rInitMax);
1077  XLALDestroyREAL8Vector( values );
1078  XLALDestroyREAL8Vector( dvalues );
1080  }
1082  rInitMax, xacc, &pr3in);
1083  if ( XLAL_IS_REAL8_FAIL_NAN( r ) )
1084  {
1085  XLALPrintError( "Failed solving the initial radius. The desired initial orbital frequency is %e\n", omega );
1086  XLALDestroyREAL8Vector( values );
1087  XLALDestroyREAL8Vector( dvalues );
1089  }
1090 
1091  /* We want the waveform to generate from a point which won't cause */
1092  /* problems with the initial conditions. Therefore we force the code */
1093  /* to start at least at r = rmin (in units of M). */
1094 
1095  r = (r<rmin) ? rmin : r;
1096  pr3in.r = r;
1097 
1098  /* Now that r is changed recompute omega corresponding */
1099  /* to that r and only then compute initial pr and pphi */
1100 
1101  omega = omegaofrP4PN( r, eta, &aCoeffs );
1102  pr3in.omega = omega;
1103  q = XLALpphiInitP4PN(r, &aCoeffs );
1104  /* first we compute vr (we need coeef->Fp6) */
1105  pr3in.q = q;
1106  pr3in.vr = XLALvrP4PN(r, omega, &pr3in);
1107  /* then we compute the initial value of p */
1108  p = XLALDBisectionFindRoot( XLALprInitP4PN, prInitMin, prInitMax, xacc, &pr3in);
1109  if ( XLAL_IS_REAL8_FAIL_NAN( p ) )
1110  {
1111  XLALDestroyREAL8Vector( values );
1112  XLALDestroyREAL8Vector( dvalues );
1114  }
1115  /* We need to change P to be the tortoise co-ordinate */
1116  /* TODO: Change prInit to calculate this directly */
1117  p = p * XLALCalculateEOBA(r, &aCoeffs);
1118  p = p / sqrt( XLALCalculateEOBD( r, eta ) );
1119 
1120  s = 0.0;
1121 
1122  values->data[0] = r;
1123  values->data[1] = s;
1124  values->data[2] = p;
1125  values->data[3] = q;
1126 
1127  /* And their higher sample rate counterparts */
1128  /* Allocate memory for temporary arrays */
1129  sigReHi = XLALCreateREAL8Vector ( lengthHiSR );
1130  sigImHi = XLALCreateREAL8Vector ( lengthHiSR );
1131  phseHi = XLALCreateREAL8Vector ( lengthHiSR );
1132  omegaHi = XLALCreateREAL8Vector ( lengthHiSR );
1133 
1134  /* Allocate NQC vectors */
1135  ampNQC = XLALCreateREAL8Vector ( lengthHiSR );
1136  q1 = XLALCreateREAL8Vector ( lengthHiSR );
1137  q2 = XLALCreateREAL8Vector ( lengthHiSR );
1138  q3 = XLALCreateREAL8Vector ( lengthHiSR );
1139  p1 = XLALCreateREAL8Vector ( lengthHiSR );
1140  p2 = XLALCreateREAL8Vector ( lengthHiSR );
1141 
1142  if ( !sigReHi || !sigImHi || !phseHi )
1143  {
1144  XLALDestroyREAL8Vector( sigReHi );
1145  XLALDestroyREAL8Vector( sigImHi );
1146  XLALDestroyREAL8Vector( phseHi );
1147  XLALDestroyREAL8Vector( omegaHi );
1148  XLALDestroyREAL8Vector( ampNQC );
1152  XLALDestroyREAL8Vector( p1 );
1153  XLALDestroyREAL8Vector( p2 );
1154  XLALDestroyREAL8Vector( values );
1155  XLALDestroyREAL8Vector( dvalues );
1157  }
1158 
1159  memset(sigReHi->data, 0, sigReHi->length * sizeof( REAL8 ));
1160  memset(sigImHi->data, 0, sigImHi->length * sizeof( REAL8 ));
1161  memset(phseHi->data, 0, phseHi->length * sizeof( REAL8 ));
1162  memset(omegaHi->data, 0, omegaHi->length * sizeof( REAL8 ));
1163  memset(ampNQC->data, 0, ampNQC->length * sizeof( REAL8 ));
1164  memset(q1->data, 0, q1->length * sizeof( REAL8 ));
1165  memset(q2->data, 0, q2->length * sizeof( REAL8 ));
1166  memset(q3->data, 0, q3->length * sizeof( REAL8 ));
1167  memset(p1->data, 0, p1->length * sizeof( REAL8 ));
1168  memset(p2->data, 0, p2->length * sizeof( REAL8 ));
1169 
1170  /* Initialize the GSL integrator */
1171  if (!(integrator = XLALAdaptiveRungeKutta4Init(nn, LALHCapDerivativesP4PN, XLALFirstStoppingCondition, EPS_ABS, EPS_REL)))
1172  {
1173  XLALDestroyREAL8Vector( sigReHi );
1174  XLALDestroyREAL8Vector( sigImHi );
1175  XLALDestroyREAL8Vector( phseHi );
1176  XLALDestroyREAL8Vector( omegaHi );
1177  XLALDestroyREAL8Vector( ampNQC );
1181  XLALDestroyREAL8Vector( p1 );
1182  XLALDestroyREAL8Vector( p2 );
1183  XLALDestroyREAL8Vector( values );
1184  XLALDestroyREAL8Vector( dvalues );
1186  }
1187 
1188  integrator->stopontestonly = 1;
1189 
1190  count = 0;
1191 
1192  /* Use the new adaptive integrator */
1193  /* TODO: Implement error checking */
1194  retLen = XLALAdaptiveRungeKutta4( integrator, &eobParams, values->data, 0., tMax/m, dt/m, &dynamics );
1195 
1196  /* We should have integrated to the peak of the frequency by now */
1197  hiSRndx = retLen - nStepBack;
1198 
1199  /* Set up the vectors, and re-initialize everything for the high sample rate */
1200  rVec.length = phiVec.length = prVec.length = pPhiVec.length = retLen;
1201  rVec.data = dynamics->data+retLen;
1202  phiVec.data = dynamics->data+2*retLen;
1203  prVec.data = dynamics->data+3*retLen;
1204  pPhiVec.data = dynamics->data+4*retLen;
1205 
1206  dt = dt/(REAL8)resampFac;
1207  values->data[0] = rVec.data[hiSRndx];
1208  values->data[1] = phiVec.data[hiSRndx];
1209  values->data[2] = prVec.data[hiSRndx];
1210  values->data[3] = pPhiVec.data[hiSRndx];
1211 
1212  /* We want to use a different stopping criterion for the higher sample rate */
1213  integrator->stop = XLALHighSRStoppingCondition;
1214 
1215  retLen = XLALAdaptiveRungeKutta4( integrator, &eobParams, values->data,
1216  0, (lengthHiSR-1)*dt/m, dt/m, &dynamicsHi );
1217 
1218  rVecHi.length = phiVecHi.length = prVecHi.length = pPhiVecHi.length = tVecHi.length = retLen;
1219  rVecHi.data = dynamicsHi->data+retLen;
1220  phiVecHi.data = dynamicsHi->data+2*retLen;
1221  prVecHi.data = dynamicsHi->data+3*retLen;
1222  pPhiVecHi.data = dynamicsHi->data+4*retLen;
1223  tVecHi.data = dynamicsHi->data;
1224 
1225  /* We are now finished with the adaptive RK, so we can free its resources */
1226  XLALAdaptiveRungeKuttaFree( integrator );
1227  integrator = NULL;
1228 
1229  /* Now we have the dynamics, we tweak the factorized coefficients for the waveform */
1231  {
1232  XLALDestroyREAL8Vector( sigReHi );
1233  XLALDestroyREAL8Vector( sigImHi );
1234  XLALDestroyREAL8Vector( phseHi );
1235  XLALDestroyREAL8Vector( omegaHi );
1236  XLALDestroyREAL8Vector( ampNQC );
1240  XLALDestroyREAL8Vector( p1 );
1241  XLALDestroyREAL8Vector( p2 );
1242  XLALDestroyREAL8Vector( values );
1243  XLALDestroyREAL8Vector( dvalues );
1245  }
1246 
1247  /* We can now prepare to output the waveform */
1248  /* We want to start outputting when the 2,2 mode crosses the user-requested fLower */
1249  /* Find the point where we reach the low frequency cutoff */
1250  REAL8 lfCut = fLower * LAL_PI*m;
1251  if (flag_fLower_extend == 1)
1252  {
1253  lfCut = pow(10., -1.5);
1254  }
1255 
1256  i = 0;
1257  /* TODO: discrete search for lfCut generates discontinuity w.r.t change in physical parameter.
1258  Implement a continuous search. */
1259  while ( i < hiSRndx )
1260  {
1261  omega = XLALCalculateOmega( eta, rVec.data[i], prVec.data[i], pPhiVec.data[i], &aCoeffs );
1262  if ( omega > lfCut || fabs( omega - lfCut ) < 1.0e-5 )
1263  {
1264  break;
1265  }
1266  i++;
1267  }
1268 
1269  if ( i == hiSRndx )
1270  {
1271  XLALDestroyREAL8Vector( sigReHi );
1272  XLALDestroyREAL8Vector( sigImHi );
1273  XLALDestroyREAL8Vector( phseHi );
1274  XLALDestroyREAL8Vector( omegaHi );
1275  XLALDestroyREAL8Vector( ampNQC );
1279  XLALDestroyREAL8Vector( p1 );
1280  XLALDestroyREAL8Vector( p2 );
1281  XLALDestroyREAL8Vector( values );
1282  XLALDestroyREAL8Vector( dvalues );
1283  XLALPrintError( "Low frequency cut-off is too close to coalescence frequency.\n" );
1285  }
1286 
1287  startIdx = i;
1288 
1289  omegaOld = 0.0;
1290  phaseCounter = 0;
1291  for ( i=0; i < (UINT4)retLen; i++ )
1292  {
1293  omega = XLALCalculateOmega( eta, rVecHi.data[i], prVecHi.data[i], pPhiVecHi.data[i], &aCoeffs );
1294  omegaHi->data[i] = omega;
1295  /* For now we re-populate values - there may be a better way to do this */
1296  values->data[0] = r = rVecHi.data[i];
1297  values->data[1] = s = phiVecHi.data[i] - sSub;
1298  values->data[2] = p = prVecHi.data[i];
1299  values->data[3] = q = pPhiVecHi.data[i];
1300 
1301  if ( omega <= omegaOld && !peakIdx )
1302  {
1303  peakIdx = i-1;
1304  }
1305  omegaOld = omega;
1306  }
1307  finalIdx = retLen - 1;
1308 
1309  /* Stuff to find the actual peak time */
1310  gsl_spline *spline = NULL;
1311  gsl_interp_accel *acc = NULL;
1312  REAL8 omegaDeriv1;
1313  REAL8 time1, time2;
1314  REAL8 timePeak, omegaDerivMid;
1315 
1316  spline = gsl_spline_alloc( gsl_interp_cspline, retLen );
1317  acc = gsl_interp_accel_alloc();
1318 
1319  time1 = dynamicsHi->data[peakIdx];
1320 
1321  gsl_spline_init( spline, dynamicsHi->data, omegaHi->data, retLen );
1322  omegaDeriv1 = gsl_spline_eval_deriv( spline, time1, acc );
1323  if ( omegaDeriv1 > 0. )
1324  {
1325  time2 = dynamicsHi->data[peakIdx+1];
1326  }
1327  else
1328  {
1329  time2 = time1;
1330  time1 = dynamicsHi->data[peakIdx-1];
1331  peakIdx--;
1332  omegaDeriv1 = gsl_spline_eval_deriv( spline, time1, acc );
1333  }
1334 
1335  do
1336  {
1337  timePeak = ( time1 + time2 ) / 2.;
1338  omegaDerivMid = gsl_spline_eval_deriv( spline, timePeak, acc );
1339 
1340  if ( omegaDerivMid * omegaDeriv1 < 0.0 )
1341  {
1342  time2 = timePeak;
1343  }
1344  else
1345  {
1346  omegaDeriv1 = omegaDerivMid;
1347  time1 = timePeak;
1348  }
1349  }
1350  while ( time2 - time1 > 1.0e-5 );
1351 
1352  /* XLALPrintInfo( "Estimation of the peak is now at time %e\n", timePeak ); */
1353 
1354  /* Set the coalescence time and phase */
1355  /* It is not easy to define an exact coalescence time and phase for an IMR time-domain model */
1356  /* Therefore we set them at the time when the orbital frequency reaches maximum */
1357  /* Note that the coalescence phase is defined for the ORBITAL phase, not the GW phasae */
1358  /* With PN corrections in the GW modes, GW phase is not exactly m times orbital phase */
1359  /* In brief, at the highest orbital frequency, the orbital phase is phiC/2 */
1360  //t = m * (dynamics->data[hiSRndx] + dynamicsHi->data[peakIdx] - dynamics->data[startIdx]);
1361  t = m * (dynamics->data[hiSRndx] + timePeak - dynamics->data[startIdx]);
1362  gsl_spline_init( spline, dynamicsHi->data, phiVecHi.data, retLen );
1363  /* sSub = phiVecHi.data[peakIdx] - phiC/2.; */
1364  sSub = 0*gsl_spline_eval( spline, timePeak, acc ) - phiC;
1365 
1366  gsl_spline_free( spline );
1367  gsl_interp_accel_free( acc );
1368 
1369  XLALGPSAdd( &epoch, -t);
1370 
1371  /* Allocate vectors for polarizations if they are being output */
1372  /* Their length should be the length of the inspiral + the merger/ringdown */
1373  if( hplus && hcross )
1374  {
1375  *hplus = XLALCreateREAL8TimeSeries( "H_PLUS", &epoch, 0.0, deltaT,
1376  &lalStrainUnit, hiSRndx - startIdx + lengthHiSR / resampFac );
1377  *hcross = XLALCreateREAL8TimeSeries( "H_CROSS", &epoch, 0.0, deltaT,
1378  &lalStrainUnit, (*hplus)->data->length );
1379 
1380  if ( !(*hplus) || !(*hcross) ) // Check hp, hc allocated properly
1381  {
1382  if ( *hplus )
1383  {
1384  XLALDestroyREAL8TimeSeries( *hplus );
1385  *hplus = NULL;
1386  }
1387  if ( *hcross )
1388  {
1389  XLALDestroyREAL8TimeSeries( *hcross );
1390  *hcross = NULL;
1391  }
1392  XLALDestroyREAL8Vector( sigReHi );
1393  XLALDestroyREAL8Vector( sigImHi );
1394  XLALDestroyREAL8Vector( phseHi );
1395  XLALDestroyREAL8Vector( omegaHi );
1396  XLALDestroyREAL8Vector( ampNQC );
1400  XLALDestroyREAL8Vector( p1 );
1401  XLALDestroyREAL8Vector( p2 );
1402  XLALDestroyREAL8Vector( values );
1403  XLALDestroyREAL8Vector( dvalues );
1404  }
1405  memset( (*hplus)->data->data, 0, (*hplus)->data->length * sizeof(REAL8) );
1406  memset( (*hcross)->data->data, 0, (*hcross)->data->length * sizeof(REAL8) );
1407  }
1408 
1409  /* We can now start calculating things for NQCs, and hiSR waveform */
1410 
1411  for ( currentMode = 0; currentMode < nModes; currentMode++ )
1412  {
1413  sigMode = XLALCreateCOMPLEX16TimeSeries( "H_MODE", &epoch, 0.0, deltaT,
1414  &lalStrainUnit, hiSRndx - startIdx + lengthHiSR / resampFac );
1415 
1416  memset(sigMode->data->data, 0, sigMode->data->length * sizeof(COMPLEX16) );
1417  count = 0;
1418 
1419  modeL = lmModes[currentMode][0];
1420  modeM = lmModes[currentMode][1];
1421 
1422  /* If we have an equal mass system, some modes will be zero */
1423  if ( eta == 0.25 && modeM % 2 )
1424  {
1425  XLALDestroyCOMPLEX16TimeSeries( sigMode );
1426  continue;
1427  }
1428 
1429  phaseCounter = 0;
1430  for ( i=0; i < (UINT4)retLen; i++ )
1431  {
1432  omega = XLALCalculateOmega( eta, rVecHi.data[i], prVecHi.data[i], pPhiVecHi.data[i], &aCoeffs );
1433  omegaHi->data[i] = omega;
1434  /* For now we re-populate values - there may be a better way to do this */
1435  values->data[0] = r = rVecHi.data[i];
1436  values->data[1] = s = phiVecHi.data[i] - sSub;
1437  values->data[2] = p = prVecHi.data[i];
1438  values->data[3] = q = pPhiVecHi.data[i];
1439 
1440  v = cbrt( omega );
1441 
1442  xlalStatus = XLALSimIMREOBGetFactorizedWaveform( &hLM, values, v, modeL, modeM, &eobParams );
1443 
1444  ampNQC->data[i] = cabs( hLM );
1445  sigReHi->data[i] = (REAL8) ampl0 * creal(hLM);
1446  sigImHi->data[i] = (REAL8) ampl0 * cimag(hLM);
1447  phseHi->data[i] = carg( hLM ) + phaseCounter * LAL_TWOPI;
1448  if ( i && phseHi->data[i] > phseHi->data[i-1] )
1449  {
1450  phaseCounter--;
1451  phseHi->data[i] -= LAL_TWOPI;
1452  }
1453  q1->data[i] = p*p / (r*r*omega*omega);
1454  q2->data[i] = q1->data[i] / r;
1455  q3->data[i] = q2->data[i] / sqrt(r);
1456  p1->data[i] = p / ( r*omega );
1457  p2->data[i] = p1->data[i] * p*p;
1458  }
1459 
1460  /* Calculate the NQC correction */
1461  XLALSimIMREOBCalculateNQCCoefficients( &nqcCoeffs, ampNQC, phseHi, q1,q2,q3,p1,p2, modeL, modeM, timePeak, dt/m, eta );
1462 
1463  /* Now create the (low-sampled) part of the waveform */
1464  i = startIdx;
1465  while ( i < hiSRndx )
1466  {
1467  omega = XLALCalculateOmega( eta, rVec.data[i], prVec.data[i], pPhiVec.data[i], &aCoeffs );
1468  /* For now we re-populate values - there may be a better way to do this */
1469  values->data[0] = r = rVec.data[i];
1470  values->data[1] = s = phiVec.data[i] - sSub;
1471  values->data[2] = p = prVec.data[i];
1472  values->data[3] = q = pPhiVec.data[i];
1473 
1474  v = cbrt( omega );
1475 
1476  xlalStatus = XLALSimIMREOBGetFactorizedWaveform( &hLM, values, v, modeL, modeM, &eobParams );
1477 
1478  xlalStatus = XLALSimIMREOBNonQCCorrection( &hNQC, values, omega, &nqcCoeffs );
1479  hLM *= hNQC;
1480 
1481  sigMode->data->data[count] = hLM * ampl0;
1482 
1483  count++;
1484  i++;
1485  }
1486 
1487  /* Now apply the NQC correction to the high sample part */
1488  for ( i = 0; i <= finalIdx; i++ )
1489  {
1490  omega = XLALCalculateOmega( eta, rVecHi.data[i], prVecHi.data[i], pPhiVecHi.data[i], &aCoeffs );
1491 
1492  /* For now we re-populate values - there may be a better way to do this */
1493  values->data[0] = r = rVecHi.data[i];
1494  values->data[1] = s = phiVecHi.data[i] - sSub;
1495  values->data[2] = p = prVecHi.data[i];
1496  values->data[3] = q = pPhiVecHi.data[i];
1497 
1498  xlalStatus = XLALSimIMREOBNonQCCorrection( &hNQC, values, omega, &nqcCoeffs );
1499 
1500  hLM = sigReHi->data[i];
1501  hLM += I * sigImHi->data[i];
1502 
1503  hLM *= hNQC;
1504  sigReHi->data[i] = creal(hLM);
1505  sigImHi->data[i] = cimag(hLM);
1506  }
1507 
1508  /*--------------------------------------------------------------
1509  * Attach the ringdown waveform to the end of inspiral
1510  -------------------------------------------------------------*/
1511  rdMatchPoint = XLALCreateREAL8Vector( 3 );
1512  if ( !rdMatchPoint )
1513  {
1514  XLALDestroyCOMPLEX16TimeSeries( sigMode );
1515  XLALDestroyREAL8TimeSeries( *hplus ); *hplus = NULL;
1516  XLALDestroyREAL8TimeSeries( *hcross ); *hcross = NULL;
1517  XLALDestroySphHarmTimeSeries( *h_lms ); *h_lms = NULL;
1518  XLALDestroyREAL8Vector( sigReHi );
1519  XLALDestroyREAL8Vector( sigImHi );
1520  XLALDestroyREAL8Vector( phseHi );
1521  XLALDestroyREAL8Vector( omegaHi );
1522  XLALDestroyREAL8Vector( ampNQC );
1526  XLALDestroyREAL8Vector( p1 );
1527  XLALDestroyREAL8Vector( p2 );
1528  XLALDestroyREAL8Vector( values );
1529  XLALDestroyREAL8Vector( dvalues );
1531  }
1532 
1533  /* Check the first matching point is sensible */
1534  if ( ceil( tStepBack / ( 2.0 * dt ) ) > peakIdx )
1535  {
1536  XLALPrintError( "Invalid index for first ringdown matching point.\n" );
1537  XLALDestroyCOMPLEX16TimeSeries( sigMode );
1538  XLALDestroyREAL8TimeSeries( *hplus ); *hplus = NULL;
1539  XLALDestroyREAL8TimeSeries( *hcross ); *hcross = NULL;
1540  XLALDestroySphHarmTimeSeries( *h_lms ); *h_lms = NULL;
1541  XLALDestroyREAL8Vector( sigReHi );
1542  XLALDestroyREAL8Vector( sigImHi );
1543  XLALDestroyREAL8Vector( phseHi );
1544  XLALDestroyREAL8Vector( omegaHi );
1545  XLALDestroyREAL8Vector( ampNQC );
1549  XLALDestroyREAL8Vector( p1 );
1550  XLALDestroyREAL8Vector( p2 );
1551  XLALDestroyREAL8Vector( values );
1552  XLALDestroyREAL8Vector( dvalues );
1554  }
1555 
1556  REAL8 combSize = XLALSimIMREOBGetRingdownAttachCombSize( modeL, modeM );
1557  REAL8 nrPeakDeltaT = XLALSimIMREOBGetNRPeakDeltaT( modeL, modeM, eta );
1558 
1559  if ( combSize > timePeak )
1560  {
1561  XLALPrintWarning( "Comb size not as big as it should be\n" );
1562  }
1563 
1564  rdMatchPoint->data[0] = combSize < timePeak + nrPeakDeltaT ? timePeak + nrPeakDeltaT - combSize : 0;
1565  rdMatchPoint->data[1] = timePeak + nrPeakDeltaT;
1566  rdMatchPoint->data[2] = dynamicsHi->data[finalIdx];
1567 
1568  rdMatchPoint->data[0] -= fmod( rdMatchPoint->data[0], dt/m );
1569  rdMatchPoint->data[1] -= fmod( rdMatchPoint->data[1], dt/m );
1570 
1571  xlalStatus = XLALSimIMREOBHybridAttachRingdown(sigReHi, sigImHi,
1572  modeL, modeM, dt, mass1, mass2, 0, 0, 0, 0, 0, 0, &tVecHi, rdMatchPoint, EOBNRv2 );
1573  if (xlalStatus != XLAL_SUCCESS )
1574  {
1575  XLALDestroyREAL8Vector( rdMatchPoint );
1576  XLALDestroyCOMPLEX16TimeSeries( sigMode );
1577  XLALDestroyREAL8TimeSeries( *hplus ); *hplus = NULL;
1578  XLALDestroyREAL8TimeSeries( *hcross ); *hcross = NULL;
1579  XLALDestroySphHarmTimeSeries( *h_lms ); *h_lms = NULL;
1580  XLALDestroyREAL8Vector( sigReHi );
1581  XLALDestroyREAL8Vector( sigImHi );
1582  XLALDestroyREAL8Vector( phseHi );
1583  XLALDestroyREAL8Vector( omegaHi );
1584  XLALDestroyREAL8Vector( ampNQC );
1588  XLALDestroyREAL8Vector( p1 );
1589  XLALDestroyREAL8Vector( p2 );
1590  XLALDestroyREAL8Vector( values );
1591  XLALDestroyREAL8Vector( dvalues );
1593  }
1594 
1595  XLALDestroyREAL8Vector( rdMatchPoint );
1596 
1597  for(j=0; j<sigReHi->length; j+=resampFac)
1598  {
1599  sigMode->data->data[count] = sigReHi->data[j];
1600  sigMode->data->data[count] += I * sigImHi->data[j];
1601  count++;
1602  }
1603 
1604  /* Add mode to final output h+ and hx */
1605  if( hplus && hcross)
1606  {
1607  XLALSimAddMode( *hplus, *hcross, sigMode, inclination, 0., modeL, modeM, 1 );
1608  }
1609  else if( !(*h_lms) ) // Create a new SphHarmTimeSeries to hold 1st mode
1610  {
1611  if (flag_fLower_extend == 1) // Find where 1st mode (2,2) hits fLower
1612  {
1613  cut_ind = find_instant_freq_hlm(sigMode, fLower, 1);
1614  sigMode = XLALResizeCOMPLEX16TimeSeries(sigMode, cut_ind,
1615  sigMode->data->length - cut_ind);
1616  if (!sigMode )
1618  }
1619  *h_lms = XLALSphHarmTimeSeriesAddMode(NULL, sigMode, modeL, modeM);
1620  }
1621  else // Append additional modes into existing SphHarmTimeSeries
1622  {
1623  if (flag_fLower_extend == 1) // Resize all modes to length of (2,2)
1624  {
1625  sigMode = XLALResizeCOMPLEX16TimeSeries(sigMode, cut_ind,
1626  sigMode->data->length - cut_ind);
1627  if (!sigMode )
1629  }
1630  *h_lms = XLALSphHarmTimeSeriesAddMode(*h_lms, sigMode, modeL, modeM);
1631  }
1632 
1633  XLALDestroyCOMPLEX16TimeSeries( sigMode );
1634 
1635  } /* End loop over modes */
1636 
1637  /* If returning polarizations, clip the parts below f_min */
1638  if (flag_fLower_extend == 1 && hplus && hcross)
1639  {
1640  if ( cos(inclination) < 0.0 )
1641  {
1642  cut_ind = find_instant_freq(*hplus, *hcross, fLower, 1, 1);
1643  }
1644  else
1645  {
1646  cut_ind = find_instant_freq(*hplus, *hcross, fLower, 1, 0);
1647  }
1648  *hplus = XLALResizeREAL8TimeSeries(*hplus, cut_ind, (*hplus)->data->length - cut_ind);
1649  *hcross = XLALResizeREAL8TimeSeries(*hcross, cut_ind, (*hcross)->data->length - cut_ind);
1650  if (!(*hplus) || !(*hcross))
1652  }
1653 
1654  /* Clean up */
1655  XLALDestroyREAL8Vector( values );
1656  XLALDestroyREAL8Vector( dvalues );
1657  XLALDestroyREAL8Array( dynamics );
1658  XLALDestroyREAL8Array( dynamicsHi );
1659  XLALDestroyREAL8Vector ( sigReHi );
1660  XLALDestroyREAL8Vector ( sigImHi );
1661  XLALDestroyREAL8Vector ( phseHi );
1662  XLALDestroyREAL8Vector ( omegaHi );
1663  XLALDestroyREAL8Vector( ampNQC );
1667  XLALDestroyREAL8Vector( p1 );
1668  XLALDestroyREAL8Vector( p2 );
1669 
1670  return XLAL_SUCCESS;
1671 }
1672 
1673 /**
1674  * @addtogroup LALSimIMREOBNRv2_c
1675  *
1676  * @author Craig Robinson
1677  *
1678  * @brief Functions to generate the EOBNRv2 waveforms, as defined in
1679  * Pan et al, PRD84, 124052(2011).
1680  *
1681  * @review EOBNRv2 reviewed by Ilya Mandel, Riccardo Sturani, Prayush Kumar, John Whelan, Yi Pan. Review concluded with git hash b29f20ff11e62095dbd44e850b248ecc58b08a13 (April 2013).
1682  *
1683  * @{
1684  */
1685 
1686 /**
1687  * This function generates the plus and cross polarizations for the dominant
1688  * (2,2) mode of the EOBNRv2 approximant. This model is defined in Pan et al,
1689  * PRD84, 124052(2011).
1690  */
1691 int
1693  REAL8TimeSeries **hplus, /**<< The +-polarization waveform (returned) */
1694  REAL8TimeSeries **hcross, /**<< The x-polarization waveform (returned) */
1695  const REAL8 phiC, /**<< The phase at the coalescence time (twice the orbital phase at the max orbital frequency moment) */
1696  const REAL8 deltaT, /**<< Sampling interval (in seconds) */
1697  const REAL8 m1SI, /**<< First component mass (in kg) */
1698  const REAL8 m2SI, /**<< Second component mass (in kg) */
1699  const REAL8 fLower, /**<< Starting frequency (in Hz) */
1700  const REAL8 distance, /**<< Distance to source (in metres) */
1701  const REAL8 inclination /**<< Inclination of the source (in radians) */
1702  )
1703 {
1704 
1705  if ( XLALSimIMREOBNRv2Generator(hplus, hcross, NULL, phiC, deltaT, m1SI, m2SI,
1706  fLower, distance, inclination, 0 ) == XLAL_FAILURE )
1707  {
1709  }
1710 
1711  return XLAL_SUCCESS;
1712 }
1713 
1714 /**
1715  * This function generates the plus and cross polarizations for the EOBNRv2 approximant
1716  * with all available modes included. This model is defined in Pan et al,
1717  * PRD84, 124052(2011).
1718  */
1719 int
1721  REAL8TimeSeries **hplus, /**<< The +-polarization waveform (returned) */
1722  REAL8TimeSeries **hcross, /**<< The x-polarization waveform (returned) */
1723  const REAL8 phiC, /**<< The orbital phase at the coalescence time */
1724  const REAL8 deltaT, /**<< Sampling interval (in seconds) */
1725  const REAL8 m1SI, /**<< First component mass (in kg) */
1726  const REAL8 m2SI, /**<< Second component mass (in kg) */
1727  const REAL8 fLower, /**<< Starting frequency (in Hz) */
1728  const REAL8 distance, /**<< Distance to source (in metres) */
1729  const REAL8 inclination /**<< Inclination of the source (in radians) */
1730  )
1731 {
1732 
1733  if ( XLALSimIMREOBNRv2Generator(hplus, hcross, NULL, phiC, deltaT, m1SI, m2SI,
1734  fLower, distance, inclination, 1 ) == XLAL_FAILURE )
1735  {
1737  }
1738 
1739  return XLAL_SUCCESS;
1740 }
1741 
1742 /**
1743  * Wrapper function to generate the -2 spin-weighted spherical harmonic modes
1744  * (as opposed to generating the polarizations). This model is defined in
1745  * Pan et al, PRD84, 124052(2011). Returns the (2,2), (2,1), (3,3), (4,4), (5,5)
1746  * SWSH modes in a SphHarmTimeSeries struct.
1747  */
1749  const REAL8 deltaT, /**< Sampling interval (s) */
1750  const REAL8 m1, /**< First component mass (kg) */
1751  const REAL8 m2, /**< Second component mass (kg) */
1752  const REAL8 fLower, /**< Starting GW frequency (Hz) */
1753  const REAL8 distance /**< Distance to sources (m) */
1754  )
1755 {
1756  SphHarmTimeSeries *hlms = NULL;
1757  if ( XLALSimIMREOBNRv2Generator(NULL, NULL, &hlms, 0., deltaT, m1, m2,
1758  fLower, distance, 0., 1) == XLAL_FAILURE )
1759  {
1761  }
1762 
1763  return hlms;
1764 }
1765 
1766 /** @} */
static REAL8 XLALSimIMREOBFactorizedFlux(REAL8Vector *values, const REAL8 omega, EOBParams *ak, const INT4 lMax)
This function calculates the factorized flux in the EOB dynamics for the EOBNR (and potentially subse...
static UNUSED int XLALCalculateEOBACoefficients(EOBACoefficients *const coeffs, const REAL8 eta)
Function to pre-compute the coefficients in the EOB A potential function.
static REAL8 XLALCalculateEOBdAdr(const REAL8 r, EOBACoefficients *restrict coeffs)
Calculated the derivative of the EOB A function with respect to r, using the pre-computed A coefficie...
static REAL8 XLALEffectiveHamiltonian(const REAL8 eta, const REAL8 r, const REAL8 pr, const REAL8 pp, EOBACoefficients *aCoeffs)
Function to calculate the EOB effective Hamiltonian for the given values of the dynamical variables.
static UNUSED int XLALSimIMREOBCalcFacWaveformCoefficients(FacWaveformCoeffs *const coeffs, const REAL8 eta)
Function which calculates the various coefficients used in the generation of the factorized waveform.
static UNUSED int XLALSimIMREOBModifyFacWaveformCoefficients(FacWaveformCoeffs *const coeffs, const REAL8 eta)
Function which adds the additional terms required for waveform generation to the factorized waveform ...
static REAL8 XLALCalculateEOBD(REAL8 r, REAL8 eta) UNUSED
Calculate the EOB D function.
static REAL8 XLALCalculateEOBA(const REAL8 r, EOBACoefficients *restrict coeffs)
This function calculates the EOB A function which using the pre-computed coefficients which should al...
static UNUSED int XLALSimIMREOBGetFactorizedWaveform(COMPLEX16 *restrict hlm, REAL8Vector *restrict values, const REAL8 v, const INT4 l, const INT4 m, EOBParams *restrict params)
Computes the factorized waveform according to the prescription given in Pan et al,...
Module to compute the ring-down waveform as linear combination of quasi-normal-modes decaying wavefor...
static UNUSED INT4 XLALSimIMREOBHybridAttachRingdown(REAL8Vector *signal1, REAL8Vector *signal2, const INT4 l, const INT4 m, const REAL8 dt, const REAL8 mass1, const REAL8 mass2, const REAL8 spin1x, const REAL8 spin1y, const REAL8 spin1z, const REAL8 spin2x, const REAL8 spin2y, const REAL8 spin2z, REAL8Vector *timeVec, REAL8Vector *matchrange, Approximant approximant)
The main workhorse function for performing the ringdown attachment for EOB models EOBNRv2 and SEOBNRv...
static UNUSED int XLALSimIMREOBCalculateNQCCoefficients(EOBNonQCCoeffs *restrict coeffs, REAL8Vector *restrict amplitude, REAL8Vector *restrict phase, REAL8Vector *restrict q1, REAL8Vector *restrict q2, REAL8Vector *restrict q3, REAL8Vector *restrict p1, REAL8Vector *restrict p2, INT4 l, INT4 m, REAL8 timePeak, REAL8 deltaT, REAL8 eta)
This function computes the coefficients a1, a2, etc.
static UNUSED int XLALSimIMREOBNonQCCorrection(COMPLEX16 *restrict nqc, REAL8Vector *restrict values, const REAL8 omega, EOBNonQCCoeffs *restrict coeffs)
This function calculates the non-quasicircular correction to apply to the waveform.
static UNUSED int XLALSimIMREOBGetCalibratedNQCCoeffs(EOBNonQCCoeffs *coeffs, INT4 l, INT4 m, REAL8 eta)
For the 2,2 mode, there are fits available for the NQC coefficients, given in Eqs.
static REAL8 XLALSimIMREOBGetNRPeakDeltaT(INT4 l, INT4 m, REAL8 eta)
Compute the time offset which should be used in computing the non-quasicircular correction and perfor...
static int XLALSimIMREOBNRv2Generator(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, SphHarmTimeSeries **h_lms, const REAL8 phiC, const REAL8 deltaT, const REAL8 m1SI, const REAL8 m2SI, const REAL8 fLower, const REAL8 distance, const REAL8 inclination, const int higherModeFlag)
static REAL8 XLALprInitP4PN(REAL8 p, void *params)
static size_t find_instant_freq(const REAL8TimeSeries *hp, const REAL8TimeSeries *hc, const REAL8 target, const size_t start, const int fsign)
static REAL8 XLALpphiInitP4PN(const REAL8 r, EOBACoefficients *restrict coeffs)
static int LALHCapDerivativesP4PN(double t, const double values[], double dvalues[], void *funcParams)
static int XLALFirstStoppingCondition(double t, const double values[], double dvalues[], void *funcParams)
static REAL8 omegaofrP4PN(const REAL8 r, const REAL8 eta, void *params)
static const int EOBNRV2_NUM_MODES_MAX
The maximum number of modes available to us in this model.
static int XLALSimIMREOBNRv2SetupFlux(expnCoeffsdEnergyFlux *ak, REAL8 eta)
The following declarations are so that the compiler quits.
static REAL8 XLALSimIMREOBGetRingdownAttachCombSize(INT4 l, INT4 m)
static REAL8 XLALrOfOmegaP4PN(REAL8 r, void *params)
static int XLALHighSRStoppingCondition(double t, const double values[], double dvalues[], void *funcParams)
static REAL8 XLALCalculateOmega(REAL8 eta, REAL8 r, REAL8 pr, REAL8 pPhi, EOBACoefficients *aCoeffs)
static REAL8 XLALvrP4PN(const REAL8 r, const REAL8 omega, pr3In *params)
static size_t find_instant_freq_hlm(const COMPLEX16TimeSeries *hlm, const REAL8 target, const size_t start)
static UNUSED int XLALSimIMREOBComputeNewtonMultipolePrefixes(NewtonMultipolePrefixes *prefix, const REAL8 m1, const REAL8 m2)
Function which computes the various coefficients in the Newtonian multipole.
const double c1
const double c2
#define nModes
const UINT4 lmModes[NMODES][2]
static REAL8 UNUSED q3(REAL8 e0, REAL8 f0, REAL8 inc, REAL8 bet, REAL8 FPlus, REAL8 FCross)
static REAL8 UNUSED q2(REAL8 e0, REAL8 f0, REAL8 inc, REAL8 bet, REAL8 FPlus, REAL8 FCross)
static REAL8 UNUSED q1(REAL8 e0, REAL8 f0, REAL8 inc, REAL8 bet, REAL8 FPlus, REAL8 FCross)
static REAL8 UNUSED z3(REAL8 e0, REAL8 f0, REAL8 inc, REAL8 bet, REAL8 FPlus, REAL8 FCross)
Module containing the energy and flux functions for waveform generation.
static REAL8 UNUSED XLALSimInspiralFp8PP(REAL8 v, expnCoeffsdEnergyFlux *ak)
REAL8 Hreal
int s
Definition: bh_qnmode.c:137
int l
Definition: bh_qnmode.c:135
double dt
Definition: bh_ringdown.c:113
double i
Definition: bh_ringdown.c:118
const double pr
const double u
const double a4
const double u3
const double r2
const double a2
const double u2
void XLALDestroyREAL8Array(REAL8Array *)
REAL8 XLALDBisectionFindRoot(REAL8(*y)(REAL8, void *), REAL8 xmin, REAL8 xmax, REAL8 xacc, void *params)
int XLALAdaptiveRungeKutta4(LALAdaptiveRungeKuttaIntegrator *integrator, void *params, REAL8 *yinit, REAL8 tinit, REAL8 tend, REAL8 deltat, REAL8Array **yout)
void XLALAdaptiveRungeKuttaFree(LALAdaptiveRungeKuttaIntegrator *integrator)
LALAdaptiveRungeKuttaIntegrator * XLALAdaptiveRungeKutta4Init(int dim, int(*dydt)(double t, const double y[], double dydt[], void *params), int(*stop)(double t, const double y[], double dydt[], void *params), double eps_abs, double eps_rel)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_TWOPI
#define LAL_MTSUN_SI
#define LAL_GAMMA
#define LAL_MRSUN_SI
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
INT4 XLALSimIMREOBGenerateQNMFreqV2(COMPLEX16Vector *modefreqs, const REAL8 mass1, const REAL8 mass2, const REAL8 spin1[3], const REAL8 spin2[3], UINT4 l, INT4 m, UINT4 nmodes, Approximant approximant)
These functions generate the quasinormal mode frequencies for a black hole ringdown.
#define EOB_RD_EFOLDS
The number of e-folds of ringdown which should be attached for EOBNR models.
Definition: LALSimIMR.h:71
int XLALSimIMREOBNRv2AllModes(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, const REAL8 phiC, const REAL8 deltaT, const REAL8 m1SI, const REAL8 m2SI, const REAL8 fLower, const REAL8 distance, const REAL8 inclination)
This function generates the plus and cross polarizations for the EOBNRv2 approximant with all availab...
SphHarmTimeSeries * XLALSimIMREOBNRv2Modes(const REAL8 deltaT, const REAL8 m1, const REAL8 m2, const REAL8 fLower, const REAL8 distance)
Wrapper function to generate the -2 spin-weighted spherical harmonic modes (as opposed to generating ...
int XLALSimIMREOBNRv2DominantMode(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, const REAL8 phiC, const REAL8 deltaT, const REAL8 m1SI, const REAL8 m2SI, const REAL8 fLower, const REAL8 distance, const REAL8 inclination)
This function generates the plus and cross polarizations for the dominant (2,2) mode of the EOBNRv2 a...
@ EOBNRv2
UNDOCUMENTED.
int XLALSimAddMode(REAL8TimeSeries *hplus, REAL8TimeSeries *hcross, COMPLEX16TimeSeries *hmode, REAL8 theta, REAL8 phi, int l, int m, int sym)
Multiplies a mode h(l,m) by a spin-2 weighted spherical harmonic to obtain hplus - i hcross,...
SphHarmTimeSeries * XLALSphHarmTimeSeriesAddMode(SphHarmTimeSeries *appended, const COMPLEX16TimeSeries *inmode, UINT4 l, INT4 m)
Prepend a node to a linked list of SphHarmTimeSeries, or create a new head.
void XLALDestroySphHarmTimeSeries(SphHarmTimeSeries *ts)
Delete list from current pointer to the end of the list.
static const INT4 r
static const INT4 m
static const INT4 q
REAL8TimeSeries * XLALResizeREAL8TimeSeries(REAL8TimeSeries *series, int first, size_t length)
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX16TimeSeries(COMPLEX16TimeSeries *series)
COMPLEX16TimeSeries * XLALResizeCOMPLEX16TimeSeries(COMPLEX16TimeSeries *series, int first, size_t length)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
COMPLEX16TimeSeries * XLALCreateCOMPLEX16TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
const LALUnit lalStrainUnit
COMPLEX16Vector * XLALCreateCOMPLEX16Vector(UINT4 length)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
void XLALDestroyCOMPLEX16Vector(COMPLEX16Vector *vector)
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR_NULL(...)
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_IS_REAL8_FAIL_NAN(val)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list p
COMPLEX16Sequence * data
COMPLEX16 * data
Structure containing the coefficients for EOBNRv2 A potential function.
The coefficients which are used in calculating the non-quasicircular correction to the EOBNRv2 model.
Structure containing all the parameters needed for the EOB waveform.
EOBNonQCCoeffs * nqcCoeffs
FacWaveformCoeffs * hCoeffs
NewtonMultipolePrefixes * prefixes
EOBACoefficients * aCoeffs
Structure containing the coefficients for calculating the factorized waveform.
int(* stop)(double t, const double y[], double dydt[], void *params)
Structure containing all the terms of the Newtonian multipole which are constant over the course of t...
REAL8 * data
REAL8Sequence * data
REAL8 * data
Structure to carry a collection of spherical harmonic modes in COMPLEX16 time series.
Definition: burst.c:245
Structure containing parameters used to determine the initial radial momentum.
REAL8 vr
< Radial velocity (dimensionless)
EOBACoefficients * aCoeffs
< Pre-computed coefficients of EOB A function
REAL8 eta
< Symmetric mass ratio
REAL8 r
< Orbital separation (units of total mass)
REAL8 omega
< Angular frequency (dimensionless combination M omega)
REAL8 q
< Momentum pphi
LIGOTimeGPS epoch
Definition: unicorn.c:20
double deltaT
Definition: unicorn.c:24