LALSimulation  5.4.0.1-89842e6
LALSimIMRPhenomD.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Michael Puerrer, Sebastian Khan, Frank Ohme, Ofek Birnholtz, Lionel London
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 
21 #include <math.h>
22 #include <gsl/gsl_math.h>
24 #include <lal/Sequence.h>
25 
27 #include "LALSimIMRPhenomUtils.h"
28 
29 UsefulPowers powers_of_pi; // declared in LALSimIMRPhenomD_internals.c
30 
31 #ifndef _OPENMP
32 #define omp ignore
33 #endif
34 
35 /*
36  * private function prototypes; all internal functions use solar masses.
37  *
38  */
39 
40 static int IMRPhenomDGenerateFD(
41  COMPLEX16FrequencySeries **htilde, /**< [out] FD waveform */
42  const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */
43  double deltaF, /**< If deltaF > 0, the frequency points given in freqs are uniformly spaced with
44  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
45  * Then we will use deltaF = 0 to create the frequency series we return. */
46  const REAL8 phi0, /**< phase at fRef */
47  const REAL8 fRef, /**< reference frequency [Hz] */
48  const REAL8 m1_in, /**< mass of companion 1 [solar masses] */
49  const REAL8 m2_in, /**< mass of companion 2 [solar masses] */
50  const REAL8 chi1_in, /**< aligned-spin of companion 1 */
51  const REAL8 chi2_in, /**< aligned-spin of companion 2 */
52  const REAL8 distance, /**< distance to source (m) */
53  LALDict *extraParams, /**< linked list containing the extra testing GR parameters */
54  NRTidal_version_type NRTidal_version /**< NRTidal version; either NRTidal_V or NRTidalv2_V or NoNRT_V in case of BBH baseline */
55 );
56 
57 /**
58  * @addtogroup LALSimIMRPhenom_c
59  * @{
60  *
61  * @name Routines for IMR Phenomenological Model "D"
62  * @{
63  *
64  * @author Michael Puerrer, Sebastian Khan, Frank Ohme
65  *
66  * @brief C code for IMRPhenomD phenomenological waveform model.
67  *
68  * This is an aligned-spin frequency domain model.
69  * See Husa et al \cite Husa:2015iqa, and Khan et al \cite Khan:2015jqa
70  * for details. Any studies that use this waveform model should include
71  * a reference to both of these papers.
72  *
73  * @note The model was calibrated to mass-ratios [1:1,1:4,1:8,1:18].
74  * * Along the mass-ratio 1:1 line it was calibrated to spins [-0.95, +0.98].
75  * * Along the mass-ratio 1:4 line it was calibrated to spins [-0.75, +0.75].
76  * * Along the mass-ratio 1:8 line it was calibrated to spins [-0.85, +0.85].
77  * * Along the mass-ratio 1:18 line it was calibrated to spins [-0.8, +0.4].
78  * The calibration points will be given in forthcoming papers.
79  *
80  * @attention The model is usable outside this parameter range,
81  * and in tests to date gives sensible physical results,
82  * but conclusive statements on the physical fidelity of
83  * the model for these parameters await comparisons against further
84  * numerical-relativity simulations. For more information, see the review wiki
85  * under https://www.lsc-group.phys.uwm.edu/ligovirgo/cbcnote/WaveformsReview/IMRPhenomDCodeReview
86  */
87 
88 
89 /**
90  * Driver routine to compute the spin-aligned, inspiral-merger-ringdown
91  * phenomenological waveform IMRPhenomD in the frequency domain.
92  *
93  * Reference:
94  * - Waveform: Eq. 35 and 36 in arXiv:1508.07253
95  * - Coefficients: Eq. 31 and Table V in arXiv:1508.07253
96  *
97  * All input parameters should be in SI units. Angles should be in radians.
98  *
99  * Compute waveform in LAL format for the IMRPhenomD model.
100  *
101  * Returns the plus and cross polarizations as a complex frequency series with
102  * equal spacing deltaF and contains zeros from zero frequency to the starting
103  * frequency fLow and zeros beyond the cutoff frequency in the ringdown.
104  */
106  COMPLEX16FrequencySeries **htilde, /**< [out] FD waveform */
107  const REAL8 phi0, /**< Orbital phase at fRef (rad) */
108  const REAL8 fRef_in, /**< reference frequency (Hz) */
109  const REAL8 deltaF, /**< Sampling frequency (Hz) */
110  const REAL8 m1_SI, /**< Mass of companion 1 (kg) */
111  const REAL8 m2_SI, /**< Mass of companion 2 (kg) */
112  const REAL8 chi1, /**< Aligned-spin parameter of companion 1 */
113  const REAL8 chi2, /**< Aligned-spin parameter of companion 2 */
114  const REAL8 f_min, /**< Starting GW frequency (Hz) */
115  const REAL8 f_max, /**< End frequency; 0 defaults to Mf = \ref f_CUT */
116  const REAL8 distance, /**< Distance of source (m) */
117  LALDict *extraParams, /**< linked list containing the extra testing GR parameters */
118  NRTidal_version_type NRTidal_version /**< Version of NRTides; can be one of NRTidal versions or NoNRT_V for the BBH baseline */
119 ) {
120  /* external: SI; internal: solar masses */
121  const REAL8 m1 = m1_SI / LAL_MSUN_SI;
122  const REAL8 m2 = m2_SI / LAL_MSUN_SI;
123 
124  /* check inputs for sanity */
125  XLAL_CHECK(0 != htilde, XLAL_EFAULT, "htilde is null");
126  if (*htilde) XLAL_ERROR(XLAL_EFAULT);
127  if (fRef_in < 0) XLAL_ERROR(XLAL_EDOM, "fRef_in must be positive (or 0 for 'ignore')\n");
128  if (deltaF <= 0) XLAL_ERROR(XLAL_EDOM, "deltaF must be positive\n");
129  if (m1 <= 0) XLAL_ERROR(XLAL_EDOM, "m1 must be positive\n");
130  if (m2 <= 0) XLAL_ERROR(XLAL_EDOM, "m2 must be positive\n");
131  if (f_min <= 0) XLAL_ERROR(XLAL_EDOM, "f_min must be positive\n");
132  if (f_max < 0) XLAL_ERROR(XLAL_EDOM, "f_max must be greater than 0\n");
133  if (distance <= 0) XLAL_ERROR(XLAL_EDOM, "distance must be positive\n");
134 
135  const REAL8 q = (m1 > m2) ? (m1 / m2) : (m2 / m1);
136 
138  XLAL_PRINT_WARNING("Warning: The model is not supported for high mass ratio, see MAX_ALLOWED_MASS_RATIO\n");
139 
140  if (chi1 > 1.0 || chi1 < -1.0 || chi2 > 1.0 || chi2 < -1.0)
141  XLAL_ERROR(XLAL_EDOM, "Spins outside the range [-1,1] are not supported\n");
142 
143  // if no reference frequency given, set it to the starting GW frequency
144  REAL8 fRef = (fRef_in == 0.0) ? f_min : fRef_in;
145 
146  const REAL8 M_sec = (m1+m2) * LAL_MTSUN_SI; // Conversion factor Hz -> dimensionless frequency
147  const REAL8 fCut = f_CUT/M_sec; // convert Mf -> Hz
148  // Somewhat arbitrary end point for the waveform.
149  // Chosen so that the end of the waveform is well after the ringdown.
150  if (fCut <= f_min)
151  XLAL_ERROR(XLAL_EDOM, "(fCut = %g Hz) <= f_min = %g\n", fCut, f_min);
152 
153  /* default f_max to Cut */
154  REAL8 f_max_prime = f_max;
155  f_max_prime = f_max ? f_max : fCut;
156  f_max_prime = (f_max_prime > fCut) ? fCut : f_max_prime;
157  if (f_max_prime <= f_min)
158  XLAL_ERROR(XLAL_EDOM, "f_max <= f_min\n");
159 
160  // Use fLow, fHigh, deltaF to compute freqs sequence
161  // Instead of building a full sequency we only transfer the boundaries and let
162  // the internal core function do the rest (and properly take care of corner cases).
164  freqs->data[0] = f_min;
165  freqs->data[1] = f_max_prime;
166  int status = IMRPhenomDGenerateFD(htilde, freqs, deltaF, phi0, fRef,
167  m1, m2, chi1, chi2,
168  distance, extraParams, NRTidal_version);
169  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to generate IMRPhenomD waveform.");
171 
172  if (f_max_prime < f_max) {
173  // The user has requested a higher f_max than Mf=fCut.
174  // Resize the frequency series to fill with zeros beyond the cutoff frequency.
175  size_t n = (*htilde)->data->length;
176  size_t n_full = NextPow2(f_max / deltaF) + 1; // we actually want to have the length be a power of 2 + 1
177  *htilde = XLALResizeCOMPLEX16FrequencySeries(*htilde, 0, n_full);
178  XLAL_CHECK ( *htilde, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, fCut, n_full, f_max );
179  }
180 
181  return XLAL_SUCCESS;
182 }
183 
184 /**
185  * Compute waveform in LAL format at specified frequencies for the IMRPhenomD model.
186  *
187  * XLALSimIMRPhenomDGenerateFD() returns the plus and cross polarizations as a complex
188  * frequency series with equal spacing deltaF and contains zeros from zero frequency
189  * to the starting frequency and zeros beyond the cutoff frequency in the ringdown.
190  *
191  * In contrast, XLALSimIMRPhenomDFrequencySequence() returns a
192  * complex frequency series with entries exactly at the frequencies specified in
193  * the sequence freqs (which can be unequally spaced). No zeros are added.
194  *
195  * If XLALSimIMRPhenomDFrequencySequence() is called with frequencies that
196  * are beyond the maxium allowed geometric frequency for the ROM, zero strain is returned.
197  *
198  * This function is designed as an entry point for reduced order quadratures.
199  */
201  COMPLEX16FrequencySeries **htilde, /**< [out] FD waveform */
202  const REAL8Sequence *freqs, /**< Frequency points at which to evaluate the waveform (Hz) */
203  const REAL8 phi0, /**< Orbital phase at fRef (rad) */
204  const REAL8 fRef_in, /**< reference frequency (Hz) */
205  const REAL8 m1_SI, /**< Mass of companion 1 (kg) */
206  const REAL8 m2_SI, /**< Mass of companion 2 (kg) */
207  const REAL8 chi1, /**< Aligned-spin parameter of companion 1 */
208  const REAL8 chi2, /**< Aligned-spin parameter of companion 2 */
209  const REAL8 distance, /**< Distance of source (m) */
210  LALDict *extraParams, /**< linked list containing the extra testing GR parameters */
211  NRTidal_version_type NRTidal_version /**< NRTidal version; either NRTidal_V or NRTidalv2_V or NoNRT_V in case of BBH baseline */
212 ) {
213  /* external: SI; internal: solar masses */
214  const REAL8 m1 = m1_SI / LAL_MSUN_SI;
215  const REAL8 m2 = m2_SI / LAL_MSUN_SI;
216 
217  /* check inputs for sanity */
218  XLAL_CHECK(0 != htilde, XLAL_EFAULT, "htilde is null");
219  if (*htilde) XLAL_ERROR(XLAL_EFAULT);
220  if (!freqs) XLAL_ERROR(XLAL_EFAULT);
221  if (fRef_in < 0) XLAL_ERROR(XLAL_EDOM, "fRef_in must be positive (or 0 for 'ignore')\n");
222  if (m1 <= 0) XLAL_ERROR(XLAL_EDOM, "m1 must be positive\n");
223  if (m2 <= 0) XLAL_ERROR(XLAL_EDOM, "m2 must be positive\n");
224  if (distance <= 0) XLAL_ERROR(XLAL_EDOM, "distance must be positive\n");
225 
226  const REAL8 q = (m1 > m2) ? (m1 / m2) : (m2 / m1);
227 
229  XLAL_PRINT_WARNING("Warning: The model is not supported for high mass ratio, see MAX_ALLOWED_MASS_RATIO\n");
230 
231  if (chi1 > 1.0 || chi1 < -1.0 || chi2 > 1.0 || chi2 < -1.0)
232  XLAL_ERROR(XLAL_EDOM, "Spins outside the range [-1,1] are not supported\n");
233 
234  // if no reference frequency given, set it to the starting GW frequency
235  REAL8 fRef = (fRef_in == 0.0) ? freqs->data[0] : fRef_in;
236 
237  int status = IMRPhenomDGenerateFD(htilde, freqs, 0, phi0, fRef,
238  m1, m2, chi1, chi2,
239  distance, extraParams, NRTidal_version);
240  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to generate IMRPhenomD waveform.");
241 
242  return XLAL_SUCCESS;
243 }
244 
245 
246 /** @} */
247 
248 /** @} */
249 
250 /* *********************************************************************************/
251 /* The following private function generates IMRPhenomD frequency-domain waveforms */
252 /* given coefficients */
253 /* *********************************************************************************/
254 
256  COMPLEX16FrequencySeries **htilde, /**< [out] FD waveform */
257  const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */
258  double deltaF, /* If deltaF > 0, the frequency points given in freqs are uniformly spaced with
259  * spacing deltaF. Otherwise, the frequency points are spaced non-uniformly.
260  * Then we will use deltaF = 0 to create the frequency series we return. */
261  const REAL8 phi0, /**< phase at fRef */
262  const REAL8 fRef, /**< reference frequency [Hz] */
263  const REAL8 m1_in, /**< mass of companion 1 [solar masses] */
264  const REAL8 m2_in, /**< mass of companion 2 [solar masses] */
265  const REAL8 chi1_in, /**< aligned-spin of companion 1 */
266  const REAL8 chi2_in, /**< aligned-spin of companion 2 */
267  const REAL8 distance, /**< distance to source (m) */
268  LALDict *extraParams, /**< linked list containing the extra testing GR parameters */
269  NRTidal_version_type NRTidal_version /**< NRTidal version; either NRTidal_V or NRTidalv2_V or NoNRT_V in case of BBH baseline */
270 ) {
271  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0, 0}
272 
273  // Make a pointer to LALDict to circumvent a memory leak
274  // At the end we will check if we created a LALDict in extraParams
275  // and destroy it if we did.
276  LALDict *extraParams_in = extraParams;
277  REAL8Sequence *amp_tidal = NULL; /* Tidal amplitude series; required only for IMRPhenomD_NRTidalv2 */
278  REAL8 dquadmon1_in = 0., dquadmon2_in = 0., lambda1_in = 0, lambda2_in = 0.;
279  if (NRTidal_version == NRTidalv2_V) {
280  dquadmon1_in = XLALSimInspiralWaveformParamsLookupdQuadMon1(extraParams);
281  dquadmon2_in = XLALSimInspiralWaveformParamsLookupdQuadMon2(extraParams);
282  lambda1_in = XLALSimInspiralWaveformParamsLookupTidalLambda1(extraParams);
283  lambda2_in = XLALSimInspiralWaveformParamsLookupTidalLambda2(extraParams);
284  }
285 
286  REAL8 chi1, chi2, m1, m2, dquadmon1, dquadmon2, lambda1, lambda2;
287  if (m1_in>=m2_in) {
288  chi1 = chi1_in;
289  chi2 = chi2_in;
290  m1 = m1_in;
291  m2 = m2_in;
292  dquadmon1 = dquadmon1_in;
293  dquadmon2 = dquadmon2_in;
294  lambda1 = lambda1_in;
295  lambda2 = lambda2_in;
296  } else { // swap spins and masses
297  chi1 = chi2_in;
298  chi2 = chi1_in;
299  m1 = m2_in;
300  m2 = m1_in;
301  dquadmon1 = dquadmon2_in;
302  dquadmon2 = dquadmon1_in;
303  lambda1 = lambda2_in;
304  lambda2 = lambda1_in;
305  if (NRTidal_version == NRTidalv2_V) {
306  XLALSimInspiralWaveformParamsInsertdQuadMon1(extraParams, dquadmon1);
307  XLALSimInspiralWaveformParamsInsertdQuadMon2(extraParams, dquadmon2);
308  }
309  }
310 
312  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initiate useful powers of pi.");
313 
314  /* Find frequency bounds */
315  if (!freqs_in || !freqs_in->data) XLAL_ERROR(XLAL_EFAULT);
316  double f_min = freqs_in->data[0];
317  double f_max = freqs_in->data[freqs_in->length - 1];
318  XLAL_CHECK(f_min > 0, XLAL_EDOM, "Minimum frequency must be positive.\n");
319  XLAL_CHECK(f_max >= 0, XLAL_EDOM, "Maximum frequency must be non-negative.\n");
320 
321  const REAL8 M = m1 + m2;
322  REAL8 eta = m1 * m2 / (M * M);
323 
324  if (eta > 0.25)
325  PhenomInternal_nudge(&eta, 0.25, 1e-6);
326  if (eta > 0.25 || eta < 0.0)
327  XLAL_ERROR(XLAL_EDOM, "Unphysical eta. Must be between 0. and 0.25\n");
328 
329  const REAL8 M_sec = M * LAL_MTSUN_SI;
330 
331  /* Compute the amplitude pre-factor */
332  const REAL8 amp0 = 2. * sqrt(5. / (64.*LAL_PI)) * M * LAL_MRSUN_SI * M * LAL_MTSUN_SI / distance;
333 
334  size_t npts = 0;
335  UINT4 offset = 0; // Index shift between freqs and the frequency series
336  REAL8Sequence *freqs = NULL;
337  if (deltaF > 0) { // freqs contains uniform frequency grid with spacing deltaF; we start at frequency 0
338  /* Set up output array with size closest power of 2 */
339  npts = NextPow2(f_max / deltaF) + 1;
340  /* Coalesce at t=0 */
341  // shift by overall length in time
342  XLAL_CHECK ( XLALGPSAdd(&ligotimegps_zero, -1. / deltaF), XLAL_EFUNC, "Failed to shift coalescence time to t=0, tried to apply shift of -1.0/deltaF with deltaF=%g.", deltaF);
343  *htilde = XLALCreateCOMPLEX16FrequencySeries("htilde: FD waveform", &ligotimegps_zero, 0.0, deltaF, &lalStrainUnit, npts);
344  XLAL_CHECK ( *htilde, XLAL_ENOMEM, "Failed to allocated waveform COMPLEX16FrequencySeries of length %zu for f_max=%f, deltaF=%g.", npts, f_max, deltaF);
345  // Recreate freqs using only the lower and upper bounds
346  size_t iStart = (size_t) (f_min / deltaF);
347  size_t iStop = (size_t) (f_max / deltaF);
348  XLAL_CHECK ( (iStop<=npts) && (iStart<=iStop), XLAL_EDOM, "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
349  freqs = XLALCreateREAL8Sequence(iStop - iStart);
350  if (!freqs)
351  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
352  for (UINT4 i=iStart; i<iStop; i++)
353  freqs->data[i-iStart] = i*deltaF;
354  offset = iStart;
355  } else { // freqs contains frequencies with non-uniform spacing; we start at lowest given frequency
356  npts = freqs_in->length;
357  *htilde = XLALCreateCOMPLEX16FrequencySeries("htilde: FD waveform", &ligotimegps_zero, f_min, deltaF, &lalStrainUnit, npts);
358  XLAL_CHECK ( *htilde, XLAL_ENOMEM, "Failed to allocated waveform COMPLEX16FrequencySeries of length %zu from sequence.", npts);
359  offset = 0;
360  freqs = XLALCreateREAL8Sequence(freqs_in->length);
361  if (!freqs)
362  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
363  for (UINT4 i=0; i<freqs_in->length; i++)
364  freqs->data[i] = freqs_in->data[i];
365  }
366 
367  memset((*htilde)->data->data, 0, npts * sizeof(COMPLEX16));
368  XLALUnitMultiply(&((*htilde)->sampleUnits), &((*htilde)->sampleUnits), &lalSecondUnit);
369 
370  // Calculate phenomenological parameters
371  const REAL8 finspin = FinalSpin0815(eta, chi1, chi2); //FinalSpin0815 - 0815 is like a version number
372 
373  if (finspin < MIN_FINAL_SPIN)
374  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
375  the model might misbehave here.", finspin);
376 
379  ComputeIMRPhenomDAmplitudeCoefficients(pAmp, eta, chi1, chi2, finspin);
380  if (!pAmp) XLAL_ERROR(XLAL_EFUNC);
381  if (extraParams==NULL)
382  extraParams=XLALCreateDict();
385  pPhi = XLALMalloc(sizeof(IMRPhenomDPhaseCoefficients));
386  ComputeIMRPhenomDPhaseCoefficients(pPhi, eta, chi1, chi2, finspin, extraParams);
387  if (!pPhi) XLAL_ERROR(XLAL_EFUNC);
388  PNPhasingSeries *pn = NULL;
389  XLALSimInspiralTaylorF2AlignedPhasing(&pn, m1, m2, chi1, chi2, extraParams);
390  if (!pn) XLAL_ERROR(XLAL_EFUNC);
391 
392  // Subtract 3PN spin-spin term below as this is in LAL's TaylorF2 implementation
393  // (LALSimInspiralPNCoefficients.c -> XLALSimInspiralPNPhasing_F2), but
394  REAL8 testGRcor=1.0;
395  testGRcor += XLALSimInspiralWaveformParamsLookupNonGRDChi6(extraParams);
396 
397  // was not available when PhenomD was tuned.
398  pn->v[6] -= (Subtract3PNSS(m1, m2, M, eta, chi1, chi2) * pn->v[0]) * testGRcor;
399 
400  PhiInsPrefactors phi_prefactors;
401  status = init_phi_ins_prefactors(&phi_prefactors, pPhi, pn);
402  XLAL_CHECK(XLAL_SUCCESS == status, status, "init_phi_ins_prefactors failed");
403 
404  // Compute coefficients to make phase C^1 continuous (phase and first derivative)
405  ComputeIMRPhenDPhaseConnectionCoefficients(pPhi, pn, &phi_prefactors, 1.0, 1.0);
406 
407  //time shift so that peak amplitude is approximately at t=0
408  //For details see https://www.lsc-group.phys.uwm.edu/ligovirgo/cbcnote/WaveformsReview/IMRPhenomDCodeReview/timedomain
409  const REAL8 t0 = DPhiMRD(pAmp->fmaxCalc, pPhi, 1.0, 1.0);
410 
411  AmpInsPrefactors amp_prefactors;
412  status = init_amp_ins_prefactors(&amp_prefactors, pAmp);
413  XLAL_CHECK(XLAL_SUCCESS == status, status, "init_amp_ins_prefactors failed");
414 
415  // incorporating fRef
416  const REAL8 MfRef = M_sec * fRef;
417  UsefulPowers powers_of_fRef;
418  status = init_useful_powers(&powers_of_fRef, MfRef);
419  XLAL_CHECK(XLAL_SUCCESS == status, status, "init_useful_powers failed for MfRef");
420  const REAL8 phifRef = IMRPhenDPhase(MfRef, pPhi, pn, &powers_of_fRef, &phi_prefactors, 1.0, 1.0);
421 
422  // factor of 2 b/c phi0 is orbital phase
423  const REAL8 phi_precalc = 2.*phi0 + phifRef;
424 
425  int status_in_for = XLAL_SUCCESS;
426  int ret = XLAL_SUCCESS;
427  /* Now generate the waveform */
428  if (NRTidal_version == NRTidalv2_V) {
429  /* Generate the tidal amplitude (Eq. 24 of arxiv: 1905.06011) to add to BBH baseline; only for IMRPhenomD_NRTidalv2 */
430  amp_tidal = XLALCreateREAL8Sequence(freqs->length);
431  ret = XLALSimNRTunedTidesFDTidalAmplitudeFrequencySeries(amp_tidal, freqs, m1, m2, lambda1, lambda2);
432  XLAL_CHECK(XLAL_SUCCESS == ret, ret, "Failed to generate tidal amplitude series to construct IMRPhenomD_NRTidalv2 waveform.");
433  /* Generated tidal amplitude corrections */
434  #pragma omp parallel for
435  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
436  double Mf = M_sec * freqs->data[i];
437  double ampT = amp_tidal->data[i];
438  int j = i + offset; // shift index for frequency series if needed
439 
440  UsefulPowers powers_of_f;
441  status_in_for = init_useful_powers(&powers_of_f, Mf);
442  if (XLAL_SUCCESS != status_in_for)
443  {
444  XLALPrintError("init_useful_powers failed for Mf, status_in_for=%d", status_in_for);
445  status = status_in_for;
446  }
447  else {
448  REAL8 amp = IMRPhenDAmplitude(Mf, pAmp, &powers_of_f, &amp_prefactors);
449  REAL8 phi = IMRPhenDPhase(Mf, pPhi, pn, &powers_of_f, &phi_prefactors, 1.0, 1.0);
450 
451  phi -= t0*(Mf-MfRef) + phi_precalc;
452  ((*htilde)->data->data)[j] = amp0 * (amp+2*sqrt(LAL_PI/5.)*ampT) * cexp(-I * phi);
453  }
454  }
455  } else {
456  #pragma omp parallel for
457  for (UINT4 i=0; i<freqs->length; i++) { // loop over frequency points in sequence
458  double Mf = M_sec * freqs->data[i];
459  int j = i + offset; // shift index for frequency series if needed
460 
461  UsefulPowers powers_of_f;
462  status_in_for = init_useful_powers(&powers_of_f, Mf);
463  if (XLAL_SUCCESS != status_in_for)
464  {
465  XLALPrintError("init_useful_powers failed for Mf, status_in_for=%d", status_in_for);
466  status = status_in_for;
467  }
468  else {
469  REAL8 amp = IMRPhenDAmplitude(Mf, pAmp, &powers_of_f, &amp_prefactors);
470  REAL8 phi = IMRPhenDPhase(Mf, pPhi, pn, &powers_of_f, &phi_prefactors, 1.0, 1.0);
471 
472  phi -= t0*(Mf-MfRef) + phi_precalc;
473  ((*htilde)->data->data)[j] = amp0 * amp * cexp(-I * phi);
474  }
475  }
476  }
477 
478  LALFree(pAmp);
479  LALFree(pPhi);
480  LALFree(pn);
482  XLALDestroyREAL8Sequence(amp_tidal);
483 
484 
485  /* If extraParams was allocated in this function and not passed in
486  * we need to free it to prevent a leak */
487  if (extraParams && !extraParams_in) {
488  XLALDestroyDict(extraParams);
489  } else {
491  }
492 
493  return status;
494 }
495 
496 ////////////////////////////////////////////////
497 // END OF REVIEWED CODE ////////////////////////
498 ////////////////////////////////////////////////
499 
500 /**
501  * Function to return the frequency (in Hz) of the peak of the frequency
502  * domain amplitude for the IMRPhenomD model.
503  *
504  * The peak is a parameter in the PhenomD model given by Eq. 20 in 1508.07253
505  * where it is called f_peak in the paper.
506  */
508  const REAL8 m1_in, /**< mass of companion 1 [Msun] */
509  const REAL8 m2_in, /**< mass of companion 2 [Msun] */
510  const REAL8 chi1_in, /**< aligned-spin of companion 1 */
511  const REAL8 chi2_in /**< aligned-spin of companion 2 */
512 ) {
513  // Ensure that m1 > m2 and that chi1 is the spin on m1
514  REAL8 chi1, chi2, m1, m2;
515  if (m1_in>m2_in) {
516  chi1 = chi1_in;
517  chi2 = chi2_in;
518  m1 = m1_in;
519  m2 = m2_in;
520  } else { // swap spins and masses
521  chi1 = chi2_in;
522  chi2 = chi1_in;
523  m1 = m2_in;
524  m2 = m1_in;
525  }
526 
527  const REAL8 M = m1 + m2;
528  const REAL8 M_sec = M * LAL_MTSUN_SI; // Conversion factor Hz -> dimensionless frequency
529 
530  REAL8 eta = m1 * m2 / (M * M);
531 
532  if (eta > 0.25)
533  PhenomInternal_nudge(&eta, 0.25, 1e-6);
534  if (eta > 0.25 || eta < 0.0)
535  XLAL_ERROR(XLAL_EDOM, "Unphysical eta. Must be between 0. and 0.25\n");
536 
537  // Calculate phenomenological parameters
538  REAL8 finspin = FinalSpin0815(eta, chi1, chi2);
539 
540  if (finspin < MIN_FINAL_SPIN)
541  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
542  the model might misbehave here.", finspin);
545  ComputeIMRPhenomDAmplitudeCoefficients(pAmp, eta, chi1, chi2, finspin);
546  if (!pAmp) XLAL_ERROR(XLAL_EFUNC);
547 
548  // PeakFreq, converted to Hz
549  REAL8 PeakFreq = ( pAmp->fmaxCalc ) / M_sec;
550 
551  LALFree(pAmp);
552 
553  return PeakFreq;
554 }
555 
556 
557 // protoype
559 
560 /**
561  * Helper function to return the value of the frequency derivative of the
562  * Fourier domain phase.
563  * This is function is wrapped by IMRPhenomDPhaseDerivative and used
564  * when estimating the length of the time domain version of the waveform.
565  * unreviewed
566  */
568 {
569 
570  // split the calculation to just 1 of 3 possible mutually exclusive ranges
571 
572  if (!StepFunc_boolean(Mf, p->fInsJoin)) // Inspiral range
573  {
574  double DPhiIns = DPhiInsAnsatzInt(Mf, p, pn);
575  return DPhiIns;
576  }
577 
578  if (StepFunc_boolean(Mf, p->fMRDJoin)) // MRD range
579  {
580  double DPhiMRDval = DPhiMRD(Mf, p, 1.0, 1.0) + p->C2MRD;
581  return DPhiMRDval;
582  }
583 
584  // Intermediate range
585  double DPhiInt = DPhiIntAnsatz(Mf, p) + p->C2Int;
586  return DPhiInt;
587 }
588 
589 /**
590 * Estimates the length of the time domain IMRPhenomD signal
591 * This does NOT taking into account any tapering that is used to condition the
592 * Fourier domain waveform to compute the inverse Fourer transform.
593 * To estimate the length we assume that the waveform only reaches the
594 * the highest physics frequency i.e. the ringdown frequency.
595 * unreviewed
596 */
598  const REAL8 m1_SI, /**< Mass of companion 1 (kg) */
599  const REAL8 m2_SI, /**< Mass of companion 2 (kg) */
600  const REAL8 chi1_in, /**< aligned-spin of companion 1 */
601  const REAL8 chi2_in, /**< aligned-spin of companion 2 */
602  const REAL8 fHzSt /**< arbitrary starting frequency in Hz */
603 ) {
604 
605  if (fHzSt <= 0) XLAL_ERROR(XLAL_EDOM, "fHzSt must be positive\n");
606 
607  if (chi1_in > 1.0 || chi1_in < -1.0 || chi2_in > 1.0 || chi2_in < -1.0)
608  XLAL_ERROR(XLAL_EDOM, "Spins outside the range [-1,1] are not supported\n");
609 
610  /* external: SI; internal: solar masses */
611  const REAL8 m1_in = m1_SI / LAL_MSUN_SI;
612  const REAL8 m2_in = m2_SI / LAL_MSUN_SI;
613 
614  REAL8 chi1, chi2, m1, m2;
615  if (m1_in>m2_in) {
616  chi1 = chi1_in;
617  chi2 = chi2_in;
618  m1 = m1_in;
619  m2 = m2_in;
620  } else { // swap spins and masses
621  chi1 = chi2_in;
622  chi2 = chi1_in;
623  m1 = m2_in;
624  m2 = m1_in;
625  }
626 
627  // check that starting frequency is not higher than the peak frequency
628  const REAL8 fHzPeak = XLALIMRPhenomDGetPeakFreq(m1, m2, chi1, chi2);
629  if (fHzSt > fHzPeak){
630  XLAL_PRINT_WARNING("Starting frequency = %f Hz is higher IMRPhenomD peak frequency %f Hz. Results may be unreliable.", fHzSt, fHzPeak);
631  }
632 
634  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initiate useful powers of pi.");
635 
636  const REAL8 M = m1 + m2;
637  REAL8 eta = m1 * m2 / (M * M);
638 
639  if (eta > 0.25)
640  PhenomInternal_nudge(&eta, 0.25, 1e-6);
641  if (eta > 0.25 || eta < 0.0)
642  XLAL_ERROR(XLAL_EDOM, "Unphysical eta. Must be between 0. and 0.25\n");
643 
644  // compute geometric frequency
645  const REAL8 M_sec = M * LAL_MTSUN_SI;
646  const REAL8 MfSt = M_sec * fHzSt;
647 
648  // Calculate phenomenological parameters
649  const REAL8 finspin = FinalSpin0815(eta, chi1, chi2); //FinalSpin0815 - 0815 is like a version number
650 
651  if (finspin < MIN_FINAL_SPIN)
652  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
653  the model might misbehave here.", finspin);
654  LALDict *extraParams = NULL;
655  if (extraParams == NULL)
656  extraParams = XLALCreateDict();
659  pPhi = XLALMalloc(sizeof(IMRPhenomDPhaseCoefficients));
660  ComputeIMRPhenomDPhaseCoefficients(pPhi, eta, chi1, chi2, finspin, extraParams);
661  if (!pPhi) XLAL_ERROR(XLAL_EFUNC);
662  PNPhasingSeries *pn = NULL;
663  XLALSimInspiralTaylorF2AlignedPhasing(&pn, m1, m2, chi1, chi2, extraParams);
664  if (!pn) XLAL_ERROR(XLAL_EFUNC);
665 
666  // Subtract 3PN spin-spin term below as this is in LAL's TaylorF2 implementation
667  // (LALSimInspiralPNCoefficients.c -> XLALSimInspiralPNPhasing_F2), but
668  // was not available when PhenomD was tuned.
669  pn->v[6] -= (Subtract3PNSS(m1, m2, M, eta, chi1, chi2) * pn->v[0]);
670 
671 
672  PhiInsPrefactors phi_prefactors;
673  status = init_phi_ins_prefactors(&phi_prefactors, pPhi, pn);
674  XLAL_CHECK(XLAL_SUCCESS == status, status, "init_phi_ins_prefactors failed");
675 
676  // Compute coefficients to make phase C^1 continuous (phase and first derivative)
677  ComputeIMRPhenDPhaseConnectionCoefficients(pPhi, pn, &phi_prefactors, 1.0, 1.0);
678 
679  // We estimate the length of the time domain signal (i.e., the chirp time)
680  // By computing the difference between the values of the Fourier domain
681  // phase derivative at two frequencies.
682  // Here the starting frequency is an input i.e., fHzSt, converted to Geometric units MfSt
683  // and the ending frequency is fixed to be the frequency of the amplitude peak in Geometric units MfPeak
684  // XLALIMRPhenomDGetPeakFreq output is in Hz, covert to Mf via / M_sec
685  const REAL8 MfPeak = XLALIMRPhenomDGetPeakFreq(m1, m2, chi1, chi2) / M_sec;
686 
687  // Compute phase derivative at starting frequency
688  const REAL8 dphifSt = PhenDPhaseDerivFrequencyPoint(MfSt, pPhi, pn);
689  // Compute phase derivative at ending (ringdown) frequency
690  const REAL8 dphifRD = PhenDPhaseDerivFrequencyPoint(MfPeak, pPhi, pn);
691  const REAL8 dphidiff = dphifRD - dphifSt;
692 
693  // The length of time is estimated as dphidiff / 2 / pi * M (In units of seconds)
694  const REAL8 ChirpTimeSec = dphidiff / 2. / LAL_PI * M_sec;
695 
696  LALFree(pPhi);
697  LALFree(pn);
698 
699  return ChirpTimeSec;
700 
701 }
702 
703 /**
704 * Function to return the final spin (spin of the remnant black hole)
705 * as predicted by the IMRPhenomD model. The final spin is calculated using
706 * the phenomenological fit described in PhysRevD.93.044006 Eq. 3.6.
707 * unreviewed
708 */
710  const REAL8 m1_in, /**< mass of companion 1 [Msun] */
711  const REAL8 m2_in, /**< mass of companion 2 [Msun] */
712  const REAL8 chi1_in, /**< aligned-spin of companion 1 */
713  const REAL8 chi2_in /**< aligned-spin of companion 2 */
714 ) {
715  // Ensure that m1 > m2 and that chi1 is the spin on m1
716  REAL8 chi1, chi2, m1, m2;
717  if (m1_in>m2_in) {
718  chi1 = chi1_in;
719  chi2 = chi2_in;
720  m1 = m1_in;
721  m2 = m2_in;
722  } else { // swap spins and masses
723  chi1 = chi2_in;
724  chi2 = chi1_in;
725  m1 = m2_in;
726  m2 = m1_in;
727  }
728 
729  const REAL8 M = m1 + m2;
730  REAL8 eta = m1 * m2 / (M * M);
731 
732  if (eta > 0.25)
733  PhenomInternal_nudge(&eta, 0.25, 1e-6);
734  if (eta > 0.25 || eta < 0.0)
735  XLAL_ERROR(XLAL_EDOM, "Unphysical eta. Must be between 0. and 0.25\n");
736 
737  REAL8 finspin = FinalSpin0815(eta, chi1, chi2);
738 
739  if (finspin < MIN_FINAL_SPIN)
740  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
741  the model might misbehave here.", finspin);
742 
743  return finspin;
744 }
745 
746 
747 /* IMRPhenomDSetupPhase */
748 /* IMRPhenomDEvaluatePhaseFrequencySequence */
749 
750 
751 
752 
753 
754 /**
755  * Helper function used in PhenomHM and PhenomPv3HM
756  * Returns the phenomD phase, with modified QNM
757  */
759  REAL8Sequence *phases, /**< [out] phase evaluated at input freqs */
760  REAL8Sequence *freqs, /**< Sequency of Geometric frequencies */
761  size_t ind_min, /**< start index for frequency loop */
762  size_t ind_max, /**< end index for frequency loop */
763  REAL8 m1, /**< mass of primary in solar masses */
764  REAL8 m2, /**< mass of secondary in solar masses */
765  REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
766  REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
767  REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
768  REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
769  REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
770  REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
771  REAL8 Rholm, /**< ratio of ringdown frequencies f_RD_22/f_RD_lm */
772  REAL8 Taulm, /**< ratio of ringdown damping times f_RM_22/f_RM_lm */
773  LALDict *extraParams /**< linked list containing the extra testing GR parameters */
774 )
775 {
776  int retcode = 0;
779  &pD, m1, m2, chi1x, chi1y, chi1z,
780  chi2x, chi2y, chi2z, Rholm, Taulm, extraParams);
781  if (retcode != XLAL_SUCCESS)
782  {
783  XLALPrintError("XLAL Error - IMRPhenomDSetupAmpAndPhaseCoefficients failed\n");
785  }
786 
787  int status_in_for = XLAL_SUCCESS;
788  /* Now generate the waveform */
789  #pragma omp parallel for
790  for (size_t i = ind_min; i < ind_max; i++)
791  {
792  REAL8 Mf = freqs->data[i]; // geometric frequency
793 
794  UsefulPowers powers_of_f;
795  status_in_for = init_useful_powers(&powers_of_f, Mf);
796  if (XLAL_SUCCESS != status_in_for)
797  {
798  XLALPrintError("init_useful_powers failed for Mf, status_in_for=%d\n", status_in_for);
799  retcode = status_in_for;
800  }
801  else
802  {
803  phases->data[i] = IMRPhenDPhase(Mf, &(pD.pPhi), &(pD.pn), &powers_of_f,
804  &(pD.phi_prefactors), Rholm, Taulm);
805  }
806  }
807 
808  // LALFree(pPhi);
809  // LALFree(pn);
810 
811  return XLAL_SUCCESS;
812 }
813 
814 /* IMRPhenomDSetupAmplitude */
815 /* IMRPhenomDEvaluateAmplitude */
816 
817 /**
818  * Helper function used in PhenomHM and PhenomPv3HM
819  * Returns the phenomD amplitude
820  */
822  REAL8Sequence *amps, /**< [out] phase evaluated at input freqs */
823  REAL8Sequence *freqs, /**< Sequency of Geometric frequencies */
824  size_t ind_min, /**< start index for frequency loop */
825  size_t ind_max, /**< end index for frequency loop */
826  REAL8 m1, /**< mass of primary in solar masses */
827  REAL8 m2, /**< mass of secondary in solar masses */
828  REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
829  REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
830  REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
831  REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
832  REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
833  REAL8 chi2z /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
834 )
835 {
836  int retcode;
837 
838  /* It's difficult to see in the code but you need to setup the
839  * powers_of_pi.
840  */
841  retcode = 0;
843  XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "Failed to initiate useful powers of pi.");
844 
845  PhenomInternal_PrecessingSpinEnforcePrimaryIsm1(&m1, &m2, &chi1x, &chi1y, &chi1z, &chi2x, &chi2y, &chi2z);
846  const REAL8 Mtot = m1 + m2;
847  const REAL8 eta = m1 * m2 / (Mtot * Mtot);
848 
849  // Calculate phenomenological parameters
850  // const REAL8 finspin = FinalSpin0815(eta, chi1z, chi2z); //FinalSpin0815 - 0815 is like a version number
851  const REAL8 chip = XLALSimPhenomUtilsChiP(m1, m2, chi1x, chi1y, chi2x, chi2y);
852  const REAL8 finspin = XLALSimPhenomUtilsPhenomPv2FinalSpin(m1, m2, chi1z, chi2z, chip);
853  // const REAL8 finspin = XLALSimPhenomUtilsPhenomPv3HMFinalSpin(m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z);
854 
855  if (finspin < MIN_FINAL_SPIN)
856  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
857  the model might misbehave here.",
858  finspin);
859 
862  ComputeIMRPhenomDAmplitudeCoefficients(pAmp, eta, chi1z, chi2z, finspin);
863  if (!pAmp)
865 
866  AmpInsPrefactors amp_prefactors;
867  retcode = 0;
868  retcode = init_amp_ins_prefactors(&amp_prefactors, pAmp);
869  XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "init_amp_ins_prefactors failed");
870 
871  int status_in_for = XLAL_SUCCESS;
872 /* Now generate the waveform */
873 #pragma omp parallel for
874  for (size_t i = ind_min; i < ind_max; i++)
875  {
876  REAL8 Mf = freqs->data[i]; // geometric frequency
877 
878  UsefulPowers powers_of_f;
879  status_in_for = init_useful_powers(&powers_of_f, Mf);
880  if (XLAL_SUCCESS != status_in_for)
881  {
882  XLALPrintError("init_useful_powers failed for Mf, status_in_for=%d", status_in_for);
883  retcode = status_in_for;
884  }
885  else
886  {
887  amps->data[i] = IMRPhenDAmplitude(Mf, pAmp, &powers_of_f, &amp_prefactors);
888  }
889  }
890 
891  LALFree(pAmp);
892 
893  return XLAL_SUCCESS;
894 }
895 
896 /**
897  * computes the time shift as the approximate time of the peak of the 22 mode.
898  */
900  REAL8 eta, /**< symmetric mass-ratio */
901  REAL8 chi1z, /**< dimensionless aligned-spin of primary */
902  REAL8 chi2z, /**< dimensionless aligned-spin of secondary */
903  REAL8 finspin, /**< final spin */
904  LALDict *extraParams /**< linked list containing the extra testing GR parameters */
905 )
906 {
907 
908  if (extraParams == NULL)
909  extraParams = XLALCreateDict();
910 
912  pPhi = XLALMalloc(sizeof(IMRPhenomDPhaseCoefficients));
913  ComputeIMRPhenomDPhaseCoefficients(pPhi, eta, chi1z, chi2z, finspin, extraParams);
914  if (!pPhi)
916 
919  ComputeIMRPhenomDAmplitudeCoefficients(pAmp, eta, chi1z, chi2z, finspin);
920  if (!pAmp)
922 
923  // double Rholm = XLALSimIMRPhenomHMRholm(eta, chi1z, chi2z, ell, mm);
924  // double Taulm = XLALSimIMRPhenomHMTaulm(eta, chi1z, chi2z, ell, mm);
925 
926  //time shift so that peak amplitude is approximately at t=0
927  //For details see https://www.lsc-group.phys.uwm.edu/ligovirgo/cbcnote/WaveformsReview/IMRPhenomDCodeReview/timedomain
928  //NOTE: All modes will have the same time offset. So we use the 22 mode.
929  //If we just use the 22 mode then we pass 1.0, 1.0 into DPhiMRD.
930  const REAL8 t0 = DPhiMRD(pAmp->fmaxCalc, pPhi, 1.0, 1.0);
931 
932  LALFree(pPhi);
933  LALFree(pAmp);
934 
935  return t0;
936 }
937 
938 /**
939  * Function to compute the amplitude and phase coefficients for PhenomD
940  * Used to optimise the calls to IMRPhenDPhase and IMRPhenDAmplitude
941  */
943  PhenDAmpAndPhasePreComp *pDPreComp, /**< [out] PhenDAmpAndPhasePreComp struct */
944  REAL8 m1, /**< mass of companion 1 (Msun) */
945  REAL8 m2, /**< mass of companion 2 (Msun) */
946  REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
947  REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
948  REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
949  REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
950  REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
951  REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
952  const REAL8 Rholm, /**< ratio of (2,2) mode to (l,m) mode ringdown frequency */
953  const REAL8 Taulm, /**< ratio of (l,m) mode to (2,2) mode damping time */
954  LALDict *extraParams /**<linked list containing the extra parameters */
955 )
956 {
957 
958  // Make a pointer to LALDict to circumvent a memory leak
959  // At the end we will check if we created a LALDict in extraParams
960  // and destroy it if we did.
961  LALDict *extraParams_in = extraParams;
962 
963  /* It's difficult to see in the code but you need to setup the
964  * powers_of_pi.
965  */
966  int retcode = 0;
968  XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "Failed to initiate useful powers of pi.");
969 
970  PhenomInternal_PrecessingSpinEnforcePrimaryIsm1(&m1, &m2, &chi1x, &chi1y, &chi1z, &chi2x, &chi2y, &chi2z);
971  const REAL8 Mtot = m1 + m2;
972  const REAL8 eta = m1 * m2 / (Mtot * Mtot);
973 
974  // Calculate phenomenological parameters
975  // const REAL8 finspin = FinalSpin0815(eta, chi1z, chi2z); //FinalSpin0815 - 0815 is like a version number
976  const REAL8 chip = XLALSimPhenomUtilsChiP(m1, m2, chi1x, chi1y, chi2x, chi2y);
977  const REAL8 finspin = XLALSimPhenomUtilsPhenomPv2FinalSpin(m1, m2, chi1z, chi2z, chip);
978  // const REAL8 finspin = XLALSimPhenomUtilsPhenomPv3HMFinalSpin(m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z);
979 
980  if (finspin < MIN_FINAL_SPIN)
981  XLAL_PRINT_WARNING("Final spin (Mf=%g) and ISCO frequency of this system are small, \
982  the model might misbehave here.",
983  finspin);
984 
985  //start phase
986  if (extraParams == NULL)
987  {
988  extraParams = XLALCreateDict();
989  }
990 
992 
994  pPhi = XLALMalloc(sizeof(IMRPhenomDPhaseCoefficients));
995  ComputeIMRPhenomDPhaseCoefficients(pPhi, eta, chi1z, chi2z, finspin, extraParams);
996  if (!pPhi)
998  PNPhasingSeries *pn = NULL;
999  XLALSimInspiralTaylorF2AlignedPhasing(&pn, m1, m2, chi1z, chi2z, extraParams);
1000  if (!pn)
1002 
1003  // Subtract 3PN spin-spin term below as this is in LAL's TaylorF2 implementation
1004  // (LALSimInspiralPNCoefficients.c -> XLALSimInspiralPNPhasing_F2), but
1005  // was not available when PhenomD was tuned.
1006  REAL8 testGRcor = 1.0;
1007  testGRcor += XLALSimInspiralWaveformParamsLookupNonGRDChi6(extraParams);
1008  pn->v[6] -= (Subtract3PNSS(m1, m2, Mtot, eta, chi1z, chi2z) * pn->v[0]) * testGRcor;
1009 
1010  PhiInsPrefactors phi_prefactors;
1011  retcode = 0;
1012  retcode = init_phi_ins_prefactors(&phi_prefactors, pPhi, pn);
1013  XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "init_phi_ins_prefactors failed");
1014 
1015  // Compute coefficients to make phase C^1 continuous (phase and first derivative)
1016  ComputeIMRPhenDPhaseConnectionCoefficients(pPhi, pn, &phi_prefactors, Rholm, Taulm);
1017  //end phase
1018 
1019  //start amp
1022  ComputeIMRPhenomDAmplitudeCoefficients(pAmp, eta, chi1z, chi2z, finspin);
1023  if (!pAmp)
1025 
1026  AmpInsPrefactors amp_prefactors;
1027  retcode = 0;
1028  retcode = init_amp_ins_prefactors(&amp_prefactors, pAmp);
1029  XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "init_amp_ins_prefactors failed");
1030  //end amp
1031 
1032  //output
1033  pDPreComp->pn = *pn;
1034  pDPreComp->pPhi = *pPhi;
1035  pDPreComp->phi_prefactors = phi_prefactors;
1036 
1037  pDPreComp->pAmp = *pAmp;
1038  pDPreComp->amp_prefactors = amp_prefactors;
1039 
1040  LALFree(pn);
1041  LALFree(pPhi);
1042  LALFree(pAmp);
1043 
1044  /* If extraParams was allocated in this function and not passed in
1045  * we need to free it to prevent a leak */
1046  if (extraParams && !extraParams_in) {
1047  XLALDestroyDict(extraParams);
1048  } else {
1050  }
1051 
1052  return XLAL_SUCCESS;
1053 }
1054 
1055 /**
1056  * Function to return the phenomD phase using the
1057  * IMRPhenomDSetupAmpAndPhaseCoefficients struct
1058  */
1060  REAL8 Mf,
1062  REAL8 Rholm,
1063  REAL8 Taulm)
1064 {
1065 
1066  UsefulPowers powers_of_f;
1067  int status = init_useful_powers(&powers_of_f, Mf);
1068  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initiate init_useful_powers");
1069  REAL8 phase = IMRPhenDPhase(Mf, &(pD.pPhi), &(pD.pn), &powers_of_f,
1070  &(pD.phi_prefactors), Rholm, Taulm);
1071  return phase;
1072 }
void XLALDestroyDict(LALDict *dict)
LALDict * XLALCreateDict(void)
#define LALFree(p)
int XLALSimNRTunedTidesFDTidalAmplitudeFrequencySeries(const REAL8Sequence *amp_tidal, const REAL8Sequence *fHz, REAL8 m1_SI, REAL8 m2_SI, REAL8 lambda1, REAL8 lambda2)
Function to call amplitude tidal series only; done for convenience to use for PhenomD_NRTidalv2 and S...
static size_t NextPow2(const size_t n)
double XLALSimIMRPhenomDFinalSpin(const REAL8 m1_in, const REAL8 m2_in, const REAL8 chi1_in, const REAL8 chi2_in)
Function to return the final spin (spin of the remnant black hole) as predicted by the IMRPhenomD mod...
double XLALSimIMRPhenomDChirpTime(const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1_in, const REAL8 chi2_in, const REAL8 fHzSt)
Estimates the length of the time domain IMRPhenomD signal This does NOT taking into account any taper...
UNUSED REAL8 IMRPhenomDPhase_OneFrequency(REAL8 Mf, PhenDAmpAndPhasePreComp pD, REAL8 Rholm, REAL8 Taulm)
Function to return the phenomD phase using the IMRPhenomDSetupAmpAndPhaseCoefficients struct.
int IMRPhenomDPhaseFrequencySequence(REAL8Sequence *phases, REAL8Sequence *freqs, size_t ind_min, size_t ind_max, REAL8 m1, REAL8 m2, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, REAL8 Rholm, REAL8 Taulm, LALDict *extraParams)
Helper function used in PhenomHM and PhenomPv3HM Returns the phenomD phase, with modified QNM.
static int IMRPhenomDGenerateFD(COMPLEX16FrequencySeries **htilde, const REAL8Sequence *freqs_in, double deltaF, const REAL8 phi0, const REAL8 fRef, const REAL8 m1_in, const REAL8 m2_in, const REAL8 chi1_in, const REAL8 chi2_in, const REAL8 distance, LALDict *extraParams, NRTidal_version_type NRTidal_version)
static double PhenDPhaseDerivFrequencyPoint(double Mf, IMRPhenomDPhaseCoefficients *p, PNPhasingSeries *pn)
Helper function to return the value of the frequency derivative of the Fourier domain phase.
double XLALIMRPhenomDGetPeakFreq(const REAL8 m1_in, const REAL8 m2_in, const REAL8 chi1_in, const REAL8 chi2_in)
Function to return the frequency (in Hz) of the peak of the frequency domain amplitude for the IMRPhe...
int IMRPhenomDAmpFrequencySequence(REAL8Sequence *amps, REAL8Sequence *freqs, size_t ind_min, size_t ind_max, REAL8 m1, REAL8 m2, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z)
Helper function used in PhenomHM and PhenomPv3HM Returns the phenomD amplitude.
REAL8 IMRPhenomDComputet0(REAL8 eta, REAL8 chi1z, REAL8 chi2z, REAL8 finspin, LALDict *extraParams)
computes the time shift as the approximate time of the peak of the 22 mode.
UsefulPowers powers_of_pi
useful powers of LAL_PI, calculated once and kept constant - to be initied with a call to init_useful...
int IMRPhenomDSetupAmpAndPhaseCoefficients(PhenDAmpAndPhasePreComp *pDPreComp, REAL8 m1, REAL8 m2, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, const REAL8 Rholm, const REAL8 Taulm, LALDict *extraParams)
Function to compute the amplitude and phase coefficients for PhenomD Used to optimise the calls to IM...
#define MAX_ALLOWED_MASS_RATIO
A large mass ratio causes memory over-runs.
#define f_CUT
Dimensionless frequency (Mf) at which define the end of the waveform.
#define MIN_FINAL_SPIN
Minimal final spin value below which the waveform might behave pathological because the ISCO frequenc...
Internal function for IMRPhenomD phenomenological waveform model. See LALSimIMRPhenom....
static void ComputeIMRPhenDPhaseConnectionCoefficients(IMRPhenomDPhaseCoefficients *p, PNPhasingSeries *pn, PhiInsPrefactors *prefactors, double Rholm, double Taulm)
This function aligns the three phase parts (inspiral, intermediate and merger-rindown) such that they...
static double IMRPhenDPhase(double f, IMRPhenomDPhaseCoefficients *p, PNPhasingSeries *pn, UsefulPowers *powers_of_f, PhiInsPrefactors *prefactors, double Rholm, double Taulm)
This function computes the IMR phase given phenom coefficients.
static int init_phi_ins_prefactors(PhiInsPrefactors *prefactors, IMRPhenomDPhaseCoefficients *p, PNPhasingSeries *pn)
static double FinalSpin0815(double eta, double chi1, double chi2)
Wrapper function for FinalSpin0815_s.
static void ComputeIMRPhenomDPhaseCoefficients(IMRPhenomDPhaseCoefficients *p, double eta, double chi1, double chi2, double finspin, LALDict *extraParams)
A struct containing all the parameters that need to be calculated to compute the phenomenological pha...
static double DPhiIntAnsatz(double Mf, IMRPhenomDPhaseCoefficients *p)
First frequency derivative of PhiIntAnsatz (this time with 1.
static void ComputeIMRPhenomDAmplitudeCoefficients(IMRPhenomDAmplitudeCoefficients *p, double eta, double chi1, double chi2, double finspin)
A struct containing all the parameters that need to be calculated to compute the phenomenological amp...
static double Subtract3PNSS(double m1, double m2, double M, double eta, double chi1, double chi2)
Subtract 3PN spin-spin term below as this is in LAL's TaylorF2 implementation (LALSimInspiralPNCoeffi...
static double IMRPhenDAmplitude(double f, IMRPhenomDAmplitudeCoefficients *p, UsefulPowers *powers_of_f, AmpInsPrefactors *prefactors)
This function computes the IMR amplitude given phenom coefficients.
static double DPhiInsAnsatzInt(double Mf, IMRPhenomDPhaseCoefficients *p, PNPhasingSeries *pn)
First frequency derivative of PhiInsAnsatzInt.
static bool StepFunc_boolean(const double t, const double t1)
‍**
static int init_amp_ins_prefactors(AmpInsPrefactors *prefactors, IMRPhenomDAmplitudeCoefficients *p)
static double DPhiMRD(double f, IMRPhenomDPhaseCoefficients *p, double Rholm, double Taulm)
First frequency derivative of PhiMRDAnsatzInt Rholm was added when IMRPhenomHM (high mode) was added.
static int init_useful_powers(UsefulPowers *p, REAL8 number)
int PhenomInternal_PrecessingSpinEnforcePrimaryIsm1(REAL8 *m1, REAL8 *m2, REAL8 *chi1x, REAL8 *chi1y, REAL8 *chi1z, REAL8 *chi2x, REAL8 *chi2y, REAL8 *chi2z)
Given m1 with spins (chi1x, chi1y, chi1z) and m2 with spins (chi2x,chi2y,chi2z).
void PhenomInternal_nudge(REAL8 *x, REAL8 X, REAL8 epsilon)
If x and X are approximately equal to relative accuracy epsilon then set x = X.
REAL8 XLALSimPhenomUtilsPhenomPv2FinalSpin(const REAL8 m1, const REAL8 m2, const REAL8 chi1_l, const REAL8 chi2_l, const REAL8 chip)
Wrapper for final-spin formula based on:
REAL8 XLALSimPhenomUtilsChiP(const REAL8 m1, const REAL8 m2, const REAL8 s1x, const REAL8 s1y, const REAL8 s2x, const REAL8 s2y)
Function to compute the effective precession parameter chi_p (1408.1810)
REAL8 XLALSimInspiralWaveformParamsLookupNonGRDChi6(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupdQuadMon1(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalLambda2(LALDict *params)
REAL8 XLALSimInspiralWaveformParamsLookupTidalLambda1(LALDict *params)
int XLALSimInspiralWaveformParamsInsertPNSpinOrder(LALDict *params, INT4 value)
REAL8 XLALSimInspiralWaveformParamsLookupdQuadMon2(LALDict *params)
int XLALSimInspiralWaveformParamsInsertdQuadMon2(LALDict *params, REAL8 value)
int XLALSimInspiralWaveformParamsInsertdQuadMon1(LALDict *params, REAL8 value)
REAL8 M
Definition: bh_qnmode.c:133
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
const double pn
COMPLEX16FrequencySeries * XLALResizeCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series, int first, size_t length)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
void * XLALMalloc(size_t n)
NRTidal_version_type
Definition: LALSimIMR.h:80
@ NRTidalv2_V
version NRTidalv2: https://arxiv.org/abs/1905.06011
Definition: LALSimIMR.h:82
int XLALSimIMRPhenomDGenerateFD(COMPLEX16FrequencySeries **htilde, const REAL8 phi0, const REAL8 fRef_in, const REAL8 deltaF, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1, const REAL8 chi2, const REAL8 f_min, const REAL8 f_max, const REAL8 distance, LALDict *extraParams, NRTidal_version_type NRTidal_version)
Driver routine to compute the spin-aligned, inspiral-merger-ringdown phenomenological waveform IMRPhe...
int XLALSimIMRPhenomDFrequencySequence(COMPLEX16FrequencySeries **htilde, const REAL8Sequence *freqs, const REAL8 phi0, const REAL8 fRef_in, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1, const REAL8 chi2, const REAL8 distance, LALDict *extraParams, NRTidal_version_type NRTidal_version)
Compute waveform in LAL format at specified frequencies for the IMRPhenomD model.
@ LAL_SIM_INSPIRAL_SPIN_ORDER_35PN
@ LAL_SIM_INSPIRAL_SPIN_ORDER_ALL
int XLALSimInspiralTaylorF2AlignedPhasing(PNPhasingSeries **pfa, const REAL8 m1, const REAL8 m2, const REAL8 chi1, const REAL8 chi2, LALDict *extraPars)
Returns structure containing TaylorF2 phasing coefficients for given physical parameters.
static const INT4 q
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_WARNING(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list p
string status
used to cache the recurring (frequency-independent) prefactors of AmpInsAnsatz.
Structure holding all coefficients for the amplitude.
Structure holding all coefficients for the phase.
A struct the store the amplitude and phase structs for phenomD.
IMRPhenomDPhaseCoefficients pPhi
IMRPhenomDAmplitudeCoefficients pAmp
used to cache the recurring (frequency-independent) prefactors of PhiInsAnsatzInt.
REAL8 * data
useful powers in GW waveforms: 1/6, 1/3, 2/3, 4/3, 5/3, 2, 7/3, 8/3, -1, -1/6, -7/6,...
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23