Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRPhenomX_PNR_beta.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 Cardiff University
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19
20#ifdef __cplusplus
21extern "C"
22{
23#endif
24
25 /**
26 * \author Eleanor Hamilton, Sebastian Khan, Jonathan E. Thompson, Marta Colleoni
27 *
28 */
29
30#include <lal/LALStdlib.h>
31#include <lal/LALConstants.h>
32#include <lal/LALDatatypes.h>
33#include <lal/XLALError.h>
34
36
37#ifndef _OPENMP
38#define omp ignore
39#endif
40
41#ifndef PHENOMXHMDEBUG
42#define DEBUG 0
43#else
44#define DEBUG 1
45#endif
46
47 /**
48 * This function evaluates Eqs. 60 and 61 of arXiv:2107.08876.
49 */
51 REAL8 Mf, /**< geometric frequency */
52 const IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
53 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
54 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
55 IMRPhenomXWaveformStruct *pWF_SingleSpin, /**< PhenomX waveform struct with approximate single spin */
56 IMRPhenomXPrecessionStruct *pPrec_SingleSpin /**< PhenomX waveform struct with approximate single spin */
57 )
58 {
59 /* get beta connection frequencies */
60 REAL8 Mf_beta_lower = betaParams->Mf_beta_lower;
61 REAL8 Mf_beta_upper = betaParams->Mf_beta_upper;
62
63 REAL8 beta_lower = betaParams->beta_lower;
64 REAL8 beta_upper = betaParams->beta_upper;
65
66 if (Mf <= Mf_beta_lower)
67 { /* Below Mf_beta_lower, we use a rescaled form of the PN beta.
68 * In the case of a two-spin system, the PN beta used may have the two-spin
69 * oscillations tapered away to connect nicely at Mf_beta_lower */
70
71 if ((pPrec->IMRPhenomXPrecVersion==223) && (beta_lower < 0.01 * beta_upper))
72 {
73 /* Catch cases in the almost anti-aligned spin limit where beta drops
74 * to almost zero before reaching Mf_beta_lower */
75 REAL8 MR_beta = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_lower, betaParams);
76 return IMRPhenomX_PNR_arctan_window(MR_beta);
77 }
78
79 REAL8 betaPN = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
80 REAL8 beta_waveform = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN, pWF, pPrec);
81 REAL8 rescaled_beta = beta_waveform * IMRPhenomX_PNR_rescale_beta_expression(Mf, betaParams);
82 return IMRPhenomX_PNR_arctan_window(rescaled_beta);
83 }
84
85 if (Mf >= Mf_beta_upper)
86 { /* above Mf_beta_upper, attach the final value of beta*/
87 REAL8 final_beta = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_upper, betaParams);
88 return IMRPhenomX_PNR_arctan_window(final_beta);
89 }
90
91 /* in between we evaluate the MR Ansatz */
92 REAL8 MR_beta = IMRPhenomX_PNR_MR_beta_expression(Mf, betaParams);
93 return IMRPhenomX_PNR_arctan_window(MR_beta);
94}
95
96
97 /**
98 * This function evaluates only the rescaled inspiral beta given in
99 * Eq. 41 of arXiv:2107.08876, without attaching the MR model or tapering
100 * the two-spin oscillations.
101 */
103 REAL8 Mf, /**< geometric frequency */
104 const IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
105 IMRPhenomXWaveformStruct *pWF, /**< PhenomX wavefrom struct */
106 IMRPhenomXPrecessionStruct *pPrec /**< PhenomX precession struct */
107 )
108 {
109
110 /* generate scaled PN beta without MR contributions */
111 REAL8 waveform_beta;
112 REAL8 pn_beta = IMRPhenomX_PNR_GetPNBetaAtFreq_fulltwospin(Mf, pWF, pPrec, betaParams);
113 REAL8 pn_waveform_beta = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, pn_beta, pWF, pPrec);
114
115 waveform_beta = pn_waveform_beta;
116
117 return IMRPhenomX_PNR_arctan_window(waveform_beta);
118 }
119
120 /**
121 * This function generates beta with the tuned angles and PN expressions blended during merger-ringdown
122 */
124 REAL8 Mf, /**< geometric frequency */
125 const IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
126 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
127 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
128 IMRPhenomXWaveformStruct *pWF_SingleSpin, /**< PhenomX waveform struct with approximate single spin */
129 IMRPhenomXPrecessionStruct *pPrec_SingleSpin /**< PhenomX waveform struct with approximate single spin */
130 )
131 {
132 /* evaluate blending window */
133 double pnr_window = IMRPhenomX_PNR_AnglesWindow(pWF, pPrec);
134 double msa_window = 1-pnr_window;
135
136 /* get beta connection frequencies */
137 REAL8 Mf_beta_lower = betaParams->Mf_beta_lower;
138 REAL8 Mf_beta_upper = betaParams->Mf_beta_upper;
139 if (Mf <= Mf_beta_lower)
140 { /* Below Mf_beta_lower, we use a rescaled form of the PN beta.
141 * In the case of a two-spin system, the PN beta used may have the two-spin
142 * oscillations tapered away to connect nicely at Mf_beta_lower */
143 REAL8 pnr_beta, pn_beta;
144 if (pPrec->IMRPhenomXPrecVersion!=330){
145 REAL8 betaPN = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
146 REAL8 beta_waveform = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN, pWF, pPrec);
147 REAL8 rescaled_beta = beta_waveform * IMRPhenomX_PNR_rescale_beta_expression(Mf, betaParams);
148 pnr_beta = rescaled_beta;
149 pn_beta = beta_waveform;
150 }
151 else{
152 pPrec->UseMRbeta = 1;
153 REAL8 betaPN1 = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
154 REAL8 beta_waveform1 = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN1, pWF, pPrec);
155 REAL8 rescaled_beta1 = beta_waveform1 * IMRPhenomX_PNR_rescale_beta_expression(Mf, betaParams);
156 pPrec->UseMRbeta = 0;
157 REAL8 betaPN2 = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
158 REAL8 beta_waveform2 = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN2, pWF, pPrec);
159 pnr_beta = rescaled_beta1;
160 pn_beta = beta_waveform2;
161 }
162 return IMRPhenomX_PNR_arctan_window(pnr_window * pnr_beta + msa_window * pn_beta);
163 }
164
165 if (Mf >= Mf_beta_upper)
166 { /* above Mf_beta_upper, attach the final value of beta*/
167 pPrec->UseMRbeta = 0;
168 REAL8 betaPN = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
169 REAL8 beta_waveform = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN, pWF, pPrec);
170 REAL8 final_beta = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_upper, betaParams);
171 return IMRPhenomX_PNR_arctan_window(pnr_window * final_beta + msa_window * beta_waveform);
172 }
173
174 /* in between we evaluate the MR Ansatz */
175 pPrec->UseMRbeta = 0;
176 REAL8 betaPN = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
177 REAL8 beta_waveform = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf, betaPN, pWF, pPrec);
178 REAL8 MR_beta = IMRPhenomX_PNR_MR_beta_expression(Mf, betaParams);
179 return IMRPhenomX_PNR_arctan_window(pnr_window * MR_beta + msa_window * beta_waveform);
180 }
181 /**
182 * We evaluate beta at the final Mf_beta_upper connection frequency
183 * to approximate the final value of beta during ringdown. This
184 * is required to analytically approximate the effective ringdown frequency. FIXME: add citation
185 */
186
188 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
189 IMRPhenomXPrecessionStruct *pPrec) /**< PhenomX precession struct */
190 {
191 /* may we continue? */
192 XLAL_CHECK(pWF != NULL, XLAL_EFAULT);
193 XLAL_CHECK(pPrec != NULL, XLAL_EFAULT);
194
195 /* get effective single spin parameters */
196 REAL8 eta = pWF->eta;
197 REAL8 chi = pPrec->chi_singleSpin;
199
200 /* approximate orientation of final spin */
201 REAL8 costhetaf = pPrec->costheta_final_singleSpin;
202
203 REAL8 betafinal = IMRPhenomX_PNR_arctan_window( acos(costhetaf) - IMRPhenomX_PNR_beta_Bf_coefficient(eta, chi, costheta) );
204
205 return betafinal;
206 }
207
208 /**
209 * A wrapper to produce either the NNLO or MSA beta depending on the IMRPhenomXPrecVersion.
210 *
211 * Should the MSA angle be called, we taper any potential oscillations induced by a time-varying
212 * total spin magnitude so that we return an effective single-spin value for beta at the
213 * lower connection frequency. This is described in Sec. 6C of arXiv:2107.08876
214 */
215
217 REAL8 Mf, /**< geometric frequency */
218 const IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
219 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
220 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
221 IMRPhenomXWaveformStruct *pWF_SingleSpin, /**< PhenomX waveform struct with approximate single spin */
222 IMRPhenomXPrecessionStruct *pPrec_SingleSpin /**< PhenomX waveform struct with approximate single spin */
223 )
224 {
225
226 REAL8 beta;
227
228 /* get PN expansion parameter v = (pi M f)^(1/3) */
229 const double omega = LAL_PI * Mf;
230 const double omega_cbrt = cbrt(omega);
231
232 switch (pPrec->IMRPhenomXPrecVersion)
233 {
234 /* ~~~~~ Use NNLO PN Euler Angles - Appendix G of arXiv:2004.06503 and https://dcc.ligo.org/LIGO-T1500602 ~~~~~ */
235 case 101:
236 case 102:
237 case 103:
238 case 104:
239 {
240 REAL8 L = XLALSimIMRPhenomXLPNAnsatz(omega_cbrt, pWF->eta / omega_cbrt, pPrec->L0, pPrec->L1, pPrec->L2, pPrec->L3, pPrec->L4, pPrec->L5, pPrec->L6, pPrec->L7, pPrec->L8, pPrec->L8L);
241
242 /*
243 Comment from IMRPhenomX_precession.c:
244 We ignore the sign of L + SL below:
245 s := Sp / (L + SL)
246 */
247 REAL8 s = pPrec->Sperp / (L + pPrec->SL);
248 REAL8 s2 = s * s;
249 beta = acos(copysign(1.0, L + pPrec->SL) / sqrt(1.0 + s2));
250
251 break;
252 }
253 case 220:
254 case 221:
255 case 222:
256 case 223:
257 case 224:
258 {
259 vector vangles = {0., 0., 0.};
260
261 /* ~~~~~ Euler Angles from Chatziioannou et al, PRD 95, 104004, (2017), arXiv:1703.03967 ~~~~~ */
262 /* First we grab the full MSA angle with possible two-spin oscillations */
263 vangles = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(omega_cbrt, pWF, pPrec);
264 REAL8 beta_full = acos(vangles.z);
265
266 /* lower connection frequency as target for taper */
267 REAL8 Mf_beta_lower = betaParams->Mf_beta_lower;
268
269 /* check if we have meaningful two-spin contributions */
271 { /* we do */
272 /* compute an effective single-spin beta that averages through oscillations */
273 const vector vangles_SingleSpin = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(omega_cbrt, pWF_SingleSpin, pPrec_SingleSpin);
274 REAL8 beta_SingleSpin = acos(vangles_SingleSpin.z);
275
276 /* if we are below the connection frequency, taper the oscillations */
277 if (Mf <= Mf_beta_lower)
278 {
279 /* tapering is described in Eq. 45 of arXiv:2107.08876 */
280 REAL8 oscillations = beta_full - beta_SingleSpin;
281 REAL8 envelope = cos(2.0 * LAL_PI * Mf / (4.0 * Mf_beta_lower)) * cos(2.0 * LAL_PI * Mf / (4.0 * Mf_beta_lower));
282 beta = (beta_SingleSpin + oscillations * envelope);
283 }
284 else
285 { /* otherwise just return single-spin beta */
286 beta = beta_SingleSpin;
287 }
288 }
289 else
290 { /* no oscillations, just return full beta */
291 beta = beta_full;
292 }
293
294 break;
295 }
296 case 330:
297 {
298
299 REAL8 beta_full= beta_SpinTaylor_IMR(Mf,pWF,pPrec,betaParams);
300 if(isnan(beta_full) || isinf(beta_full)) XLAL_ERROR(XLAL_EINVAL, "Error in %s: beta_SpinTaylor_IMR returned invalid value.\n",__func__);
301
302 /* lower connection frequency as target for taper */
303 REAL8 Mf_beta_lower = betaParams->Mf_beta_lower;
304
305
306 /* check if we have meaningful two-spin contributions */
308 { /* we do */
309 /* compute an effective single-spin beta that averages through oscillations */
310 const vector vangles_SingleSpin = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(omega_cbrt, pWF_SingleSpin, pPrec_SingleSpin);
311 REAL8 beta_SingleSpin = acos(vangles_SingleSpin.z);
312
313 /* if we are below the connection frequency, taper the oscillations */
314 if (Mf <= Mf_beta_lower)
315 {
316 /* tapering is described in Eq. 45 of arXiv:2107.08876 */
317 REAL8 oscillations = beta_full - beta_SingleSpin;
318 REAL8 envelope = cos(2.0 * LAL_PI * Mf / (4.0 * Mf_beta_lower)) * cos(2.0 * LAL_PI * Mf / (4.0 * Mf_beta_lower));
319 beta = (beta_SingleSpin + oscillations * envelope);
320 }
321 else
322 { /* otherwise just return single-spin beta */
323 beta = beta_SingleSpin;
324 }
325 }
326 else
327 { /* no oscillations, just return full beta */
328 beta = beta_full;
329 }
330
331 break;
332 }
333 default:
334 {
335 XLAL_ERROR(XLAL_EINVAL, "Error: IMRPhenomXPrecessionVersion not recognized in IMRPhenomX_PNR_GetPNBetaAtFreq.\n");
336 break;
337 }
338 }
339
340 return beta;
341 }
342
343 /**
344 * A wrapper to produce either the NNLO or MSA beta depending on the IMRPhenomXPrecVersion.
345 *
346 * This version does not modify the two-spin oscillations.
347 */
348
350 REAL8 Mf, /**< geometric frequency */
351 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
352 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
353 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
354 )
355 {
356 REAL8 beta;
357
358 /* get PN expansion parameter v = (pi M f)^(1/3) */
359 const double omega = LAL_PI * Mf;
360 const double omega_cbrt = cbrt(omega);
361
362 switch (pPrec->IMRPhenomXPrecVersion)
363 {
364 /* ~~~~~ Use NNLO PN Euler Angles - Appendix G of arXiv:2004.06503 and https://dcc.ligo.org/LIGO-T1500602 ~~~~~ */
365 case 101:
366 case 102:
367 case 103:
368 case 104:
369 {
370
371 const REAL8 L = XLALSimIMRPhenomXLPNAnsatz(omega_cbrt, pWF->eta / omega_cbrt, pPrec->L0, pPrec->L1, pPrec->L2, pPrec->L3, pPrec->L4, pPrec->L5, pPrec->L6, pPrec->L7, pPrec->L8, pPrec->L8L);
372
373 /* Comment from IMRPhenomX_precession.c:
374 We ignore the sign of L + SL below:
375 s := Sp / (L + SL)
376 */
377 REAL8 s = pPrec->Sperp / (L + pPrec->SL);
378 REAL8 s2 = s * s;
379 beta = acos(copysign(1.0, L + pPrec->SL) / sqrt(1.0 + s2));
380
381 break;
382 }
383 case 220:
384 case 221:
385 case 222:
386 case 223:
387 case 224:
388 {
389 vector vangles = {0., 0., 0.};
390
391 /* ~~~~~ Euler Angles from Chatziioannou et al, PRD 95, 104004, (2017), arXiv:1703.03967 ~~~~~ */
392 vangles = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(omega_cbrt, pWF, pPrec);
393
394 beta = acos(vangles.z);
395
396 break;
397 }
398 case 330:
399 {
400
401 beta= beta_SpinTaylor_IMR(Mf,pWF,pPrec,betaParams);
402 if(isnan(beta) || isinf(beta)) XLAL_ERROR(XLAL_EINVAL, "Error in %s: beta_SpinTaylor_IMR returned invalid value.\n",__func__);
403
404 break;
405
406 }
407 default:
408 {
409 XLAL_ERROR(XLAL_EINVAL, "Error: IMRPhenomXPrecessionVersion not recognized in IMRPhenomX_PNR_GetPNBetaAtFreq_fulltwospin.\n");
410 break;
411 }
412 }
413
414 return beta;
415 }
416
417 /**
418 * A wrapper to generate the "waveform" PN beta from Eq. 41 of arXiv:2107.08876.
419 *
420 * The wrapper goes through the trouble of computing the frequency-dependent Sperp
421 * given by Eq. 47 of arXiv:2107.08876.
422 */
423
425 REAL8 Mf, /**< geometric frequency */
426 REAL8 pn_beta, /**< MSA or NNLO beta */
427 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
428 IMRPhenomXPrecessionStruct *pPrec /**< PhenomX precession struct */
429 )
430 {
431 /* grab needed parameters */
432 REAL8 M = pWF->Mtot;
433 REAL8 m1 = pWF->m1 * M;
434 REAL8 m2 = pWF->m2 * M;
435 REAL8 J0 = pPrec->J0;
436 REAL8 L0 = pPrec->LRef;
437 REAL8 chi_eff = pWF->chiEff;
438
439 /* compute derived terms */
440 REAL8 chi_parr = (m1 + m2) * chi_eff / m1;
441
442 /* get orbital angular momentum */
443 REAL8 v = cbrt(LAL_PI * Mf);
444 REAL8 L_norm = pWF->eta / v;
445 REAL8 L_3PN = M*M*XLALSimIMRPhenomXLPNAnsatz(v, L_norm, pPrec->L0, pPrec->L1, pPrec->L2, pPrec->L3, pPrec->L4, pPrec->L5, pPrec->L6, pPrec->L7, pPrec->L8, pPrec->L8L);
446
447 /* compute spin and costheta in Eqs. 18-19 of arXiv:2107.08876 at given Mf */
448 REAL8 chi_temp = IMRPhenomX_PNR_chi_calc(m1, L_3PN, J0, L0, chi_parr, pn_beta);
449 REAL8 costheta_temp = chi_parr / chi_temp;
450
451 /* evaluate Eq. 41 of arXiv:2107.08876 */
452 return IMRPhenomX_PNR_PNWaveformBeta(Mf, pn_beta, m1, m2, chi_temp, costheta_temp);
453 }
454
455 /**
456 * The magnitude of the effective total spin is computed from
457 * the total and orbital angular momenta, J0 and L0 resp., along with the opening
458 * angle, beta, between them.
459 *
460 * This procedure is outlined in Eqs. 47 and 18 of arXiv:2107.08876.
461 */
462
464 REAL8 m1, /**< mass of primary (Msun) */
465 REAL8 L, /**< magnitude of L and Mf */
466 REAL8 J0, /**< initial magnitude of J at Mf_ref */
467 REAL8 L0, /**< initial magnitude of L at Mf_ref */
468 REAL8 chi_parr, /**< combined spin parallel to L0 */
469 REAL8 beta /**< PN opening angle, either MSA or NNLO */
470 )
471 {
472 /* compute frequency-dependent Sperp and scale by mass */
473 REAL8 S_perp = (J0 - (L0 - L)) * sin(beta);
474 REAL8 chi_p = S_perp / (m1 * m1);
475
476 /* find magnitude */
477 REAL8 chi = sqrt(chi_parr * chi_parr + chi_p * chi_p);
478
479 return chi;
480 }
481
482 /**
483 * The "waveform" PN beta from Eq. 41 of arXiv:2107.08876.
484 *
485 * This function maps the dynamics iota to a version of beta
486 * more closely resembling the angle associated with the optimal
487 * emission direction described in Sec. 6B of arXiv:2107.08876.
488 */
489
491 REAL8 Mf, /**< geometric frequency */
492 REAL8 iota, /**< dynamics precession cone opening angle */
493 REAL8 m1, /**< mass of primary (scaled to total mass 1) */
494 REAL8 m2, /**< mass of secondary (scaled to total mass 1) */
495 REAL8 chi, /**< effective single spin magnitude */
496 REAL8 costheta /**< effective single spin polar angle (rad) */
497 )
498 {
499
500 /* calculate combinations of masses */
501 REAL8 M = m1 + m2;
502 REAL8 nu = (m1 * m2) / (M * M);
503 REAL8 delta = (m1 - m2) / M;
504
505 /* get polar angle */
506 REAL8 theta = acos(costheta);
507
508 /* calculate invariant velocity */
509 REAL8 w_orb = LAL_PI * Mf;
510 REAL8 v = pow(w_orb, 1.0 / 3.0);
511 REAL8 v2 = v * v;
512 REAL8 v3 = v * v2;
513
514 /* calculate needed trig functions */
515 REAL8 cos_iota = cos(iota);
516 REAL8 sin_iota = sin(iota);
517
518 REAL8 cos_half_iota = cos(iota / 2.0);
519 REAL8 sin_half_iota = sin(iota / 2.0);
520
521 REAL8 cos_theta = cos(theta);
522 REAL8 sin_theta = sin(theta);
523
524 /* compute numerator expansion of h21/h22: N0 + N2 * v**2 + N3 * v**3*/
525 REAL8 N0 = 84.0 * sin_iota;
526 REAL8 N2 = 2.0 * (55.0 * nu - 107.0) * sin_iota;
527 REAL8 N3 = -7.0 * (5.0 * nu + 6.0 * delta + 6.0) * chi * (2.0 * cos_iota - 1.0) * sin_theta + 56.0 * (3.0 * LAL_PI - (1.0 + delta - nu) * chi * cos_theta) * sin_iota;
528
529 REAL8 N = (N0 + N2 * v2 + N3 * v3) / cos_half_iota;
530
531 /* compute denominator expansion of h21/h22: D0 + D2 * v**2 + D3 * v**3*/
532 REAL8 D0 = 84.0 * cos_half_iota;
533 REAL8 D2 = 2.0 * (55.0 * nu - 107.0) * cos_half_iota;
534 REAL8 D3 = 14.0 * 4.0 * (3.0 * LAL_PI + (nu - 1.0 - delta) * chi * cos_theta) * cos_half_iota + 14.0 * (6.0 + 6.0 * delta + 5.0 * nu) * chi * sin_theta * sin_half_iota;
535
536 REAL8 D = D0 + D2 * v2 + D3 * v3;
537
538 /* evaluate Eq. 41 of arXiv:2107.08876. NOTE: there's a typo in arXiv:2107.08876
539 * whereby the factor of 2 in the denominator of Eq. 39 was dropped. */
540 return 2.0 * XLALSimIMRPhenomXatan2tol(N, 2.0 * D, MAX_TOL_ATAN);
541 }
542
543 /**
544 * This function evaluates the Ansatz coefficients of beta outlined in
545 * Eq. 49 of arXiv:2107.08876.
546 *
547 * See the discussion in Sec. 8D of arXiv:2107.08876 for an explanation of
548 * the condition on B4.
549 *
550 * The definition of B0 has since changed and now depends on the angle of
551 * the final spin; see discussion in the technical document. FIXME: add citation
552 */
553
555 IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
556 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
557 IMRPhenomXPrecessionStruct *pPrec /**< PhenomX precession struct */
558 )
559 {
560
561 /* get effective single spin parameters */
562 REAL8 eta = pWF->eta;
563 if( pPrec->IMRPhenomXPrecVersion==330 ){
564 eta = ( pWF->eta >= 0.09 ) ? pPrec->eta : 0.09;
565 }
566 else{
567 eta = pWF->eta;
568 }
569 REAL8 chiboundary = 0.80 - 0.20 * exp( -pow((pWF->q - 6.0)/1.5, 8) );
570 REAL8 chi;
571 if( pPrec->IMRPhenomXPrecVersion==330 ){
572 chi = ( pPrec->chi_singleSpin <= chiboundary ) ? pPrec->chi_singleSpin : chiboundary;
573 }
574 else{
575 chi = pPrec->chi_singleSpin;
576 }
578
579 /* approximate orientation of final spin */
580 REAL8 costhetaf = pPrec->costheta_final_singleSpin;
581
582 /* ensure B4 is sufficiently large */
584 if (B4 <= 175.0)
585 {
586 B4 = 175.0;
587 }
588
589 betaParams->B0 = acos(costhetaf) - IMRPhenomX_PNR_beta_B0_coefficient(eta, chi, costheta);
590 betaParams->B1 = IMRPhenomX_PNR_beta_B1_coefficient(eta, chi, costheta);
591 betaParams->B2 = IMRPhenomX_PNR_beta_B2_coefficient(eta, chi, costheta);
592 betaParams->B3 = betaParams->B2 * IMRPhenomX_PNR_beta_B3_coefficient(eta, chi, costheta);
593 betaParams->B4 = B4;
594 betaParams->B5 = IMRPhenomX_PNR_beta_B5_coefficient(eta, chi, costheta);
595
596 return XLAL_SUCCESS;
597 }
598
599 /**
600 * These three functions produce the inspiral rescaling
601 * of beta described in Sec. 8B of arXiv:2107.08876.
602 *
603 * - IMRPhenomX_PNR_beta_rescaling_1 computes b1 in Eq. 54
604 * - IMRPhenomX_PNR_beta_rescaling_2 computes b2 in Eq. 55
605 * - IMRPhenomX_PNR_rescale_beta_expression combines the results
606 * to produce Eq. 53.
607 */
608
610 REAL8 Mf, /**< geometric frequency */
611 REAL8 beta1, /**< PN beta evaluated at Mf */
612 REAL8 beta2, /**< MR beta evaluated at Mf */
613 REAL8 dbeta1, /**< derivative of PN beta at Mf */
614 REAL8 dbeta2 /**< derivative of MR beta at Mf */
615 )
616 {
617
618 REAL8 D = beta1 * beta1 * Mf;
619 REAL8 N = -2.0 * beta1 * (beta2 - beta1) + (beta1 * dbeta2 - beta2 * dbeta1) * Mf;
620
621 return -N / D;
622 }
623
625 REAL8 Mf, /**< geometric frequency */
626 REAL8 beta1, /**< PN beta evaluated at Mf */
627 REAL8 beta2, /**< MR beta evaluated at Mf */
628 REAL8 dbeta1, /**< derivative of PN beta at Mf */
629 REAL8 dbeta2 /**< derivative of MR beta at Mf */
630 )
631 {
632
633 REAL8 D = (beta1 * Mf) * (beta1 * Mf);
634 REAL8 N = beta1 * (beta2 - beta1) - (beta1 * dbeta2 - beta2 * dbeta1) * Mf;
635
636 return -N / D;
637 }
638
640 REAL8 Mf, /**< geometric frequency */
641 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
642 )
643 {
644
645 REAL8 b1 = betaParams->beta_rescale_1;
646 REAL8 b2 = betaParams->beta_rescale_2;
647
648 return 1.0 + b1 * Mf + b2 * Mf * Mf;
649 }
650
651 /**
652 * These four functions produce the MR Ansatz
653 * of beta described in Sec. 7A of arXiv:2107.08876.
654 *
655 * - IMRPhenomX_PNR_MR_beta_expression computes the MR Ansatz
656 * detailed in Eq. 49
657 * - IMRPhenomX_PNR_MR_dbeta_expression computes the first derivative of Eq. 49
658 * - IMRPhenomX_PNR_MR_ddbeta_expression computes the second derivative of Eq. 49
659 * - IMRPhenomX_PNR_MR_dddbeta_expression computes the third derivative of Eq. 49
660 */
662 REAL8 Mf, /**< geometric frequency */
663 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
664 )
665 {
666
667 REAL8 B0 = betaParams->B0;
668 REAL8 B1 = betaParams->B1;
669 REAL8 B2 = betaParams->B2;
670 REAL8 B3 = betaParams->B3;
671 REAL8 B4 = betaParams->B4;
672 REAL8 B5 = betaParams->B5;
673
674 return B0 + (B1 + B2 * Mf + B3 * Mf * Mf) / (1.0 + B4 * (Mf + B5) * (Mf + B5));
675 }
676
677 /**
678 * expression for first derivative of beta in merger-ringdown regime
679 */
681 REAL8 Mf, /**< geometric frequency */
682 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
683 )
684 {
685
686 REAL8 B1 = betaParams->B1;
687 REAL8 B2 = betaParams->B2;
688 REAL8 B3 = betaParams->B3;
689 REAL8 B4 = betaParams->B4;
690 REAL8 B5 = betaParams->B5;
691
692 return ((2.0 * B3 * B4 * B5 - B2 * B4) * Mf * Mf + (2.0 * B3 - 2.0 * B1 * B4 + 2.0 * B3 * B4 * B5 * B5) * Mf + (B2 - 2.0 * B1 * B4 * B5 + B2 * B4 * B5 * B5)) / pow((1.0 + B4 * (Mf + B5) * (Mf + B5)), 2);
693 }
694
695 /**
696 * expression for second derivative of beta in merger-ringdown regime
697 */
699 REAL8 Mf, /**< geometric frequency */
700 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
701 )
702 {
703
704 REAL8 B1 = betaParams->B1;
705 REAL8 B2 = betaParams->B2;
706 REAL8 B3 = betaParams->B3;
707 REAL8 B4 = betaParams->B4;
708 REAL8 B5 = betaParams->B5;
709
710 REAL8 a = B2 * B4 * B4 - 2.0 * B3 * B4 * B4 * B5;
711 REAL8 b = -3.0 * B3 * B4 + 3.0 * B1 * B4 * B4 - 3.0 * B3 * B4 * B4 * B5 * B5;
712 REAL8 c = -3.0 * B2 * B4 + 6.0 * B1 * B4 * B4 * B5 - 3.0 * B2 * B4 * B4 * B5 * B5;
713 REAL8 d = B3 - B1 * B4 - 2.0 * B2 * B4 * B5 + 2.0 * B3 * B4 * B5 * B5 + 3.0 * B1 * B4 * B4 * B5 * B5 - 2.0 * B2 * B4 * B4 * B5 * B5 * B5 + B3 * B4 * B4 * B5 * B5 * B5 * B5;
714
715 return 2.0 * (a * Mf * Mf * Mf + b * Mf * Mf + c * Mf + d) / pow((1.0 + B4 * (B5 + Mf) * (B5 + Mf)), 3);
716 }
717
718 /**
719 * expression for third derivative of beta in merger-ringdown regime
720 */
722 REAL8 Mf, /**< geometric frequency */
723 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
724 )
725 {
726
727 REAL8 B1 = betaParams->B1;
728 REAL8 B2 = betaParams->B2;
729 REAL8 B3 = betaParams->B3;
730 REAL8 B4 = betaParams->B4;
731 REAL8 B5 = betaParams->B5;
732
733 REAL8 a = -B2 * B4 * B4 + 2.0 * B3 * B4 * B4 * B5;
734 REAL8 b = 4.0 * B3 * B4 - 4.0 * B1 * B4 * B4 + 4.0 * B3 * B4 * B4 * B5 * B5;
735 REAL8 c = 6.0 * B2 * B4 - 12.0 * B1 * B4 * B4 * B5 + 6.0 * B2 * B4 * B4 * B5 * B5;
736 REAL8 d = -4.0 * B3 + 4.0 * B1 * B4 + 8.0 * B2 * B4 * B5 - 8.0 * B3 * B4 * B5 * B5 - 12.0 * B1 * B4 * B4 * B5 * B5 + 8.0 * B2 * B4 * B4 * B5 * B5 * B5 - 4.0 * B3 * B4 * B4 * B5 * B5 * B5 * B5;
737 REAL8 e = -B2 - 2.0 * B3 * B5 + 4.0 * B1 * B4 * B5 + 2.0 * B2 * B4 * B5 * B5 - 4.0 * B3 * B4 * B5 * B5 * B5 - 4.0 * B1 * B4 * B4 * B5 * B5 * B5 + 3.0 * B2 * B4 * B4 * B5 * B5 * B5 * B5 - 2.0 * B3 * B4 * B4 * B5 * B5 * B5 * B5 * B5;
738
739 return 6.0 * B4 * (a * Mf * Mf * Mf * Mf + b * Mf * Mf * Mf + c * Mf * Mf + d * Mf + e) / pow((1.0 + B4 * (B5 + Mf) * (B5 + Mf)), 4);
740 }
741
742 /**
743 * Here we work through the construction of the connection frequency
744 * for beta, outlined in Sec. 8B of arXiv:2107.08876, along with
745 * discussion in Sec. 8D.
746 *
747 * In particular, this function performs the following tasks in order:
748 * - compute the inflection frequency required to get beta_inf
749 * - get derivative of beta at that frequency
750 * - get the extremal frequencies of beta
751 * - choose the lower and upper connection frequencies
752 *
753 */
755 IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
756 )
757 {
758 /* check for initialization */
759 XLAL_CHECK(betaParams != NULL, XLAL_EFAULT);
760
761 REAL8 B1 = betaParams->B1;
762 REAL8 B2 = betaParams->B2;
763 REAL8 B3 = betaParams->B3;
764 REAL8 B4 = betaParams->B4;
765 REAL8 B5 = betaParams->B5;
766
767 REAL8 Mf_inflection;
768 REAL8 root_term;
769 REAL8 Mf_plus;
770 REAL8 Mf_minus;
771 REAL8 ddbeta_Mf_plus;
772 REAL8 Mf_at_minimum;
773 REAL8 Mf_at_maximum;
774 REAL8 Mf_low;
775 REAL8 Mf_IM;
776 REAL8 Mf_MR;
777 REAL8 ddbeta;
778 REAL8 dddbeta;
779 REAL8 dbeta_inflection;
780 REAL8 chosen_dbeta;
781 REAL8 d1;
782 REAL8 d2;
783 REAL8 delta;
784
785 /* calculate inflection frequency to get beta_inf */
786 Mf_inflection = IMRPhenomX_PNR_single_inflection_point(betaParams);
787
788 /* calculate the derivative of beta at the inflection, dbeta_inf*/
789 dbeta_inflection = IMRPhenomX_PNR_MR_dbeta_expression(Mf_inflection, betaParams);
790
791 /* next we seek to compute Mf_max used in Eq. 57 of arXiv:2107.08876 */
792 /* start by calculating the two extrema of beta FIXME: add documentation */
793 root_term = B4 * (B2 - 2.0 * B3 * B5) * (B2 - 2.0 * B1 * B4 * B5 + B2 * B4 * B5 * B5) + (B3 - B1 * B4 + B3 * B4 * B5 * B5) * (B3 - B1 * B4 + B3 * B4 * B5 * B5);
794
795 Mf_plus = ((B3 - B1 * B4 + B3 * B4 * B5 * B5) + sqrt(root_term)) / (B4 * (B2 - 2.0 * B3 * B5));
796 Mf_minus = ((B3 - B1 * B4 + B3 * B4 * B5 * B5) - sqrt(root_term)) / (B4 * (B2 - 2.0 * B3 * B5));
797
798 /* classify extrema as either maximum or minimum depending on sign of second derivative */
799 ddbeta_Mf_plus = IMRPhenomX_PNR_MR_ddbeta_expression(Mf_plus, betaParams);
800
801 if (ddbeta_Mf_plus > 0.0)
802 {
803 /* smiley face, Mf_plus is the minimum */
804 Mf_at_minimum = Mf_plus;
805 Mf_at_maximum = Mf_minus;
806 }
807 else
808 {
809 /* frowny face, Mf_plus is the maximum */
810 Mf_at_minimum = Mf_minus;
811 Mf_at_maximum = Mf_plus;
812 }
813
814 /* calculate the second and third derivatives at the maximum frequency */
815 ddbeta = IMRPhenomX_PNR_MR_ddbeta_expression(Mf_at_maximum, betaParams);
816 dddbeta = IMRPhenomX_PNR_MR_dddbeta_expression(Mf_at_maximum, betaParams);
817
818 /* ensure that the sign of dbeta_inflection is maintained in Eq. 56 of arXiv:2107.08876,
819 * even though dbeta_inflection is squared */
820 REAL8 sign = 0.0;
821 if (dbeta_inflection > 0.0)
822 {
823 sign = +1.0;
824 }
825 else
826 {
827 sign = -1.0;
828 }
829 /* compute Eq. 56 of arXiv:2107.08876 */
830 chosen_dbeta = sign * ((dbeta_inflection / 100.0) * (dbeta_inflection / 100.0)) * 25.0;
831
832 /* compute the two possible square roots for Eq. 57 of arXiv:2107.08876 */
833 d1 = 1.0 / dddbeta * (-ddbeta + sqrt(ddbeta * ddbeta + 2.0 * dddbeta * chosen_dbeta));
834 d2 = 1.0 / dddbeta * (-ddbeta - sqrt(ddbeta * ddbeta + 2.0 * dddbeta * chosen_dbeta));
835
836 /* select the most appropriate case. The logic is as follows:
837 * - if both d1 and d2 are positive, select the smallest
838 * - if d2 < 0 and d1 > 0, choose d1
839 * - if d1 < 0, choose d2 */
840 if (d1 > 0.0)
841 {
842 if (d2 > 0.0)
843 {
844 /* choose the smallest positive solution */
845 delta = (d1 < d2) ? d1 : d2;
846 }
847 else
848 {
849 delta = d1;
850 }
851 }
852 else
853 {
854 delta = d2;
855 }
856
857 /* specify the connection frequency based on Eq. 58 of arXiv:2107.08876
858 * for cases where the turnover is not present within the fitting region.
859 * We will decide whether to use this or not below. */
860 if (Mf_inflection >= 0.06)
861 {
862 Mf_low = Mf_inflection - 0.03;
863 }
864 else
865 {
866 Mf_low = 3.0 * Mf_inflection / 5.0;
867 }
868
869 /* quantify the shape of beta for this case: see Fig. 10 of arXiv:2107.08876 for
870 * visualization of the three different cases.
871 *
872 * We start by checking to see if the minimum happens at a higher frequency to the maximum
873 * and if the chosen inflection point is also at higher frequency than the maximum. In this case,
874 * we are in the first two panels of Fig. 10. */
875 if ((Mf_at_minimum > Mf_at_maximum) || (Mf_inflection > Mf_at_maximum))
876 {
877 /* If the maximum occurs at a higher frequency than in Eq. 58, pick Eq. 57 as the connection frequency.
878 * Otherwise use Eq. 58. */
879 if (Mf_at_maximum >= Mf_low)
880 {
881 Mf_IM = Mf_at_maximum + delta;
882 }
883 else
884 {
885 Mf_IM = Mf_low;
886 }
887 }
888 else /* Here we are in the right-most panel of Fig. 10 */
889 {
890 /* ensure that we have enough room to start below the minimum frequency */
891 if (Mf_at_minimum > 0.06)
892 {
893 Mf_IM = Mf_at_minimum - 0.03;
894 }
895 else
896 {
897 Mf_IM = 3.0 * Mf_at_minimum / 5.0;
898 }
899 }
900
901 /* Specify the upper connection frequency where we either transition to a constant
902 * value for beta at the minimum to enforce zero slope, or we are in the first panel
903 * of Fig. 10 where beta will asymptote to some value.
904 * In the latter case, we simply set the upper connection frequency to be very large */
905 if (Mf_at_minimum > Mf_inflection)
906 {
907 Mf_MR = Mf_at_minimum;
908 }
909 else
910 {
911 Mf_MR = 100.;
912 }
913
914 /* failsafe if the lower connection frequency is negative, then we won't be using the MR fit */
915 if ((Mf_IM < 0.0) || isnan(Mf_IM))
916 {
917 betaParams->Mf_beta_lower = 100.0;
918 betaParams->Mf_beta_upper = 100.0;
919 }
920 else
921 {
922 betaParams->Mf_beta_lower = Mf_IM;
923 betaParams->Mf_beta_upper = Mf_MR;
924 }
925
926 return XLAL_SUCCESS;
927 }
928
929 /**
930 * Compute the three roots of a depressed cubic given by
931 * Eq. 68 of arXiv:2107.08876.
932 *
933 */
935 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
936 )
937 {
938
939 REAL8 B1 = betaParams->B1;
940 REAL8 B2 = betaParams->B2;
941 REAL8 B3 = betaParams->B3;
942 REAL8 B4 = betaParams->B4;
943 REAL8 B5 = betaParams->B5;
944
945 COMPLEX16 a;
946 COMPLEX16 b;
947 COMPLEX16 c;
948 COMPLEX16 d;
949 COMPLEX16 r;
950 COMPLEX16 s;
951 COMPLEX16 phi;
952 static COMPLEX16 f[3];
953
954 /* cubic ax^3 + bx^2 + cx + d FIXME: add documentation */
955 a = 2 * (B2 * B4 * B4 - 2 * B3 * B4 * B4 * B5);
956 b = 6 * (-B3 * B4 + B1 * B4 * B4 - B3 * B4 * B4 * B5 * B5);
957 c = 6 * (-B2 * B4 + 2 * B1 * B4 * B4 * B5 - B2 * B4 * B4 * B5 * B5);
958 d = 2 * (B3 - B1 * B4 - 2 * B2 * B4 * B5 + 2 * B3 * B4 * B5 * B5 + 3 * B1 * B4 * B4 * B5 * B5 - 2 * B2 * B4 * B4 * B5 * B5 * B5 + B3 * B4 * B4 * B5 * B5 * B5 * B5);
959
960 /* convert to depressed cubic t^3 + rt +s, t = x + b/3a */
961 r = (3 * a * c - b * b) / (3 * a * a);
962 s = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
963
964 phi = acos(((3 * s) / (2 * r)) * csqrt(-3 / r));
965
966 for (int n = 0; n < 3; n++)
967 {
968 f[n] = 2 * csqrt(-r / 3) * cos((phi - 2 * n * LAL_PI) / 3) - b / (3 * a);
969 }
970
971 return f;
972 }
973
974 /**
975 * Compute the two roots of a depressed cubic given by
976 * Eq. 68 of arXiv:2107.08876 when the cubic term vanishes.
977 *
978 */
980 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
981 )
982 {
983
984 REAL8 B1 = betaParams->B1;
985 REAL8 B2 = betaParams->B2;
986 REAL8 B3 = betaParams->B3;
987 REAL8 B4 = betaParams->B4;
988 REAL8 B5 = betaParams->B5;
989
990 REAL8 b;
991 REAL8 c;
992 REAL8 d;
993
994 static COMPLEX16 f[2];
995
996 /* cubic ax^3 + bx^2 + cx + d, here a=0 */
997 b = 6 * (-B3 * B4 + B1 * B4 * B4 - B3 * B4 * B4 * B5 * B5);
998 c = 6 * (-B2 * B4 + 2 * B1 * B4 * B4 * B5 - B2 * B4 * B4 * B5 * B5);
999 d = 2 * (B3 - B1 * B4 - 2 * B2 * B4 * B5 + 2 * B3 * B4 * B5 * B5 + 3 * B1 * B4 * B4 * B5 * B5 - 2 * B2 * B4 * B4 * B5 * B5 * B5 + B3 * B4 * B4 * B5 * B5 * B5 * B5);
1000
1001 f[0] = (1 / (2 * b)) * (-c + csqrt(c * c - 4 * b * d));
1002 f[1] = (1 / (2 * b)) * (-c - csqrt(c * c - 4 * b * d));
1003
1004 return f;
1005 }
1006
1007 /**
1008 * Compute the roots of a depressed cubic given by
1009 * Eq. 68 of arXiv:2107.08876, then select the correct
1010 * root to use for the inflection frequency based on
1011 * Eq. 69 and discussion in Sec. 8D.
1012 *
1013 */
1015 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
1016 )
1017 {
1018
1019 REAL8 B1 = betaParams->B1;
1020 REAL8 B2 = betaParams->B2;
1021 REAL8 B3 = betaParams->B3;
1022 REAL8 B4 = betaParams->B4;
1023 REAL8 B5 = betaParams->B5;
1024
1025 // cubic terms
1026 REAL8 a;
1027 REAL8 b;
1028 REAL8 c;
1029 REAL8 d;
1030
1031 int i;
1032
1033 REAL8 grad;
1034 REAL8 f_inflection = 0.0;
1035
1036 /* cubic ax^3 + bx^2 + cx + d */
1037 a = 2.0 * (B2 * B4 * B4 - 2.0 * B3 * B4 * B4 * B5);
1038 b = 6.0 * (-B3 * B4 + B1 * B4 * B4 - B3 * B4 * B4 * B5 * B5);
1039 c = 6.0 * (-B2 * B4 + 2.0 * B1 * B4 * B4 * B5 - B2 * B4 * B4 * B5 * B5);
1040 d = 2.0 * (B3 - B1 * B4 - 2.0 * B2 * B4 * B5 + 2.0 * B3 * B4 * B5 * B5 + 3.0 * B1 * B4 * B4 * B5 * B5 - 2.0 * B2 * B4 * B4 * B5 * B5 * B5 + B3 * B4 * B4 * B5 * B5 * B5 * B5);
1041
1042 /* treat cases where co-efficients of cubic term is zero (or less than 10^-10 to account for numerical error) */
1043 if (fabs(a) < 1e-10)
1044 {
1045 /* co-efficient of quadratic term is also zero */
1046 if (fabs(b) < 2e-10)
1047 {
1048 /* calculate single inflection point */
1049 f_inflection = -d / c;
1050 }
1051 else
1052 {
1053 COMPLEX16 *f_inf;
1054
1055 /* calculate 2 inflection points */
1056 f_inf = IMRPhenomX_PNR_two_inflection_points(betaParams);
1057
1058 /* choose inflection point with negative gradient */
1059 for (i = 0; i < 2; i++)
1060 {
1061 grad = IMRPhenomX_PNR_MR_dbeta_expression(f_inf[i], betaParams);
1062 if (grad < 0.0)
1063 {
1064 f_inflection = f_inf[i];
1065 }
1066 }
1067 }
1068 }
1069 /* treat cases with 3 roots */
1070 else
1071 {
1072 COMPLEX16 *f_inf;
1073 REAL8 f_temp = 0;
1074 REAL8 f_IM = 0;
1075 int w = 0; // initialise counter
1076
1077 /* calculate all 3 inflection points */
1078 f_inf = IMRPhenomX_PNR_three_inflection_points(betaParams);
1079
1080 /* check for substantial imaginary component and select real root if this component exists */
1081 for (i = 0; i < 3; i++)
1082 {
1083 f_IM = cimag(f_inf[i]);
1084 if (f_IM < 1e-10)
1085 {
1086 w += 1;
1087 f_temp = creal(f_inf[i]);
1088 }
1089 }
1090 /* case where we have just one real root */
1091 if (w == 1)
1092 {
1093 f_inflection = f_temp;
1094 }
1095 /* case where we have all 3 real roots */
1096 else
1097 {
1098 if (a < 0.0)
1099 {
1100 /* take the central root */
1101 f_inflection = creal(f_inf[1]);
1102 }
1103 else
1104 {
1105 /* enforce Eq. 69 */
1106 if (b / (3.0 * a) > B5 / 2.0 - (2141.0 / 90988.0)) // FIXME: add documentation
1107 {
1108 f_inflection = creal(f_inf[0]);
1109 }
1110 else
1111 {
1112 f_inflection = creal(f_inf[2]);
1113 }
1114 }
1115 }
1116 }
1117
1118 return f_inflection;
1119 }
1120
1121 /**
1122 * This function combines several functions together to
1123 * compute the connection frequencies and the inspiral rescaling.
1124 *
1125 */
1127 IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
1128 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
1129 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
1130 IMRPhenomXWaveformStruct *pWF_SingleSpin, /**< PhenomX waveform struct with single-spin mapping */
1131 IMRPhenomXPrecessionStruct *pPrec_SingleSpin /**< PhenomX precession struct with single-spin mapping */
1132 )
1133 {
1134 /* may we continue? Single-spin structs might be NULL */
1135 XLAL_CHECK(betaParams != NULL, XLAL_EFAULT);
1136 XLAL_CHECK(pWF != NULL, XLAL_EFAULT);
1137 XLAL_CHECK(pPrec != NULL, XLAL_EFAULT);
1138
1139 /* define frequency spacing over which to calculate derivatives */
1140 /* here set to be 0.0005Mf */
1141 REAL8 dMf = 0.0005;
1142
1143 /* generate beta connection frequencies*/
1145
1146 if((pPrec->IMRPhenomXPrecVersion==330)&&(betaParams->Mf_beta_lower-2.*dMf<pPrec->Mfmin_integration))
1147 betaParams->Mf_beta_lower = 100.;
1148
1149 /* evaluate expressions for beta at lower connection frequency */
1150 REAL8 Mf_beta_lower = betaParams->Mf_beta_lower;
1151
1152 /* get the values of PN and MR beta at Mf_beta_lower, as well as around that
1153 * frequency for the centered FD derivatives */
1154 REAL8 beta_temp = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf_beta_lower - dMf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
1155 REAL8 b1 = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf_beta_lower - dMf, beta_temp, pWF, pPrec);
1156
1157 beta_temp = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf_beta_lower, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
1158 REAL8 beta_lower = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf_beta_lower, beta_temp, pWF, pPrec);
1159
1160 beta_temp = IMRPhenomX_PNR_GetPNBetaAtFreq(Mf_beta_lower + dMf, betaParams, pWF, pPrec, pWF_SingleSpin, pPrec_SingleSpin);
1161 REAL8 b3 = IMRPhenomX_PNR_PNWaveformBetaWrapper(Mf_beta_lower + dMf, beta_temp, pWF, pPrec);
1162
1163 REAL8 b4 = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_lower - dMf, betaParams);
1164 REAL8 beta_upper = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_lower, betaParams);
1165 REAL8 b6 = IMRPhenomX_PNR_MR_beta_expression(Mf_beta_lower + dMf, betaParams);
1166
1167 /* calculate derivative of alpha at connection frequencies using central finite difference method */
1168 REAL8 derivative_beta_lower = (b3 - b1) / (2.0 * dMf);
1169 REAL8 derivative_beta_upper = (b6 - b4) / (2.0 * dMf);
1170
1171 /* compute the inspiral rescaling */
1172 REAL8 beta_rescale_1 = IMRPhenomX_PNR_beta_rescaling_1(Mf_beta_lower, beta_lower, beta_upper, derivative_beta_lower, derivative_beta_upper);
1173 REAL8 beta_rescale_2 = IMRPhenomX_PNR_beta_rescaling_2(Mf_beta_lower, beta_lower, beta_upper, derivative_beta_lower, derivative_beta_upper);
1174
1175 beta_rescale_1 = isnan(beta_rescale_1) ? 0.0 : beta_rescale_1;
1176 beta_rescale_2 = isnan(beta_rescale_2) ? 0.0 : beta_rescale_2;
1177
1178 /* save beta values to the parameter dict */
1179 betaParams->beta_lower = beta_lower;
1180 betaParams->beta_upper = beta_upper;
1181 betaParams->derivative_beta_lower = derivative_beta_lower;
1182 betaParams->derivative_beta_upper = derivative_beta_upper;
1183 betaParams->beta_rescale_1 = beta_rescale_1;
1184 betaParams->beta_rescale_2 = beta_rescale_2;
1185
1186 return XLAL_SUCCESS;
1187 }
1188
1189 /**
1190 * Function to calculate beta and first derivative at connection frequency between SpinTaylor and PNR angles
1191 */
1192
1194 IMRPhenomX_PNR_beta_parameters *betaParams, /**< beta parameter struct */
1195 IMRPhenomXWaveformStruct *pWF, /**< PhenomX waveform struct */
1196 IMRPhenomXPrecessionStruct *pPrec, /**< PhenomX precession struct */
1197 IMRPhenomXWaveformStruct *pWF_SingleSpin, /**< PhenomX waveform struct with max-spin mapping */
1198 IMRPhenomXPrecessionStruct *pPrec_SingleSpin /**< PhenomX precession struct with max-spin mapping */
1199
1200 )
1201 {
1202 /* may we continue? Single-spin structs might be NULL */
1203 XLAL_CHECK(betaParams != NULL, XLAL_EFAULT);
1204 XLAL_CHECK(pPrec != NULL, XLAL_EFAULT);
1205
1206 /* define frequency spacing over which to calculate derivatives */
1207 /* here set to be 0.0005Mf */
1208 REAL8 dMf = 0.0005;
1209
1210 /* generate beta connection frequencies*/
1212
1213 /* frequencies marking beginning and end of interpolation region */
1214 REAL8 ftrans = ( pPrec->ftrans_MRD <= 0.9*betaParams->Mf_beta_lower ) ? pPrec->ftrans_MRD : 0.9*betaParams->Mf_beta_lower;
1215 REAL8 MfA = ( ftrans-dMf < pPrec->Mfmin_integration + 2.*dMf ? pPrec->Mfmin_integration + 2*dMf : ftrans - dMf );
1216 REAL8 MfB = betaParams->Mf_beta_lower;
1217
1218 /* evaulate SpinTaylor angles around lower connection frequency */
1219 REAL8 cosbeta=0.;
1220 int status=GSL_SUCCESS;
1221
1222 status=gsl_spline_eval_e(pPrec->cosbeta_spline, MfA - dMf, pPrec->cosbeta_acc,&cosbeta);
1223 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "%s: error in beta interpolation for q=%.12f, Mtot=%.12f and chi1=[%.12f, %.12f,%.12f], chi2=[%.12f, %.12f,%.12f]\n",__func__,pWF->q,pWF->M, pPrec->chi1x,pPrec->chi1y,pPrec->chi1z,pPrec->chi2x,pPrec->chi2y,pPrec->chi2z);
1224 REAL8 bA1 = acos(MAX(-1, MIN(1, cosbeta)));
1225
1226 status=gsl_spline_eval_e(pPrec->cosbeta_spline, MfA, pPrec->cosbeta_acc,&cosbeta);
1227 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "%s: error in beta interpolation for q=%.12f, Mtot=%.12f and chi1=[%.12f, %.12f,%.12f], chi2=[%.12f, %.12f,%.12f]\n",__func__,pWF->q,pWF->M, pPrec->chi1x,pPrec->chi1y,pPrec->chi1z,pPrec->chi2x,pPrec->chi2y,pPrec->chi2z);
1228 REAL8 bA = acos(MAX(-1, MIN(1, cosbeta)));
1229
1230 status=gsl_spline_eval_e(pPrec->cosbeta_spline, MfA + dMf, pPrec->cosbeta_acc,&cosbeta);
1231 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "%s: error in beta interpolation for q=%.12f, Mtot=%.12f and chi1=[%.12f, %.12f,%.12f], chi2=[%.12f, %.12f,%.12f]\n",__func__,pWF->q,pWF->M, pPrec->chi1x,pPrec->chi1y,pPrec->chi1z,pPrec->chi2x,pPrec->chi2y,pPrec->chi2z);
1232 REAL8 bA2 = acos(MAX(-1, MIN(1, cosbeta)));
1233
1234 /* evaluate single-spin MSA angles at upper connection frequency */
1235 const double omega = LAL_PI * MfB;
1236 const double domega = LAL_PI * dMf;
1237
1238 REAL8 bB1, bB, bB2;
1239 if (IMRPhenomX_PNR_CheckTwoSpin(pPrec))
1240 {
1241 const vector vangles_SingleSpin1 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega - domega), pWF_SingleSpin, pPrec_SingleSpin);
1242 bB1 = acos(vangles_SingleSpin1.z);
1243
1244 const vector vangles_SingleSpin2 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega), pWF_SingleSpin, pPrec_SingleSpin);
1245 bB = acos(vangles_SingleSpin2.z);
1246
1247 const vector vangles_SingleSpin3 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega + domega), pWF_SingleSpin, pPrec_SingleSpin);
1248 bB2 = acos(vangles_SingleSpin3.z);
1249 }
1250 else
1251 {
1252 int user_version = pPrec->IMRPhenomXPrecVersion;
1253 pPrec->IMRPhenomXPrecVersion=223;
1255 pPrec->IMRPhenomXPrecVersion=user_version;
1256
1257 const vector vangles_SingleSpin1 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega - domega), pWF, pPrec);
1258 bB1 = acos(vangles_SingleSpin1.z);
1259
1260 const vector vangles_SingleSpin2 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega), pWF, pPrec);
1261 bB = acos(vangles_SingleSpin2.z);
1262
1263 const vector vangles_SingleSpin3 = IMRPhenomX_Return_phi_zeta_costhetaL_MSA(cbrt(omega + domega), pWF, pPrec);
1264 bB2 = acos(vangles_SingleSpin3.z);
1265 }
1266
1267 /* compute numerical gradient */
1268 REAL8 dbA = (bA2-bA1)/(2.0*dMf);
1269 REAL8 dbB = (bB2-bB1)/(2.0*dMf);
1270
1271 /* compute and store connection co-efficients */
1272 REAL8 b0 = IMRPhenomX_ST_PNR_beta_coeffs_0( MfA, MfB, bA, bA, dbA, dbB );
1273 REAL8 b1 = IMRPhenomX_ST_PNR_beta_coeffs_1( MfA, MfB, bA, bA, dbA, dbB );
1274 REAL8 b2 = IMRPhenomX_ST_PNR_beta_coeffs_2( MfA, MfB, bA, bA, dbA, dbB );
1275 REAL8 b3 = IMRPhenomX_ST_PNR_beta_coeffs_3( MfA, MfB, bA, bA, dbA, dbB );
1276
1277 betaParams->beta_interp_0 = b0;
1278 betaParams->beta_interp_1 = b1;
1279 betaParams->beta_interp_2 = b2;
1280 betaParams->beta_interp_3 = b3;
1281
1282 /* Now parameters for rescaling */
1283
1284 REAL8 bBnew = IMRPhenomX_PNR_CheckTwoSpin(pPrec) ? bB : bA;
1285 // MSA value if two spin because already tapered to this point
1286 // SpinTaylor otherwise to avoid introducing kink in beta where ST and MSA apparoximants disagree
1287
1288 REAL8 bC1 = IMRPhenomX_PNR_PNWaveformBetaWrapper(MfB - dMf, bB1, pWF, pPrec);
1289 REAL8 bC = IMRPhenomX_PNR_PNWaveformBetaWrapper(MfB, bBnew, pWF, pPrec);
1290 REAL8 bC2 = IMRPhenomX_PNR_PNWaveformBetaWrapper(MfB + dMf, bB2, pWF, pPrec);
1291
1292 REAL8 bD1 = IMRPhenomX_PNR_MR_beta_expression(MfB - dMf, betaParams);
1293 REAL8 bD = IMRPhenomX_PNR_MR_beta_expression(MfB, betaParams);
1294 REAL8 bD2 = IMRPhenomX_PNR_MR_beta_expression(MfB + dMf, betaParams);
1295
1296 /* calculate derivative of beta at connection frequencies using central finite difference method */
1297 REAL8 dbC = (bC2 - bC1) / (2.0 * dMf);
1298 REAL8 dbD = (bD2 - bD1) / (2.0 * dMf);
1299
1300 /* compute the inspiral rescaling */
1301 REAL8 beta_rescale_1 = IMRPhenomX_PNR_beta_rescaling_1(MfB, bC, bD, dbC, dbD);
1302 REAL8 beta_rescale_2 = IMRPhenomX_PNR_beta_rescaling_2(MfB, bC, bD, dbC, dbD);
1303
1304 beta_rescale_1 = isnan(beta_rescale_1) ? 0.0 : beta_rescale_1;
1305 beta_rescale_2 = isnan(beta_rescale_2) ? 0.0 : beta_rescale_2;
1306
1307 /* save beta values to the parameter dict */
1308 betaParams->beta_lower = bC;
1309 betaParams->beta_upper = bD;
1310 betaParams->derivative_beta_lower = dbC;
1311 betaParams->derivative_beta_upper = dbD;
1312 betaParams->beta_rescale_1 = beta_rescale_1;
1313 betaParams->beta_rescale_2 = beta_rescale_2;
1314
1315 //printf("%f, %f \n", beta_rescale_1, beta_rescale_2);
1316 //printf("%f, %f, %f, %f, %f, %f \n", MfA, MfB, bA, bB, dbA, dbB);
1317 //printf("%f, %f, %f, %f\n", betaParams->beta_interp_0, betaParams->beta_interp_1, betaParams->beta_interp_2, betaParams->beta_interp_3);
1318 //printf("-------\n");
1319
1320 return XLAL_SUCCESS;
1321 }
1322
1323 /**
1324 * Series of functions to calculation co-efficients in beta interpolation function
1325 * These expressions come from enforcing C(1) connectivity to the ST and PNR expressions
1326 * See discussion below Eq. (19) in https://dcc.ligo.org/LIGO-T2400368
1327 */
1328
1330 REAL8 Mf1, /**< geometric frequency at lower connection point */
1331 REAL8 Mf2, /**< geometric frequency at lower connection point */
1332 REAL8 beta1, /**< PN beta evaluated at Mf1 */
1333 REAL8 beta2, /**< MR beta evaluated at Mf2 */
1334 REAL8 dbeta1, /**< derivative of PN beta at Mf1 */
1335 REAL8 dbeta2 /**< derivative of MR beta at Mf2 */
1336 )
1337 {
1338 REAL8 Mf1_2 = Mf1*Mf1;
1339 REAL8 Mf1_3 = Mf1_2*Mf1;
1340
1341 REAL8 Mf2_2 = Mf2*Mf2;
1342 REAL8 Mf2_3 = Mf2_2*Mf2;
1343
1344 REAL8 N = -beta2*Mf1_3 + 3*beta2*Mf1_2*Mf2 + dbeta2*Mf1_3*Mf2 - 3*beta1*Mf1*Mf2_2 + dbeta1*Mf1_2*Mf2_2 - dbeta2*Mf1_2*Mf2_2 + beta1*Mf2_3 - dbeta1*Mf1*Mf2_3;
1345 REAL8 D = (Mf1-Mf2)*(Mf1-Mf2)*(Mf1-Mf2);
1346
1347 return -N/D;
1348 }
1349
1351 REAL8 Mf1, /**< geometric frequency at lower connection point */
1352 REAL8 Mf2, /**< geometric frequency at lower connection point */
1353 REAL8 beta1, /**< PN beta evaluated at Mf1 */
1354 REAL8 beta2, /**< MR beta evaluated at Mf2 */
1355 REAL8 dbeta1, /**< derivative of PN beta at Mf1 */
1356 REAL8 dbeta2 /**< derivative of MR beta at Mf2 */
1357 )
1358 {
1359 REAL8 Mf1_2 = Mf1*Mf1;
1360 REAL8 Mf1_3 = Mf1_2*Mf1;
1361
1362 REAL8 Mf2_2 = Mf2*Mf2;
1363 REAL8 Mf2_3 = Mf2_2*Mf2;
1364
1365 REAL8 N = -dbeta2*Mf1_3 + 6*beta1*Mf1*Mf2 - 6*beta2*Mf1*Mf2 - 2*dbeta1*Mf1_2*Mf2 - dbeta2*Mf1_2*Mf2 + dbeta1*Mf1*Mf2_2 + 2*dbeta2*Mf1*Mf2_2 + dbeta1*Mf2_3;
1366 REAL8 D = (Mf1-Mf2)*(Mf1-Mf2)*(Mf1-Mf2);
1367
1368 return -N/D;
1369 }
1370
1372 REAL8 Mf1, /**< geometric frequency at lower connection point */
1373 REAL8 Mf2, /**< geometric frequency at lower connection point */
1374 REAL8 beta1, /**< PN beta evaluated at Mf1 */
1375 REAL8 beta2, /**< MR beta evaluated at Mf2 */
1376 REAL8 dbeta1, /**< derivative of PN beta at Mf1 */
1377 REAL8 dbeta2 /**< derivative of MR beta at Mf2 */
1378 )
1379 {
1380 REAL8 Mf1_2 = Mf1*Mf1;
1381 REAL8 Mf2_2 = Mf2*Mf2;
1382
1383 REAL8 N = -3*(beta1 - beta2)*(Mf1 + Mf2) + (dbeta1 + 2*dbeta2)*Mf1_2 + (dbeta1 - dbeta2)*Mf1*Mf2 - (2*dbeta1 + dbeta2)*Mf2_2;
1384 REAL8 D = (Mf1-Mf2)*(Mf1-Mf2)*(Mf1-Mf2);
1385
1386 return -N/D;
1387 }
1388
1390 REAL8 Mf1, /**< geometric frequency at lower connection point */
1391 REAL8 Mf2, /**< geometric frequency at lower connection point */
1392 REAL8 beta1, /**< PN beta evaluated at Mf1 */
1393 REAL8 beta2, /**< MR beta evaluated at Mf2 */
1394 REAL8 dbeta1, /**< derivative of PN beta at Mf1 */
1395 REAL8 dbeta2 /**< derivative of MR beta at Mf2 */
1396 )
1397 {
1398
1399 REAL8 N = 2*(beta1-beta2) - (dbeta1+dbeta2)*(Mf1-Mf2);
1400 REAL8 D = (Mf1-Mf2)*(Mf1-Mf2)*(Mf1-Mf2);
1401
1402 return -N/D;
1403 }
1404
1405 /**
1406 * Utility function to compute the arctan windowing described
1407 * in Eq. 62 of arXiv:2107.08876.
1408 *
1409 */
1411 REAL8 beta /**< beta angle (rad) */
1412 )
1413 {
1414 /* specify the width as described in Sec. 8C of arXiv:2107.08876*/
1415 REAL8 window_border = 0.01;
1416
1417 /* if beta is close to zero or PI, window it */
1418 if ((beta <= window_border) || (beta >= LAL_PI - window_border))
1419 {
1420 /* precompute some things, then evaluate the arctan */
1421 REAL8 p = 0.002;
1422 REAL8 PI_by_2 = 1.570796326794897;
1423 REAL8 PI_by_2_1mp = 1.569378278348018;
1424 REAL8 PI_by_2_1oq = 7.308338225719002e97;
1425 REAL8 sign = (beta < PI_by_2) ? -1.0 : 1.0;
1426
1427 return sign * PI_by_2_1mp * pow(atan2(pow(beta - PI_by_2, 1.0 / p), PI_by_2_1oq), p) + PI_by_2;
1428 }
1429
1430 return beta;
1431 }
1432
1433 /**
1434 * Determine whether to attach the MR contributions to beta.
1435 * - If the connection frequency is too low, < 0.009
1436 * - If the connection frequency is 100.0
1437 * - if the final Ansatz value of beta is negative at the
1438 * lower connection frequency
1439 *
1440 */
1442 const IMRPhenomX_PNR_beta_parameters *betaParams /**< beta parameter struct */
1443 )
1444 {
1445 /* check for initialization */
1446 XLAL_CHECK(betaParams != NULL, XLAL_EFAULT);
1447
1448 if ((betaParams->Mf_beta_lower < 0.009) || (betaParams->Mf_beta_lower == 100.0) || (betaParams->beta_upper <= 0.0) || (betaParams->beta_upper > 5.0 * (betaParams->B0 + 0.1)))
1449 {
1450 return 0;
1451 }
1452
1453 return 1;
1454 }
1455
1456#ifdef __cplusplus
1457}
1458#endif
const double b1
const double b2
const double b0
#define MAX_TOL_ATAN
Tolerance used below which numbers are treated as zero for the calculation of atan2.
static double double delta
#define MAX(a, b)
#define MIN(a, b)
REAL8 IMRPhenomX_PNR_GetPNBetaAtFreq_fulltwospin(REAL8 Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, const IMRPhenomX_PNR_beta_parameters *betaParams)
A wrapper to produce either the NNLO or MSA beta depending on the IMRPhenomXPrecVersion.
REAL8 IMRPhenomX_PNR_MR_dbeta_expression(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams)
expression for first derivative of beta in merger-ringdown regime
REAL8 IMRPhenomX_PNR_GeneratePNRBetaNoMR(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function evaluates only the rescaled inspiral beta given in Eq.
UINT4 IMRPhenomX_PNR_AttachMRBeta(const IMRPhenomX_PNR_beta_parameters *betaParams)
Determine whether to attach the MR contributions to beta.
COMPLEX16 * IMRPhenomX_PNR_three_inflection_points(const IMRPhenomX_PNR_beta_parameters *betaParams)
Compute the three roots of a depressed cubic given by Eq.
REAL8 IMRPhenomX_PNR_MR_ddbeta_expression(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams)
expression for second derivative of beta in merger-ringdown regime
COMPLEX16 * IMRPhenomX_PNR_two_inflection_points(const IMRPhenomX_PNR_beta_parameters *betaParams)
Compute the two roots of a depressed cubic given by Eq.
REAL8 IMRPhenomX_PNR_MR_dddbeta_expression(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams)
expression for third derivative of beta in merger-ringdown regime
REAL8 IMRPhenomX_PNR_GenerateRingdownPNRBeta(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
We evaluate beta at the final Mf_beta_upper connection frequency to approximate the final value of be...
REAL8 IMRPhenomX_PNR_GetPNBetaAtFreq(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXWaveformStruct *pWF_SingleSpin, IMRPhenomXPrecessionStruct *pPrec_SingleSpin)
A wrapper to produce either the NNLO or MSA beta depending on the IMRPhenomXPrecVersion.
REAL8 IMRPhenomX_ST_PNR_beta_coeffs_1(REAL8 Mf1, REAL8 Mf2, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
REAL8 IMRPhenomX_PNR_arctan_window(REAL8 beta)
Utility function to compute the arctan windowing described in Eq.
int IMRPhenomX_PNR_precompute_beta_coefficients(IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function evaluates the Ansatz coefficients of beta outlined in Eq.
REAL8 IMRPhenomX_ST_PNR_beta_coeffs_2(REAL8 Mf1, REAL8 Mf2, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
REAL8 IMRPhenomX_PNR_PNWaveformBetaWrapper(REAL8 Mf, REAL8 pn_beta, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
A wrapper to generate the "waveform" PN beta from Eq.
REAL8 IMRPhenomX_PNR_MR_beta_expression(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams)
These four functions produce the MR Ansatz of beta described in Sec.
REAL8 IMRPhenomX_PNR_beta_rescaling_2(REAL8 Mf, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
REAL8 IMRPhenomX_ST_PNR_beta_coeffs_3(REAL8 Mf1, REAL8 Mf2, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
REAL8 IMRPhenomX_PNR_GenerateMergedPNRBetaAtMf(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXWaveformStruct *pWF_SingleSpin, IMRPhenomXPrecessionStruct *pPrec_SingleSpin)
This function generates beta with the tuned angles and PN expressions blended during merger-ringdown.
REAL8 IMRPhenomX_PNR_chi_calc(REAL8 m1, REAL8 L, REAL8 J0, REAL8 L0, REAL8 chi_parr, REAL8 beta)
The magnitude of the effective total spin is computed from the total and orbital angular momenta,...
int IMRPhenomX_PNR_BetaConnectionFrequencies(IMRPhenomX_PNR_beta_parameters *betaParams)
Here we work through the construction of the connection frequency for beta, outlined in Sec.
int IMRPhenomX_PNR_beta_connection_parameters(IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXWaveformStruct *pWF_SingleSpin, IMRPhenomXPrecessionStruct *pPrec_SingleSpin)
This function combines several functions together to compute the connection frequencies and the inspi...
REAL8 IMRPhenomX_PNR_rescale_beta_expression(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams)
REAL8 IMRPhenomX_PNR_GeneratePNRBetaAtMf(REAL8 Mf, const IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXWaveformStruct *pWF_SingleSpin, IMRPhenomXPrecessionStruct *pPrec_SingleSpin)
This function evaluates Eqs.
REAL8 IMRPhenomX_PNR_beta_rescaling_1(REAL8 Mf, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
These three functions produce the inspiral rescaling of beta described in Sec.
REAL8 IMRPhenomX_PNR_PNWaveformBeta(REAL8 Mf, REAL8 iota, REAL8 m1, REAL8 m2, REAL8 chi, REAL8 costheta)
The "waveform" PN beta from Eq.
int IMRPhenomX_ST_PNR_beta_connection_parameters(IMRPhenomX_PNR_beta_parameters *betaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXWaveformStruct *pWF_SingleSpin, IMRPhenomXPrecessionStruct *pPrec_SingleSpin)
Function to calculate beta and first derivative at connection frequency between SpinTaylor and PNR an...
REAL8 IMRPhenomX_ST_PNR_beta_coeffs_0(REAL8 Mf1, REAL8 Mf2, REAL8 beta1, REAL8 beta2, REAL8 dbeta1, REAL8 dbeta2)
Series of functions to calculation co-efficients in beta interpolation function These expressions com...
REAL8 IMRPhenomX_PNR_single_inflection_point(const IMRPhenomX_PNR_beta_parameters *betaParams)
Compute the roots of a depressed cubic given by Eq.
REAL8 IMRPhenomX_PNR_beta_B4_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_B1_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_B5_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_B3_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_B2_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_Bf_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
REAL8 IMRPhenomX_PNR_beta_B0_coefficient(REAL8 eta, REAL8 chi, REAL8 costheta)
expressions for each of the co-efficients that appear in the merger-ringdown expression for beta
REAL8 IMRPhenomX_PNR_AnglesWindow(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
INT4 IMRPhenomX_PNR_CheckTwoSpin(IMRPhenomXPrecessionStruct *pPrec)
This function quickly checks to see if we expect two-spin effects to be present in the inspiral prece...
REAL8 beta_SpinTaylor_IMR(REAL8 Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, const IMRPhenomX_PNR_beta_parameters *betaParams)
int IMRPhenomX_Initialize_MSA_System(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, int ExpansionOrder)
This function initializes all the core variables required for the MSA system.
REAL8 XLALSimIMRPhenomXLPNAnsatz(REAL8 v, REAL8 LNorm, REAL8 L0, REAL8 L1, REAL8 L2, REAL8 L3, REAL8 L4, REAL8 L5, REAL8 L6, REAL8 L7, REAL8 L8, REAL8 L8L)
This is a convenient wrapper function for PN orbital angular momentum.
vector IMRPhenomX_Return_phi_zeta_costhetaL_MSA(const double v, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
Wrapper to generate , and at a given frequency.
REAL8 XLALSimIMRPhenomXatan2tol(REAL8 a, REAL8 b, REAL8 tol)
INT4 D0(REAL8 *f, REAL8 dx, INT4 n, REAL8 *df)
XLALWignerdMatrix, XLALWignerDMatrix in <lal/SphericalHarmonics.h>
INT4 D2(REAL8 *f, REAL8 dx, INT4 n, REAL8 *d2f)
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 ...
static double beta(const double a, const double b, const sysq *system)
Internal function that computes the spin-orbit couplings.
#define c
int s
Definition: bh_qnmode.c:137
REAL8 M
Definition: bh_qnmode.c:133
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
double theta
Definition: bh_sphwf.c:118
const double w
const double costheta
#define LAL_PI
double complex COMPLEX16
double REAL8
uint32_t UINT4
static const INT4 r
static const INT4 a
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EINVAL
string status
int N
p
REAL8 Mfmin_integration
Minimum frequency covered by the integration of PN spin-precessing equations for SpinTaylor models
INT4 ExpansionOrder
Flag to control expansion order of MSA system of equations.
REAL8 costheta_singleSpin
Polar angle of effective single spin, Eq.
INT4 IMRPhenomXPrecVersion
Flag to set version of Euler angles used.
REAL8 chi_singleSpin
Magnitude of effective single spin used for tapering two-spin angles, Eq.
REAL8 costheta_final_singleSpin
Polar angle of approximate final spin, see technical document FIXME: add reference.