LALSimulation  5.4.0.1-fe68b98
LALSimIMRTEOBResumSUtils.c
Go to the documentation of this file.
1 
2 /*
3  * This file is part of TEOBResumS
4  *
5  * Copyright (C) 2017-2018 Alessandro Nagar, Sebastiano Bernuzzi,
6  * Sarp Ackay, Gregorio Carullo, Walter Del Pozzo, Ka Wa Tsang, Michalis Agathos
7  * LALSimulation implementation by Michalis Agathos
8  *
9  * TEOBResumS is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * TEOBResumS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see http://www.gnu.org/licenses/.
21  *
22  */
23 
24 #ifdef __GNUC__
25 #define UNUSED __attribute__ ((unused))
26 #else
27 #define UNUSED
28 #endif
29 
30 //#ifndef _OPENMP
31 //#define omp ignore
32 //#endif
33 
34 #include <complex.h>
35 #include <math.h>
36 
37 #include <gsl/gsl_const.h>
38 #include <gsl/gsl_errno.h>
39 #include <gsl/gsl_math.h>
40 #include <gsl/gsl_odeiv.h>
41 
42 #include "LALSimTEOBResumS.h"
43 
44 #include <stdio.h>
45 
46 
47 /* Return symm mass ratio from q */
49 {
50  REAL8 nu = 0;
51  XLAL_CHECK_REAL8(q>0.0, XLAL_EDOM, "Mass ratio q cannot be negative!");
52  if (q>0.)
53  nu = q/((q+1.)*(q+1.));
54  return nu;
55 }
56 
57 /* Return mass ratio M1/M from nu */
58 REAL8 nu_to_X1(const REAL8 nu)
59 {
60  return 0.5*(1.+sqrt(1.-4.*nu));
61 }
62 
63 /* Eulerlog function (constants are defined in header) */
64 static const REAL8 Logm[] = {0.,Log1,Log2,Log3,Log4,Log5,Log6,Log7};
65 REAL8 Eulerlog(const REAL8 x,const INT4 m)
66 {
67  REAL8 logm = 0.;
68  if ((m>0) & (m<8)) logm = Logm[m];
69  else logm = log((REAL8)m);
70  return LAL_GAMMA + LAL_LN2 + logm + 0.5*log(x);
71 }
72 
73 /* Spline interpolation with GSL routines */
74 void interp_spline(double *t, double *y, int n, double *ti, int ni, REAL8 *yi)
75 {
76  //#pragma omp parallel
77  //{
78  gsl_interp_accel *acc = gsl_interp_accel_alloc ();
79  gsl_spline *spline = gsl_spline_alloc (gsl_interp_cspline, n);
80  gsl_spline_init (spline, t, y, n);
81 
82  //#pragma omp for
83  for (INT4 k = 0; k < ni; k++)
84  {
85  yi[k] = (REAL8) gsl_spline_eval (spline, ti[k], acc);
86  }
87  gsl_spline_free (spline);
88  gsl_interp_accel_free (acc);
89  //}
90 }
91 
92 /* Find nearest point index in 1d array */
94 {
95  INT4 i0 = o-1, i1 = n-o;
96  INT4 i;
97  if (n < 2*o)
98  {
99  XLAL_ERROR(XLAL_EDOM, "not enough points to interpolate");
100  }
101  if (x <= xp[i0]) return 0;
102  if (x > xp[i1]) return n-2*o;
103  while (i0 != i1-1)
104  {
105  i = (i0+i1)/2;
106  if (x < xp[i]) i1 = i; else i0 = i;
107  }
108  return i0-o+1;
109 }
110 
111 /* Barycentric Lagrange interpolation at xx with n points of f(x),
112  equivalent to standard Lagrangian interpolation */
113 #define tiny 1e-12
115 {
116  REAL8 omega[n];
117  REAL8 o, num, den, div, ci;
118  INT4 i, j;
119  for (i = 0; i < n; i++)
120  {
121  if (fabs(xx - x[i]) <= tiny) return f[i];
122  o = 1.;
123  for (j = 0; j < n; j++)
124  {
125  if (j != i)
126  {
127  o /= (x[i] - x[j]);
128  }
129  }
130  omega[i] = o;
131  }
132  num = den = 0.;
133  for (i = 0; i < n; i++)
134  {
135  div = xx - x[i];
136  ci = omega[i]/div;
137  den += ci;
138  num += ci * f[i];
139  }
140  return( num/den );
141 }
142 
143 /* Barycentric Lagrange interpolation at xx with n points of f(x),
144  compute weights */
145 void baryc_weights(INT4 n, REAL8 *x, REAL8 *omega)
146 {
147  REAL8 o;
148  INT4 i, j;
149  for (i = 0; i < n; i++)
150  {
151  o = 1.;
152  for (j = 0; j < n; j++)
153  {
154  if (j != i)
155  {
156  o /= (x[i] - x[j]);
157  }
158  }
159  omega[i] = o;
160  }
161 }
162 
163 /* Barycentric Lagrange interpolation at xx with n points of f(x),
164  use precomputed weights */
166 {
167  INT4 i;
168  REAL8 num, den, div, ci;
169  num = den = 0.;
170  for (i = 0; i < n; i++)
171  {
172  div = xx - x[i];
173  if (fabs(div) <= tiny) return f[i];
174  ci = omega[i]/div;
175  den += ci;
176  num += ci * f[i];
177  }
178  return( num/den );
179 }
180 
181 /* 1d Lagrangian barycentric interpolation */
182 REAL8 interp1d (const INT4 order, REAL8 xx, INT4 nx, REAL8 *f, REAL8 *x)
183 {
184  REAL8 ff;
185  INT4 ix;
186  INT4 ox = order > nx ? nx : order;
187  ix = find_point_bisection(xx, nx, x, ox/2);
188  ff = baryc_f(xx, ox, &f[ix], &x[ix]);
189  return( ff );
190 }
191 
192 /* Find max location by poynomial interpolation around x0 (uniform grid) */
193 REAL8 find_max (const INT4 n, REAL8 dx, REAL8 x0, REAL8 *f, REAL8 *fmax)
194 {
195  const INT4 i = (n-1)/2; /* To centre the grid for n = N, e.g., n=7, i-3 = 0. */
196  REAL8 xmax = x0;
197  REAL8 d1f = 0., d2f = 0.;
198  if (n==3)
199  {
200  d1f = 0.5*(f[i+1]-f[i-1]);
201  d2f = (f[i-1]-2*f[i]+f[i+1]);
202  }
203  else if (n==5)
204  {
205  d1f = (8.*(f[i+1]-f[i-1]) - f[i+2] + f[i-2]);
206  d2f = (-30*f[i]+16*(f[i+1]+f[i-1])-(f[i+2]+f[i-2]));
207  }
208  else if (n==7)
209  {
210  d1f = ( 45.0*(f[i+1]-f[i-1]) - 9.0*(f[i+2] - f[i-2]) + f[i+3] - f[i-3] )/(60.0);
211  d2f = ( -490.0*f[i]+270.0*(f[i+1]+f[i-1])-27.0*(f[i+2]+f[i-2])+2.0*(f[i+3]+f[i-3]) )/(180.0);
212  }
213  else XLAL_ERROR_REAL8(XLAL_EINVAL, "Implemented only n = 3,5,7");
214 
215  if (d2f != 0.)
216  {
217  xmax -= dx*d1f/d2f;
218  }
219  /* Eval function */
220  if (fmax!=NULL)
221  {
222  if (n==3)
223  {
224  *fmax = ( -((dx + x0 - xmax)*(-x0 + xmax)*f[-1 + i])
225  + (dx - x0 + xmax)*(2*(dx + x0 - xmax)*f[i] + (-x0 + xmax)*f[1 + i]) );
226  *fmax /= (2.*SQ(dx));
227  }
228  else if (n==5)
229  {
230  *fmax = ((dx + x0 - xmax)*(2*dx + x0 - xmax)*(-x0 + xmax)*(dx - x0 + xmax)*f[-2 + i]
231  + (2*dx - x0 + xmax)*(-4*(dx + x0 - xmax)*(2*dx + x0 - xmax)*(-x0 + xmax)*f[-1 + i]+(dx - x0 + xmax)*(6*(dx + x0 - xmax)*(2*dx + x0 - xmax)*f[i] + (-x0 + xmax)*(4*(2*dx + x0 - xmax)*f[1 + i]- (dx + x0 - xmax)*f[2 + i]))));
232  *fmax /= (24.*pow(dx,4));
233 
234  }
235  else
236  {
237  XLAL_ERROR_REAL8(XLAL_EINVAL, "Implemented only n = 3,5");
238  }
239  }
240 
241  return xmax;
242 }
243 
244 ///* Factorial */
245 //double fact(int n)
246 //{
247 // double f[] = {1., 1., 2., 6., 24., 120., 720., 5040., 40320., 362880.,
248 // 3628800., 39916800., 479001600., 6227020800., 87178291200.};
249 // if (n < 0){
250 // errorexit(" computing a negative factorial.\n");
251 // } else if (n <= 14){
252 // return f[n];
253 // } else {
254 // return n*fact(n-1);
255 // }
256 //}
257 
258 ///* Wigner d-function */
259 //double wigner_d_function(int l, int m, int s, double i)
260 //{
261 // double dWig = 0.;
262 // double costheta = cos(i*0.5);
263 // double sintheta = sin(i*0.5);
264 // int ki = MAX( 0 , m-s );
265 // int kf = MIN( l+m, l-s );
266 // int k;
267 // for( k = ki; k <= kf; k++ ){
268 // dWig +=
269 // ( pow(-1.,k) * pow(costheta,2*l+m-s-2*k) * pow(sintheta,2*k+s-m) )/
270 // ( fact(k) * fact(l+m-k) * fact(l-s-k) * fact(s-m+k) );
271 // }
272 // return (sqrt(fact(l+m) * fact(l-m) * fact(l+s) * fact(l-s)) * dWig);
273 //}
274 
275 ///* Spin-weighted spherical harmonic
276 // Ref: https://arxiv.org/pdf/0709.0093.pdf */
277 //int spinsphericalharm(double *rY, double *iY, int s, int l, int m, double phi, double i)
278 //{
279 // if ((l<0) || (m<-l) || (m>l)) {
280 // errorexit(" wrong (l,m) inside spinspharmY\n");
281 // }
282 // double c = pow(-1.,-s) * sqrt( (2.*l+1.)/(4.*M_PI) );
283 // double dWigner = c * wigner_d_function(l,m,-s,i);
284 // *rY = cos((double)(m)*phi) * dWigner;
285 // *iY = sin((double)(m)*phi) * dWigner;
286 // return XLAL_SUCCESS;
287 //}
288 
289 /*
290  * ModeArray is a structure which allows to select the modes to include
291  * in the waveform.
292  * This function will create a structure with the given selection of modes
293  * as enumerated in LALSimTEOBResumS.h.
294  * Default values for different types of binaries are hardcoded as macros.
295  */
296 INT4 XLALSetup_TEOB_mode_array(LALValue *ModeArray, INT4 modeType)
297 {
298  switch (modeType)
299  {
300  /* Only include (2,2) and (2,-2) mode */
301  case TEOB_MODES_22:
303  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 2);
304  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
305  break;
306  /* For BNS all modes up to l=8 are available */
307  case TEOB_MODES_ALL:
309  break;
310 
311  default:
312  XLAL_ERROR(XLAL_EINVAL, "Unknown TEOB mode-list code.");
313  break;
314  }
315 
316  return XLAL_SUCCESS;
317 }
318 
319 /*
320  * ModeArray is a structure which allows to select the modes to include.
321  * This function checks if the selected modes are available for a given type
322  * of binary with TEOBResumS. It also checks that the symmetric modes are
323  * consistently active.
324  */
325 INT4 XLALCheck_TEOB_mode_array(LALValue *ModeArray,
326  UINT4 use_tidal)
327 {
328  /* If one select BNS all the modes up to (8,8) are available */
329  /* If not, only the (2,2) mode is available */
330 
331  /*Loop over all the possible modes
332  *we only check +m modes, when one select (l,m) mode is actually
333  *selecting (l,|m|) mode
334  */
335  for (UINT4 ELL = 2; ELL <= LAL_SIM_L_MAX_MODE_ARRAY; ELL++)
336  {
337  for (INT4 EMM = 0; EMM <= (INT4) ELL; EMM++)
338  {
339  if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ELL, EMM))
340  {
341  /* Make sure that no modes exist with l>8 */
342  XLAL_CHECK(ELL<=8, XLAL_ENOSYS, "Modes with l>8 are not available in TEOBResumS.\n");
343 
344  /* Make sure that for non-BNS systems, only \f$(2,\pm 2)\f$ modes are active */
345  if (!use_tidal) XLAL_CHECK((ELL==2) && (abs(EMM)==2), XLAL_EDOM, "Modes beyond (2,\\pm 2) are only available for BNS in TEOBResumS.");
346 
347  /* Make sure (l,-m) mode is activated if (l,m) is active. Does not
348  * exit with error but silently adds the symmetric mode if not present.
349  * Bitwise operation in implementation ensures that no check is necessary.
350  */
351  XLALSimInspiralModeArrayActivateMode(ModeArray, ELL, -EMM);
352  }
353  else if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ELL, -EMM))
354  {
355  /* Make sure (l,m) mode is active if (l,-m) is active */
356  XLAL_CHECK(XLALSimInspiralModeArrayIsModeActive(ModeArray, ELL, EMM), XLAL_EDOM, "Symmetric (l,-m) mode cannot be included without the (l,m) mode being active.");
357  }
358  }
359  }
360 
361  return XLAL_SUCCESS;
362 }
363 
364 /* (h+, hx) polarizations from the multipolar waveform in the source frame */
365 void XLALSimIMRComputePolarisations(REAL8Sequence *hplus_out,
366  REAL8Sequence *hcross_out,
367  SphHarmTimeSeries *hlm,
368  LALValue *modeArray,
369  REAL8 amplitude_prefactor,
370  REAL8 theta,
371  REAL8 phi)
372 {
373  INT4 mneg = 1; /* m>0 modes only, add m<0 modes afterwards */
374  COMPLEX16 Y, Ym=0.0, hpc;
375  UINT4 l;
376  INT4 m;
377  SphHarmTimeSeries *this_mode = hlm;
378 
379  while (this_mode)
380  {
381  l = this_mode->l;
382  m = this_mode->m;
383  if (!XLALSimInspiralModeArrayIsModeActive(modeArray, l, m))
384  {
385  this_mode = this_mode->next;
386  continue;
387  }
388  mneg = XLALSimInspiralModeArrayIsModeActive(modeArray, l, - m);
389 
390  Y = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m);
391  if ( (mneg) && (m != 0) )
392  {
393  Ym = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, - m);
394  if ( l % 2 ) Ym = -Ym; /* l is odd */
395  }
396 
397  for (UINT4 i=0; i < this_mode->mode->data->length; i++)
398  {
399  hpc=0.0;
400  hpc += this_mode->mode->data->data[i] * Y;
401  /* add m<0 modes */
402  if ( (mneg) && (m != 0) )
403  hpc += conj(this_mode->mode->data->data[i]) * Ym;
404 
405  hpc *= amplitude_prefactor;
406  hplus_out->data[i] += creal(hpc);
407  hcross_out->data[i] -= cimag(hpc);
408  }
409 
410  this_mode = this_mode->next;
411  }
412 
413  return;
414 }
415 
416 /* (h+, hx) polarizations from the multipolar waveform in the source frame;
417  polar representation of time series */
418 void XLALSimIMRComputePolarisationsPolar(REAL8Sequence *hplus_out,
419  REAL8Sequence *hcross_out,
420  SphHarmPolarTimeSeries *hlm,
421  LALValue *modeArray,
422  REAL8 amplitude_prefactor,
423  REAL8 theta,
424  REAL8 phi)
425 {
426  INT4 mneg = 1; /* m>0 modes only, add m<0 modes afterwards */
427  COMPLEX16 Y, Ym = 0.0, hpc;
428  UINT4 l;
429  INT4 m;
430  SphHarmPolarTimeSeries *this_mode = hlm;
431 
432  while (this_mode)
433  {
434  l = this_mode->l;
435  m = this_mode->m;
436  if (!XLALSimInspiralModeArrayIsModeActive(modeArray, l, m))
437  {
438  this_mode = this_mode->next;
439  continue;
440  }
441  mneg = XLALSimInspiralModeArrayIsModeActive(modeArray, l, - m);
442  //#pragma omp parallel
443  //{
444  /* Convention (master) theta = (-)incl and phi = pi/2 - phiRef */
445  Y = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m);
446  if ( (mneg) && (m != 0) )
447  {
448  Ym = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, -m);
449  if ( l % 2 ) Ym = -Ym; /* l is odd */
450  }
451  //#pragma omp for
452  for (UINT4 i=0; i < this_mode->ampl->data->length; i++)
453  {
454  hpc = cpolar(this_mode->ampl->data->data[i], -this_mode->phase->data->data[i]) * Y;
455 
456  /* add m<0 modes */
457  if ( (mneg) && (m != 0) )
458  hpc += cpolar(this_mode->ampl->data->data[i], this_mode->phase->data->data[i]) * Ym;
459 
460  hpc *= amplitude_prefactor;
461  hplus_out->data[i] += creal(hpc);
462  hcross_out->data[i] -= cimag(hpc);
463  }
464  //}
465  this_mode = this_mode->next;
466  }
467 
468  return;
469 }
470 
471 
472 /* 4th order centered stencil first derivative, uniform grids */
473 INT4 D0(REAL8 *f, REAL8 dx, INT4 n, REAL8 *df)
474 {
475  const REAL8 oo12dx = 1./(12*dx);
476  INT4 i;
477  for (i=2; i<n-2; i++)
478  {
479  df[i] = (8.*(f[i+1]-f[i-1]) - f[i+2] + f[i-2])*oo12dx;
480  }
481  i = 0;
482  df[i] = (-25.*f[i] + 48.*f[i+1] - 36.*f[i+2] + 16.*f[i+3] - 3.*f[i+4])*oo12dx;
483  i = 1;
484  df[i] = (-3.*f[i-1] - 10.*f[i] + 18.*f[i+1] - 6.*f[i+2] + f[i+3])*oo12dx;
485  i = n-2;
486  df[i] = - (-3.*f[i+1] - 10.*f[i] + 18.*f[i-1] - 6.*f[i-2] + f[i-3])*oo12dx;
487  i = n-1;
488  df[i] = - (-25.*f[i] + 48.*f[i-1] - 36.*f[i-2] + 16.*f[i-3] - 3.*f[i-4])*oo12dx;
489  return XLAL_SUCCESS;
490 }
491 
492 /* 4th order centered stencil second derivative, uniform grids */
493 INT4 D2(REAL8 *f, REAL8 dx, INT4 n, REAL8 *d2f)
494 {
495  const REAL8 oo12dx2 = 1./(dx*dx*12);
496  INT4 i;
497  for (i=2; i<n-2; i++)
498  {
499  d2f[i] = (-30*f[i]+16*(f[i+1]+f[i-1])-(f[i+2]+f[i-2]))*oo12dx2;
500  }
501  i= 0;
502  d2f[i] = (45*f[i]-154*f[i+1]+214*f[i+2]-156*f[i+3]+61*f[i+4]-10*f[i+5])*oo12dx2;
503  i= 1;
504  d2f[i] = (10*f[i-1]-15*f[i]-4*f[i+1]+14*f[i+2]-6*f[i+3]+f[i+4])*oo12dx2;
505  i = n-2;
506  d2f[i] = (10*f[i+1]-15*f[i]-4*f[i-1]+14*f[i-2]-6*f[i-3]+f[i-4])*oo12dx2;
507  i = n-1;
508  d2f[i] = (45*f[i]-154*f[i-1]+214*f[i-2]-156*f[i-3]+61*f[i-4]-10*f[i-5])*oo12dx2;
509  return XLAL_SUCCESS;
510 }
511 
512 /* Third-order polynomial integration */
513 REAL8 cumint3(REAL8 *f, REAL8 *x, const INT4 n, REAL8 *sum)
514 {
515  REAL8 xe[n+2], fe[n+2];
516  REAL8 *x0,*x1,*x2,*x3;
517  REAL8 *f0,*f1,*f2,*f3;
518  REAL8 a,b,c,d,e,h,g,z;
519  const REAL8 oo12 = 0.08333333333333333;
520 
521  for (INT4 i=1; i < n+1; i++)
522  {
523  xe[i] = x[i-1];
524  fe[i] = f[i-1];
525  }
526  xe[0] = x[3];
527  xe[n+1] = x[n-4];
528  fe[0] = f[3];
529  fe[n+1] = f[n-4];
530 
531  x0 = &xe[0];
532  x1 = &xe[1];
533  x2 = &xe[2];
534  x3 = &xe[3];
535 
536  f0 = &fe[0];
537  f1 = &fe[1];
538  f2 = &fe[2];
539  f3 = &fe[3];
540 
541  sum[0] = 0.;
542  for (INT4 i=0; i < n-1; i++)
543  {
544  a = x1[i]-x0[i];
545  b = x2[i]-x1[i];
546  c = x3[i]-x2[i];
547  d = f1[i]-f0[i];
548  e = f2[i]-f1[i];
549  h = f3[i]-f2[i];
550  g = 0.5*(f1[i]+f2[i]);
551  z = b*g + oo12*b*b*(c*b*(2*c+b)*(c+b)*d-a*c*(c-a)*(2*c+2*a+3*b)*e-a*b*(2*a+b)*(a+b)*h)/(a*c*(a+b)*(c+b)*(c+a+b));
552  sum[i+1] = sum[i] + z;
553  }
554 
555  return sum[n-1];
556 }
557 
558 /* Simple unwrap for phase angles */ // Do NOT mess with it
559 void unwrap(REAL8 *p, const INT4 size)
560 {
561  if (size < 1) return;
562  INT4 j;
563  INT4 fact = 0; // For making the initial negative phase angles positive
564  REAL8 curr, prev;
565  REAL8 corr = 0.0;
566  REAL8 dphi = 0.0;
567 
568  prev = p[0];
569  if( p[0] < 0 ) fact = 1;
570  if( p[1] < p[0] )
571  dphi = LAL_TWOPI;
572 
573  for (j = 1; j < size; j++)
574  {
575  p[j] += fact*LAL_TWOPI;
576  curr = p[j];
577  if( curr < prev )
578  dphi = LAL_TWOPI;
579  corr += dphi;
580  p[j] += corr - fact*LAL_TWOPI;
581  prev = curr;
582  dphi = 0.0;
583  }
584 }
585 
586 /* Unwrap unsign number of cycles from reference phase as proxy */
587 void unwrap_proxy(REAL8 *p, REAL8 *r, const INT4 size, const INT4 shift0)
588 {
589  if (size < 1) return;
590 
591  INT4 *n = (INT4 *) calloc(size, sizeof(INT4));
592  XLAL_CHECK_VOID(n, XLAL_ENOMEM, "Out of memory");
593 
594  const REAL8 ooTwoPi = 1.0/(LAL_TWOPI);
595  const REAL8 r0 = r[0];
596 
597  /* no cycles from reference phase, r>0 */
598  for (INT4 i = 0; i < size; i++)
599  n[i] = floor ( (r[i] - r0) * ooTwoPi );
600 
601  if (shift0)
602  {
603  /* shift phase : p(0) = r(0) */
604  const REAL8 dp = (r0 - p[0]);
605  for (INT4 i = 0; i < size; i++)
606  p[i] += dp;
607  }
608 
609  /* unwrap based on no cycles */
610  const REAL8 p0 = p[0];
611  INT4 np = 0;
612  for (INT4 i = 0; i < size; i++)
613  {
614  p[i] += n[i]*LAL_TWOPI;
615  /* correct cases p = - Pi + epsilon */
616  np = floor ( ( p[i] - p0 )*ooTwoPi );
617  p[i] += (n[i]-np)*LAL_TWOPI;
618  }
619 
620  XLALFree(n);
621 }
622 
623 /* Compute size of a uniform grid t0:dt:tf */
624 INT4 get_uniform_size(const REAL8 tN, const REAL8 t0, const REAL8 dt)
625 {
626  return ((INT4)((tN - t0)/dt + 1));
627 }
628 
629 /* Compute optimized timestep after merger */
630 REAL8 get_mrg_timestep(REAL8 q, REAL8 chi1, REAL8 chi2)
631 {
632  REAL8 dt = q+chi1+chi2; // MA: just to get rid of UNUSED errors
633  dt = 0.1;
634  // ...
635  return dt;
636 }
637 
638 /* Multipolar waveform at time point (complex) */
639 void Waveform_lm_t_alloc (LALTEOBResumSWaveformModeSingleTime **wav)
640 {
641  *wav = (LALTEOBResumSWaveformModeSingleTime *) calloc(1, sizeof(LALTEOBResumSWaveformModeSingleTime));
642  XLAL_CHECK_VOID(wav, XLAL_ENOMEM, "Could not allocate mode instance.\n");
643  (*wav)->time = 0.;
644 
645  return;
646 }
647 
648 void Waveform_lm_t_free (LALTEOBResumSWaveformModeSingleTime *wav)
649 {
650  free(wav);
651  return;
652 }
653 
654 /* NQC data */
655 void NQCdata_alloc (NQCdata **nqc)
656 {
657  *nqc = (NQCdata *) calloc(1, sizeof(NQCdata));
658  XLAL_CHECK_VOID(nqc, XLAL_ENOMEM, "Out of memory");
659  (*nqc)->flx = (NQCcoefs *) calloc(1, sizeof(NQCcoefs));
660  XLAL_CHECK_VOID((*nqc)->flx, XLAL_ENOMEM, "Out of memory");
661  (*nqc)->hlm = (NQCcoefs *) calloc(1, sizeof(NQCcoefs));
662  XLAL_CHECK_VOID((*nqc)->hlm, XLAL_ENOMEM, "Out of memory");
663 }
664 
665 void NQCdata_free (NQCdata *nqc)
666 {
667  if(nqc->flx) free (nqc->flx);
668  if(nqc->hlm) free (nqc->hlm);
669  if(nqc) free (nqc);
670 }
671 
672 
673 /* Dynamics */
674 void XLALTEOBDynamicsInit (LALTEOBResumSDynamics **dyn, INT4 size, const char *name)
675 {
676  (*dyn) = calloc(1, sizeof(LALTEOBResumSDynamics));
677  XLAL_CHECK_VOID(dyn, XLAL_ENOMEM, "Could not allocate TEOB Dynamics.\n");
678 
679  strcpy((*dyn)->name,name);
680  (*dyn)->size = size;
681  (*dyn)->time = calloc ((size_t) size, sizeof(REAL8) ); // TODO: speedup: calloc < malloc+memset
682 
683  for (INT4 v = 0; v < TEOB_DYNAMICS_NVARS; v++)
684  {
685  (*dyn)->data[v] = calloc ((size_t) size, sizeof(REAL8) );
686  }
687  NQCdata_alloc(&(*dyn)->NQC);
688  return;
689 }
690 
691 void XLALTEOBDynamicsPush (LALTEOBResumSDynamics **dyn, INT4 size)
692 {
693  (*dyn)->time = realloc( (*dyn)->time, size * sizeof(REAL8) );
694  for (INT4 v = 0; v < TEOB_DYNAMICS_NVARS; v++)
695  {
696  (*dyn)->data[v] = realloc ( (*dyn)->data[v], size * sizeof(REAL8) );
697  if ((*dyn)->data[v] == NULL) XLAL_ERROR_VOID(XLAL_ENOMEM, "Could not allocate TEOB Dynamics.\n");
698  /* if (dn>0) memset( (*dyn)->data[v] + n, 0, dn * sizeof(REAL8) ); */ // TODO: MA: use this?
699  }
700  (*dyn)->size = size;
701 }
702 
703 /* Interp and overwrite a multipolar waveform */
704 void XLALTEOBDynamicsInterp (LALTEOBResumSDynamics *dyn, const INT4 size, const REAL8 t0, const REAL8 dt, const char *name)
705 {
706  /* Alloc and init aux memory */
707  LALTEOBResumSDynamics *dyn_aux;
708  const INT4 oldsize = dyn->size;
709  XLALTEOBDynamicsInit(&dyn_aux, oldsize, "");
710  memcpy(dyn_aux->time, dyn->time, oldsize * sizeof(REAL8));
711  for (int v = 0; v < TEOB_DYNAMICS_NVARS; v++)
712  memcpy(dyn_aux->data[v], dyn->data[v], oldsize * sizeof(REAL8));
713 
714  /* Overwrite and realloc arrays */
715  dyn->dt = dt;
716  dyn->size = size;
717 
718  if (strcmp(name, "")) strcpy(dyn->name, name);
719  if(dyn->time) free(dyn->time);
720 
721  dyn->time = malloc ( size * sizeof(REAL8) );
722 
723  for (int v = 0; v < TEOB_DYNAMICS_NVARS; v++)
724  {
725  if (dyn->data[v]) free(dyn->data[v]);
726  dyn->data[v] = malloc ( size * sizeof(REAL8) );
727  /* memset(dyn->data[v], 0., size*sizeof(double)); */
728  }
729 
730  /* Fill new time array */
731  for (int i = 0; i < size; i++)
732  dyn->time[i] = i*dt + t0;
733 
734  /* Interp */
735  for (int k = 0; k < TEOB_DYNAMICS_NVARS; k++)
736  interp_spline(dyn_aux->time, dyn_aux->data[k], dyn_aux->size, dyn->time, size, dyn->data[k]);
737 
738  /* Free aux memory */
739  XLALFreeTEOBDynamics (dyn_aux);
740 }
741 
742 /* Extract Dynamics at times t >= to and t < tn, Alloc a new Dynamics var */
743 void XLALTEOBDynamicsExtract (LALTEOBResumSDynamics *dyna, const REAL8 to, const REAL8 tn, LALTEOBResumSDynamics **dynb, const char *name)
744 {
745  /* Check limits */
746  if (tn<to)
747  XLAL_ERROR_VOID(XLAL_EINVAL, "Bad choice of times: tn < to");
748  if (to > dyna->time[dyna->size-1])
749  XLAL_ERROR_VOID(XLAL_EINVAL, "Nothing to extract, to > time[size-1]");
750  if (tn < dyna->time[0])
751  XLAL_ERROR_VOID(XLAL_EINVAL, "Nothing to extract, tn < time[0]");
752 
753  /* Find indexes of closest elements to (to, tn) */
754  INT4 io = 0;
755  INT4 in = dyna->size-1;
756  if (to > dyna->time[0])
757  io = find_point_bisection(to, dyna->size, dyna->time, 1);
758  if (tn < dyna->time[dyna->size-1])
759  in = find_point_bisection(tn, dyna->size, dyna->time, 0);
760 
761  /* Calculate the new size */
762  const INT4 N = in-io;
763 
764 
765  /* Alloc output waveform b */
766  XLALTEOBDynamicsInit (dynb, N, name);
767 
768  /* TODO: Parameters are not copied in the new wf !*/
769  /*
770  (*dynb) = (Dynamics *) calloc(1, sizeof(Dynamics));
771  if (dynb == NULL)
772  errorexit("Out of memory");
773  strcpy((*dynb)->name,name);
774  (*dynb)->size = N;
775  memcpy(*dynb, dyna, sizeof(Dynamics)); // copy parameters
776  (*dynb)->time = malloc ( N * sizeof(double) );
777  for (int v = 0; v < TEOB_DYNAMICS_NVARS; v++)
778  (*dynb)->data[v] = malloc ( N * sizeof(double) );
779  */
780 
781  /* Copy the relevant part of a into b */
782  for (int i = 0; i < N; i++)
783  (*dynb)->time[i] = dyna->time[io + i];
784  for (int v = 0; v < TEOB_DYNAMICS_NVARS; v++)
785  {
786  for (int i = 0; i < N; i++)
787  {
788  (*dynb)->data[v][i] = dyna->data[v][io + i];
789  }
790  }
791 
792 }
793 
794 /* Join two dynamics time series at t = to */
795 void XLALTEOBDynamicsJoin (LALTEOBResumSDynamics *dyna, LALTEOBResumSDynamics *dynb, REAL8 to)
796 {
797  /* Time arrays are suppose to be ordered as
798  dyna->time: x x x x x x x x x
799  dynb->time: o o o o o o o o o
800  to : |
801  But they do not need to overlap or be uniformly spaced.
802  Note to can be
803  to > dyna->time[hlma->size-1] => extend the dynamics data
804  to < dynb->time[0] => join the whole b dynamics
805  Following checks enforce the above structure, if possible.
806  */
807  if (dyna->time[0] > dynb->time[0]) SWAPTRS( dyna, dynb );
808  XLAL_CHECK_VOID (to <= dynb->time[dynb->size-1], XLAL_EINVAL, "Joining time outside range. Dynamics not joined.");
809  XLAL_CHECK_VOID (to > dyna->time[0], XLAL_EINVAL, "Joining time outside range. Dynamics not joined.");
810 
811  /* Find indexes of closest elements to to */
812  const INT4 ioa = find_point_bisection(to, dyna->size, dyna->time, 1);
813  INT4 iob = find_point_bisection(to, dynb->size, dynb->time, 1);
814  if ( DEQUAL(dyna->time[ioa], dynb->time[iob], 1e-10) ) iob++;
815 
816  /* Calculate the new size */
817  const INT4 Nb = dynb->size - iob;
818  const INT4 N = ioa + Nb;
819 
820  /* Resize a */
821  XLALTEOBDynamicsPush (&dyna, N);
822 
823  /* Copy the relevant part of b into a */
824  for (int i = 0; i < Nb; i++)
825  dyna->time[ioa + i] = dynb->time[iob + i];
826  for (int v = 0; v < TEOB_DYNAMICS_NVARS; v++)
827  {
828  for (int i = 0; i < Nb; i++)
829  {
830  dyna->data[v][ioa + i] = dynb->data[v][iob + i];
831  }
832  }
833 }
834 
835 
836 void XLALFreeTEOBDynamics (LALTEOBResumSDynamics *dyn)
837 {
838  if(dyn->time) free(dyn->time);
839  for (INT4 v = 0; v < TEOB_DYNAMICS_NVARS; v++)
840  if (dyn->data[v]) free(dyn->data[v]);
841  NQCdata_free(dyn->NQC);
842  free(dyn);
843  return;
844 }
845 
846 
847 /* Sync some quick access parameters in dyn with parameter database
848  to be used carefully */
849 void XLALTEOBDynamicsSetParams(LALTEOBResumSDynamics *dyn, /*< pointer to LALTEOBResumSDynamics struct to be filled in */
850  UNUSED LALValue **pModeArray, /*< Mode array to be returned */
851  const REAL8 m1, /*< mass of companion 1 (kg) */
852  const REAL8 m2, /*< mass of companion 2 (kg) */
853  const REAL8 UNUSED S1x, /*< x-component of the dimensionless spin of object 1 */
854  const REAL8 UNUSED S1y, /*< y-component of the dimensionless spin of object 1 */
855  const REAL8 S1z, /*< z-component of the dimensionless spin of object 1 */
856  const REAL8 UNUSED S2x, /*< x-component of the dimensionless spin of object 2 */
857  const REAL8 UNUSED S2y, /*< y-component of the dimensionless spin of object 2 */
858  const REAL8 S2z, /*< z-component of the dimensionless spin of object 2 */
859  const REAL8 dt, /*< sampling interval (s) */
860  const REAL8 lambda1, /*< l=2 tidal polarizability for m1 */
861  const REAL8 lambda2, /*< l=2 tidal polarizability for m2 */
862  const REAL8 lambda1oct, /*< l=3 tidal polarizability for m1 */
863  const REAL8 lambda2oct, /*< l=3 tidal polarizability for m2 */
864  const REAL8 lambda1hex, /*< l=4 tidal polarizability for m1 */
865  const REAL8 lambda2hex, /*< l=4 tidal polarizability for m2 */
866  LALDict *LALparams /*< LALDict dictionary for extra waveform options */
867  )
868 {
869  LALSimInspiralSpinOrder spinO = XLALSimInspiralWaveformParamsLookupPNSpinOrder(LALparams);
870  LALSimInspiralTidalOrder tidalO = XLALSimInspiralWaveformParamsLookupPNTidalOrder(LALparams);
871  LALSimInspiralGETides geTides = TEOB_GE_TIDES_DEFAULT;
872  LALSimInspiralGMTides gmTides = TEOB_GM_TIDES_DEFAULT;
873  if (XLALDictContains(LALparams, "GEtideO"))
874  geTides = XLALSimInspiralWaveformParamsLookupGETides(LALparams);
875  if (XLALDictContains(LALparams, "GMtideO"))
876  gmTides = XLALSimInspiralWaveformParamsLookupGMTides(LALparams);
877 
878 
879  /* Set auxiliary parameters */
880  dyn->dt = dt;
881  dyn->M = (m1+m2)/LAL_MSUN_SI; /* Msun */
882  dyn->q = m1/m2;
883  dyn->nu = q_to_nu(dyn->q);
884  dyn->X1 = nu_to_X1(dyn->nu);
885  dyn->X2 = 1. - dyn->X1;
886 
887  dyn->chi1 = S1z;
888  dyn->chi2 = S2z;
889  dyn->S1 = SQ(dyn->X1) * dyn->chi1;
890  dyn->S2 = SQ(dyn->X2) * dyn->chi2;
891  dyn->a1 = dyn->X1*dyn->chi1;
892  dyn->a2 = dyn->X2*dyn->chi2;
893  REAL8 aK = dyn->a1 + dyn->a2;
894  dyn->aK2 = SQ(aK);
895  dyn->S = dyn->S1 + dyn->S2; /* in the EMRL this becomes the spin of the BH */
896  dyn->Sstar = dyn->X2*dyn->a1 + dyn->X1*dyn->a2; /* in the EMRL this becomes the spin of the particle */
897 
898  INT4 ssorder;
899  INT4 rc_order;
900  REAL8 c3 = 0.;
901  INT4 teobModeChoice = TEOB_MODES_NOPT; /* initialize to unavailable value */
902 
903 
904  /* Reading tidal order, spin order and GM tides from LALDict */
905 
906  if (geTides > LAL_SIM_INSPIRAL_GETIDES_NOPT) XLAL_ERROR_VOID(XLAL_EDATA, "Gravitoelectric tides option not supported.");
907 
908  switch (tidalO)
909  {
910  case LAL_SIM_INSPIRAL_TIDAL_ORDER_ALL:
911  dyn->use_tidal = geTides;
912  break;
913  case LAL_SIM_INSPIRAL_TIDAL_ORDER_0PN:
914  dyn->use_tidal = LAL_SIM_INSPIRAL_GETIDES_OFF;
915  break;
916  default:
917  XLAL_ERROR_VOID(XLAL_EDATA, "Tidal order not supported.");
918  }
919 
920  /* Determine the type of binary based on lambda being 0 */
921  dyn->bhns = 0;
922  if (lambda1 == 0.0 && lambda2 ==0.0) dyn->use_tidal = LAL_SIM_INSPIRAL_GETIDES_OFF;
923  else if (lambda1 == 0.0) dyn->bhns = 1;
924  else if (lambda2 == 0.0) dyn->bhns = 2;
925 
926  INT4 use_Yagi_fits = 1;
927  if (XLALDictContains(LALparams, "use_Yagi_fits"))
928  use_Yagi_fits = XLALDictLookupINT4Value(LALparams, "use_Yagi_fits");
929 
930  if ((dyn->use_tidal != LAL_SIM_INSPIRAL_GETIDES_OFF) && (!use_Yagi_fits))
931  {
932  use_Yagi_fits = 0;
933  XLAL_CHECK_VOID(lambda1 != 0 && lambda2 != 0 && lambda1oct != 0 && lambda2oct != 0 && lambda1hex != 0 && lambda2hex != 0, XLAL_EDOM, "If Yagi fits are not used, then all tidal parameters (quad, oct, hex) need to be positive!");
934  }
935 
936  if (gmTides > LAL_SIM_INSPIRAL_GMTIDES_NOPT) XLAL_ERROR_VOID(XLAL_EDATA, "Gravitomagnetic tides option not supported.");
937  dyn->use_tidal_gravitomagnetic = gmTides;
938 
939  switch (spinO)
940  {
941  case LAL_SIM_INSPIRAL_SPIN_ORDER_ALL:
942  dyn->use_spins = 1;
943  break;
944  case LAL_SIM_INSPIRAL_SPIN_ORDER_0PN:
945  dyn->use_spins = 0;
946  break;
947  default:
948  XLAL_ERROR_VOID(XLAL_EDATA, "Spin order not supported.");
949  }
950 
951 
952  if (dyn->use_tidal!=LAL_SIM_INSPIRAL_GETIDES_OFF)
953  {
954  REAL8 LambdaAl2 = lambda1;
955  REAL8 LambdaBl2 = lambda2;
956  REAL8 LambdaAl3, LambdaAl4, LambdaBl3, LambdaBl4, SigmaAl2, SigmaBl2;
957  LambdaAl3 = lambda1oct;
958  LambdaAl4 = lambda1hex;
959  LambdaBl3 = lambda2oct;
960  LambdaBl4 = lambda2hex;
961  SigmaAl2 = SigmaBl2 = 0.0;
962 
963  if (use_Yagi_fits)
964  {
965  /* Allow for manual override of oct and hex Lambdas */
966  if (LambdaAl3==0.0) LambdaAl3 = Yagi13_fit_barlamdel(LambdaAl2, 3);
967  if (LambdaBl3==0.0) LambdaBl3 = Yagi13_fit_barlamdel(LambdaBl2, 3);
968  if (LambdaAl4==0.0) LambdaAl4 = Yagi13_fit_barlamdel(LambdaAl2, 4);
969  if (LambdaBl4==0.0) LambdaBl4 = Yagi13_fit_barlamdel(LambdaBl2, 4);
970 
971  /* Write new values to LALDict so that they are globally accessible */
972  XLALSimInspiralWaveformParamsInsertTidalOctupolarLambda1(LALparams, LambdaAl3);
973  XLALSimInspiralWaveformParamsInsertTidalOctupolarLambda2(LALparams, LambdaBl3);
974  XLALSimInspiralWaveformParamsInsertTidalHexadecapolarLambda1(LALparams, LambdaAl4);
975  XLALSimInspiralWaveformParamsInsertTidalHexadecapolarLambda2(LALparams, LambdaBl4);
976 
977  /* Old fits [ref] */
978  // dyn->SigmaAl2 = Yagi13_fit_barsigmalambda(dyn->LambdaAl2);
979  // dyn->SigmaBl2 = Yagi13_fit_barsigmalambda(dyn->LambdaBl2);
980 
981  /* New fits [ref] */
982  SigmaAl2 = JFAPG_fit_Sigma_Irrotational(LambdaAl2);
983  SigmaBl2 = JFAPG_fit_Sigma_Irrotational(LambdaBl2);
984  }
985 
986  if (dyn->use_tidal_gravitomagnetic != LAL_SIM_INSPIRAL_GMTIDES_OFF)
987  {
988  SigmaAl2 = JFAPG_fit_Sigma_Irrotational(LambdaAl2);
989  SigmaBl2 = JFAPG_fit_Sigma_Irrotational(LambdaBl2);
990  }
991 
992  /* Tidal coupling constants */
993  REAL8 XA = dyn->X1;
994  REAL8 XB = dyn->X2;
995  dyn->kapA2 = 3. * LambdaAl2 * XA*XA*XA*XA*XA / dyn->q;
996  dyn->kapA3 = 15. * LambdaAl3 * XA*XA*XA*XA*XA*XA*XA / dyn->q;
997  dyn->kapA4 = 105. * LambdaAl4 * XA*XA*XA*XA*XA*XA*XA*XA*XA / dyn->q;
998 
999  dyn->kapB2 = 3. * LambdaBl2 * XB*XB*XB*XB*XB * dyn->q;
1000  dyn->kapB3 = 15. * LambdaBl3 * XB*XB*XB*XB*XB*XB*XB * dyn->q;
1001  dyn->kapB4 = 105. * LambdaBl4 * XB*XB*XB*XB*XB*XB*XB*XB*XB * dyn->q;
1002 
1003  /* gravitomagnetic tidal coupling constants el = 2 only */
1004  dyn->kapA2j = 24. * SigmaAl2 * XA*XA*XA*XA*XA / dyn->q;
1005  dyn->kapB2j = 24. * SigmaBl2 * XB*XB*XB*XB*XB * dyn->q;
1006 
1007  dyn->kapT2 = dyn->kapA2 + dyn->kapB2;
1008  dyn->kapT3 = dyn->kapA3 + dyn->kapB3;
1009  dyn->kapT4 = dyn->kapA4 + dyn->kapB4;
1010  dyn->kapT2j = dyn->kapA2j + dyn->kapB2j;
1011 
1012  XLAL_CHECK_VOID(dyn->kapT2 > 0., XLAL_EDOM, "kappaT2 must be >= 0");
1013  XLAL_CHECK_VOID(dyn->kapT3 > 0., XLAL_EDOM, "kappaT3 must be >= 0");
1014  XLAL_CHECK_VOID(dyn->kapT4 > 0., XLAL_EDOM, "kappaT4 must be >= 0");
1015 
1016  /* Tidal coefficients cons dynamics
1017  \f$\bar{\alpha}_n^{(\ell)}\f$, Eq.(37) of Damour&Nagar, PRD 81, 084016 (2010) */
1018  dyn->bar_alph2_1 = (5./2.*XA*dyn->kapA2 + 5./2.*XB*dyn->kapB2)/dyn->kapT2;
1019  dyn->bar_alph2_2 = ((3.+XA/8.+ 337./28.*XA*XA)*dyn->kapA2 + (3.+XB/8.+ 337./28.*XB*XB)*dyn->kapB2)/dyn->kapT2;
1020  dyn->bar_alph3_1 = ((-2.+15./2.*XA)*dyn->kapA3 + (-2.+15./2.*XB)*dyn->kapB3)/dyn->kapT3;
1021  dyn->bar_alph3_2 = ((8./3.-311./24.*XA+110./3.*XA*XA)*dyn->kapA3 + (8./3.-311./24.*XB+110./3.*XB*XB)*dyn->kapB3)/dyn->kapT3;
1022  /* Gravitomagnetic term, see Eq.(6.27) if Bini-Damour-Faye 2012 */
1023  dyn->bar_alph2j_1 = ( dyn->kapA2j*(1. + (11./6.)*XA + XA*XA) + dyn->kapB2j*(1. + (11./6.)*XB + XB*XB) )/dyn->kapT2j;
1024 
1025  /* Tidal coefficients for the amplitude */
1026  dyn->khatA2 = 3./2. * LambdaAl2 * XB/XA * (REAL8) gsl_pow_int((double) XA,5);
1027  dyn->khatB2 = 3./2. * LambdaBl2 * XA/XB * (REAL8) gsl_pow_int((double) XB,5);
1028 
1029  /* Self-spin coefficients */
1030  dyn->C_Q1 = 1.;
1031  dyn->C_Q2 = 1.;
1032  dyn->C_Oct1 = 1.;
1033  dyn->C_Oct2 = 1.;
1034  dyn->C_Hex1 = 1.;
1035  dyn->C_Hex2 = 1.;
1036  if (LambdaAl2>0.)
1037  {
1038  REAL8 logC_Q1 = logQ(log(LambdaAl2));
1039  dyn->C_Q1 = exp(logC_Q1);
1040  dyn->C_Oct1 = Yagi14_fit_Coct(dyn->C_Q1);
1041  dyn->C_Hex1 = Yagi14_fit_Chex(dyn->C_Q1);
1042  }
1043  if (LambdaBl2>0.)
1044  {
1045  REAL8 logC_Q2 = logQ(log(LambdaBl2));
1046  dyn->C_Q2 = exp(logC_Q2);
1047  dyn->C_Oct2 = Yagi14_fit_Coct(dyn->C_Q2);
1048  dyn->C_Hex2 = Yagi14_fit_Chex(dyn->C_Q2);
1049  }
1050 
1051  /* Set more as needed ... */
1052  ssorder = SS_NLO;
1053  rc_order = RC_NNLO;
1054  c3 = 0.;
1055 
1056  /* Use default modes for BNS */
1057  teobModeChoice = TEOB_MODES_BNS_DEFAULT;
1058  }
1059  else
1060  {
1061  ssorder = SS_LO;
1062  rc_order = RC_NLO;
1063  c3 = eob_c3_fit_global(dyn->nu, dyn->chi1, dyn->chi2, dyn->X1, dyn->X2, dyn->a1, dyn->a2);
1064  /* Use default modes for BBH */
1065  teobModeChoice = TEOB_MODES_BBH_DEFAULT;
1066  }
1067  dyn->cN3LO = c3;
1068 
1069  if (*pModeArray == NULL)
1070  {
1071  *pModeArray = XLALSimInspiralCreateModeArray();
1072  XLALSetup_TEOB_mode_array(*pModeArray, teobModeChoice);
1073  }
1074  XLALCheck_TEOB_mode_array(*pModeArray, dyn->use_tidal);
1075 
1076  /* Default NQC settings:
1077  * - if tides are on no NQC for flux and hlm (BNS/BHNS)
1078  * - if tides are off and spins are on, calculate NQC for hlm but not for flux (BBH spins)
1079  * - if tides and spins are off, then calculate NQC for flux and hlm using nrfit_nospin201602 (BBH no spins)
1080  * TODO: parse optional flags in LALDict
1081  */
1082 
1083  if (dyn->use_tidal)
1084  {
1085  /* BNS setup */
1086  dyn->nqc_coeffs_hlm = NQC_OFF;
1087  dyn->nqc_coeffs_flx = NQC_OFF;
1088  }
1089  else
1090  {
1091  if (dyn->use_spins)
1092  {
1093  /* BBH spins setup */
1094  dyn->nqc_coeffs_hlm = NQC_COMPUTE;
1095  dyn->nqc_coeffs_flx = NQC_OFF;
1096  }
1097  else
1098  {
1099  /* BBH no spins setup */
1100  dyn->nqc_coeffs_hlm = NQC_NR_NOSPIN;
1101  dyn->nqc_coeffs_flx = NQC_NR_NOSPIN;
1102  }
1103  }
1104 
1105  /* NQC data */
1106  eob_nqc_setcoefs(dyn);
1107 
1108  if (dyn->use_tidal)
1109  {
1110  /* back up */
1111  INT4 utidal_tmp, uspin_tmp;
1112  utidal_tmp = dyn->use_tidal;
1113  uspin_tmp = dyn->use_spins;
1114 
1115  /* Temporarily set tidal to NNLO and switch off spin for LR estimation */
1116  dyn->use_tidal = LAL_SIM_INSPIRAL_GETIDES_NNLO;
1117  dyn->use_spins = 0;
1118  int status;
1119 
1120  // TODO: tidesFlag usage?
1121  XLAL_CHECK_VOID((status = eob_dyn_adiabLR(dyn, &(dyn->rLR_tidal), utidal_tmp))==XLAL_SUCCESS, status, "Light ring not found! Exiting...");
1122 
1123  /* restore */
1124  dyn->use_tidal = utidal_tmp;
1125  dyn->use_spins = uspin_tmp;
1126  }
1127 
1128  /* p-order 2GSF pole in the tidal interaction.
1129 
1130  See Eq.(29) of TEOBResumS paper
1131  A. Nagar et al. Phys. Rev. D 98, 104052 (2018), arXiv:1806.01772 [gr-qc]
1132  originating from calculations in
1133  D. Bini and T. Damour, Phys.Rev. D90, 124037 (2014), arXiv:1409.6933 [gr-qc]
1134  and
1135  S. R. Dolan, P. Nolan, A. C. Ottewill, N. Warburton, and B. Wardell,
1136  Phys. Rev. D91, 023009 (2015), arXiv:1406.4890 [gr-qc]
1137 
1138  The interested user may set a custom value
1139  AT THEIR OWN RISK by passing the appropriate
1140  REAL8 parameter "pGSF_tidal" through LALDict.
1141  */
1142  dyn->pGSF_tidal = 4.0;
1143  if (XLALDictContains(LALparams, "pGSF_tidal"))
1144  dyn->pGSF_tidal = XLALDictLookupREAL8Value(LALparams, "pGSF_tidal");
1145 
1146  if (!(dyn->use_tidal))
1147  {
1148  HealyBBHFitRemnant(S1z, S2z, dyn->q, &(dyn->Mbhf), &(dyn->abhf));
1149  dyn->abhf = JimenezFortezaRemnantSpin(dyn->nu, dyn->X1, dyn->X2, S1z, S2z);
1150  }
1151 
1152  dyn->ode_timestep = ODE_TSTEP_ADAPTIVE;
1153  dyn->t_stop = 1e10; // HARDCODED
1154  dyn->r_stop = 1.0; // HARDCODED
1155 
1156  /* Function pointers */
1157  EOBWavFlmSFunc eob_wav_flm_s;
1158  EOBDynSGetRCFunc eob_dyn_s_get_rc;
1159 
1160  /* Set f_lm fun pointer */
1161  if (ssorder==SS_LO) {
1162  /* eob_wav_flm_s = &eob_wav_flm_s_old; */
1163  eob_wav_flm_s = &eob_wav_flm_s_SSLO;
1164  } else if (ssorder==SS_NLO) {
1165  eob_wav_flm_s = &eob_wav_flm_s_SSNLO;
1166  } else XLAL_ERROR_VOID(XLAL_EINVAL, "SS order not recognized.\n");
1167  dyn->eob_wav_flm_s = eob_wav_flm_s;
1168 
1169  /* Set rc fun pointer */
1170  if (rc_order==RC_LO)
1171  {
1172  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_LO;
1173  }
1174  else if (rc_order==RC_NLO)
1175  {
1176  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_NLO;
1177  }
1178  else if (rc_order==RC_NNLO)
1179  {
1180  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_NNLO;
1181  }
1182  else if (rc_order==RC_NNLOS4)
1183  {
1184  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_NNLO_S4;
1185  }
1186  else if (rc_order==RC_NOSPIN)
1187  {
1188  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_NOSPIN;
1189  }
1190  else if (rc_order==RC_NOTIDES)
1191  {
1192  eob_dyn_s_get_rc = &eob_dyn_s_get_rc_NOTIDES;
1193  }
1194  else XLAL_ERROR_VOID(XLAL_EINVAL, "Centrifugal radius option not recognized.\n");
1195  dyn->eob_dyn_s_get_rc = eob_dyn_s_get_rc;
1196 
1197  /* Pre-compute coefficients for resummed amplitudes */
1198  eob_wav_flm_coeffs(dyn->nu, dyn->clm);
1199 
1200  return;
1201 }
1202 
1203 /* Convert time in sec to dimensionless and mass-rescaled units */
1204 REAL8 time_units_factor(REAL8 M)
1205 {
1206  return 1./(M*LAL_MTSUN_SI);
1207 }
1208 
1209 REAL8 time_units_conversion(REAL8 M, REAL8 t)
1210 {
1211  return t/(M*LAL_MTSUN_SI);
1212 }
1213 
1214 /* Convert frequency in Hz to dimensionless radius */
1215 REAL8 radius0(REAL8 M, REAL8 fHz)
1216 {
1217  REAL8 x = (M*LAL_MTSUN_SI*fHz*2.*LAL_PI)/2.;
1218  return cbrt(1/(x*x));
1219 }
1220 
1221 /* Mass and angular momentum of the final black hole
1222  Healey, Lousto and Zochlower (HLZ),
1223  arXiv: 1406.7295, published as PRD 90, 104004 (2014)
1224  WARNING: the formula uses the convention that M2 > M1, so that
1225  chi2 should refer to the black hole with the largest
1226  mass. In the EOB code, this is given by chi1, since
1227  in EOB code we use the convention that M1 > M2
1228 
1229  Here it is q=M2/M1, with M2>M1
1230 
1231  Improved with (Eisco, Jisco) + iterative procedure 23/02/2016
1232  parameters (TABLE VI)
1233  */
1234 void HealyBBHFitRemnant(REAL8 chi1, REAL8 chi2, REAL8 q, REAL8 *mass, REAL8 *spin)
1235 {
1236 
1237  /* Final mass: Angular momentum: */
1238 
1239  REAL8 M0 = 0.951507; REAL8 L0 = 0.686710;
1240  REAL8 K1 = -0.051379; REAL8 L1 = 0.613247;
1241  REAL8 K2a = -0.004804; REAL8 L2a = -0.145427;
1242  REAL8 K2b = -0.054522; REAL8 L2b = -0.115689;
1243  REAL8 K2c = -0.000022; REAL8 L2c = -0.005254;
1244  REAL8 K2d = 1.995246; REAL8 L2d = 0.801838;
1245  REAL8 K3a = 0.007064; REAL8 L3a = -0.073839;
1246  REAL8 K3b = -0.017599; REAL8 L3b = 0.004759;
1247  REAL8 K3c = -0.119175; REAL8 L3c = -0.078377;
1248  REAL8 K3d = 0.025000; REAL8 L3d = 1.585809;
1249  REAL8 K4a = -0.068981; REAL8 L4a = -0.003050;
1250  REAL8 K4b = -0.011383; REAL8 L4b = -0.002968;
1251  REAL8 K4c = -0.002284; REAL8 L4c = 0.004364;
1252  REAL8 K4d = -0.165658; REAL8 L4d = -0.047204;
1253  REAL8 K4e = 0.019403; REAL8 L4e = -0.053099;
1254  REAL8 K4f = 2.980990; REAL8 L4f = 0.953458;
1255  REAL8 K4g = 0.020250; REAL8 L4g = -0.067998;
1256  REAL8 K4h = -0.004091; REAL8 L4h = 0.001629;
1257  REAL8 K4i = 0.078441; REAL8 L4i = -0.066693;
1258 
1259  /* Parameters */
1260  REAL8 nu = q/((1.+q)*(1.+q));
1261 
1262  /* Masses: convention here is that m2>m1 */
1263  REAL8 X2 = 0.5*(1.+sqrt(1.-4*nu));
1264  REAL8 X1 = 1.-X2;
1265 
1266  /* Spin variables */
1267  REAL8 s1 = X1*X1*chi1;
1268  REAL8 s2 = X2*X2*chi2;
1269  REAL8 S = s1 + s2;
1270  REAL8 S2 = S*S;
1271  REAL8 S3 = S*S2;
1272  REAL8 S4 = S2*S2;
1273  REAL8 Delta = X1/X2*s2 - X2/X1*s1 + s2 - s1;
1274  REAL8 Delta2 = Delta*Delta;
1275  REAL8 Delta3 = Delta*Delta2;
1276  REAL8 Delta4 = Delta2*Delta2;
1277 
1278  /* Mass ratio variables */
1279  REAL8 deltam = -sqrt(1-4*nu); // X1 - X2
1280  REAL8 deltam2 = deltam*deltam;
1281  REAL8 deltam3 = deltam*deltam2;
1282  REAL8 deltam4 = deltam*deltam3;
1283  REAL8 deltam6 = deltam2*deltam4;
1284 
1285  /* Initialize the angular momentum */
1286  REAL8 a0 = s1 + s2;
1287  INT4 a0_sign = 0;
1288 
1289  if (a0==0)
1290  {
1291  a0_sign=0;
1292  } else if (a0>0)
1293  {
1294  a0_sign=1;
1295  } else
1296  { // if (a0<0) {
1297  a0_sign=-1;
1298  }
1299 
1300  /* Set-up an interative procedure to compute properly the "isco" quantities */
1301  REAL8 a2;
1302  REAL8 Z1;
1303  REAL8 Z2;
1304  REAL8 risco;
1305  REAL8 uisco;
1306  REAL8 Eisco;
1307  REAL8 Jisco;
1308  REAL8 abh;
1309  REAL8 Mbh=0.;
1310 
1311  UINT4 i;
1312  for(i=0; i<20; i++)
1313  {
1314  a2 = a0*a0;
1315  Z1 = 1 + cbrt(1-a2)*(cbrt(1+a0) + cbrt(1-a0));
1316  Z2 = sqrt(3*a2 + Z1*Z1);
1317  risco = 3 + Z2 - a0_sign*sqrt((3-Z1)*(3+Z1+2.*Z2));
1318  uisco = 1./risco;
1319  Eisco = (1 - 2.*uisco + a0*sqrt(uisco*uisco*uisco))/sqrt(1-3*uisco + 2*a0*sqrt(uisco*uisco*uisco));
1320  Jisco = 2./(sqrt(3.*risco))*(3.*sqrt(risco)-2.*a0);
1321 
1322  /* Dimensionless spin: J/Mbh^2 */
1323  abh = (4*nu)*(4*nu)*(L0 + L1*S + L2a*Delta*deltam + L2b*S2 + L2c*Delta2 + L2d*deltam2 + L3a*Delta*S*deltam + L3b*S*Delta2 + L3c*S3 + L3d*S*deltam2 + L4a*Delta*S2*deltam + L4b*Delta3*deltam + L4c*Delta4 + L4d*S4 + L4e*Delta2*S2 + L4f*deltam4 + L4g*Delta*deltam3 + L4h*Delta2*deltam2 + L4i*S2*deltam2) + S*(1+8*nu)*deltam4 + nu*Jisco*deltam6;
1324 
1325  Mbh = (4*nu)*(4*nu)*(M0 + K1*S + K2a*Delta*deltam + K2b*S2 + K2c*Delta2 + K2d*deltam2 + K3a*Delta*S*deltam + K3b*S*Delta2 + K3c*S3 + K3d*S*deltam2 + K4a*Delta*S2*deltam + K4b*Delta3*deltam + K4c*Delta4 + K4d*S4 + K4e*Delta2*S2 + K4f*deltam4 + K4g*Delta*deltam3 + K4h*Delta2*deltam2 + K4i*S2*deltam2) + (1 + nu*(Eisco + 11))*deltam6;
1326 
1327  a0 = abh;
1328  }
1329 
1330  *mass = Mbh;
1331  *spin = abh;
1332 }
1333 
1334 /* Final spin fit of */
1335 // TODO: Refs needed
1336 REAL8 JimenezFortezaRemnantSpin(REAL8 nu, REAL8 X1, REAL8 X2, REAL8 chi1, REAL8 chi2)
1337 {
1338 
1339  const REAL8 xnu = sqrt(1.0-4.0*nu);
1340  const REAL8 Dchi = chi1-chi2;
1341  const REAL8 S = (X1*X1*chi1+X2*X2*chi2)/(X1*X1+X2*X2);
1342  const REAL8 a2 = 3.833;
1343  const REAL8 a3 = -9.49;
1344  const REAL8 a5 = 2.513;
1345 
1346  /* The functional form is taken from eq. (7), page 5. */
1347  REAL8 Lorb_spin_zero = (1.3*a3*nu*nu*nu + 5.24*a2*nu*nu + 2.*sqrt(3)*nu)/(2.88*a5*nu + 1);
1348 
1349  /* Coeffcients taken from Table II, page 6: */
1350  REAL8 b1 = 1.00096;
1351  REAL8 b2 = 0.788;
1352  REAL8 b3 = 0.654;
1353  REAL8 b5 = 0.840;
1354 
1355  /* These values are taken from Table III, page 7: */
1356  REAL8 f21 = 8.774;
1357  REAL8 f31 = 22.83;
1358  REAL8 f50 = 1.8805;
1359  REAL8 f11 = 0.345225*f21 + 0.0321306*f31 - 3.66556*f50 + 7.5397;
1360 
1361  /* These values are taken from Table IV, page 10 */
1362  REAL8 f12 = 0.512;
1363  REAL8 f22 = -32.1;
1364  REAL8 f32 = -154;
1365  REAL8 f51 = -4.77;
1366 
1367  /* The following quantities were taken from the relation given in eq. (11), */
1368  /* page 7: fi3 = 64 - 64.*fi0 - 16.*fi1 - 4.*fi2; */
1369  REAL8 f13 = 64 - 16.*f11 - 4.*f12;
1370  REAL8 f23 = 64 - 16.*f21 - 4.*f22;
1371  REAL8 f33 = 64 - 16.*f31 - 4.*f32;
1372  REAL8 f53 = 64 - 64.*f50 - 16.*f51;
1373 
1374  /* this transformation is given in eq. (9), page (7) */
1375  REAL8 b1t = b1*(f11*nu + f12*nu*nu + f13*nu*nu*nu);
1376  REAL8 b2t = b2*(f21*nu + f22*nu*nu + f23*nu*nu*nu);
1377  REAL8 b3t = b3*(f31*nu + f32*nu*nu + f33*nu*nu*nu);
1378  REAL8 b5t = b5*(f50 + f51*nu + f53*nu*nu*nu);
1379 
1380  /* The functional form is taken from eq. (8), page 6. */
1381  REAL8 Lorb_eq_spin = (0.00954*b3t*S*S*S + 0.0851*b2t*S*S - 0.194*b1t*S)/(1 - 0.579*b5t*S);
1382 
1383  /* These values are taken from Table IV, page 10: */
1384  REAL8 d10 = 0.322;
1385  REAL8 d11 = 9.33;
1386  REAL8 d20 = -0.0598;
1387  REAL8 d30 = 2.32;
1388  REAL8 d31 = -3.26;
1389 
1390  /* The functional form is taken from eq. (19a-c), page 10.*/
1391  REAL8 A1 = d10*xnu*nu*nu*(d11*nu+1);
1392  REAL8 A2 = d20*nu*nu*nu;
1393  REAL8 A3 = d30*xnu*nu*nu*nu*(d31*nu+1);
1394 
1395  /* The functional form is taken from eq. (15), page 9. */
1396  REAL8 Lorb_uneq_mass = A1*Dchi + A2*Dchi*Dchi + A3*S*Dchi;
1397 
1398  return X1*X1*chi1+X2*X2*chi2 + Lorb_spin_zero + Lorb_eq_spin + Lorb_uneq_mass;
1399 }
1400 
1401 /* logQ-vs-log(lambda) fit of Table I of Yunes-Yagi
1402  here x = log(lambda) and the output is the log of the coefficient
1403  that describes the quadrupole deformation due to spin. */
1404 REAL8 logQ(REAL8 x)
1405 {
1406  const REAL8 ai = 0.194;
1407  const REAL8 bi = 0.0936;
1408  const REAL8 ci = 0.0474;
1409  const REAL8 di = -4.21e-3;
1410  const REAL8 ei = 1.23e-4;
1411  const REAL8 x2 = x*x;
1412  const REAL8 x3 = x*x2;
1413  const REAL8 x4 = x*x3;
1414  return ai + bi*x + ci*x2 + di*x3 + ei*x4;
1415 }
1416 
1417 /* Yagi 2013 fits for NS multipolar
1418  \f$\bar{\lambda}_\ell = 2 k_\ell/(C^{2\ell+1} (2\ell-1)!!)\f$
1419  Eq.(9,10),(61); Tab.I; Fig.8 http://arxiv.org/abs/1311.0872 */
1420 REAL8 Yagi13_fit_barlamdel(REAL8 barlam2, int ell)
1421 {
1422  if (barlam2<=0.) return 0.;
1423  REAL8 lnx = log(barlam2);
1424  REAL8 coeffs[5];
1425  if (ell == 3)
1426  {
1427  coeffs[0] = 2.52e-5;
1428  coeffs[1] = -1.31e-3;
1429  coeffs[2] = 2.51e-2;
1430  coeffs[3] = 1.18;
1431  coeffs[4] = -1.15;
1432  }
1433  else if (ell == 4)
1434  {
1435  coeffs[0] = 2.8e-5;
1436  coeffs[1] = -1.81e-3;
1437  coeffs[2] = 3.95e-2;
1438  coeffs[3] = 1.43;
1439  coeffs[4] = -2.45;
1440  }
1441  else
1442  XLAL_ERROR_REAL8(XLAL_EINVAL, "Yagi fits are for ell=3,4.");
1443  REAL8 lny = coeffs[0]*lnx*lnx*lnx*lnx+coeffs[1]*lnx*lnx*lnx+coeffs[2]*lnx*lnx+coeffs[3]*lnx+coeffs[4];
1444  return exp(lny);
1445 }
1446 
1447 /* Yagi 2013 fits for NS multipolar
1448  \f$\bar{\sigma_2}( \bar{\lambda}_2 )\f$
1449  Eq.(9,11),(61); Tab.I; Fig.9 http://arxiv.org/abs/1311.0872
1450  See also later erratum */
1451 REAL8 Yagi13_fit_barsigmalambda(REAL8 barlam2)
1452 {
1453  if (barlam2<=0.) return 0.;
1454  REAL8 lnx = log(barlam2);
1455  REAL8 coeffs[5];
1456  /*
1457  coeffs[4] = 0.126;
1458  coeffs[3] = 0.617;
1459  coeffs[2] = 2.81e-2;
1460  coeffs[1] = 3.59e-4;
1461  coeffs[0] = -3.61e-5;
1462  */
1463  coeffs[4] = -2.01;
1464  coeffs[3] = 0.462;
1465  coeffs[2] = 1.68e-2;
1466  coeffs[1] = -1.58e-4;
1467  coeffs[0] = -6.03e-6;
1468  REAL8 lny = coeffs[0]*lnx*lnx*lnx*lnx+coeffs[1]*lnx*lnx*lnx+coeffs[2]*lnx*lnx+coeffs[3]*lnx+coeffs[4];
1469 
1470  return -1.0*exp(lny);
1471 }
1472 
1473 /* Yagi et al. fits for C_Oct
1474  Eq. (90) and Table I of https://arxiv.org/abs/1403.6243 */
1475 REAL8 Yagi14_fit_Coct(REAL8 C_Q)
1476 {
1477  REAL8 A0 = -0.925;
1478  REAL8 B1 = 1.98;
1479  REAL8 nu1 = 0.273;
1480 
1481  REAL8 cubrootCoct = A0 + B1*pow(C_Q,nu1);
1482 
1483  return cubrootCoct*cubrootCoct*cubrootCoct;
1484 }
1485 
1486 /* Yagi et al. fits for C_Hex
1487  Eq. (90) and Table I of https://arxiv.org/abs/1403.6243 */
1488 REAL8 Yagi14_fit_Chex(REAL8 C_Q)
1489 {
1490  REAL8 A0 = -0.413;
1491  REAL8 B1 = 1.5;
1492  REAL8 nu1 = 0.466;
1493 
1494  REAL8 fourthrootChex = A0 + B1*pow(C_Q,nu1);
1495 
1496  return SQ(SQ(fourthrootChex));
1497 }
1498 
1499 // TODO: Refs needed
1500 REAL8 JFAPG_fit_Sigma_Irrotational(REAL8 barlam2)
1501 {
1502  if (barlam2<=0.) return 0.;
1503  REAL8 lnx = log(barlam2);
1504  REAL8 coeffs[6];
1505 
1506  coeffs[5] = -2.03;
1507  coeffs[4] = 0.487;
1508  coeffs[3] = 9.69e-3;
1509  coeffs[2] = 1.03e-3;
1510  coeffs[1] = -9.37e-5;
1511  coeffs[0] = 2.24e-6;
1512  REAL8 lny = coeffs[0]*lnx*lnx*lnx*lnx*lnx+coeffs[1]*lnx*lnx*lnx*lnx+coeffs[2]*lnx*lnx*lnx+coeffs[3]*lnx*lnx+coeffs[4]*lnx+coeffs[5];
1513 
1514  return -1.0*exp(lny);
1515 }
1516 
1517 // TODO: Refs needed
1518 REAL8 JFAPG_fit_Sigma_Static(REAL8 barlam2)
1519 {
1520  if (barlam2<=0.) return 0.;
1521  REAL8 lnx = log(barlam2);
1522  REAL8 coeffs[6];
1523 
1524  coeffs[5] = -2.66;
1525  coeffs[4] = 0.786;
1526  coeffs[3] = -0.01;
1527  coeffs[2] = 1.28e-3;
1528  coeffs[1] = -6.37e-5;
1529  coeffs[0] = 1.18e-6;
1530  REAL8 lny = coeffs[0]*lnx*lnx*lnx*lnx*lnx+coeffs[1]*lnx*lnx*lnx*lnx+coeffs[2]*lnx*lnx*lnx+coeffs[3]*lnx*lnx+coeffs[4]*lnx+coeffs[5];
1531 
1532  return exp(lny);
1533 }
1534 
1535 /* Join two multipolar waveforms at t = to */
1536 void XLALSphHarmPolarJoin (SphHarmPolarTimeSeries *hlma, SphHarmPolarTimeSeries *hlmb, REAL8 to)
1537 {
1538  /* Time arrays are suppose to be ordered as
1539  hlma->tdata->data: x x x x x x x x x
1540  hlmb->tdata->data: o o o o o o o o o
1541  t0 : |
1542  But they do not need to overlap or be uniformly spaced.
1543  Note to can be
1544  t0 > hlma->time[hlma->size-1] => extend the a waveform
1545  t0 < hlmb->time[0] => join the whole b waveform
1546  Following checks enforce the above structure, if possible.
1547  */
1548  if (hlma->tdata->data[0] > hlmb->tdata->data[0])
1549  {
1550  SWAPTRS( hlma, hlmb );
1551  }
1552  if ((to > hlmb->tdata->data[hlmb->tdata->length-1]) || (to <= hlma->tdata->data[0])) return;
1553 
1554  /* Find indexes of closest elements to "to"
1555  If the two arrays exactly overlap at "to" this should give:
1556  time_a[ioa] = time_b[iob] */
1557  const int ioa = find_point_bisection(to, hlma->tdata->length, hlma->tdata->data, 1);
1558  int iob = find_point_bisection(to, hlmb->tdata->length, hlmb->tdata->data, 1);
1559 
1560  if ( DEQUAL(hlma->tdata->data[ioa], hlmb->tdata->data[iob], 1e-10) ) iob++;
1561 
1562  /* Calculate the new size N */
1563  const int N = ioa + hlmb->tdata->length - iob;
1564 
1565  /* Resize a */
1566  XLALResizeSphHarmPolarTimeSeries(hlma, 0, N);
1567  XLALResizeREAL8Sequence(hlma->tdata, 0, N);
1568 
1569  /* Copy the relevant part of b into a */
1570  for (int i = ioa; i < N; i++)
1571  {
1572  hlma->tdata->data[i] = hlmb->tdata->data[iob + i - ioa];
1573  }
1574  SphHarmPolarTimeSeries *this = hlma;
1575  SphHarmPolarTimeSeries *that = hlmb;
1576  while (this && that)
1577  {
1578  for (int i = ioa; i < N; i++)
1579  {
1580  XLAL_CHECK_VOID((this->l==that->l) && (this->m==that->m), XLAL_EFAULT, "Mismatch of l and m when joining modes.");
1581  this->ampl->data->data[i] = that->ampl->data->data[iob + i - ioa];
1582  this->phase->data->data[i] = that->phase->data->data[iob + i - ioa];
1583  }
1584  this = this->next;
1585  that = that->next;
1586  }
1587  XLAL_CHECK_VOID(!this && !that, XLAL_EFAULT, "SphHarmTimeSeries to be joined must have the same set of modes");
1588 }
INT4 find_point_bisection(REAL8 x, INT4 n, REAL8 *xp, INT4 o)
void baryc_weights(INT4 n, REAL8 *x, REAL8 *omega)
void interp_spline(double *t, double *y, int n, double *ti, int ni, REAL8 *yi)
INT4 XLALSetup_TEOB_mode_array(LALValue *ModeArray, INT4 modeType)
Should not be needed in LAL (all parameters passed to interface function)
REAL8 baryc_f_weights(REAL8 xx, INT4 n, REAL8 *f, REAL8 *x, REAL8 *omega)
REAL8 q_to_nu(const REAL8 q)
REAL8 baryc_f(REAL8 xx, INT4 n, REAL8 *f, REAL8 *x)
REAL8 Eulerlog(const REAL8 x, const INT4 m)
static const REAL8 Logm[]
REAL8 nu_to_X1(const REAL8 nu)
#define tiny
REAL8 interp1d(const INT4 order, REAL8 xx, INT4 nx, REAL8 *f, REAL8 *x)
INT4 XLALCheck_TEOB_mode_array(LALValue *ModeArray, UINT4 use_tidal)
REAL8 find_max(const INT4 n, REAL8 dx, REAL8 x0, REAL8 *f, REAL8 *fmax)
This file is part of TEOBResumS.
#define Log2
#define Log1
#define Log4
@ TEOB_MODES_22
@ TEOB_MODES_ALL
#define Log3
#define Log7
#define Log5
#define Log6
#define SQ(a)
int l
Definition: bh_qnmode.c:135
double i
Definition: bh_ringdown.c:118
const double nx
#define LAL_LN2
#define LAL_GAMMA
double REAL8
uint32_t UINT4
int32_t INT4
#define LAL_SIM_L_MAX_MODE_ARRAY
Maximum L spherical harmonic mode that is supported in Mode Array.
@ TEOBResumS
Resummed Spin-aligned Tidal EOB.
LALValue * XLALSimInspiralModeArrayActivateAllModes(LALValue *modes)
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralModeArrayDeactivateAllModes(LALValue *modes)
LALValue * XLALSimInspiralModeArrayActivateMode(LALValue *modes, unsigned l, int m)
static const INT4 m
static const INT4 q
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_REAL8(assertion,...)
XLAL_SUCCESS
XLAL_EDOM
XLAL_EINVAL
list x
list y