Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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
28
29UsefulPowers 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
40static 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 = 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();
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();
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
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
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 * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
COMPLEX16FrequencySeries * XLALResizeCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series, int first, 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)
string status
p
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