LALSimulation  5.4.0.1-fe68b98
LALSimIMRPhenomX_AntisymmetricWaveform.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
21 extern "C"
22 {
23 #endif
24 
25 /* LALSimulation */
26 #include "LALSimIMR.h"
27 
28 /* Spherical harmonics */
29 #include <lal/SphericalHarmonics.h>
30 #include <lal/LALConstants.h>
31 
32 
33 /* Phenom */
34 #include "LALSimIMRPhenomX.h"
38 #include "LALSimIMRPhenomUtils.h"
43 
44 
46 
48 
49 
50 #ifndef _OPENMP
51 #define omp ignore
52 #endif
53 
54 #ifndef PHENOMXHMDEBUG
55 #define DEBUG 0
56 #else
57 #define DEBUG 1
58 #endif
59 
60  /**
61  * \author Shrobana Ghosh
62  */
63 
64  /**
65  * EXTERNAL GENERATE antisymmetric waveform
66  * This is an external wrapper to generate the (2,2) and (2,-2) antisymmetric waveform,
67  * given the standard inputs given to generate FD waveforms.
68  * Note that at present this is only compatible with the PNR angles (refer arxiv XXXX.YYYYY)
69  */
71  REAL8Sequence **antisymamp, /**< [out] Amplitude of antisymmetric (2,2) waveform */
72  REAL8Sequence **antisymphase, /**< [out] Phase of antisymmetric (2,2) waveform */
73  REAL8 m1_SI, /**< mass of companion 1 (kg) */
74  REAL8 m2_SI, /**< mass of companion 2 (kg) */
75  REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
76  REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
77  REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
78  REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
79  REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
80  REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
81  REAL8 distance, /**< distance to source **/
82  REAL8 inclination, /**< Angle between orbital angular momentum and line-of-sight vector at reference frequency (rad) */
83  REAL8 deltaF, /**< Frequency spacing (Hz) */
84  REAL8 f_min, /**< Starting GW frequency (Hz) */
85  REAL8 f_max, /**< Ending GW frequency (Hz) */
86  REAL8 fRef_In, /**< Reference frequency (Hz) */
87  REAL8 phiRef, /**< phase at reference frequency (Hz) */
88  LALDict *lalParams /**< LAL Dictionary struct */
89  )
90  {
91  /* Simple check on masses and spins */
92  UINT4 status = 0;
93  status = XLALIMRPhenomXPCheckMassesAndSpins(&m1_SI, &m2_SI, &chi1x, &chi1y, &chi1z, &chi2x, &chi2y, &chi2z);
94  XLAL_CHECK(
96  XLAL_EFUNC,
97  "Error: XLALIMRPhenomXPCheckMassesAndSpins failed in XLALSimIMRPhenomX_PNR_GenerateAntisymmetricWaveform.\n");
98 
99  /* Ensure we have a dictionary */
100 
102  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.\n");
103 
104  LALDict *lalParams_aux;
105  if (lalParams == NULL)
106  {
107  lalParams_aux = XLALCreateDict();
108  }
109  else
110  {
111  lalParams_aux = XLALDictDuplicate(lalParams);
112  }
113 
116  {
117  XLAL_PRINT_WARNING("Warning:Antisymmetric waveform generation currently not supported without PNR angles. Turning on PNR angles ... \n");
119  }
120 
121  /* Map fRef to the start frequency if need be, then make sure it's within the frequency range */
122  REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
123 
124  /* Generate a uniformly sampled frequency grid of spacing deltaF. */
125  /* Frequencies will be set using only the lower and upper bounds that we passed */
126  size_t iStart = (size_t)(f_min / deltaF);
127  size_t iStop = (size_t)(f_max / deltaF) + 1;
128 
129  XLAL_CHECK(
130  (iStart <= iStop),
131  XLAL_EDOM,
132  "Error: the starting frequency index is greater than the stopping index! Please ensure that f_min <= f_max.\n");
133 
134 
135  REAL8Sequence *freqs = NULL;
136  freqs = XLALCreateREAL8Sequence(iStop - iStart);
137  *antisymamp = XLALCreateREAL8Sequence(iStop - iStart);
138  *antisymphase = XLALCreateREAL8Sequence(iStop - iStart);
139 
140  for (UINT4 i = iStart; i < iStop; i++)
141  {
142  freqs->data[i - iStart] = i * deltaF;
143  }
144 
146  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
147  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1z, chi2z, deltaF, fRef, phiRef, f_min, f_max, distance, inclination, lalParams_aux, PHENOMXDEBUG);
148  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
149 
151  pPrec = XLALMalloc(sizeof(IMRPhenomXPrecessionStruct));
152  status = IMRPhenomXGetAndSetPrecessionVariables(pWF, pPrec, m1_SI, m2_SI, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, lalParams_aux, DEBUG);
153  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetPrecessionVariables failed.\n");
154 
155  IMRPhenomX_PNR_GenerateAntisymmetricWaveform(*antisymamp,*antisymphase,freqs,pWF,pPrec,lalParams_aux);
156 
157  LALFree(pWF);
158  if(pPrec->pWF22AS){
159  LALFree(pPrec->pWF22AS);
160  }
161  LALFree(pPrec);
162  XLALDestroyDict(lalParams_aux);
164 
165  return XLAL_SUCCESS;
166  }
167 
168  /**
169  * EXTERNAL GENERATE Antisymmetric Amplitude Ratio
170  * This is an external wrapper to generate the (2,2) antisymmetric amplitude ratio
171  * amplitude given the standard inputs given to generate FD waveforms.
172  */
174  REAL8Sequence **kappa, /**< [out] Antisymmetric amplitude ratio */
175  REAL8Sequence **freqs, /**< [out] Frequency array (Hz) */
176  REAL8 m1_SI, /**< mass of companion 1 (kg) */
177  REAL8 m2_SI, /**< mass of companion 2 (kg) */
178  REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
179  REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
180  REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
181  REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
182  REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
183  REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
184  REAL8 inclination, /**< Angle between orbital angular momentum and line-of-sight vector at reference frequency (rad) */
185  REAL8 deltaF, /**< Frequency spacing (Hz) */
186  REAL8 f_min, /**< Starting GW frequency (Hz) */
187  REAL8 f_max, /**< Ending GW frequency (Hz) */
188  REAL8 fRef_In, /**< Reference frequency (Hz) */
189  LALDict *lalParams /**< LAL Dictionary struct */
190  )
191  {
192  /* Simple check on masses and spins */
193  UINT4 status = 0;
194  status = XLALIMRPhenomXPCheckMassesAndSpins(&m1_SI, &m2_SI, &chi1x, &chi1y, &chi1z, &chi2x, &chi2y, &chi2z);
195  XLAL_CHECK(
196  XLAL_SUCCESS == status,
197  XLAL_EFUNC,
198  "Error: XLALIMRPhenomXPCheckMassesAndSpins failed in XLALSimIMRPhenomX_PNR_GenerateAntisymmetricAmpRatio.\n");
199 
200  /* Ensure we have a dictionary */
201  LALDict *lalParams_aux;
202  if (lalParams == NULL)
203  {
204  lalParams_aux = XLALCreateDict();
205  }
206  else
207  {
208  lalParams_aux = XLALDictDuplicate(lalParams);
209  }
210 
213  {
214  XLAL_PRINT_WARNING("Warning:Antisymmetric waveform generation currently not supported without PNR angles. Turning on PNR angles ... \n");
216  }
217 
218  /* Map fRef to the start frequency if need be, then make sure it's within the frequency range */
219  REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
220 
221  /* Generate a uniformly sampled frequency grid of spacing deltaF. */
222  /* Frequencies will be set using only the lower and upper bounds that we passed */
223  size_t iStart = (size_t)(f_min / deltaF);
224  size_t iStop = (size_t)(f_max / deltaF) + 1;
225 
226  XLAL_CHECK(
227  (iStart <= iStop),
228  XLAL_EDOM,
229  "Error: the starting frequency index is greater than the stopping index! Please ensure that f_min <= f_max.\n");
230 
231  /* Allocate memory for frequency array and terminate if this fails */
232  *freqs = XLALCreateREAL8Sequence(iStop - iStart);
233  *kappa = XLALCreateREAL8Sequence(iStop - iStart);
234 
235  /* Specify arbitrary parameters for the angle generation */
236  REAL8 distance = 1.0;
237  REAL8 phiRef = 0.0;
238  // REAL8 inclination = 0.0;
239 
240  for (UINT4 i = iStart; i < iStop; i++)
241  {
242  (*freqs)->data[i - iStart] = i * deltaF;
243  }
244 
245  /* Use the true minimum and maximum frequency values */
246  REAL8 f_min_eval = (*freqs)->data[0];
247  REAL8 f_max_eval = (*freqs)->data[(*freqs)->length - 1];
248 
249  /* Initialize PhenomX Waveform struct and check that it initialized correctly */
251  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
252  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1z, chi2z, deltaF, fRef, phiRef, f_min_eval, f_max_eval, distance, inclination, lalParams_aux, DEBUG);
253  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
254 
256  pPrec = XLALMalloc(sizeof(IMRPhenomXPrecessionStruct));
257  status = IMRPhenomXGetAndSetPrecessionVariables(pWF, pPrec, m1_SI, m2_SI, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, lalParams_aux, DEBUG);
258  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetPrecessionVariables failed.\n");
259 
260  status = IMRPhenomX_PNR_GenerateAntisymmetricAmpRatio(*kappa, *freqs, pWF, pPrec);
261  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomX_Generate_AntisymmetricAmpRatio failed.\n");
262 
263  /* Clean up memory allocation */
264  LALFree(pWF);
265  if(pPrec->pWF22AS){
266  LALFree(pPrec->pWF22AS);
267  }
268  LALFree(pPrec);
269  XLALDestroyDict(lalParams_aux);
270 
271  return XLAL_SUCCESS;
272  }
273 
275  REAL8Sequence *antisymamp, /**< [out] Amplitude of antisymmetric (2,2) waveform */
276  REAL8Sequence *antisymphase, /**< [out] Phase of antisymmetric (2,2) waveform */
277  const REAL8Sequence *freqs, /**< input frequency array (Hz) */
278  IMRPhenomXWaveformStruct *pWF, /**< waveform struct */
279  IMRPhenomXPrecessionStruct *pPrec, /**< precession struct **/
280  LALDict *lalParams /**< LAL Dictionary struct */
281  )
282  {
283  UINT4 status = 0;
285  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.\n");
286 
287  IMRPhenomXPhaseCoefficients *pPhase22;
288  pPhase22 = XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
289  status = IMRPhenomXGetPhaseCoefficients(pWF,pPhase22);
290  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXGetPhaseCoefficients failed.\n");
291 
293 
295  pAmp22 = XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
297  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXGetAmplitudeCoefficients failed.\n");
298 
299  REAL8Sequence *kappa = NULL;
300  kappa = XLALCreateREAL8Sequence(freqs->length);
301 
302  status = IMRPhenomX_PNR_GenerateAntisymmetricAmpRatio(kappa, freqs, pWF, pPrec);
303  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomX_Generate_AntisymmetricAmpRatio failed.\n");
304 
305  double MfT = 0.85 * pWF->fRING;
306  double lina = 0.0;
307  double linb = IMRPhenomX_TimeShift_22(pPhase22, pWF);
308  REAL8 inveta = (1.0 / pWF->eta);
309 
310  REAL8 A0 = 0.0;
311  REAL8 phi_A0 = 0.0;
312  REAL8 phi_B0 = 0.0;
313 
314  status = IMRPhenomX_PNR_GenerateAntisymmetricPhaseCoefficients(&A0, &phi_A0, &phi_B0, MfT, lina, linb, inveta, pWF, pPrec,pPhase22);
315  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomX_Generate_AntisymmetricPhaseCoefficients failed.\n");
316 
317  REAL8 fPhaseIN = pPhase22->fPhaseMatchIN;
318  REAL8 fPhaseIM = pPhase22->fPhaseMatchIM;
319  REAL8 fAmpIN = pAmp22->fAmpMatchIN;
320  REAL8 fAmpIM = pAmp22->fAmpRDMin;
321  REAL8 C1IM = pPhase22->C1Int;
322  REAL8 C2IM = pPhase22->C2Int;
323  REAL8 C1RD = pPhase22->C1MRD;
324  REAL8 C2RD = pPhase22->C2MRD;
325 
326  REAL8Sequence *alphaPNR = NULL;
327 
328  alphaPNR = XLALCreateREAL8Sequence(freqs->length);
329 
331  freqs, pWF, pPrec,
332  lalParams);
333  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomX_PNR_GeneratePNRAngles failed.\n");
334 
335  IMRPhenomX_UsefulPowers powers_of_MfRef;
336  IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
337 
338  REAL8 phiref22 = -inveta*IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF) - linb*pWF->MfRef - lina + 2.0*pWF->phi0 + LAL_PI_4;
339 
340  for (UINT4 idx = 0; idx <freqs->length; idx++)
341  {
342  double Mf = pWF->M_sec * freqs->data[idx];
343  REAL8 amp = 0.0;
344  REAL8 phi = 0.0;
345  REAL8 phi_AS = 0.0;
346  REAL8 amp_AS = 0.0;
347 
348  IMRPhenomX_UsefulPowers powers_of_Mf;
349  IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
350 
351  /* Get symmetric phase */
352  if(Mf < fPhaseIN)
353  {
354  phi = IMRPhenomX_Inspiral_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pPhase22);
355  }
356  else if(Mf > fPhaseIM)
357  {
358  phi = IMRPhenomX_Ringdown_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pWF, pPhase22) + C1RD + (C2RD * Mf);
359  }
360  else
361  {
362  phi = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pWF, pPhase22) + C1IM + (C2IM * Mf);
363  }
364  /* Scale phase by 1/eta and apply phase and time shifts */
365  phi *= inveta;
366  phi += linb*Mf + lina + phiref22;
367 
368  /* Get smmetric amplitude */
369  if(Mf < fAmpIN)
370  {
371  amp = IMRPhenomX_Inspiral_Amp_22_Ansatz(Mf, &powers_of_Mf, pWF, pAmp22);
372  }
373  else if(Mf > fAmpIM)
374  {
375  amp = IMRPhenomX_Ringdown_Amp_22_Ansatz(Mf, pWF, pAmp22);
376  }
377  else
378  {
379  amp = IMRPhenomX_Intermediate_Amp_22_Ansatz(Mf, &powers_of_Mf, pWF, pAmp22);
380  }
381 
382  /****** antisymmetric amplitude ******/
383  amp_AS = kappa->data[idx] * amp;
384 
385 
386  if(Mf < MfT)
387  {
388  phi_AS = phi/2 + alphaPNR->data[idx] + A0*Mf + phi_A0;
389  }
390  else
391  {
392  phi_AS = phi + phi_B0;
393  }
394 
395  REAL8 Amp0 = pWF->amp0 * pWF->ampNorm;
396 
397  antisymamp->data[idx] = Amp0 * powers_of_Mf.m_seven_sixths * amp_AS;
398  antisymphase->data[idx] = phi_AS;
399  }
400 
401  /* Clean up memory allocation */
402 
403  LALFree(pPhase22);
404  LALFree(pAmp22);
405 
407  XLALDestroyREAL8Sequence(alphaPNR);
408 
409  return XLAL_SUCCESS;
410  }
411 
412  /**
413  *
414  *
415  * GENERATE Antisymmetric amplitude ratio
416  *
417  */
419  REAL8Sequence *kappa, /**< [out] antisymmetric amplitude ratio */
420  const REAL8Sequence *freqs, /**< input frequency array (Hz) */
421  IMRPhenomXWaveformStruct *pWF, /**< waveform struct */
422  IMRPhenomXPrecessionStruct *pPrec /**< precession struct **/
423  )
424  {
425 
426  /**** populating parameters of binary from pWF ******/
427  const double m2 = pWF->m2;
428  const double M = pWF->Mtot;
429  const REAL8 delta = 1 - 2*m2;
430  const REAL8 eta = pWF->eta;
431  const double MfRD = pWF->fRING;
432  const REAL8 theta = pPrec->theta_antisymmetric;
433  const REAL8 Chi = pPrec->chi_singleSpin_antisymmetric;
434 
435  /* coefficients for phenemenological fit of amplitude ratio in PN-NR transition*/
436  double b0 = 18.0387;
437  double b1 = 15.4509;
438  double b2 = 55.1140;
439  double b3 = -203.6290;
440 
441  double b = b0 + b1*eta + b2*theta + b3*eta*theta;
442 
443  REAL8 vRD = cbrt (LAL_PI * MfRD );
444  const double kappaRD = GetKappa_at_frequency(vRD,delta,Chi,theta,eta,b);
445 
446  for (size_t i = 0; i < freqs->length; i++)
447  {
448  REAL8 Mf = XLALSimPhenomUtilsHztoMf(freqs->data[i], M);
449  REAL8 v = cbrt (LAL_PI * Mf );
450  if (Mf < MfRD)
451  {
452  kappa->data[i] = GetKappa_at_frequency(v,delta,Chi,theta,eta,b);
453  }
454  else
455  {
456  kappa->data[i] = kappaRD;
457  }
458  }
459 
460  size_t width = 80;
461  double df = 0.0;
462  if(width > kappa->length - 1)
463  {
464  width = (size_t)floor((double)(kappa->length) / 2.0);
465  }
466  size_t half_width = (size_t)floor((double)(width / 2.0));
467 
468 
469  for (size_t id = 0; id < kappa->length-width-1; id++)
470  {
471  double smoothed_ratio = 0.0;
472  double frequency_width = 0.0;
473  for (size_t j = 0; j < width+1; j++)
474  {
475  df = freqs->data[id+j+1] - freqs->data[id+j];
476  smoothed_ratio += (kappa->data[id+j]*df);
477  frequency_width += df;
478  }
479  kappa->data[id+half_width] = smoothed_ratio *1.0/frequency_width;
480  }
481 
482  return XLAL_SUCCESS;
483  }
484 
486  {
487  REAL8 v2 = v * v;
488  REAL8 v3 = v2 * v;
489  REAL8 v5 = v3 * v2;
490  REAL8 kappaPNnum = (21 * v2 * (1 + delta) * Chi * sin(theta));
491  REAL8 kappaPNden = 2 * (42 + 84 * LAL_PI * v3 + v2 * (55 * eta - 107) - 28 * v3 * (1 + delta - eta) * Chi * cos ( theta ));
492  REAL8 amp_ratio = kappaPNnum/kappaPNden * (1 + b * v5 );
493  return amp_ratio;
494  }
495 
496  /**
497  * Anti-symmetric phase coefficients/offsets
498  *
499  */
501  REAL8 *A0, /**< [out] A0 parameter */
502  REAL8 *phi_A0, /**< [out] phi_A0 parameter */
503  REAL8 *phi_B0, /**< [out] phi_B0 parameter */
504  const double MfT, /**< Geometric transition frequency */
505  double lina, /**< lina parameter */
506  double linb, /**< linb parameter */
507  double inveta, /**< inveta parameter */
508  IMRPhenomXWaveformStruct *pWF, /**< waveform struct */
509  IMRPhenomXPrecessionStruct *pPrec, /**< precession struct **/
510  IMRPhenomXPhaseCoefficients *pPhase22 /**< symmetric phase coefficients struct */
511  )
512  {
513  UINT4 status = 0;
514  IMRPhenomX_PNR_alpha_parameters* alphaParams = NULL;
515  alphaParams = XLALMalloc(sizeof(IMRPhenomX_PNR_alpha_parameters));
516 
517  status = IMRPhenomX_PNR_precompute_alpha_coefficients(alphaParams, pWF, pPrec);
518  XLAL_CHECK(
519  XLAL_SUCCESS == status,
520  XLAL_EFUNC,
521  "Error: IMRPhenomX_PNR_precompute_alpha_coefficients failed.\n");
522 
523  status = IMRPhenomX_PNR_alpha_connection_parameters(alphaParams, pWF, pPrec);
524  XLAL_CHECK(
525  XLAL_SUCCESS == status,
526  XLAL_EFUNC,
527  "Error: IMRPhenomX_PNR_alpha_connection_parameters failed.\n");
528 
529  REAL8 phi_der_MfT = 0.0;
530  REAL8 phi_MfT = 0.0;
531  REAL8 alpha_MfT = 0.0;
532  REAL8 alpha_der_MfT = 0.0;
533 
534  REAL8 fPhaseIN = pPhase22->fPhaseMatchIN;
535  REAL8 fPhaseIM = pPhase22->fPhaseMatchIM;
536  REAL8 C1IM = pPhase22->C1Int;
537  REAL8 C2IM = pPhase22->C2Int;
538  REAL8 C1RD = pPhase22->C1MRD;
539  REAL8 C2RD = pPhase22->C2MRD;
540 
541  IMRPhenomX_UsefulPowers powers_of_MfT;
542  IMRPhenomX_Initialize_Powers(&powers_of_MfT, MfT);
543 
544  const double deltaMF = 0.0005;
545  const double Mf_right = MfT + deltaMF;
546  const double Mf_left = MfT - deltaMF;
547 
548  REAL8 q = pWF->q;
549  REAL8 chi = pPrec->chi_singleSpin;
550 
551  /* inside callibration region */
552  if ((q <= pPrec->PNR_q_window_lower) && (chi <= pPrec->PNR_chi_window_lower))
553  {
554  alpha_der_MfT = ( IMRPhenomX_PNR_GeneratePNRAlphaAtMf(Mf_right, alphaParams, pWF, pPrec) - IMRPhenomX_PNR_GeneratePNRAlphaAtMf(Mf_left, alphaParams, pWF, pPrec) )/2/deltaMF;
555  alpha_MfT = IMRPhenomX_PNR_GeneratePNRAlphaAtMf(MfT, alphaParams, pWF, pPrec);
556  }
557  /* inside transition region */
558  else if ((q <= pPrec->PNR_q_window_upper) && (chi <= pPrec->PNR_chi_window_upper))
559  {
560  alpha_der_MfT = ( IMRPhenomX_PNR_GenerateMergedPNRAlphaAtMf(Mf_right, alphaParams, pWF, pPrec) - IMRPhenomX_PNR_GenerateMergedPNRAlphaAtMf(Mf_left, alphaParams, pWF, pPrec) )/2/deltaMF;
561  alpha_MfT = IMRPhenomX_PNR_GenerateMergedPNRAlphaAtMf(MfT, alphaParams, pWF, pPrec);
562  }
563  /* fully in outside calibration region */
564  else
565  {
566  alpha_der_MfT = ( IMRPhenomX_PNR_GetPNAlphaAtFreq(Mf_right, pWF, pPrec) - IMRPhenomX_PNR_GetPNAlphaAtFreq(Mf_left, pWF, pPrec) )/2/deltaMF;
567  alpha_MfT = IMRPhenomX_PNR_GetPNAlphaAtFreq(MfT, pWF, pPrec);
568  }
569 
570  // alpha_der_MfT = ( IMRPhenomX_PNR_GeneratePNRAlphaAtMf(Mf_right, alphaParams, pWF, pPrec) - IMRPhenomX_PNR_GeneratePNRAlphaAtMf(Mf_left, alphaParams, pWF, pPrec) )/2/deltaMF;
571  // alpha_MfT = IMRPhenomX_PNR_GeneratePNRAlphaAtMf(MfT, alphaParams, pWF, pPrec);
572 
573  if(MfT < fPhaseIN)
574  {
575  phi_der_MfT = IMRPhenomX_Inspiral_Phase_22_Ansatz(MfT, &powers_of_MfT, pPhase22);
576  phi_MfT = IMRPhenomX_Inspiral_Phase_22_AnsatzInt(MfT, &powers_of_MfT, pPhase22);
577  }
578  else if(MfT > fPhaseIM)
579  {
580  phi_der_MfT = IMRPhenomX_Ringdown_Phase_22_Ansatz(MfT, &powers_of_MfT, pWF, pPhase22) + C2RD;
581  phi_MfT = IMRPhenomX_Ringdown_Phase_22_AnsatzInt(MfT, &powers_of_MfT, pWF, pPhase22) + C1RD + (C2RD * MfT);
582  }
583  else
584  {
585  phi_der_MfT = IMRPhenomX_Intermediate_Phase_22_Ansatz(MfT, &powers_of_MfT, pWF, pPhase22) + C2IM;
586  phi_MfT = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(MfT, &powers_of_MfT, pWF, pPhase22) + C1IM + (C2IM * MfT);
587  }
588 
589  /* Scale phase by 1/eta and apply phase and time shifts */
590  IMRPhenomX_UsefulPowers powers_of_MfRef;
591  IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
592  REAL8 phiref22 = -inveta*IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF) - linb*pWF->MfRef - lina + 2.0*pWF->phi0 + LAL_PI_4;
593 
594  phi_der_MfT *= inveta;
595  phi_der_MfT += linb;
596  phi_MfT *= inveta;
597  phi_MfT += linb*MfT + lina + phiref22;
598 
599  *A0 = phi_der_MfT/2 - alpha_der_MfT;
600  *phi_A0 = pPrec-> alpha_offset;
601  *phi_B0 = alpha_MfT - phi_MfT/2 + *A0 * MfT + *phi_A0;
602 
603  LALFree(alphaParams);
604 
605  return XLAL_SUCCESS;
606  }
607 
608 #ifdef __cplusplus
609 }
610 #endif
611 
612 
void XLALDestroyDict(LALDict *dict)
LALDict * XLALDictDuplicate(LALDict *old)
LALDict * XLALCreateDict(void)
#define LALFree(p)
const double b1
const double b2
const double b0
static double double delta
double XLALSimPhenomUtilsHztoMf(REAL8 fHz, REAL8 Mtot_Msun)
Convert from frequency in Hz to geometric frequency.
#define PHENOMXDEBUG
int XLALSimIMRPhenomX_PNR_GenerateAntisymmetricAmpRatio(REAL8Sequence **kappa, REAL8Sequence **freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, REAL8 inclination, REAL8 deltaF, REAL8 f_min, REAL8 f_max, REAL8 fRef_In, LALDict *lalParams)
EXTERNAL GENERATE Antisymmetric Amplitude Ratio This is an external wrapper to generate the (2,...
int IMRPhenomX_PNR_GenerateAntisymmetricPhaseCoefficients(REAL8 *A0, REAL8 *phi_A0, REAL8 *phi_B0, const double MfT, double lina, double linb, double inveta, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, IMRPhenomXPhaseCoefficients *pPhase22)
Anti-symmetric phase coefficients/offsets.
IMRPhenomX_UsefulPowers powers_of_lalpi
int IMRPhenomX_PNR_GenerateAntisymmetricAmpRatio(REAL8Sequence *kappa, const REAL8Sequence *freqs, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
GENERATE Antisymmetric amplitude ratio.
double GetKappa_at_frequency(REAL8 v, REAL8 delta, REAL8 Chi, REAL8 theta, REAL8 eta, double b)
int IMRPhenomX_PNR_GenerateAntisymmetricWaveform(REAL8Sequence *antisymamp, REAL8Sequence *antisymphase, const REAL8Sequence *freqs, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, LALDict *lalParams)
int XLALSimIMRPhenomX_PNR_GenerateAntisymmetricWaveform(REAL8Sequence **antisymamp, REAL8Sequence **antisymphase, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, REAL8 distance, REAL8 inclination, REAL8 deltaF, REAL8 f_min, REAL8 f_max, REAL8 fRef_In, REAL8 phiRef, LALDict *lalParams)
EXTERNAL GENERATE antisymmetric waveform This is an external wrapper to generate the (2,...
int IMRPhenomX_PNR_precompute_alpha_coefficients(IMRPhenomX_PNR_alpha_parameters *alphaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function evaluates the coefficients outlined in Sec 7A of arXiv:2107.08876 for alpha.
REAL8 IMRPhenomX_PNR_GetPNAlphaAtFreq(REAL8 Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
Here we write a wrapper function to produce either MSA or NNLO alpha for use in IMRPhenomX_PNR_Genera...
REAL8 IMRPhenomX_PNR_GeneratePNRAlphaAtMf(REAL8 Mf, const IMRPhenomX_PNR_alpha_parameters *alphaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function evaluates Eq.
int IMRPhenomX_PNR_alpha_connection_parameters(IMRPhenomX_PNR_alpha_parameters *alphaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function evaluates the connection frequencies Mf1 and Mf2 detailed in Sec.
REAL8 IMRPhenomX_PNR_GenerateMergedPNRAlphaAtMf(REAL8 Mf, const IMRPhenomX_PNR_alpha_parameters *alphaParams, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec)
This function generates the blended PNR and PN expressions for alpha for the transition region of par...
static double IMRPhenomX_Inspiral_Phase_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase)
static double IMRPhenomX_Inspiral_Phase_22_AnsatzInt(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase)
Ansatz for the inspiral phase.
static double IMRPhenomX_Inspiral_Amp_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
static double IMRPhenomX_Intermediate_Phase_22_AnsatzInt(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
static double IMRPhenomX_Intermediate_Amp_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
static double IMRPhenomX_Intermediate_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
int IMRPhenomXSetWaveformVariables(IMRPhenomXWaveformStruct *wf, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1L_In, const REAL8 chi2L_In, const REAL8 deltaF, const REAL8 fRef, const REAL8 phi0, const REAL8 f_min, const REAL8 f_max, const REAL8 distance, const REAL8 inclination, LALDict *LALParams, UNUSED const UINT4 debug)
double IMRPhenomX_TimeShift_22(IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
void IMRPhenomX_Phase_22_ConnectionCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
int IMRPhenomXGetAmplitudeCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
int IMRPhenomX_Initialize_Powers(IMRPhenomX_UsefulPowers *p, REAL8 number)
double IMRPhenomX_Phase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
int IMRPhenomXGetPhaseCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
int IMRPhenomXGetAndSetPrecessionVariables(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, LALDict *lalParams, INT4 debug_flag)
Function to populate the IMRPhenomXPrecessionStruct:
static double IMRPhenomX_Ringdown_Phase_22_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
static double IMRPhenomX_Ringdown_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
static double IMRPhenomX_Ringdown_Amp_22_Ansatz(double ff, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
INT4 XLALIMRPhenomXPCheckMassesAndSpins(REAL8 *m1, REAL8 *m2, REAL8 *chi1x, REAL8 *chi1y, REAL8 *chi1z, REAL8 *chi2x, REAL8 *chi2y, REAL8 *chi2z)
Check if m1 > m2.
int XLALSimInspiralWaveformParamsInsertPhenomXPNRUseTunedAngles(LALDict *params, INT4 value)
int XLALSimInspiralWaveformParamsInsertPhenomXAntisymmetricWaveform(LALDict *params, INT4 value)
INT4 XLALSimInspiralWaveformParamsLookupPhenomXPNRUseTunedAngles(LALDict *params)
REAL8 M
Definition: bh_qnmode.c:133
double i
Definition: bh_ringdown.c:118
double theta
Definition: bh_sphwf.c:118
#define LAL_PI
#define LAL_PI_4
double REAL8
uint32_t UINT4
void * XLALMalloc(size_t n)
int IMRPhenomX_PNR_GeneratePNRAlphaForAntisymmetry(REAL8Sequence *alphaPNR, const REAL8Sequence *freqs, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, LALDict *lalParams)
Internal helper function to generate PNR alpha for the antisymmetric waveform.
static const INT4 q
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_WARNING(...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
string status
IMRPhenomXWaveformStruct * pWF22AS
REAL8 chi_singleSpin_antisymmetric
magnitude of effective single spin of a two spin system for the antisymmetric waveform
REAL8 chi_singleSpin
Magnitude of effective single spin used for tapering two-spin angles, Eq.
REAL8 theta_antisymmetric
Polar angle effective single spin for antisymmetric waveform.
REAL8 * data
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23