LALSimulation  5.4.0.1-fe68b98
LALSimIMRPhenomXUtilities.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 Geraint Pratten
3  *
4  * This code adapts functions from:
5  * LALSimIMRPhenomP.c
6  * LALSimIMRPhenomD.c
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with with program; see the file COPYING. If not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
22  */
23 
24 /**
25  * \author Geraint Pratten
26  *
27  * \file
28  *
29  * \brief Utility functions for IMRPhenomX framework, arXiv:2001.11412
30  *
31  */
32 
33 #include <gsl/gsl_math.h>
34 
36 
37 /* ******************** MECO, ISCO, etc ******************** */
38 
39 /**
40  * Phenomenological fit to hybrid minimum energy circular orbit (MECO) function.
41  * Uses 3.5PN hybridised with test-particle limit.
42  * Reference: M Cabero et al, PRD, 95, 064016, (2017), arXiv:1602.03134
43  */
45 
46  REAL8 eta2 = (eta*eta);
47  REAL8 eta3 = (eta2*eta);
48  REAL8 eta4 = (eta3*eta);
49 
50  REAL8 delta = sqrt(1.0 - 4.0*eta);
51 
52  REAL8 S = XLALSimIMRPhenomXchiPNHat(eta,chi1L,chi2L);
53  REAL8 S2 = (S*S);
54  REAL8 S3 = (S2*S);
55  //REAL8 S4 = (S3*S);
56 
57  REAL8 noSpin, eqSpin, uneqSpin;
58 
59  REAL8 dchi = chi1L - chi2L;
60  REAL8 dchi2 = (dchi*dchi);
61 
62 
63  noSpin = (0.018744340279608845 + 0.0077903147004616865*eta + 0.003940354686136861*eta2 - 0.00006693930988501673*eta3)/(1. - 0.10423384680638834*eta);
64 
65  eqSpin = (S*(0.00027180386951683135 - 0.00002585252361022052*S + eta4*(-0.0006807631931297156 + 0.022386313074011715*S - 0.0230825153005985*S2) + eta2*(0.00036556167661117023 - 0.000010021140796150737*S - 0.00038216081981505285*S2) + eta*(0.00024422562796266645 - 0.00001049013062611254*S - 0.00035182990586857726*S2) + eta3*(-0.0005418851224505745 + 0.000030679548774047616*S + 4.038390455349854e-6*S2) - 0.00007547517256664526*S2))/(0.026666543809890402 + (-0.014590539285641243 - 0.012429476486138982*eta + 1.4861197211952053*eta4 + 0.025066696514373803*eta2 + 0.005146809717492324*eta3)*S + (-0.0058684526275074025 - 0.02876774751921441*eta - 2.551566872093786*eta4 - 0.019641378027236502*eta2 - 0.001956646166089053*eta3)*S2 + (0.003507640638496499 + 0.014176504653145768*eta + 1.*eta4 + 0.012622225233586283*eta2 - 0.00767768214056772*eta3)*S3);
66 
67  uneqSpin = dchi2*(0.00034375176678815234 + 0.000016343732281057392*eta)*eta2 + dchi*delta*eta*(0.08064665214195679*eta2 + eta*(-0.028476219509487793 - 0.005746537021035632*S) - 0.0011713735642446144*S);
68 
69  return (noSpin + eqSpin + uneqSpin);
70 }
71 
72 /**
73  * Fitting function for hybrid minimum energy circular orbit (MECO) function
74  */
76 
77  REAL8 OmegaISCO, rISCO;
78  REAL8 rISCOsq, rISCO3o2;
79  REAL8 Z1, Z2;
80 
81  Z1 = 1.0 + cbrt( (1.0 - chif*chif) ) * ( cbrt(1 + chif) + cbrt(1 - chif) );
82  if(Z1>3) Z1=3.; //Finite precission may give Z1>3, but this can not happen.
83  Z2 = sqrt(3.0*chif*chif + Z1*Z1);
84 
85  rISCO = 3.0 + Z2 - XLALSimIMRPhenomXsign(chif)*sqrt( (3 - Z1) * (3 + Z1 + 2*Z2) );
86  rISCOsq = sqrt(rISCO);
87  rISCO3o2 = rISCOsq * rISCOsq * rISCOsq;
88 
89  OmegaISCO = 1.0 / ( rISCO3o2 + chif);
90 
91  return OmegaISCO / LAL_PI;
92 
93 }
94 
95 /* ******************** FINAL STATE ********************
96 
97  These functions are here as we exposed them violate
98  the XLAL wrappers.
99 */
100 
101 /**
102  * Energy Radiated: X Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
103  */
105 
106  REAL8 delta = sqrt(1.0 - 4.0*eta);
107 
108  REAL8 eta2 = eta*eta;
109  REAL8 eta3 = eta2*eta;
110  REAL8 eta4 = eta3*eta;
111 
112  REAL8 S = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
113  REAL8 S2 = S*S;
114  REAL8 S3 = S2*S;
115 
116  REAL8 dchi = chi1L - chi2L;
117  REAL8 dchi2 = dchi*dchi;
118 
119  REAL8 noSpin, eqSpin, uneqSpin;
120 
121  noSpin = 0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4;
122 
123  /* Because of the way this is written, we need to subtract the noSpin term */
124  eqSpin = ((0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4)*
125  ( 1
126  + (-0.13084389181783257 - 1.1387311580238488*eta + 5.49074464410971*eta2)*S
127  + (-0.17762802148331427 + 2.176667900182948*eta2)*S2
128  + (-0.6320191645391563 + 4.952698546796005*eta - 10.023747993978121*eta2)*S3))
129  / (1 + (-0.9919475346968611 + 0.367620218664352*eta + 4.274567337924067*eta2)*S);
130 
131  eqSpin = eqSpin - noSpin;
132 
133  uneqSpin = - 0.09803730445895877*dchi*delta*(1 - 3.2283713377939134*eta)*eta2
134  + 0.01118530335431078*dchi2*eta3
135  - 0.01978238971523653*dchi*delta*(1 - 4.91667749015812*eta)*eta*S;
136 
137  return (noSpin + eqSpin + uneqSpin);
138 
139 }
140 
141 /**
142  * Final Mass = 1 - Energy Radiated, X Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
143  */
145 
146  REAL8 delta = sqrt(1.0 - 4.0*eta);
147  REAL8 eta2 = eta*eta;
148  REAL8 eta3 = eta2*eta;
149  REAL8 eta4 = eta3*eta;
150 
151  REAL8 S = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
152  REAL8 S2 = S*S;
153  REAL8 S3 = S2*S;
154 
155  REAL8 dchi = chi1L - chi2L;
156  REAL8 dchi2 = dchi*dchi;
157 
158  REAL8 noSpin, eqSpin, uneqSpin;
159 
160  noSpin = 0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4;
161 
162  /* Because of the way this is written, we need to subtract the noSpin term */
163  eqSpin = ((0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4)*
164  ( 1
165  + (-0.13084389181783257 - 1.1387311580238488*eta + 5.49074464410971*eta2)*S
166  + (-0.17762802148331427 + 2.176667900182948*eta2)*S2
167  + (-0.6320191645391563 + 4.952698546796005*eta - 10.023747993978121*eta2)*S3))
168  / (1 + (-0.9919475346968611 + 0.367620218664352*eta + 4.274567337924067*eta2)*S);
169 
170  eqSpin = eqSpin - noSpin;
171 
172  uneqSpin = - 0.09803730445895877*dchi*delta*(1 - 3.2283713377939134*eta)*eta2
173  + 0.01118530335431078*dchi2*eta3
174  - 0.01978238971523653*dchi*delta*(1 - 4.91667749015812*eta)*eta*S;
175 
176  /* Mfinal = 1 - Erad, assuming that M = m1 + m2 = 1 */
177  return (1.0 - (noSpin + eqSpin + uneqSpin));
178 
179 
180 }
181 
182 /**
183  * Final Dimensionless Spin, X Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
184  */
186 
187  REAL8 delta = sqrt(1.0 - 4.0*eta);
188  REAL8 m1 = 0.5 * (1.0 + delta);
189  REAL8 m2 = 0.5 * (1.0 - delta);
190  REAL8 m1Sq = m1*m1;
191  REAL8 m2Sq = m2*m2;
192 
193  REAL8 eta2 = eta*eta;
194  REAL8 eta3 = eta2*eta;
195 
196  //REAL8 S = (m1Sq * chi1L + m2Sq * chi2L) / (m1Sq + m2Sq);
197  REAL8 S = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
198  REAL8 S2 = S*S;
199  REAL8 S3 = S2*S;
200 
201  REAL8 dchi = chi1L - chi2L;
202  REAL8 dchi2 = dchi*dchi;
203 
204  REAL8 noSpin, eqSpin, uneqSpin;
205 
206  noSpin = (3.4641016151377544*eta + 20.0830030082033*eta2 - 12.333573402277912*eta3)/(1 + 7.2388440419467335*eta);
207 
208  eqSpin = (m1Sq + m2Sq)*S
209  + ((-0.8561951310209386*eta - 0.09939065676370885*eta2 + 1.668810429851045*eta3)*S
210  + (0.5881660363307388*eta - 2.149269067519131*eta2 + 3.4768263932898678*eta3)*S2
211  + (0.142443244743048*eta - 0.9598353840147513*eta2 + 1.9595643107593743*eta3)*S3)
212  / (1 + (-0.9142232693081653 + 2.3191363426522633*eta - 9.710576749140989*eta3)*S);
213 
214  uneqSpin = 0.3223660562764661*dchi*delta*(1 + 9.332575956437443*eta)*eta2 /* Linear in spin difference */
215  - 0.059808322561702126*dchi2*eta3 /* Quadratic in spin difference */
216  + 2.3170397514509933*dchi*delta*(1 - 3.2624649875884852*eta)*eta3*S; /* Mixed spin difference + total spin term */
217 
218 
219  return (noSpin + eqSpin + uneqSpin);
220 }
221 
222 /**
223  * Wrapper for the final spin in generically precessing binary black holes
224  */
226  const REAL8 eta, /**< Symmetric mass ratio */
227  const REAL8 chi1L, /**< Aligned spin of BH 1 */
228  const REAL8 chi2L, /**< Aligned spin of BH 2 */
229  const REAL8 chi_inplane /**< Effective precessions spin parameter, see Section IV D of arXiv:XXXX.YYYY */
230 )
231 {
232  REAL8 m1 = 0.5 * (1.0 + sqrt(1 - 4.0*eta));
233  REAL8 m2 = 0.5 * (1.0 - sqrt(1 - 4.0*eta));
234  REAL8 M = m1 + m2;
235 
236  if (eta > 0.25) IMRPhenomX_InternalNudge(eta, 0.25, 1e-6);
237 
238  REAL8 af_parallel, q_factor;
239  if (m1 >= m2) {
240  q_factor = m1 / M;
241  af_parallel = XLALSimIMRPhenomXFinalSpin2017(eta, chi1L, chi2L);
242  }
243  else {
244  q_factor = m2 / M;
245  af_parallel = XLALSimIMRPhenomXFinalSpin2017(eta, chi2L, chi1L);
246  }
247 
248  REAL8 Sperp = chi_inplane * q_factor * q_factor;
249  REAL8 af = copysign(1.0, af_parallel) * sqrt(Sperp*Sperp + af_parallel*af_parallel);
250  return af;
251 }
252 
253 /* ******************** SPIN PARAMETERIZATIONS ******************** */
254 /**
255  * PN reduced spin parameter
256  */
258  // Convention m1 >= m2 and chi1 is the spin on m1
259  REAL8 delta = sqrt(1.0 - 4.0*eta);
260  REAL8 mm1 = 0.5*(1+delta);
261  REAL8 mm2 = 0.5*(1-delta);
262  REAL8 chi_eff = (mm1*chi1L + mm2*chi2L);
263 
264  return chi_eff - (38.0/113.0)*eta*(chi1L + chi2L);
265 }
266 
267 /**
268  * Normalised PN reduced spin parameter
269  */
271  // Convention m1 >= m2 and chi1 is the spin on m1
272  REAL8 delta = sqrt(1.0 - 4.0*eta);
273  REAL8 mm1 = 0.5*(1.0 + delta);
274  REAL8 mm2 = 0.5*(1.0 - delta);
275  REAL8 chi_eff = (mm1*chi1L + mm2*chi2L);
276 
277  return (chi_eff - (38.0/113.0)*eta*(chi1L + chi2L) ) / (1.0 - (76.0*eta/113.0));
278 }
279 
280 /**
281  * Effective aligned spin parameter
282  */
284  // Convention m1 >= m2 and chi1 is the spin on m1
285  REAL8 delta = sqrt(1.0 - 4.0*eta);
286  REAL8 mm1 = 0.5*(1+delta);
287  REAL8 mm2 = 0.5*(1-delta);
288 
289  return (mm1*chi1L + mm2*chi2L);
290 }
291 
292 /**
293  * Total spin normalised to [-1,1]
294  */
296  // Convention m1 >= m2 and chi1z is the spin projected along Lz on m1
297  REAL8 delta = sqrt(1.0 - 4.0*eta);
298  REAL8 m1 = 0.5*(1 + delta);
299  REAL8 m2 = 0.5*(1 - delta);
300  REAL8 m1s = m1*m1;
301  REAL8 m2s = m2*m2;
302 
303  return ((m1s * chi1L + m2s * chi2L) / (m1s + m2s));
304 }
305 
306 /**
307  * Spin difference
308  */
310 
311  return chi1L - chi2L;
312 }
313 
314 /* ******************** FREQUENCY CONVERSIONS ******************** */
315 /**
316  * Convert from geometric frequency to Hz
317  */
319  REAL8 Mf, /**< Geometric frequency */
320  REAL8 Mtot_Msun /**< Total mass in solar masses */
321 )
322 {
323  return Mf / (LAL_MTSUN_SI * Mtot_Msun);
324 }
325 
326 /**
327  * Convert from frequency in Hz to geometric frequency
328  */
330  REAL8 fHz, /**< Frequency in Hz */
331  REAL8 Mtot_Msun /**< Total mass in solar masses */
332 )
333 {
334  return fHz * (LAL_MTSUN_SI * Mtot_Msun);
335 }
336 
337 /**
338  * We apply a linear time and phase shift to ~ align peak
339  * LinShift = (PNLina[\f$\eta,\chi_1,\chi_2\f$] + \f$\pi\f$ + f PNLinb[\f$\eta,\chi_1,\chi_2\f$]);
340  * Linear time and phase shift: a + b*f
341  */
343  REAL8 eta, /**< Geometric frequency */
344  REAL8 S, /**< Total mass in solar masses */
345  REAL8 dchi, /**< Total mass in solar masses */
346  REAL8 delta /**< Total mass in solar masses */
347 )
348 {
349 
350  double eta2 = eta*eta;
351  double eta3 = eta2*eta;
352 
353  double S2 = S*S;
354  double S3 = S2*S;
355  double S4 = S3*S;
356  double S5 = S4*S;
357 
358  double noSpin, eqSpin, uneqSpin;
359 
360  noSpin = (1.0691011796680957e7 + 1.185905809135487e6*eta)/(1. + 30289.726104019595*eta);
361 
362  eqSpin = (3590.4466629551066 - 43200.79177912654*eta +
363  200094.57177252226*eta2 - 319307.42983118095*eta3)*S +
364  eta*(-1108.7615587239336 + 25622.545977741574*eta -
365  83180.15680637326*eta2)*S3 + (379.0250508368122 -
366  1355.868129015304*eta)*eta2*S4 + (-23306.844979169644 +
367  91977.08490230633*eta)*eta2*S5 + (-204.5064259069199 + 1046.9991525832384*eta - 5906.920781540527*eta3)*S2;
368 
369  uneqSpin = 44.87175399132858*dchi*delta*eta;
370 
371  return (noSpin + eqSpin + uneqSpin) + LAL_PI;
372 
373 }
374 
375 /**
376  * This is a fit of the time-difference between t_peak of strain and t_peak of psi4
377  * needed to align in time our waveforms, which are calibrated to psi4
378  */
379 REAL8 XLALSimIMRPhenomXPsi4ToStrain(double eta, double S, double dchi) {
380  double eta2,eta3,eta4,S2,S3,S4;
381  eta2 = pow(eta,2);
382  eta3 = pow(eta,3);
383  eta4 = pow(eta,4);
384  S2 = pow(S,2);
385  S3 = pow(S,3);
386  S4 = pow(S,4);
387  double noSpin = 13.39320482758057 - 175.42481512989315*eta + 2097.425116152503*eta2 - 9862.84178637907*eta3 + 16026.897939722587*eta4;
388  double eqSpin = (4.7895602776763 - 163.04871764530466*eta + 609.5575850476959*eta2)*S + (1.3934428041390161 - 97.51812681228478*eta + 376.9200932531847*eta2)*S2 + (15.649521097877374 + 137.33317057388916*eta - 755.9566456906406*eta2)*S3 + (13.097315867845788 + 149.30405703643288*eta - 764.5242164872267*eta2)*S4;
389  double uneqSpin = 105.37711654943146*dchi*sqrt(1. - 4.*eta)*eta2;
390  return( noSpin + eqSpin + uneqSpin);
391 
392 
393 }
394 
395 
397  REAL8 eta, /**< Geometric frequency */
398  REAL8 S, /**< Total mass in solar masses */
399  REAL8 dchi, /**< Total mass in solar masses */
400  REAL8 delta /**< Total mass in solar masses */
401 )
402 {
403  double eta2 = eta*eta;
404  double eta3= eta2*eta, eta4= eta3*eta, eta5=eta3*eta2, eta6=eta4*eta2;
405  double S2 = S*S;
406  double S3 = S2*S;
407  double S4 = S3*S;
408  double noSpin = 3155.1635543201924 + 1257.9949740608242*eta - 32243.28428870599*eta2 + 347213.65466875216*eta3 - 1.9223851649491738e6*eta4 + 5.3035911346921865e6*eta5 - 5.789128656876938e6*eta6;
409  double eqSpin = (-24.181508118588667 + 115.49264174560281*eta - 380.19778216022763*eta2)*S + (24.72585609641552 - 328.3762360751952*eta + 725.6024119989094*eta2)*S2 + (23.404604124552 - 646.3410199799737*eta + 1941.8836639529036*eta2)*S3 + (-12.814828278938885 - 325.92980012408367*eta + 1320.102640190539*eta2)*S4;
410  double uneqSpin = -148.17317525117338*dchi*delta*eta2;
411 
412 
413  return (noSpin + eqSpin + uneqSpin);
414 
415 }
416 
417 
418 /* ******************** NUMERICAL ROUTINES ******************** */
419 /**
420  * This function determines whether x and y are approximately equal to a relative accuracy epsilon.
421  * Note that x and y are compared to relative accuracy, so this function is not suitable for testing whether a value is approximately zero.
422  */
424  return !gsl_fcmp(x, y, epsilon);
425 }
426 
427 /**
428  * If x and X are approximately equal to relative accuracy epsilon then set x = X.
429  * If X = 0 then use an absolute comparison.
430  */
432  if (X != 0.0) {
433  if (IMRPhenomX_ApproxEqual(x, X, epsilon)) {
434  XLAL_PRINT_INFO("Nudging value %.15g to %.15g\n", x, X);
435  x = X;
436  }
437  }
438  else {
439  if (fabs(x - X) < epsilon)
440  x = X;
441  }
442 }
443 
445 {
446  REAL8 c;
447  if (fabs(a) < tol && fabs(b) < tol)
448  c = 0.;
449  else
450  c = atan2(a, b);
451  return c;
452 }
453 
454 /**** Define some useful powers ****/
455 size_t NextPow2(const size_t n)
456 {
457  // use pow here, not bit-wise shift, as the latter seems to run against an upper cutoff long before SIZE_MAX, at least on some platforms
458  return (size_t) pow(2,ceil(log2(n)));
459 }
460 
461 bool IMRPhenomX_StepFuncBool(const double t, const double t1) {
462  return (t >= t1);
463 }
464 
466 {
467  return (x > 0.) ? 1.0 : ((x < 0.0) ? -1.0 : 0.0);
468 }
469 
470 
471 /* Useful powers to avoid pow(.,.) function */
472 /**
473  * calc square of number without floating point 'pow'
474  */
475 double pow_2_of(double number)
476 {
477  return (number*number);
478 }
479 
480 /**
481  * calc cube of number without floating point 'pow'
482  */
483 double pow_3_of(double number)
484 {
485  return (number*number*number);
486 }
487 
488 /**
489  * calc fourth power of number without floating point 'pow'
490  */
491 double pow_4_of(double number)
492 {
493  double pow2 = pow_2_of(number);
494  return pow2 * pow2;
495 }
496 
497 /**
498  * calc fifth power of number without floating point 'pow'
499  */
500 double pow_5_of(double number)
501 {
502  double pow2 = pow_2_of(number);
503  return pow2 * pow2 * number;
504 }
505 
506 /**
507  * calc sixth power of number without floating point 'pow'
508  */
509 double pow_6_of(double number)
510 {
511  double pow2 = pow_2_of(number);
512  return pow2 * pow2 * pow2;
513 }
514 
515 /**
516  * calc seventh power of number without floating point 'pow'
517  */
518 double pow_7_of(double number)
519 {
520  double pow2 = pow_2_of(number);
521  return pow2 * pow2 * pow2 * number;
522 }
523 
524 /**
525  * calc eigth power of number without floating point 'pow'
526  */
527 double pow_8_of(double number)
528 {
529  double pow2 = pow_2_of(number);
530  double pow4 = pow2*pow2;
531  return pow4 * pow4;
532 }
533 
534 /**
535  * calc ninth power of number without floating point 'pow'
536  */
537 double pow_9_of(double number)
538 {
539  double pow2 = pow_2_of(number);
540  double pow4 = pow2*pow2;
541  return pow4 * pow4 * number;
542 }
543 
544 /**
545  * Check if m1 > m2. If not, swap the masses and spin vectors such that body is the heavier compact object.
546  */
548  REAL8 *m1, /**< [out] mass of body 1 */
549  REAL8 *m2, /**< [out] mass of body 2 */
550  REAL8 *chi1x, /**< [out] x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
551  REAL8 *chi1y, /**< [out] y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
552  REAL8 *chi1z, /**< [out] z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
553  REAL8 *chi2x, /**< [out] x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
554  REAL8 *chi2y, /**< [out] y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
555  REAL8 *chi2z /**< [out] z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
556 )
557 {
558  REAL8 m1_tmp, m2_tmp;
559  REAL8 chi1x_tmp, chi1y_tmp, chi1z_tmp;
560  REAL8 chi2x_tmp, chi2y_tmp, chi2z_tmp;
561 
562  if (*m1 > *m2)
563  {
564  chi1x_tmp = *chi1x;
565  chi1y_tmp = *chi1y;
566  chi1z_tmp = *chi1z;
567 
568  chi2x_tmp = *chi2x;
569  chi2y_tmp = *chi2y;
570  chi2z_tmp = *chi2z;
571 
572  m1_tmp = *m1;
573  m2_tmp = *m2;
574  }
575  else
576  {
577  //printf("Swapping spins!\n");
578 
579  /* swap spins and masses */
580  chi1x_tmp = *chi2x;
581  chi1y_tmp = *chi2y;
582  chi1z_tmp = *chi2z;
583 
584  chi2x_tmp = *chi1x;
585  chi2y_tmp = *chi1y;
586  chi2z_tmp = *chi1z;
587 
588  m1_tmp = *m2;
589  m2_tmp = *m1;
590  }
591 
592  /* Update the masses and spins */
593  *m1 = m1_tmp;
594  *m2 = m2_tmp;
595  *chi1x = chi1x_tmp;
596  *chi1y = chi1y_tmp;
597  *chi1z = chi1z_tmp;
598 
599  *chi2x = chi2x_tmp;
600  *chi2y = chi2y_tmp;
601  *chi2z = chi2z_tmp;
602 
603  if(*m1 < *m2)
604  {
605  XLAL_ERROR(XLAL_EDOM,"An error occured in XLALIMRPhenomXPCheckMassesAndSpins when trying to enfore that m1 should be the larger mass.\
606  After trying to enforce this m1 = %f and m2 = %f\n", *m1, *m2);
607 
608  }
609 
610  return XLAL_SUCCESS;
611 }
612 
613 
614 /* ******************** ANALYTICAL MODEL WRAPPERS ******************** */
615 /**
616  "Analytical" phenomenological ringdown ansatz for phase. This is used by the higher mode functions and
617  can be used to prototype or test model. Convenient wrapper exposed via XLAL.
618 */
620 {
621 
622  REAL8 invf = 1.0 / ff;
623  REAL8 invf2 = invf * invf;
624  REAL8 invf3 = invf2 * invf;
625  //REAL8 invf4 = invf2 * invf2;
626  REAL8 logfv = log(ff);
627 
628  REAL8 phaseOut;
629 
630  phaseOut = ( a0*ff + a1*logfv - a2*invf - (a4 * invf3 / 3.0) + (aL * atan( (ff - fRD)/fDA ) / fDA ) );
631 
632  return phaseOut;
633 }
634 
635 /**
636  "Analytical" phenomenological ringdown ansatz for phase derivative. This is used by the higher mode functions and
637  can be used to prototype or test model. Convenient wrapper exposed via XLAL.
638 
639  a_0 + a_1 f^(-1) + a_2 f^(-2) + a_3 f^(-3) + a_4 f^(-4) + ( aRD ) / ( (f_damp^2 + (f - f_ring)^2 ) )
640 
641  where a_L = - dphase0 * aRD
642 
643  Our canonical ringdown ansatz sets a_3 = 0.
644 */
646 {
647 
648  REAL8 invf = 1.0 / ff;
649  REAL8 invf2 = invf * invf;
650  //REAL8 invf3 = invf2 * invf;
651  REAL8 invf4 = invf2 * invf2;
652 
653  REAL8 phaseOut;
654 
655  phaseOut = ( a0 + a1*invf + a2*invf2 + a4*invf4 + ( aL / (fDA*fDA + (ff - fRD)*(ff - fRD)) ) );
656 
657  return phaseOut;
658 }
659 
660 /**
661  "Analytical" phenomenological ringdown ansatz for amplitude. This is used by the higher mode functions but
662  can also be used to prototype or test model. Convenient wrapper exposed via XLAL.
663 */
665 {
666  REAL8 gammaD13 = fDA * gamma1 * gamma3;
667  REAL8 gammaR = gamma2 / (gamma3 * fDA);
668  REAL8 gammaD2 = (fDA * gamma3) * (fDA * gamma3);
669  REAL8 dfr = ff - fRD;
670  REAL8 ampOut;
671 
672  ampOut = exp(- dfr * gammaR ) * (gammaD13) / (dfr*dfr + gammaD2);
673 
674  return ampOut;
675 }
676 
677 /*
678  This is the canonical intermediate ansatz:
679 
680  a_0 + a_1 ft^(-1) + a_2 ft^(-2) + a_3 ft^(-3) + a4 ft^(-4) + (4 * a_RD) / ( (2 * f_fdamp)^2 + (f - f_ring)^2 )
681 
682  ft = (f / f_ring)
683 */
685 {
686  return ff7o6 / ( a0 + ff*(a1 + ff*(a2 + ff*(a3 + ff*(a4 + ff*a5)))) );
687 }
688 
689 /*
690  This is the canonical intermediate ansatz:
691 
692  a_0 + a_1 ft^(-1) + a_2 ft^(-2) + a_3 ft^(-3) + a4 ft^(-4) + (4 * a_RD) / ( (2 * f_fdamp)^2 + (f - f_ring)^2 )
693 
694  ft = (f / f_ring)
695 */
697 {
698  REAL8 invff1 = 1.0 / ff;
699  REAL8 invff2 = invff1 * invff1;
700  REAL8 invff3 = invff2 * invff1;
701  REAL8 invff4 = invff3 * invff1;
702 
703  REAL8 LorentzianTerm;
704  REAL8 phaseOut;
705 
706  /* This is the Lorentzian term where aL = - a_{RD} dphase0 */
707  LorentzianTerm = (4.0 * aL) / ( (4.0*fDA*fDA) + (ff - fRD)*(ff - fRD) );
708 
709  /* Return a polynomial embedded in the background from the merger */
710  phaseOut = a0 + a1*invff1 + a2*invff2 + a3*invff3 + a4*invff4 + LorentzianTerm;
711 
712  return phaseOut;
713 }
714 
715 /* Leading order amplitude pre-factor, see Eq. 6.2 of arXiv:2001.11412 */
717 {
718  REAL8 ampOut;
719  ampOut = sqrt(2.0/3.0) * sqrt(eta) / pow(LAL_PI,1.0/6.0);
720  return ampOut;
721 }
722 
723 
724 
725 /*
726  The functions below are XLAL exposed of the QNM ringdown and damping frequency used for the
727  IMRPhenomX model: https://arxiv.org/abs/2001.11412.
728 */
729 
730 /**
731  Ringdown frequency for 22 mode, given final dimensionless spin
732 
733  https://arxiv.org/src/2001.10914v1/anc/QNMs/CoefficientStatsfring22.m
734 */
736  const REAL8 af /* Dimensionless final spin */
737 )
738 {
739  REAL8 return_val;
740 
741  if (fabs(af) > 1.0) {
742  XLAL_ERROR(XLAL_EDOM, "PhenomX evaluate_QNMfit_fring22 \
743  function: |finalDimlessSpin| > 1.0 not supported");
744  }
745 
746  REAL8 x2= af*af;
747  REAL8 x3= x2*af;
748  REAL8 x4= x2*x2;
749  REAL8 x5= x3*x2;
750  REAL8 x6= x3*x3;
751  REAL8 x7= x4*x3;
752 
753  return_val = (0.05947169566573468 - \
754  0.14989771215394762*af + 0.09535606290986028*x2 + \
755  0.02260924869042963*x3 - 0.02501704155363241*x4 - \
756  0.005852438240997211*x5 + 0.0027489038393367993*x6 + \
757  0.0005821983163192694*x7)/(1 - 2.8570126619966296*af + \
758  2.373335413978394*x2 - 0.6036964688511505*x4 + \
759  0.0873798215084077*x6);
760  return return_val;
761 }
762 
763 
764 /**
765  Damping frequency for 22 mode, given final dimensionless spin.
766 
767  https://arxiv.org/src/2001.10914v1/anc/QNMs/CoefficientStatsfdamp22.m
768 */
770  const REAL8 af /* Dimensionless final spin */
771 )
772 {
773  REAL8 return_val;
774 
775  if (fabs(af) > 1.0) {
776  XLAL_ERROR(XLAL_EDOM, "PhenomX evaluate_QNMfit_fdamp22 \
777  function: |finalDimlessSpin| > 1.0 not supported");
778  }
779 
780  REAL8 x2= af*af;
781  REAL8 x3= x2*af;
782  REAL8 x4= x2*x2;
783  REAL8 x5= x3*x2;
784  REAL8 x6= x3*x3;
785 
786  return_val = (0.014158792290965177 - \
787  0.036989395871554566*af + 0.026822526296575368*x2 + \
788  0.0008490933750566702*x3 - 0.004843996907020524*x4 - \
789  0.00014745235759327472*x5 + 0.0001504546201236794*x6)/(1 - \
790  2.5900842798681376*af + 1.8952576220623967*x2 - \
791  0.31416610693042507*x4 + 0.009002719412204133*x6);
792  return return_val;
793 }
794 
795 /** Function to unwrap a time series that contains an angle, to obtain a continuous time series. */
796 void XLALSimIMRPhenomXUnwrapArray(double *in, double *out, int len) {
797  out[0] = in[0];
798  for (int i = 1; i < len; i++) {
799  double d = in[i] - in[i-1];
800  d = d > M_PI ? d - 2 * M_PI : (d < -M_PI ? d + 2 * M_PI : d);
801  out[i] = out[i-1] + d;
802  }
803 }
static double double delta
REAL8 XLALSimIMRPhenomXfMECO(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Phenomenological fit to hybrid minimum energy circular orbit (MECO) function.
void IMRPhenomX_InternalNudge(REAL8 x, REAL8 X, REAL8 epsilon)
If x and X are approximately equal to relative accuracy epsilon then set x = X.
REAL8 XLALSimIMRPhenomXFinalMass2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Final Mass = 1 - Energy Radiated, X Jimenez-Forteza et al, PRD, 95, 064024, (2017),...
bool IMRPhenomX_ApproxEqual(REAL8 x, REAL8 y, REAL8 epsilon)
This function determines whether x and y are approximately equal to a relative accuracy epsilon.
REAL8 XLALSimIMRPhenomXErad2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Energy Radiated: X Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332.
REAL8 XLALSimIMRPhenomXfring22(const REAL8 af)
Ringdown frequency for 22 mode, given final dimensionless spin.
void XLALSimIMRPhenomXUnwrapArray(double *in, double *out, int len)
Function to unwrap a time series that contains an angle, to obtain a continuous time series.
REAL8 XLALSimIMRPhenomXRingdownPhaseDeriv22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL)
"Analytical" phenomenological ringdown ansatz for phase derivative.
INT4 XLALIMRPhenomXPCheckMassesAndSpins(REAL8 *m1, REAL8 *m2, REAL8 *chi1x, REAL8 *chi1y, REAL8 *chi1z, REAL8 *chi2x, REAL8 *chi2y, REAL8 *chi2z)
Check if m1 > m2.
REAL8 XLALSimIMRPhenomXRingdownPhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL)
"Analytical" phenomenological ringdown ansatz for phase.
double pow_9_of(double number)
calc ninth power of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXfISCO(REAL8 chif)
Fitting function for hybrid minimum energy circular orbit (MECO) function.
REAL8 XLALSimIMRPhenomXFinalSpin2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Final Dimensionless Spin, X Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611....
bool IMRPhenomX_StepFuncBool(const double t, const double t1)
REAL8 XLALSimIMRPhenomXIntermediateAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 ff7o6, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 a5)
double pow_4_of(double number)
calc fourth power of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXatan2tol(REAL8 a, REAL8 b, REAL8 tol)
REAL8 XLALSimIMRPhenomXRingdownAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 gamma1, REAL8 gamma2, REAL8 gamma3)
"Analytical" phenomenological ringdown ansatz for amplitude.
REAL8 XLALSimIMRPhenomXUtilsHztoMf(REAL8 fHz, REAL8 Mtot_Msun)
Convert from frequency in Hz to geometric frequency.
double pow_3_of(double number)
calc cube of number without floating point 'pow'
double pow_8_of(double number)
calc eigth power of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXsign(REAL8 x)
REAL8 XLALSimIMRPhenomXUtilsMftoHz(REAL8 Mf, REAL8 Mtot_Msun)
Convert from geometric frequency to Hz.
REAL8 XLALSimIMRPhenomXPrecessingFinalSpin2017(const REAL8 eta, const REAL8 chi1L, const REAL8 chi2L, const REAL8 chi_inplane)
Wrapper for the final spin in generically precessing binary black holes.
REAL8 XLALSimIMRPhenomXSTotR(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Total spin normalised to [-1,1].
double pow_7_of(double number)
calc seventh power of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXdchi(REAL8 chi1L, REAL8 chi2L)
Spin difference.
double pow_5_of(double number)
calc fifth power of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXLina(REAL8 eta, REAL8 S, REAL8 dchi, REAL8 delta)
We apply a linear time and phase shift to ~ align peak LinShift = (PNLina[ ] + + f PNLinb[ ]); Linea...
REAL8 XLALSimIMRPhenomXIntermediatePhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 aL)
REAL8 XLALSimIMRPhenomXfdamp22(const REAL8 af)
Damping frequency for 22 mode, given final dimensionless spin.
REAL8 XLALSimIMRPhenomXPsi4ToStrain(double eta, double S, double dchi)
This is a fit of the time-difference between t_peak of strain and t_peak of psi4 needed to align in t...
double pow_6_of(double number)
calc sixth power of number without floating point 'pow'
size_t NextPow2(const size_t n)
REAL8 XLALSimIMRPhenomXchiPNHat(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Normalised PN reduced spin parameter.
REAL8 XLALSimIMRPhenomXLinb(REAL8 eta, REAL8 S, REAL8 dchi, REAL8 delta)
double pow_2_of(double number)
calc square of number without floating point 'pow'
REAL8 XLALSimIMRPhenomXchiPN(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
PN reduced spin parameter.
REAL8 XLALSimIMRPhenomXchiEff(REAL8 eta, REAL8 chi1L, REAL8 chi2L)
Effective aligned spin parameter.
REAL8 XLALSimIMRPhenomXAmp22Prefactor(REAL8 eta)
static vector d(const double L_norm, const double J_norm, const vector roots)
Internal function that returns the coefficients "d_0", "d_2" and "d_4" from 1703.03967 corresponding ...
#define c
REAL8 M
Definition: bh_qnmode.c:133
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
const double a4
const double a2
#define LAL_PI
#define LAL_MTSUN_SI
double REAL8
int32_t INT4
static const INT4 a
#define XLAL_PRINT_INFO(...)
#define XLAL_ERROR(...)
XLAL_SUCCESS
XLAL_EDOM
list x
list y