Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-8a6b96f
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRPhenomPv3HM.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017 Sebastian Khan
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 * \author Sebastian Khan
22 *
23 * \file
24 *
25 * \brief PhenomPv3HM model
26 *
27 * Inspiral-merger and ringdown phenomenological, frequecny domain
28 * waveform model for spinning precessing binary black holes systems.
29 * Models not only the dominant (l,|m|) = (2,2) modes
30 * but also some of the sub-domant modes too in the co-precessing frame.
31 *
32 * The model has been validated against precessing NR simulations up to mass-ratio 6
33 * but due to lack of precessing NR simulations above mass-ratio 6 we cannot validate it's accuracy.
34 *
35 * Tested Range: up to mass-ratio 6, any spin magnitude and orientation.
36 * Usage Range: up to mass-ratio 20, any spin magnitude and orientation.
37 */
38
39#include <lal/Date.h>
40#include <lal/Sequence.h>
41#include <lal/LALConstants.h>
42#include <lal/FrequencySeries.h>
43#include <lal/Units.h>
44#include <lal/SphericalHarmonics.h>
45
48
50
51#define L_MAX_PLUS_1 5
52#define PHENOM_DEFAULT_MAXF 0.5
53
54/**
55 * read in a LALDict.
56 * If ModeArray in LALDict is NULL then create a ModrArray
57 * with the default modes in PhenomPv3HM.
58 * If ModeArray is not NULL then use the modes supplied by user.
59 */
61 LALDict *extraParams)
62{
63
64 /* setup ModeArray */
65 if (extraParams == NULL)
66 extraParams = XLALCreateDict();
67 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(extraParams);
68 if (ModeArray == NULL)
69 { /* Default behaviour */
70 /* TODO: Move this into a function */
71 XLAL_PRINT_INFO("Using default modes for PhenomPv3HM.\n");
73 /* Only need to define the positive m modes/
74 * The negative m modes are automatically added.
75 */
82 // XLALSimInspiralModeArrayPrintModes(ModeArray);
83 /* Don't forget to insert ModeArray back into extraParams. */
85 }
86 else
87 {
88 XLAL_PRINT_INFO("Using custom modes for PhenomPv3HM.\n");
89 }
90
91 XLALDestroyValue(ModeArray);
92 /*TODO: Add an error check here somehow?*/
93
94 return extraParams;
95}
96
97/**
98 * Reads in a ModeArray and checks that it is valid.
99 * i.e., that it contains the 2,2 mode
100 * and may only contain the modes in the model
101 * i.e., 22, 21, 33, 32, 44, 43
102 * Only checks upto ell=8 though.
103 */
104static int IMRPhenomPv3HM_check_mode_array(LALValue *ModeArray)
105{
106 // if 22 mode not active -> error
107 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, 2) != 1)
108 {
109 XLAL_ERROR(XLAL_EFUNC, "(2,2) mode required\n");
110 }
111
112 // if no 22,21,33,32,44,43 mode and active -> error
113 // these modes are not in the model
114 for (INT4 ell = 2; ell <= 8; ell++)
115 {
116 for (INT4 mm = -ell; mm < ell + 1; mm++)
117 {
118 if (ell == 2 && mm == 2){
119 continue;
120 }
121 else if (ell == 2 && mm == 1)
122 {
123 continue;
124 }
125 else if (ell == 3 && mm == 3)
126 {
127 continue;
128 }
129 else if (ell == 3 && mm == 2)
130 {
131 continue;
132 }
133 else if (ell == 4 && mm == 4)
134 {
135 continue;
136 }
137 else if (ell == 4 && mm == 3)
138 {
139 continue;
140 }
141
142 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, mm) == 1)
143 {
144 XLAL_ERROR(XLAL_EFUNC, "(%i,%i) mode in ModeArray but model does not include this!\n", ell, mm);
145 }
146 }
147 }
148 return XLAL_SUCCESS;
149}
150
151/**
152 * Precomputes useful quantities and populates the
153 * PhenomPv3HMStorage and sysq (for precession angles) structs.
154 */
155UNUSED static int init_PhenomPv3HM_Storage(
156 PhenomPv3HMStorage *p, /**< [out] PhenomPv3Storage struct */
157 sysq *pAngles, /**< [out] precession angle pre-computations struct */
158 REAL8 m1_SI, /**< mass of primary in SI (kg) */
159 REAL8 m2_SI, /**< mass of secondary in SI (kg) */
160 REAL8 S1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
161 REAL8 S1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
162 REAL8 S1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
163 REAL8 S2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
164 REAL8 S2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
165 REAL8 S2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
166 const REAL8 distance, /**< distance of source (m) */
167 const REAL8 inclination, /**< inclination of source (rad) */
168 const REAL8 phiRef, /**< reference orbital phase (rad) */
169 const REAL8 deltaF, /**< Sampling frequency (Hz) */
170 const REAL8 f_min, /**< Starting GW frequency (Hz) */
171 const REAL8 f_max, /**< End frequency; 0 defaults to ringdown cutoff freq */
172 const REAL8 f_ref /**< Reference GW frequency (Hz) */
173)
174{
175 XLAL_CHECK(0 != p, XLAL_EFAULT, "p is NULL");
176 XLAL_CHECK(0 != pAngles, XLAL_EFAULT, "pAngles is NULL");
177
178 // We check if the systems is precessing because we skip angle
179 // computation if this is the case.
180 p->PRECESSING = 0;
181 if (S1x == 0. && S1y == 0. && S2x == 0. && S2y == 0.)
182 {
183 p->PRECESSING = 1; // This means the system is not precessing
184 }
185
186 /* input parameters */
187 p->m1_SI = m1_SI;
188 p->m2_SI = m2_SI;
189 p->chi1x = S1x;
190 p->chi1y = S1y;
191 p->chi1z = S1z;
192 p->chi2x = S2x;
193 p->chi2y = S2y;
194 p->chi2z = S2z;
195 p->distance_SI = distance;
196 p->phiRef = phiRef;
197 p->deltaF = deltaF;
198 p->f_min = f_min;
199 p->f_max = f_max;
200 p->f_ref = f_ref;
201
202 int retcode = 0;
204 &(p->m1_SI),
205 &(p->m2_SI),
206 &(p->chi1x),
207 &(p->chi1y),
208 &(p->chi1z),
209 &(p->chi2x),
210 &(p->chi2y),
211 &(p->chi2z));
213 XLAL_SUCCESS == retcode,
215 "PhenomInternal_AlignedSpinEnforcePrimaryIsm1 failed");
216
217 /* derived parameters */
218 p->m1_Msun = m1_SI / LAL_MSUN_SI;
219 p->m2_Msun = m2_SI / LAL_MSUN_SI;
220 p->Mtot_SI = p->m1_SI + p->m2_SI;
221 p->Mtot_Msun = p->m1_Msun + p->m2_Msun;
222
223 p->eta = p->m1_Msun * p->m2_Msun / (p->Mtot_Msun * p->Mtot_Msun);
224 p->q = p->m1_Msun / p->m2_Msun; /* with m1>=m2 so q>=1 */
225
226 /* check for rounding errors */
227 if (p->eta > 0.25 || p->q < 1.0)
228 {
229 PhenomInternal_nudge(&(p->eta), 0.25, 1e-6);
230 PhenomInternal_nudge(&(p->q), 1.0, 1e-6);
231 }
232
233 p->Msec = p->Mtot_Msun * LAL_MTSUN_SI; /* Total mass in seconds */
234
235 p->amp0 = (p->Mtot_Msun) * LAL_MRSUN_SI * (p->Mtot_Msun) * LAL_MTSUN_SI / (p->distance_SI);
236
237 /* chi1_l == chi1z, chi2_l == chi2z so we don't need to save them as they are duplicates */
238 REAL8 chi1_l, chi2_l;
239
240 /* rotate from LAL to PhenomP frame */
242 &chi1_l, &chi2_l, &(p->chip), &(p->thetaJN), &(p->alpha0), &(p->phi_aligned), &(p->zeta_polariz),
243 p->m1_SI, p->m2_SI, p->f_ref, p->phiRef, inclination,
244 p->chi1x, p->chi1y, p->chi1z,
245 p->chi2x, p->chi2y, p->chi2z, IMRPhenomPv3_V);
246 XLAL_CHECK(errcode == XLAL_SUCCESS, XLAL_EFUNC, "XLALSimIMRPhenomPCalculateModelParametersFromSourceFrame failed");
247
248 p->inclination = p->thetaJN;
249
250 // printf("(p->zeta_polariz) = %.16f\n", (p->zeta_polariz));
251
252 /* compute spins in polar coordinates */
253 PhenomInternal_ComputeIMRPhenomPv3CartesianToPolar(&(p->chi1_theta), &(p->chi1_phi), &(p->chi1_mag), p->chi1x, p->chi1y, p->chi1z);
254 PhenomInternal_ComputeIMRPhenomPv3CartesianToPolar(&(p->chi2_theta), &(p->chi2_phi), &(p->chi2_mag), p->chi2x, p->chi2y, p->chi2z);
255
256 if (p->PRECESSING != 1) // precessing case. compute angles
257 {
258 /* Initialize precession angles */
259 /* evaluating the angles at the reference frequency */
260 p->f_ref_Orb_Hz = 0.5 * p->f_ref; /* factor of 0.5 to go from GW to Orbital frequency */
261 /* precompute everything needed to compute precession angles from LALSimInspiralFDPrecAngles.c */
262 /* note that the reference frequency that you pass into InitializeSystem is the GW frequency */
263
264 /* ExpansionOrder specifies how many terms in the PN expansion of the precession angles to use.
265 * In PhenomP3 we set this to 5, i.e. all but the highest order terms.
266 * */
267 int ExpansionOrder = 5;
268 errcode = InitializeSystem(pAngles,
269 p->m1_SI, p->m2_SI,
271 cos(p->chi1_theta), p->chi1_phi, p->chi1_mag,
272 cos(p->chi2_theta), p->chi2_phi, p->chi2_mag,
273 p->f_ref, ExpansionOrder);
274 XLAL_CHECK(errcode == XLAL_SUCCESS, XLAL_EFUNC, "InitializeSystem failed");
275 }
276
277 return XLAL_SUCCESS;
278}
279
280/**
281 * This version doesn't construct precessing hlm modes but instead constructs hplus, hcross directly.
282 */
284 UNUSED COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
285 UNUSED COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
286 UNUSED REAL8Sequence *freqs, /**< frequency sequency in Hz */
287 UNUSED REAL8 m1_SI, /**< mass of companion 1 (kg) */
288 UNUSED REAL8 m2_SI, /**< mass of companion 2 (kg) */
289 UNUSED REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
290 UNUSED REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
291 UNUSED REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
292 UNUSED REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
293 UNUSED REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
294 UNUSED REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
295 UNUSED const REAL8 distance, /**< distance of source (m) */
296 UNUSED const REAL8 inclination, /**< inclination of source (rad) */
297 UNUSED const REAL8 phiRef, /**< reference orbital phase (rad) */
298 UNUSED const REAL8 deltaF, /**< Sampling frequency (Hz). To use arbitrary frequency points set deltaF <= 0. */
299 UNUSED REAL8 f_ref, /**< Reference frequency */
300 UNUSED LALDict *extraParams /**< LALDict struct */
301)
302{
303
304 XLAL_CHECK(f_ref > 0, XLAL_EDOM, "f_ref must be greater than zero.\n");
305
306 /* Use an auxiliar laldict to not overwrite the input argument */
307 LALDict *extraParams_aux;
308
309 /* setup mode array */
310 if (extraParams == NULL)
311 {
312 extraParams_aux = XLALCreateDict();
313 }
314 else{
315 extraParams_aux = XLALDictDuplicate(extraParams);
316 }
317 extraParams_aux = IMRPhenomPv3HM_setup_mode_array(extraParams_aux);
318 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(extraParams_aux);
319 int rcode = IMRPhenomPv3HM_check_mode_array(ModeArray);
320 XLAL_CHECK(XLAL_SUCCESS == rcode, rcode, "IMRPhenomPv3HM_check_mode_array failed");
321
322 UNUSED const REAL8 Mtot_Msun = (m1_SI + m2_SI) / LAL_MSUN_SI;
323
324 REAL8 f_min=0.;
325 REAL8 f_max=0.;
326 size_t npts=0;
327 REAL8Sequence *freqs_seq=NULL;
328
329 LIGOTimeGPS tC = LIGOTIMEGPSZERO; // = {0, 0}
330
331 if ((freqs->length == 2) && (deltaF > 0.))
332 {
333 // uniform frequencies
334 f_min = freqs->data[0];
335 f_max = freqs->data[1];
336
337 if (f_max == 0.)
338 {
340 }
341 npts = PhenomInternal_NextPow2(f_max / deltaF) + 1;
342
343 freqs_seq = XLALCreateREAL8Sequence(npts);
344 for (size_t j = 0; j < npts; j++)
345 {
346 freqs_seq->data[j] = j * deltaF;
347 }
348 /* shift zero frequency to avoid evaluating angles at f=0.*/
349 freqs_seq->data[0] = 1e-13;
350 /* coalesce at t=0 */
351 /* Shift by overall length in time */
353 XLALGPSAdd(&tC, -1. / deltaF),
355 "Failed to shift coalescence time to t=0,\
356tried to apply shift of -1.0/deltaF with deltaF=%g.",
357 deltaF);
358
359 }
360 else if ((freqs->length != 2) && (deltaF <= 0.))
361 { /* else if 2. i.e. not uniformly spaced then we don't shift. */
362 // custom frequencies
363 f_min = freqs->data[0];
364 f_max = freqs->data[freqs->length - 1]; /* Last element */
365 npts = freqs->length;
366 freqs_seq = XLALCreateREAL8Sequence(npts);
367 for (size_t j = 0; j < npts; j++)
368 {
369 freqs_seq->data[j] = freqs->data[j];
370 }
371
372 } else {
373 XLAL_ERROR(XLAL_EFUNC, "cannot interpret frequency bounds!\n");
374 }
375
376 /* Store useful variables and compute derived and frequency independent variables */
377 PhenomPv3HMStorage *pv3HM;
379
380 /* Struct that stores the precession angle variables */
381 sysq *pAngles;
382 pAngles = (sysq *)XLALMalloc(sizeof(sysq));
383
384 int retcode = init_PhenomPv3HM_Storage(pv3HM, pAngles,
385 m1_SI, m2_SI,
386 chi1x, chi1y, chi1z,
387 chi2x, chi2y, chi2z,
388 distance, inclination, phiRef,
389 deltaF, f_min, f_max, f_ref);
390 XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "init_PhenomPv3HM_Storage failed");
391
392
393
395 *hlmsD = NULL;
396 /* XLALSimIMRPhenomHMGethlmModes currently takes only the positive m modes */
398 hlmsD,
399 freqs,
400 m1_SI,
401 m2_SI,
402 chi1x,
403 chi1y,
404 chi1z,
405 chi2x,
406 chi2y,
407 chi2z,
408 pv3HM->phiRef,
409 deltaF,
410 f_ref,
411 extraParams_aux);
412 XLAL_CHECK(XLAL_SUCCESS == retcode,
413 XLAL_EFUNC, "XLALSimIMRPhenomHMGethlmModes failed");
414
415 /* Allocate hptilde and hctilde */
416 *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
417 if (!(hptilde))
419 memset((*hptilde)->data->data, 0, npts * sizeof(COMPLEX16));
420 XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
421
422 *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
423 if (!(hctilde))
425 memset((*hctilde)->data->data, 0, npts * sizeof(COMPLEX16));
426 XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
427
428 /* Frequency domain amplitude pre-factor */
429 const REAL8 amp0 = XLALSimPhenomUtilsFDamp0(Mtot_Msun, distance);
430
431 /* logic for looping over modes
432 if 22 mode active:
433 # compute Ylms
434 for i in frequencies:
435 # compute wigner-D
436
437 if 21 mode active:
438 # compute Ylms
439 for i in frequencies:
440 # compute wigner-D
441
442 if 33 mode active:
443 # compute Ylms
444 for i in frequencies:
445 # compute wigner-D
446
447 etc...
448 */
449
450 UINT4 ell=0;
451 INT4 mprime=0;
452
453 int ret = 0;
454 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, 2) == 1)
455 {
456 ell=2;
457 mprime=2;
458
459 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
460 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
461
462 }
463 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, 1) == 1)
464 {
465 ell=2;
466 mprime=1;
467
468 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
469 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
470 }
471 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 3, 3) == 1)
472 {
473 ell = 3;
474 mprime = 3;
475
476 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
477 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
478 }
479 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 3, 2) == 1)
480 {
481 ell = 3;
482 mprime = 2;
483
484 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
485 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
486 }
487 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 4, 4) == 1)
488 {
489 ell = 4;
490 mprime = 4;
491
492 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
493 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
494 }
495 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, 4, 3) == 1)
496 {
497 ell = 4;
498 mprime = 3;
499
500 ret = IMRPhenomPv3HM_Compute_Mode(hptilde, hctilde, ell, mprime, Mtot_Msun, pv3HM, hlmsD, pAngles, freqs_seq);
501 XLAL_CHECK(XLAL_SUCCESS == ret, ret, "IMRPhenomPv3HM_Compute_Mode failed for the %i, %i mode\n", ell, mprime);
502 }
503
504 // LALFree(hlmD);
505 XLALDestroyREAL8Sequence(freqs_seq);
506 XLALDestroyValue(ModeArray);
508 XLALFree(hlmsD);
509
510 COMPLEX16 PhPpolp, PhPpolc; /* for polarisation application */
511
512 REAL8 cos_2zeta, sin_2zeta;
513 /* apply polarisation angle - Moved this from LALSimInspiral to indide here for PhenomPv3 */
514 cos_2zeta = cos(2.0 * pv3HM->zeta_polariz);
515 sin_2zeta = sin(2.0 * pv3HM->zeta_polariz);
516
517 for (UINT4 i = 0; i < (*hptilde)->data->length; i++)
518 { // loop over frequency points in sequence
519
520 // also applying Frequency Domain distance scale here - amp0
521 PhPpolp = amp0 * (*hptilde)->data->data[i];
522 PhPpolc = amp0 * (*hctilde)->data->data[i];
523 (*hptilde)->data->data[i] = cos_2zeta * PhPpolp + sin_2zeta * PhPpolc;
524 (*hctilde)->data->data[i] = cos_2zeta * PhPpolc - sin_2zeta * PhPpolp;
525 }
526
527 /* free pointers */
528 LALFree(pv3HM);
529 LALFree(pAngles);
530 XLALDestroyDict(extraParams_aux);
531
532 return XLAL_SUCCESS;
533}
534
535/**
536 * Driver routine to compute the precessing inspiral-merger-ringdown
537 * phenomenological waveform IMRPhenomPv3 in the frequency domain.
538 *
539 * Reference:
540 * - Hannam et al., arXiv:1308.3271 [gr-qc]
541 * - Bohe et al., PhenomPv2 technical document LIGO-T1500602
542 * - Chatziioannou et al., arXiv 1703.03967 [gr-qc]
543 *
544 * This function can be used for equally-spaced frequency series.
545 * For unequal spacing, use XLALSimIMRPhenomPv3FrequencySequence instead.
546 *
547 * This function calls XLALSimIMRPhenomPv3HMGetHplusHcross with just
548 * the l=m=2 mode
549 *
550 */
552 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
553 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
554 REAL8Sequence *freqs, /**< frequency sequency in Hz */
555 REAL8 m1_SI, /**< mass of companion 1 (kg) */
556 REAL8 m2_SI, /**< mass of companion 2 (kg) */
557 REAL8 S1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
558 REAL8 S1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
559 REAL8 S1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
560 REAL8 S2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
561 REAL8 S2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
562 REAL8 S2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
563 const REAL8 distance, /**< distance of source (m) */
564 const REAL8 inclination, /**< inclination of source (rad) */
565 const REAL8 phiRef, /**< reference orbital phase (rad) */
566 const REAL8 deltaF, /**< Sampling frequency (Hz) */
567 const REAL8 f_ref, /**< Reference frequency */
568 LALDict *extraParams) /**<linked list containing the extra testing GR parameters */
569{
570
571 /* Use an auxiliar laldict to not overwrite the input argument */
572 LALDict *extraParams_aux;
573
574 /* setup mode array */
575 if (extraParams == NULL)
576 {
577 extraParams_aux = XLALCreateDict();
578 }
579 else{
580 extraParams_aux = XLALDictDuplicate(extraParams);
581 }
582 LALValue *ModeArray = XLALSimInspiralCreateModeArray();
584 XLALSimInspiralWaveformParamsInsertModeArray(extraParams_aux, ModeArray);
585 XLALDestroyValue(ModeArray);
586
588 hptilde,
589 hctilde,
590 freqs,
591 m1_SI,
592 m2_SI,
593 S1x,
594 S1y,
595 S1z,
596 S2x,
597 S2y,
598 S2z,
599 distance,
600 inclination,
601 phiRef,
602 deltaF,
603 f_ref,
604 extraParams_aux);
606 XLAL_SUCCESS == ret,
608 "XLALSimIMRPhenomPv3HMGetHplusHcross failed in IMRPhenomPv3");
609
610 XLALDestroyDict(extraParams_aux);
611
612 return XLAL_SUCCESS;
613}
614
615/**
616 * This is an internal function that returns the precession angles
617 * at a single frequency
618 */
619static int IMRPhenomPv3HM_Compute_a_b_e(REAL8 *alpha, REAL8 *beta, REAL8 *mprime_epsilon, REAL8 fHz, INT4 mprime, const REAL8 twopi_Msec, PhenomPv3HMStorage *pv3HM, sysq *pAngles)
620{
621
622 vector angles;
623 REAL8 f_mprime = 0.;
624 REAL8 xi = 0.;
625
626 f_mprime = fHz / mprime;
627 xi = pow(f_mprime * twopi_Msec, pAngles->onethird);
628 angles = compute_phiz_zeta_costhetaL3PN(xi, pAngles);
629
630 *alpha = angles.x + pv3HM->alpha0;
631 REAL8 epsilon = angles.y;
632
633 *mprime_epsilon = mprime * epsilon;
634
635 /* angles.z can sometimes nan just above 1.
636 * The following nudge seems to be a good fix.
637 */
638 PhenomInternal_nudge(&(angles.z), 1.0, 1e-6); //This could even go from 1e-6 to 1e-15 - then would have to also change in Pv3 code. Should just fix the problem in the angles code.
639 *beta = acos(angles.z);
640
641 return XLAL_SUCCESS;
642}
643
644/**
645 * This is an internal function computes terms
646 * required to compute hptilde and hctilde
647 */
649{
650 INT4 minus1l=0; /* (-1)^ell */
651 if (ell % 2)
652 minus1l = -1;
653 else
654 minus1l = 1;
655
656 COMPLEX16 Term1_sum = 0.;
657 COMPLEX16 Term2_sum = 0.;
658
659 if (ell == 2 && mprime == 2)
660 {
661 for (int mm = -ell; mm <= ell; mm++)
662 {
663 COMPLEX16 WigD = als->alpha2[mm + ell] * wigs->d22[0][mm + ell];
664 COMPLEX16 WigDmConj = als->alpha2[-mm + ell] * wigs->d22[1][mm + ell];
665
666 Term1_sum += ylms->Ylm2[0][mm + ell] * WigD;
667 Term2_sum += minus1l * ylms->Ylm2[1][mm + ell] * WigDmConj;
668 }
669 }
670 else if (ell == 2 && mprime == 1)
671 {
672 for (int mm = -ell; mm <= ell; mm++)
673 {
674 COMPLEX16 WigD = als->alpha2[mm + ell] * wigs->d21[0][mm + ell];
675 COMPLEX16 WigDmConj = als->alpha2[-mm + ell] * wigs->d21[1][mm + ell];
676
677 Term1_sum += ylms->Ylm2[0][mm + ell] * WigD;
678 Term2_sum += minus1l * ylms->Ylm2[1][mm + ell] * WigDmConj;
679 }
680 }
681 else if (ell == 3 && mprime == 3)
682 {
683 for (int mm = -ell; mm <= ell; mm++)
684 {
685 COMPLEX16 WigD = als->alpha3[mm + ell] * wigs->d33[0][mm + ell];
686 COMPLEX16 WigDmConj = als->alpha3[-mm + ell] * wigs->d33[1][mm + ell];
687
688 Term1_sum += ylms->Ylm3[0][mm + ell] * WigD;
689 Term2_sum += minus1l * ylms->Ylm3[1][mm + ell] * WigDmConj;
690 }
691 }
692 else if (ell == 3 && mprime == 2)
693 {
694 for (int mm = -ell; mm <= ell; mm++)
695 {
696 COMPLEX16 WigD = als->alpha3[mm + ell] * wigs->d32[0][mm + ell];
697 COMPLEX16 WigDmConj = als->alpha3[-mm + ell] * wigs->d32[1][mm + ell];
698
699 Term1_sum += ylms->Ylm3[0][mm + ell] * WigD;
700 Term2_sum += minus1l * ylms->Ylm3[1][mm + ell] * WigDmConj;
701 }
702 }
703 else if (ell == 4 && mprime == 4)
704 {
705 for (int mm = -ell; mm <= ell; mm++)
706 {
707 COMPLEX16 WigD = als->alpha4[mm + ell] * wigs->d44[0][mm + ell];
708 COMPLEX16 WigDmConj = als->alpha4[-mm + ell] * wigs->d44[1][mm + ell];
709
710 Term1_sum += ylms->Ylm4[0][mm + ell] * WigD;
711 Term2_sum += minus1l * ylms->Ylm4[1][mm + ell] * WigDmConj;
712 }
713 }
714 else if (ell == 4 && mprime == 3)
715 {
716 for (int mm = -ell; mm <= ell; mm++)
717 {
718 COMPLEX16 WigD = als->alpha4[mm + ell] * wigs->d43[0][mm + ell];
719 COMPLEX16 WigDmConj = als->alpha4[-mm + ell] * wigs->d43[1][mm + ell];
720
721 Term1_sum += ylms->Ylm4[0][mm + ell] * WigD;
722 Term2_sum += minus1l * ylms->Ylm4[1][mm + ell] * WigDmConj;
723 }
724 }
725 else
726 {
727 XLAL_ERROR(XLAL_EFUNC, "mode %i, %i not available.\n", ell, mprime);
728 }
729
730 *Term1 = Term1_sum;
731 *Term2 = Term2_sum;
732
733 return XLAL_SUCCESS;
734}
735
736/**
737 * This is an internal function that returns hptilde and hctilde
738 * for a single mode in the inertial frame
739 */
741 COMPLEX16FrequencySeries **hptilde,
742 COMPLEX16FrequencySeries **hctilde,
743 UINT4 ell,
744 INT4 mprime,
745 const REAL8 Mtot_Msun,
746 PhenomPv3HMStorage *pv3HM,
748 sysq *pAngles,
749 REAL8Sequence *freqs_seq)
750{
751
752 if (pv3HM->PRECESSING == 1) // non-precessing case. skip angles
753 {
754 INT4 sym; /* sym will decide whether to add the -m mode (when equatorial symmetry is present) */
756 if (!(hlm))
758
759 /* We test for hypothetical m=0 modes */
760 if (mprime == 0)
761 {
762 sym = 0;
763 }
764 else
765 {
766 sym = 1;
767 }
768 PhenomInternal_IMRPhenomHMFDAddMode(*hptilde, *hctilde, hlm, pv3HM->inclination, 0., ell, mprime, sym);
769 } else { // precessing case. compute angles and do the twist
770
771 const REAL8 Msec = Mtot_Msun * LAL_MTSUN_SI; /* Total mass in seconds */
772 const REAL8 twopi_Msec = LAL_TWOPI * Msec;
773 REAL8 fHz = 0.;
774
775 COMPLEX16 half_amp_eps;
776
777 COMPLEX16 Term1_sum = 0;
778 COMPLEX16 Term2_sum = 0;
779
780 UNUSED INT4 minus1l = 0; /* (-1)^ell */
781 int ret_abe;
782 int retloop;
783
784 REAL8 alpha = 0.;
785 REAL8 beta = 0.;
786 REAL8 mprime_epsilon = 0.;
787
788 // compute Ylms
790 // get non-prec mode
792 if (!(hlmD))
794
796 memset(als, 0, sizeof(IMRPhenomPv3HMAlphaStruct));
797
799 memset(wigs, 0, sizeof(IMRPhenomPv3HMWignderStruct));
800
801 int ret_als;
802 int ret_wigs;
803
804 // frequency loop
805 for (size_t j = 0; j < freqs_seq->length; j++)
806 {
807 fHz = freqs_seq->data[j]; //for the angles
808 // compute alpha, beta and mprime*epsilon
809 ret_abe = IMRPhenomPv3HM_Compute_a_b_e(&alpha, &beta, &mprime_epsilon, fHz, mprime, twopi_Msec, pv3HM, pAngles);
811 XLAL_SUCCESS == ret_abe,
813 "IMRPhenomPv3HM_Compute_a_b_e failed");
814 /* Precompute wigner-d elements */
815 ret_wigs = XLALSimIMRPhenomPv3HMComputeWignerdElements(&wigs, ell, mprime, -beta);
817 XLAL_SUCCESS == ret_wigs,
819 "XLALSimIMRPhenomPv3HMComputeWignerdElements failed");
820 /* Precompute powers of e^{i m alpha} */
823 XLAL_SUCCESS == ret_als,
825 "XLALSimIMRPhenomPv3HMComputeAlphaElements failed");
826 retloop = IMRPhenomPv3HM_wigner_loop(&Term1_sum, &Term2_sum, ell, mprime, ylms, als, wigs);
828 XLAL_SUCCESS == retloop,
830 "IMRPhenomPv3HM_wigner_loop failed");
831
832 COMPLEX16 hlmD_j = (hlmD->data->data[j]);
833 half_amp_eps = 0.5 * hlmD_j * cexp(-I * mprime_epsilon);
834 (*hptilde)->data->data[j] += half_amp_eps * (Term1_sum + Term2_sum);
835 (*hctilde)->data->data[j] += -I * half_amp_eps * (Term1_sum - Term2_sum);
836 }
837
838 XLALFree(wigs);
839 XLALFree(als);
840 XLALFree(ylms); // allocated in XLALSimIMRPhenomPv3HMComputeYlmElements
841 }
842
843 return XLAL_SUCCESS;
844}
845
846/**
847 * Returns frequency domain hlm's in inertial frame
848 *
849 */
851 SphHarmFrequencySeries **hlms, /**< [out] SphHarmFrequencySeries struct containing inertial frame hlm modes */
852 REAL8Sequence *freqs, /**< frequency sequency in Hz */
853 REAL8 m1_SI, /**< mass of companion 1 (kg) */
854 REAL8 m2_SI, /**< mass of companion 2 (kg) */
855 REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
856 REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
857 REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
858 REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
859 REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
860 REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
861 const REAL8 phiRef, /**< reference orbital phase (rad) */
862 const REAL8 deltaF, /**< Sampling frequency (Hz) */
863 const REAL8 f_ref, /**< Reference frequency */
864 LALDict *extraParams) /**<linked list containing the extra testing GR parameters */
865{
866
867 XLAL_ERROR(XLAL_EFUNC, "Function (XLALSimIMRPhenomPv3HMModes) not implemented!\n");
868
869 XLAL_CHECK(f_ref > 0, XLAL_EDOM, "f_ref must be greater than zero.\n");
870
871 /* Use an auxiliar laldict to not overwrite the input argument */
872 LALDict *extraParams_aux;
873
874 /* setup mode array */
875 if (extraParams == NULL)
876 {
877 extraParams_aux = XLALCreateDict();
878 }
879 else{
880 extraParams_aux = XLALDictDuplicate(extraParams);
881 }
882 extraParams_aux = IMRPhenomPv3HM_setup_mode_array(extraParams_aux);
883 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(extraParams_aux);
884 int rcode = IMRPhenomPv3HM_check_mode_array(ModeArray);
885 XLAL_CHECK(XLAL_SUCCESS == rcode, rcode, "IMRPhenomPv3HM_check_mode_array failed");
886
887 UNUSED const REAL8 Mtot_Msun = (m1_SI + m2_SI) / LAL_MSUN_SI;
888
889 REAL8 f_min = 0.;
890 REAL8 f_max = 0.;
891 size_t npts = 0;
892 REAL8Sequence *freqs_seq = NULL;
893
894 LIGOTimeGPS tC = LIGOTIMEGPSZERO; // = {0, 0}
895
896 if ((freqs->length == 2) && (deltaF > 0.))
897 {
898 // uniform frequencies
899 f_min = freqs->data[0];
900 f_max = freqs->data[1];
901
902 if (f_max == 0.)
903 {
904 f_max = XLALSimPhenomUtilsMftoHz(0.5, Mtot_Msun);
905 }
906 npts = PhenomInternal_NextPow2(f_max / deltaF) + 1;
907
908 freqs_seq = XLALCreateREAL8Sequence(npts);
909 for (size_t j = 0; j < npts; j++)
910 {
911 freqs_seq->data[j] = j * deltaF;
912 }
913 /* coalesce at t=0 */
914 /* Shift by overall length in time */
916 XLALGPSAdd(&tC, -1. / deltaF),
918 "Failed to shift coalescence time to t=0,\
919tried to apply shift of -1.0/deltaF with deltaF=%g.",
920 deltaF);
921 }
922 else if ((freqs->length != 2) && (deltaF <= 0.))
923 { /* else if 2. i.e. not uniformly spaced then we don't shift. */
924 // custom frequencies
925 f_min = freqs->data[0];
926 f_max = freqs->data[freqs->length - 1]; /* Last element */
927 npts = freqs->length;
928 freqs_seq = XLALCreateREAL8Sequence(npts);
929 for (size_t j = 0; j < npts; j++)
930 {
931 freqs_seq->data[j] = freqs->data[j];
932 }
933 }
934 else
935 {
936 XLAL_ERROR(XLAL_EDOM, "Input frequencies not as expected. Aborting.\n");
937 }
938
939 /* Store useful variables and compute derived and frequency independent variables */
940 PhenomPv3HMStorage *pv3HM;
942
943 /* Struct that stores the precession angle variables */
944 sysq *pAngles;
945 pAngles = (sysq *)XLALMalloc(sizeof(sysq));
946
947 // distance and inclination are not used in the modes
948 // so we just parse dummy variables
949 REAL8 distance = 1.;
950 REAL8 inclination = 0.;
951
952 int retcode = init_PhenomPv3HM_Storage(pv3HM, pAngles,
953 m1_SI, m2_SI,
954 chi1x, chi1y, chi1z,
955 chi2x, chi2y, chi2z,
956 distance, inclination, phiRef,
957 deltaF, f_min, f_max, f_ref);
958 XLAL_CHECK(XLAL_SUCCESS == retcode, retcode, "init_PhenomPv3HM_Storage failed");
959
960 // hlmsD = co-precessing frame modes
962 *hlmsD = NULL;
963 /* XLALSimIMRPhenomHMGethlmModes currently takes only the positive m modes */
965 hlmsD,
966 freqs,
967 m1_SI,
968 m2_SI,
969 chi1x,
970 chi1y,
971 chi1z,
972 chi2x,
973 chi2y,
974 chi2z,
975 pv3HM->phiRef,
976 deltaF,
977 f_ref,
978 extraParams_aux);
979 XLAL_CHECK(XLAL_SUCCESS == retcode,
980 XLAL_EFUNC, "XLALSimIMRPhenomHMGethlmModes failed");
981
982 const REAL8 Msec = Mtot_Msun * LAL_MTSUN_SI; /* Total mass in seconds */
983 const REAL8 twopi_Msec = LAL_TWOPI * Msec;
984 REAL8 fHz = 0.;
985
986 int ret_abe;
987 int ret_wig_element;
988
989 REAL8 alpha = 0.;
990 REAL8 beta = 0.;
991 REAL8 mprime_epsilon = 0.;
992 REAL8 wig_d = 0.;
993
994 /* loop over modes */
995 /* at this point ModeArray should contain the list of modes
996 * and therefore if NULL then something is wrong and abort.
997 */
998 if (ModeArray == NULL)
999 {
1000 XLAL_ERROR(XLAL_EDOM, "ModeArray is NULL when it shouldn't be. Aborting.\n");
1001 }
1002 for (UINT4 ell = 2; ell < L_MAX_PLUS_1; ell++)
1003 { // inertial frame ell modes
1004 for (INT4 mm = -ell; mm < (INT4)ell + 1; mm++)
1005 { // inertial frame mm modes
1006 // inertial frame mode FrequencySeries
1007 COMPLEX16FrequencySeries *hlm = XLALCreateCOMPLEX16FrequencySeries("hlm: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, npts);
1008 memset(hlm->data->data, 0, npts * sizeof(COMPLEX16));
1009
1010 for (INT4 mprime = 1; mprime < (INT4)ell + 1; mprime++)
1011 {
1012 /* The negative m modes are automatically added. */
1013 /* first check if (l,m) mode is 'activated' in the ModeArray */
1014 /* if activated then generate the mode, else skip this mode. */
1015 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, mprime) != 1)
1016 { /* skip mode */
1017 XLAL_PRINT_INFO("SKIPPING ell = %i mprime = %i\n", ell, mprime);
1018 continue;
1019 } /* else: generate mode */
1020 XLAL_PRINT_INFO("generateing ell = %i mprime = %i\n", ell, mprime);
1021
1023 if (!(hlmD))
1024 XLAL_ERROR(XLAL_EFUNC, "XLALSphHarmFrequencySeriesGetMode failed for (%i,%i) mode\n", ell, mprime);
1025
1026 // frequency loop
1027 for (size_t j = 0; j < freqs_seq->length; j++)
1028 {
1029
1030 fHz = freqs_seq->data[j]; //for the angles
1031 // compute alpha, beta and mprime*epsilon
1032 ret_abe = IMRPhenomPv3HM_Compute_a_b_e(&alpha, &beta, &mprime_epsilon, fHz, mprime, twopi_Msec, pv3HM, pAngles);
1033 XLAL_CHECK(
1034 XLAL_SUCCESS == ret_abe,
1035 XLAL_EFUNC,
1036 "IMRPhenomPv3HM_Compute_a_b_e failed");
1037
1038 ret_wig_element = XLALSimPhenomUtilsPhenomPv3HMWignerdElement(&wig_d, ell, mprime, mm, -beta);
1039 XLAL_CHECK(
1040 XLAL_SUCCESS == ret_wig_element,
1041 XLAL_EFUNC,
1042 "XLALSimPhenomUtilsPhenomPv3HMWignerdElement failed");
1043
1044 COMPLEX16 hlmD_j = hlmD->data->data[j];
1045 hlm->data->data[j] += hlmD_j * cexp(-I * mprime_epsilon) * cexp(I * mm * alpha) * wig_d;
1046 }
1047 }
1048
1049 *hlms = XLALSphHarmFrequencySeriesAddMode(*hlms, hlm, ell, mm);
1050
1052 }
1053 }
1054
1055 // LALFree(hlmD);
1056 XLALDestroyREAL8Sequence(freqs_seq);
1057 XLALDestroyValue(ModeArray);
1059 XLALFree(hlmsD);
1060
1061
1062 /* free pointers */
1063 LALFree(pv3HM);
1064 LALFree(pAngles);
1065 XLALDestroyDict(extraParams_aux);
1066
1067 return XLAL_SUCCESS;
1068}
void XLALDestroyDict(LALDict *dict)
LALDict * XLALDictDuplicate(const LALDict *orig)
LALDict * XLALCreateDict(void)
#define LALFree(p)
int XLALSimIMRPhenomHMGethlmModes(SphHarmFrequencySeries **hlms, REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, const REAL8 phiRef, const REAL8 deltaF, REAL8 f_ref, LALDict *extraParams)
void PhenomInternal_ComputeIMRPhenomPv3CartesianToPolar(REAL8 *polar, REAL8 *azimuthal, REAL8 *magnitude, REAL8 x, REAL8 y, REAL8 z)
function to convert from 3d cartesian components to polar angles and vector magnitude.
int PhenomInternal_IMRPhenomHMFDAddMode(COMPLEX16FrequencySeries *hptilde, COMPLEX16FrequencySeries *hctilde, COMPLEX16FrequencySeries *hlmtilde, REAL8 theta, REAL8 phi, INT4 l, INT4 m, INT4 sym)
helper function to multiple hlm with Ylm.
size_t PhenomInternal_NextPow2(const size_t n)
Return the closest higher power of 2.
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.
int XLALSimIMRPhenomPv3HMModes(SphHarmFrequencySeries **hlms, REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, const REAL8 phiRef, const REAL8 deltaF, const REAL8 f_ref, LALDict *extraParams)
Returns frequency domain hlm's in inertial frame.
int XLALSimIMRPhenomPv3HMGetHplusHcross(UNUSED COMPLEX16FrequencySeries **hptilde, UNUSED COMPLEX16FrequencySeries **hctilde, UNUSED REAL8Sequence *freqs, UNUSED REAL8 m1_SI, UNUSED REAL8 m2_SI, UNUSED REAL8 chi1x, UNUSED REAL8 chi1y, UNUSED REAL8 chi1z, UNUSED REAL8 chi2x, UNUSED REAL8 chi2y, UNUSED REAL8 chi2z, UNUSED const REAL8 distance, UNUSED const REAL8 inclination, UNUSED const REAL8 phiRef, UNUSED const REAL8 deltaF, UNUSED REAL8 f_ref, UNUSED LALDict *extraParams)
This version doesn't construct precessing hlm modes but instead constructs hplus, hcross directly.
static int IMRPhenomPv3HM_check_mode_array(LALValue *ModeArray)
Reads in a ModeArray and checks that it is valid.
#define L_MAX_PLUS_1
int XLALSimIMRPhenomPv3(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, const REAL8 distance, const REAL8 inclination, const REAL8 phiRef, const REAL8 deltaF, const REAL8 f_ref, LALDict *extraParams)
Driver routine to compute the precessing inspiral-merger-ringdown phenomenological waveform IMRPhenom...
static UNUSED int init_PhenomPv3HM_Storage(PhenomPv3HMStorage *p, sysq *pAngles, REAL8 m1_SI, REAL8 m2_SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, const REAL8 distance, const REAL8 inclination, const REAL8 phiRef, const REAL8 deltaF, const REAL8 f_min, const REAL8 f_max, const REAL8 f_ref)
Precomputes useful quantities and populates the PhenomPv3HMStorage and sysq (for precession angles) s...
static LALDict * IMRPhenomPv3HM_setup_mode_array(LALDict *extraParams)
read in a LALDict.
static int IMRPhenomPv3HM_wigner_loop(COMPLEX16 *Term1, COMPLEX16 *Term2, INT4 ell, INT4 mprime, IMRPhenomPv3HMYlmStruct *ylms, IMRPhenomPv3HMAlphaStruct *als, IMRPhenomPv3HMWignderStruct *wigs)
This is an internal function computes terms required to compute hptilde and hctilde.
#define PHENOM_DEFAULT_MAXF
static int IMRPhenomPv3HM_Compute_a_b_e(REAL8 *alpha, REAL8 *beta, REAL8 *mprime_epsilon, REAL8 fHz, INT4 mprime, const REAL8 twopi_Msec, PhenomPv3HMStorage *pv3HM, sysq *pAngles)
This is an internal function that returns the precession angles at a single frequency.
static int IMRPhenomPv3HM_Compute_Mode(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, UINT4 ell, INT4 mprime, const REAL8 Mtot_Msun, PhenomPv3HMStorage *pv3HM, SphHarmFrequencySeries **hlmsD, sysq *pAngles, REAL8Sequence *freqs_seq)
This is an internal function that returns hptilde and hctilde for a single mode in the inertial frame...
#define LHAT_PHI
#define LHAT_COS_THETA
double XLALSimPhenomUtilsFDamp0(REAL8 Mtot_Msun, REAL8 distance)
compute the frequency domain amplitude pre-factor
int XLALSimIMRPhenomPv3HMComputeAlphaElements(IMRPhenomPv3HMAlphaStruct **p, UINT4 ell, REAL8 alpha)
int XLALSimIMRPhenomPv3HMComputeWignerdElements(IMRPhenomPv3HMWignderStruct **p, UNUSED UINT4 ell, UNUSED INT4 mprime, UNUSED REAL8 b)
computes the wigner-d elements for -beta in batches.
double XLALSimPhenomUtilsMftoHz(REAL8 Mf, REAL8 Mtot_Msun)
Convert from geometric frequency to frequency in Hz.
IMRPhenomPv3HMYlmStruct * XLALSimIMRPhenomPv3HMComputeYlmElements(REAL8 theta, REAL8 phi, INT4 ell)
int XLALSimPhenomUtilsPhenomPv3HMWignerdElement(REAL8 *wig_d, UINT4 ell, INT4 mprime, INT4 mm, REAL8 b)
Hard coded expressions for relevant Wignerd matrix elements.
static UNUSED int InitializeSystem(sysq *system, const double m1, const double m2, const double mul, const double phl, const double mu1, const double ph1, const double ch1, const double mu2, const double ph2, const double ch2, const double f_0, const int ExpansionOrder)
InitializeSystem computes all the prefactors needed to generate precession angles from Chatziioannou ...
static UNUSED vector compute_phiz_zeta_costhetaL3PN(const double xi, const sysq *system)
Internal function that computes phiz, zeta, and costhetaL at 3PN.
static double beta(const double a, const double b, const sysq *system)
Internal function that computes the spin-orbit couplings.
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
int XLALSimInspiralWaveformParamsInsertModeArray(LALDict *params, LALValue *value)
void XLALDestroyValue(LALValue *value)
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define LAL_MSUN_SI
#define LAL_TWOPI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
void XLALFree(void *p)
@ IMRPhenomPv3_V
version 3: based on IMRPhenomD and the precession angles from Katerina Chatziioannou PhysRevD....
Definition: LALSimIMR.h:77
int XLALSimIMRPhenomPCalculateModelParametersFromSourceFrame(REAL8 *chi1_l, REAL8 *chi2_l, REAL8 *chip, REAL8 *thetaJN, REAL8 *alpha0, REAL8 *phi_aligned, REAL8 *zeta_polariz, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 f_ref, const REAL8 phiRef, const REAL8 incl, const REAL8 s1x, const REAL8 s1y, const REAL8 s1z, const REAL8 s2x, const REAL8 s2y, const REAL8 s2z, IMRPhenomP_version_type IMRPhenomP_version)
Function to map LAL parameters (masses, 6 spin components, phiRef and inclination at f_ref) (assumed ...
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralModeArrayActivateMode(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralCreateModeArray(void)
Create a LALValue pointer to store the mode array.
COMPLEX16FrequencySeries * XLALSphHarmFrequencySeriesGetMode(SphHarmFrequencySeries *ts, UINT4 l, INT4 m)
Get the time series of a waveform's (l,m) spherical harmonic mode from a SphHarmFrequencySeries linke...
SphHarmFrequencySeries * XLALSphHarmFrequencySeriesAddMode(SphHarmFrequencySeries *appended, const COMPLEX16FrequencySeries *inmode, UINT4 l, INT4 m)
Prepend a node to a linked list of SphHarmFrequencySeries, or create a new head.
void XLALDestroySphHarmFrequencySeries(SphHarmFrequencySeries *ts)
Delete list from current pointer to the end of the list.
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_PRINT_INFO(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
p
double alpha
Definition: sgwb.c:106
COMPLEX16Sequence * data
COMPLEX16 * data
a strcut to keep the complex exponential terms of the alpha precession angle
COMPLEX16 alpha4[9]
optimised elements for complex exponential of the alpha angle for ell = 4
COMPLEX16 alpha3[7]
optimised elements for complex exponential of the alpha angle for ell = 3
COMPLEX16 alpha2[5]
optimised elements for complex exponential of the alpha angle for ell = 2
a strcut to keep the wigner-d matrix elements
REAL8 d33[2][7]
wigner-d matrix elements for ell=3, mprime=+/-3 and positive[0] and negative[1] mprime
REAL8 d43[2][9]
wigner-d matrix elements for ell=4, mprime=+/-3 and positive[0] and negative[1] mprime
REAL8 d21[2][5]
wigner-d matrix elements for ell=2, mprime=+/-1 and positive[0] and negative[1] mprime
REAL8 d44[2][9]
wigner-d matrix elements for ell=4, mprime=+/-4 and positive[0] and negative[1] mprime
REAL8 d32[2][7]
wigner-d matrix elements for ell=3, mprime=+/-2 and positive[0] and negative[1] mprime
REAL8 d22[2][5]
wigner-d matrix elements for ell=2, mprime=+/-2 and positive[0] and negative[1] mprime
a strcut to keep the spherical harmonic terms
COMPLEX16 Ylm2[2][5]
optimised elements Ylms for ell = 2.
COMPLEX16 Ylm4[2][9]
optimised elements Ylms for ell = 4.
COMPLEX16 Ylm3[2][7]
optimised elements Ylms for ell = 3.
Structure storing initial and derived variables for IMRPhenomPv3HM.
REAL8 inclination
inclination - used to compute the angle thetaJN (rad)
REAL8 alpha0
Initial value of alpha angle (azimuthal precession angle)
REAL8 zeta_polariz
Angle to rotate the polarizations.
INT4 PRECESSING
integer to signify if system is precessing, 1 for false (not precessing), 0 for true (precessing)
REAL8 * data
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23