Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-00ddc7f
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRPhenomXHM.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2019 Marta Colleoni, Cecilio García Quirós
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// Created by Marta on 13/02/2019.
21//
22
23#include <lal/LALSimIMR.h>
24#include <lal/SphericalHarmonics.h>
25#include <lal/Sequence.h>
26#include <lal/Date.h>
27#include <lal/Units.h>
28#include <lal/LALConstants.h>
29#include <lal/FrequencySeries.h>
30#include <lal/LALDatatypes.h>
31#include <lal/LALStdlib.h>
32#include <lal/XLALError.h>
33
34#include <stdbool.h>
35#include <stdio.h>
36#include <stdlib.h>
37
38#ifndef _OPENMP
39#define omp ignore
40#endif
41
42#define L_MAX 4
43
44#ifndef PHENOMXHMDEBUG
45#define DEBUG 0
46#else
47#define DEBUG 1 //print debugging info
48#endif
49
50#ifndef PHENOMXHMMBAND
51#define MBAND 0
52#else
53#define MBAND PHENOMXHMMBAND //use multibanding
54#endif
55
58
62
63//#include "LALSimIMRPhenomXHM.h" (non-precessing review version )
64
65#include "LALSimIMRPhenomXPHM.c"
66
67/* Note: This is declared in LALSimIMRPhenomX_internals.c and avoids namespace clash */
69
70
71//This is a wrapper function for adding higher modes to the ModeArray
72static LALDict *IMRPhenomXHM_setup_mode_array(LALDict *lalParams);
73
74/*
75* Helper function to multiple hlm with Ylm.
76* Adapted from LALSimIMREOBNRv2HMROMUtilities.c
77*/
78static int IMRPhenomXHMFDAddMode(
79 COMPLEX16FrequencySeries *hptilde, /**<[out] hp series*/
80 COMPLEX16FrequencySeries *hctilde, /**<[out] hc series */
81 COMPLEX16FrequencySeries *hlmtilde, /**< hlm mode to add */
82 REAL8 theta, /**< Inclination [rad] */
83 REAL8 phi, /**< Azimuthal angle [rad]*/
84 INT4 l, /**< l index of the lm mode */
85 INT4 m, /**< m index of the lm mode */
86 INT4 sym /**< Equatorial symmetry */
87);
88
89
90/* Return hptilde and hctilde from a sum of modes */
91static int IMRPhenomXHM_MultiMode(
92 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
93 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
94 REAL8 m1_SI, /**< primary mass [kg] */
95 REAL8 m2_SI, /**< secondary mass [kg] */
96 REAL8 chi1z, /**< aligned spin of primary */
97 REAL8 chi2z, /**< aligned spin of secondary */
98 REAL8 f_min, /**< Starting GW frequency (Hz) */
99 REAL8 f_max, /**< End frequency; 0 defaults to Mf = 0.3 */
100 REAL8 deltaF, /**< Sampling frequency (Hz) */
101 REAL8 distance, /**< distance of source (m) */
102 REAL8 inclination, /**< inclination of source (rad) */
103 REAL8 phiRef, /**< reference orbital phase (rad) */
104 REAL8 fRef_In, /**< Reference frequency */
105 LALDict *lalParams /**< LALDict struct */
106);
107
108/* Return hptilde and hctilde from a sum of modes */
109static int IMRPhenomXHM_MultiMode2(
110 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
111 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
112 const REAL8Sequence *freqs_In, /**< min and max frequency [Hz] */
113 IMRPhenomXWaveformStruct *pWF, /**< waveform parameters */
114 LALDict *lalParams /**< LALDict struct */
115);
116
117
118/* Definitions of functions */
119
120
121/* Wrapper function for adding higher modes to the ModeArray */
122static LALDict *IMRPhenomXHM_setup_mode_array(LALDict *lalParams)
123{
124 /* setup ModeArray */
125 INT4 lalParams_In = 0;
126 if (lalParams == NULL)
127 {
128 lalParams_In = 1;
129 lalParams = XLALCreateDict();
130 }
131 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
132
133 /* If the mode array is empty, populate using a default choice of modes */
134 if (ModeArray == NULL)
135 {
136 /* Default behaviour */
137 XLAL_PRINT_INFO("Using default modes for IMRPhenomXHM.\n");
138 ModeArray = XLALSimInspiralCreateModeArray();
139
140 /* Only define +m modes as we get -m modes for free */
141 /* IMRPhenomXHM has the following calibrated modes. 22 mode taken from IMRPhenomXAS */
147 XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
148 XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -1);
149 XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -3);
150 XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -2);
151 XLALSimInspiralModeArrayActivateMode(ModeArray, 4, -4);
152
154 }
155 else {XLAL_PRINT_INFO("Using custom modes for PhenomXHM.\n"); }
156
157 XLALDestroyValue(ModeArray);
158 if(lalParams_In == 1)
159 {
160 XLALDestroyDict(lalParams);
161 }
162
163 return lalParams;
164}
165
166
167/* Compute the frequency array and initialize htildelm to the corresponding length. */
169 REAL8Sequence **freqs, /**< [out] frequency grid [Hz */
170 COMPLEX16FrequencySeries **htildelm, /**< [out] Frequency domain hlm GW strain */
171 const REAL8Sequence *freqs_In, /**< fmin, fmax [Hz] */
172 IMRPhenomXWaveformStruct *pWF, /**< Waveform structure with parameters */
173 LIGOTimeGPS ligotimegps_zero /**< = {0,0} */
174)
175{
176
177 /* Inherit minimum and maximum frequencies to generate wavefom from input frequency grid */
178 double f_min = freqs_In->data[0];
179 double f_max = freqs_In->data[freqs_In->length - 1];
180
181 /* Size of array */
182 size_t npts = 0;
183
184 /* Index shift between freqs and the frequency series */
185 UINT4 offset = 0;
186
187 /* If deltaF is non-zero then we need to generate a uniformly sampled frequency grid of spacing deltaF. Start at f = 0. */
188 if(pWF->deltaF > 0)
189 {
190 /* Return the closest power of 2 */
191 npts = (size_t) (f_max / pWF->deltaF) + 1;
192
193 /* Debug information */
194 #if DEBUG == 1
195 printf("npts = %zu\n",npts);
196 printf("fMin = %.6f\n",f_min);
197 printf("fMax = %.6f\n",f_max);
198 printf("dF = %.6f\n",pWF->deltaF);
199 printf("f_max / deltaF = %.6f\n", f_max / pWF->deltaF);
200 #endif
201
202 /* Coalescence time is fixed to t=0, shift by overall length in time. Model is calibrated such that it peaks approx 500M before the end of the waveform, add this time to the epoch. */
203 XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.",pWF->deltaF);
204 /* Initialize the htilde frequency series */
205 *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,npts);
206 /* Check that frequency series generated okay */
207 XLAL_CHECK(*htildelm,XLAL_ENOMEM,"Failed to allocate COMPLEX16FrequencySeries of length %zu for f_max = %f, deltaF = %g.\n",npts,f_max,pWF->deltaF);
208
209 /* Frequencies will be set using only the lower and upper bounds that we passed */
210 size_t iStart = (size_t) (f_min / pWF->deltaF);
211 size_t iStop = (size_t) (f_max / pWF->deltaF) + 1;
212
213 XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
214 "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
215
216 #if DEBUG == 1
217 printf("f_min asked returned = %.16e %.16e \n",f_min, iStart*pWF->deltaF);
218 printf("f_max asked returned = %.16e %.16e \n",f_max, iStop*pWF->deltaF);
219 #endif
220
221 /* Allocate memory for frequency array and terminate if this fails */
222 (*freqs) = XLALCreateREAL8Sequence(iStop - iStart);
223 if (!(*freqs))
224 {
225 XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
226 }
227 /* Populate frequency array */
228 for (UINT4 i = iStart; i < iStop; i++)
229 {
230 (*freqs)->data[i-iStart] = i * pWF->deltaF;
231 }
232 offset = iStart;
233 }
234 else
235 {
236 /* freqs is a frequency grid with non-uniform spacing, so we start at the lowest given frequency */
237 npts = freqs_In->length;
238 *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform, 22 mode", &ligotimegps_zero, f_min, pWF->deltaF, &lalStrainUnit, npts);
239 XLAL_CHECK (*htildelm, XLAL_ENOMEM, "Failed to allocated waveform COMPLEX16FrequencySeries of length %zu from sequence.", npts);
240 offset = 0;
241 (*freqs) = XLALCreateREAL8Sequence(freqs_In->length);
242
243 /* Allocate memory for frequency array and terminate if this fails */
244 if (!(*freqs))
245 {
246 XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
247 }
248
249 /* Populate frequency array */
250 for (UINT4 i = 0; i < freqs_In->length; i++)
251 {
252 (*freqs)->data[i] = freqs_In->data[i];
253 }
254 }//end loop of freqs
255
256 memset((*htildelm)->data->data, 0, npts * sizeof(COMPLEX16));
257 XLALUnitMultiply(&((*htildelm)->sampleUnits), &((*htildelm)->sampleUnits), &lalSecondUnit);
258
259 return offset;
260}
261
262
263/**
264 * @addtogroup LALSimIMRPhenomX_c
265 * @{
266 *
267 * @name Routines for IMRPhenomXHM
268 * @{
269 */
270
271
272
273/********************************/
274/* */
275/* SINGLE MODE */
276/* */
277/********************************/
278
279/* Functions to compute the strain of just one mode htildelm */
280
281/** Returns the Fourier domain strain of just one mode: h_lm. Supports positive and negative m.
282Notice than even when the specified frequencies are positives, the m>0 only lives in the negative frequencies regime.
283With m>0 the mode h_lm is zero for positive frequencies and for the negative frequencies is equal to (-1)^l h*_l-m(-f).
284In the contrary, h_l-m is zero for negative frequencies and only lives for positive frequencies.
285This is a wrapper function that uses XLALSimIMRPhenomXASGenerateFD for the 22 mode and IMRPhenomXHMGenerateFDOneMode for the higher modes.
286 */
288 COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
289 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
290 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
291 REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
292 REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
293 UINT4 ell, /**< l index of the mode */
294 INT4 emm, /**< m index of the mode */
295 REAL8 distance, /**< Luminosity distance (m) */
296 REAL8 f_min, /**< Starting GW frequency (Hz) */
297 REAL8 f_max, /**< End frequency; 0 defaults to Mf = 0.3 */
298 REAL8 deltaF, /**< Sampling frequency (Hz) */
299 REAL8 phiRef, /**< Orbital phase at fRef (rad) */
300 REAL8 fRef_In, /**< Reference frequency (Hz) */
301 LALDict *lalParams /**< Extra params */
302 )
303 {
304
305 /* If the 22 is required, call to PhenomX. */
306 if(ell == 2 && abs(emm) == 2){
308 htildelm,
309 m1_SI,
310 m2_SI,
311 chi1L,
312 chi2L,
313 distance,
314 f_min,
315 f_max,
316 deltaF,
317 phiRef,
318 fRef_In,
319 lalParams
320 );
321 if(emm>0){
322 #if DEBUG == 1
323 printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
324 #endif
325 for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
326 (*htildelm)->data->data[idx] = conj((*htildelm)->data->data[idx]);
327 }
328 }
329 size_t iStart = (size_t) (f_min / deltaF);
330 return iStart;
331 }
332 /***** Higher modes ****/
333 else{
334
336
337 #if DEBUG == 1
338 printf("\n**********************************************************************\n");
339 printf("\n* IMRPhenomXHMGenereateFDOneMode %i%i *\n", ell, abs(emm));
340 printf("\n**********************************************************************\n");
341 printf("fRef_In : %e\n",fRef_In);
342 printf("m1_SI : %e\n",m1_SI);
343 printf("m2_SI : %e\n",m2_SI);
344 printf("chi1L : %e\n",chi1L);
345 printf("chi2L : %e\n\n",chi2L);
346 printf("Performing sanity checks...\n");
347 #endif
348
349 /* Sanity checks */
350 if(*htildelm) { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT); }
351 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
352 if(deltaF <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n"); }
353 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
354 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
355 if(f_min <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n"); }
356 if(f_max < 0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n"); }
357 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
358
359 /*
360 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
361 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
362 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
363 - For mass ratios > 1000: throw a hard error that model is not valid.
364 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
365
366 */
367 REAL8 mass_ratio;
368 if(m1_SI > m2_SI)
369 {
370 mass_ratio = m1_SI / m2_SI;
371 }
372 else
373 {
374 mass_ratio = m2_SI / m1_SI;
375 }
376 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
377 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
378 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
379
380 /* Use an auxiliar laldict to not overwrite the input argument */
381 LALDict *lalParams_aux;
382 /* setup mode array */
383 if (lalParams == NULL)
384 {
385 lalParams_aux = XLALCreateDict();
386 }
387 else{
388 lalParams_aux = XLALDictDuplicate(lalParams);
389 }
390 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
391 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
392
393 /* first check if (l,m) mode is 'activated' in the ModeArray */
394 /* if activated then generate the mode, else skip this mode. */
395 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1 )
396 { /* skip mode */
397 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
399 } /* else: generate mode */
400
401
402 /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
403 REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
404
405 #if DEBUG == 1
406 printf("\n\n **** Initializing waveform struct... **** \n\n");
407 #endif
408
409 /* Initialize the useful powers of LAL_PI */
412 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
413
414
415 /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
418 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, 0.0, lalParams_aux, DEBUG);
419 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
420
421 #if DEBUG == 1
422 printf("\n f_max_prime = %.16f, fMax = %.16f \n",pWF->f_max_prime, pWF->fMax);
423 #endif
424
425
426 /* Return the closest power of 2 */
427 size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
428 /* Frequencies will be set using only the lower and upper bounds that we passed */
429 size_t iStart = (size_t) (f_min / deltaF);
430 size_t iStop = (size_t) (pWF->f_max_prime / deltaF);
431 XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
432 "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
433
434 /* Create a REAL8 frequency series only passing the boundaries (fMin, fMax). */
436 freqs->data[0] = pWF->fMin;
437 freqs->data[1] = pWF->f_max_prime;
438
439
440 #if DEBUG == 1
441 printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[1]);
442 printf("\n\n **** Calling IMRPhenomXHMGenerateFDOneMode... **** \n\n");
443 printf("\n f_max_prime = %.16f, fMax = %.16f \n", pWF->f_max_prime, pWF->fMax);
444 #endif
445
446 /*** Call core single mode waveform generator ***/
447 status = IMRPhenomXHMGenerateFDOneMode(htildelm, freqs, pWF, ell, abs(emm), lalParams_aux);
448 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHMGenerateFDOneMode failed to generate IMRPhenomXHM waveform.");
449
450 #if DEBUG == 1
451 printf("\n\n **** Call to IMRPhenomXHMGenerateFD complete. **** \n\n");
452 printf("\n f_max_prime = %.16f, fMax = %.16f \n",pWF->f_max_prime, pWF->fMax);
453 #endif
454
455
456 if(emm>0){
457 #if DEBUG == 1
458 printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
459 #endif
460 INT4 minus1l = 1;
461 if(ell%2!=0){
462 #if DEBUG == 1
463 printf("\nl odd\n");
464 #endif
465 minus1l = -1;
466 }
467 for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
468 (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
469 }
470 }
471
472 /* Resize htildelm if needed */
473 REAL8 lastfreq;
474 if (pWF->f_max_prime < pWF->fMax)
475 {
476 /* The user has requested a higher f_max than Mf = fCut.
477 Resize the frequency series to fill with zeros beyond the cutoff frequency. */
478 lastfreq = pWF->fMax;
479 XLAL_PRINT_WARNING("The input f_max = %.2f Hz is larger than the internal cutoff of Mf=0.3 (%.2f Hz). Array will be filled with zeroes between these two frequencies.\n", pWF->fMax, pWF->f_max_prime);
480 }
481 else
482 {
483 lastfreq = pWF->f_max_prime;
484 }
485 size_t n = (*htildelm)->data->length;
486 // We want to have the length be a power of 2 + 1
487 size_t n_full = NextPow2(lastfreq / pWF->deltaF) + 1;
488
489 /* Resize the COMPLEX16 frequency series */
490 *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
491 XLAL_CHECK (*htildelm, 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, pWF->f_max_prime, n_full, pWF->fMax );
492
493
494 /* Free allocated memory */
495 LALFree(pWF);
497 XLALDestroyValue(ModeArray);
498 XLALDestroyDict(lalParams_aux);
499
500 #if DEBUG == 1
501 printf("\n Leaving XLALSimIMRPhenomXHMGenerateFDOneMode \n");
502 #endif
503
504 return iStart;
505 }//Higher modes
506 }
507/** @} **
508* @} **/
509
510/* Core function to generate the waveform of one mode: htildelm. */
512 COMPLEX16FrequencySeries **htildelm, /**< [out] hlm for one mode **/
513 const REAL8Sequence *freqs_In, /**< fmin, fmax [Hz] **/
514 IMRPhenomXWaveformStruct *pWF, /**< structure of the 22 mode **/
515 UINT4 ell, /**< first index of the mode **/
516 UINT4 emm, /**< second index of the mode **/
517 LALDict *lalParams /**< extra params **/
518)
519{
520
521 #if DEBUG == 1
522 printf("\n\n ***** IMRPhenomXHMGenerateFDOneMode **** \n\n");
523 #endif
524
525 /* Set LIGOTimeGPS */
526 LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
527
528 UINT4 initial_status = XLAL_SUCCESS;
529
530 REAL8Sequence *freqs;
531 UINT4 offset = SetupWFArrays(&freqs, htildelm, freqs_In, pWF, ligotimegps_zero);
532
533 #if DEBUG == 1
534 printf("\nIMRPhenomXHMGenerateFDOneMode: Length@freqs, offset %i %u",freqs->length,offset);
535 printf("\nIMRPhenomXHMGenerateFDOneMode: fstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
536 #endif
537
538 /* Check if LAL dictionary exists. If not, create a LAL dictionary. */
539 INT4 lalParams_In = 0;
540 if(lalParams == NULL)
541 {
542 lalParams_In = 1;
543 lalParams = XLALCreateDict();
544 }
545
546 // allocate qnm struct
547 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
549
550 // Populate pWFHM
552 IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams);
553 LALFree(qnms);
554
555
556 /* Fill only the modes that are not zero. Odd modes for equal mass, equal spins are zero. */
557 /* Since hlmtilde is initialized with zeros, for zero modes we just go to the return line. */
558 if(pWFHM->Ampzero==0){
559
560 /* Allocate coefficients of 22 mode */
563 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
564
565 /* Allocate and initialize the PhenomXHM lm amplitude and phae coefficients struct */
568
569 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
572
573 /* Get coefficients for Amplitude and phase */
574 if (pWFHM->MixingOn == 1) {
575 // For mode with mixing we need the spheroidal coeffs of the 32 phase and the 22 amplitude coeffs.
576 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
578 }
579 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
580 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
581
582
583 /* Find phase and phase derivative shift, lina and linb respectively that
584 align the PNR coprecessing model with XHM at a defined alignment frequency
585 during inspiral */
586 double lina = 0;
587 double linb = 0;
588 if (
589 pWF->APPLY_PNR_DEVIATIONS && pWF->IMRPhenomXPNRForceXHMAlignment && (ell != 2) && (emm != 2)
590 )
591 {
592 IMRPhenomXHM_PNR_EnforceXHMPhaseAlignment( &lina,&linb,ell,emm,pWF,lalParams);
593 }
594
595
596 IMRPhenomX_UsefulPowers powers_of_Mf;
597 REAL8 Msec = pWF->M_sec; // Variable to transform Hz to Mf
598 REAL8 Amp0 = pWF->amp0; // Transform amplitude from NR to physical units
599 REAL8 amp, phi;
600
601 /* Multiply by (-1)^l to get the true h_l-m(f) */
602 if(ell%2 != 0){
603 Amp0 = -Amp0;
604 }
605
606 #if DEBUG == 1
607 //Initialize file to print h_l-m with freqs, amplitude and phase in "Physical" units
608 FILE *file;
609 char fileSpec[40];
610 sprintf(fileSpec, "simulation%i_SM.dat", pWFHM->modeTag);
611 printf("\nOutput file: %s\r\n",fileSpec);
612 file = fopen(fileSpec,"w");
613 fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->chi1L, pWF->chi2L, 22, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
614 fprintf(file,"# Frequency (Hz) Amplitude Phase\n");
615 #endif
616
617
618 /* Loop over frequencies to generate waveform */
619 /* Modes with mixing */
620 if(pWFHM->MixingOn==1)
621 {
622 REAL8 Mf;
623 for (UINT4 idx = 0; idx < freqs->length; idx++)
624 {
625 Mf = Msec * freqs->data[idx];
626
627 /* We do not want to generate the waveform at frequencies > Mf_max (default Mf = 0.3) */
628 if(Mf <= (pWF->f_max_prime * pWF->M_sec))
629 {
630
631 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
632 if(initial_status != XLAL_SUCCESS)
633 {
634 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
635 }
636 else
637 {
638 amp = IMRPhenomXHM_Amplitude_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
639 phi = IMRPhenomXHM_Phase_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
640 // Add potential correction s.t. PNR CoPrec aligns with XHM during inspiral. See IMRPhenomXHM_PNR_EnforceXHMPhaseAlignment.
641 phi += lina + Mf*linb;
642
643 /* Reconstruct waveform: h_l-m(f) = A(f) * Exp[I phi(f)] */
644 ((*htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
645
646 #if DEBUG == 1
647 fprintf(file, "%.16f %.16e %.16f\n", freqs->data[idx], Amp0*amp, phi);
648 #endif
649 }
650 }
651 else
652 {
653 ((*htildelm)->data->data)[idx+offset] = 0.0 + I*0.0;
654 }
655 }
656 }
657 /* Modes without mixing */
658 else
659 {
660 for (UINT4 idx = 0; idx < freqs->length; idx++)
661 {
662 REAL8 Mf = Msec * freqs->data[idx];
663
664 /* We do not want to generate the waveform at frequencies > Mf_max (default Mf = 0.3) */
665 if(Mf <= (pWF->f_max_prime * pWF->M_sec))
666 {
667 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
668 if(initial_status != XLAL_SUCCESS)
669 {
670 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
671 }
672 else
673 {
674 amp = IMRPhenomXHM_Amplitude_noModeMixing(&powers_of_Mf, pAmp, pWFHM);
675 phi = IMRPhenomXHM_Phase_noModeMixing(&powers_of_Mf, pPhase, pWFHM, pWF);
676
677 // Add potential correction s.t. PNR CoPrec aligns with XHM during inspiral. See IMRPhenomXHM_PNR_EnforceXHMPhaseAlignment.
678 phi += lina + Mf*linb;
679
680 // /* Reconstruct waveform: h_l-m(f) = A(f) * Exp[I phi(f)] */
681 // ((*htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
682
683 /* NOTE that the above lines are commented out to clarify legacy code structure.
684 HERE, we allow the user to toggle output of ONLY the model's phase using lalParams.
685 The intended use of this option is to enable exact output of the phase, without unwanted numerical effects that result from unwrapping the complete waveform. In particular, at low frequencies, the phase may vary so quickly that adjacent frequency points correctly differ by more than 2*pi, thus limiting unwrap routines which assume that this is not the case.
686 */
687 if ( pWF->PhenomXOnlyReturnPhase ) {
688 //
689
690 /* Here we mimic the line above (just above "#if DEBUG == 1") that negates the amplitude if ell is odd: Multiply by (-1)^l to get the true h_l-m(f) */
691 if(ell%2 != 0){
692 // Amp0 = -Amp0;
693 phi = phi + LAL_PI;
694 }
695
696 ((*htildelm)->data->data)[idx+offset] = phi;
697 } else {
698 /* Reconstruct waveform: h_l-m(f) = A(f) * Exp[I phi(f)] */
699 ((*htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
700 }
701
702 #if DEBUG == 1
703 fprintf(file, "%.16f %.16e %.16f\n", freqs->data[idx], Amp0*amp, phi);
704 #endif
705 }
706 }
707 else
708 {
709 ((*htildelm)->data->data)[idx+offset] = 0.0 + I*0.0;
710 }
711 }
712 }
713 #if DEBUG == 1
714 fclose(file);
715 #endif
716
717
718 // Free allocated memory
719 LALFree(pAmp);
720 LALFree(pPhase);
721 LALFree(pAmp22);
722 LALFree(pPhase22);
723 } // End of non-vanishing modes
724
725 // Free allocated memory
726 LALFree(pWFHM);
728 if(lalParams_In == 1)
729 {
730 XLALDestroyDict(lalParams);
731 }
732
733 #if DEBUG == 1
734 printf("\nIMRPhenomXHMGenerateFDOneMode: Leaving... \n");
735 #endif
736
737
738 return initial_status;
739
740}
741
742
743/** @addtogroup LALSimIMRPhenomX_c
744* @{
745* @name Routines for IMRPhenomXHM
746* @{ **/
747
748/** Get the model evaluated in a prebuilt frequency array.
749 It does not use Multibanding.
750 */
752 COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
753 const REAL8Sequence *freqs, /**< frequency array to evaluate model (positives) (Hz) */
754 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
755 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
756 REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
757 REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
758 UINT4 ell, /**< l index of the mode */
759 INT4 emm, /**< m index of the mode */
760 REAL8 distance, /**< Luminosity distance (m) */
761 REAL8 phiRef, /**< Orbital phase at fRef (rad) */
762 REAL8 fRef_In, /**< Reference frequency (Hz) */
763 LALDict *lalParams /**< UNDOCUMENTED */
764)
765{
766
767 if(ell == 2 && abs(emm) == 2){
769 htildelm,
770 freqs,
771 m1_SI,
772 m2_SI,
773 chi1L,
774 chi2L,
775 distance,
776 phiRef,
777 fRef_In,
778 lalParams
779 );
780 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "XLALSimIMRPhenomXHMFrequencySequenceOneMode failed to generate IMRPhenomXHM waveform.");
781 /* Transfor to positive m mode if needed. Do (-1)^l*Conjugate[htildelm]. The frequencies must be negative. */
782 if(emm>0){
783 for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
784 (*htildelm)->data->data[idx] = conj((*htildelm)->data->data[idx]);
785 }
786 }
787 return status;
788 }
789 else{ //Higher modes
790
791 /* Variable to check correct calls to functions. */
792 INT4 status = 0;
793
794 /* Sanity checks */
795 if(*htildelm) { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT); }
796 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
797 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
798 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
799 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
800
801 /*
802 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
803 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
804 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
805 - For mass ratios > 1000: throw a hard error that model is not valid.
806 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
807
808 */
809 REAL8 mass_ratio;
810 if(m1_SI > m2_SI)
811 {
812 mass_ratio = m1_SI / m2_SI;
813 }
814 else
815 {
816 mass_ratio = m2_SI / m1_SI;
817 }
818 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
819 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
820 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
821
822 /* Use an auxiliar laldict to not overwrite the input argument */
823 LALDict *lalParams_aux;
824 /* setup mode array */
825 if (lalParams == NULL)
826 {
827 lalParams_aux = XLALCreateDict();
828 }
829 else{
830 lalParams_aux = XLALDictDuplicate(lalParams);
831 }
832 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
833 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
834
835 /* first check if (l,m) mode is 'activated' in the ModeArray */
836 /* if activated then generate the mode, else skip this mode. */
837 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1 )
838 { /* skip mode */
839 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
841 } /* else: generate mode */
842
843
844 /* If fRef is not provided (i.e. set to 0), then take fRef to be the starting GW Frequency. */
845 REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In;
846
847
848 /* Initialize the useful powers of LAL_PI */
850 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
852 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
853
854 /* Get minimum and maximum frequencies. */
855 REAL8 f_min_In = freqs->data[0];
856 REAL8 f_max_In = freqs->data[freqs->length - 1];
857
858 /*
859 Initialize IMRPhenomX waveform struct and perform sanity check.
860 Passing deltaF = 0 tells us that freqs contains a frequency grid with non-uniform spacing.
861 The function waveform start at lowest given frequency.
862 */
865 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, 0.0, fRef, phiRef, f_min_In, f_max_In, distance, 0.0, lalParams_aux, PHENOMXDEBUG);
866 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: failed.\n");
867
868 /* Now call the IMRPhenomXHM one mode waveform generator */
870 htildelm,
871 freqs,
872 pWF,
873 ell,
874 abs(emm),
875 lalParams_aux
876 );
877 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "XLALSimIMRPhenomXHMFrequencySequenceOneMode failed to generate IMRPhenomXHM waveform.");
878
879 /* Transfor to positive m mode if needed. Do (-1)^l*Conjugate[htildelm]. The frequencies must be negative. */
880 if(emm>0){
881 INT4 minus1l = 1;
882 if(ell%2!=0){
883 minus1l = -1;
884 }
885 for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
886 (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
887 }
888 }
889
890 /* Free memory */
891 LALFree(pWF);
892 XLALDestroyValue(ModeArray);
893 XLALDestroyDict(lalParams_aux);
894
895
896 return XLAL_SUCCESS;
897
898 }//Higher modes
899}
900
901
902/** Function to obtain a SphHarmFrequencySeries with the individual modes h_lm.
903 By default it returns all the modes available in the model, both positive and negatives.
904 With the mode array option in the LAL dictionary, the user can specify a custom mode array.
905 This function is to be used by ChooseFDModes.
906*/
908 SphHarmFrequencySeries **hlms, /**< [out] list with single modes h_lm */
909 REAL8 m1_SI, /**< mass of companion 1 (kg) */
910 REAL8 m2_SI, /**< mass of companion 2 (kg) */
911 REAL8 S1z, /**< z-component of the dimensionless spin of object 1 */
912 REAL8 S2z, /**< z-component of the dimensionless spin of object 2 */
913 REAL8 deltaF, /**< frequency spacing (Hz) */
914 REAL8 f_min, /**< starting GW frequency (Hz) */
915 REAL8 f_max, /**< ending GW frequency (Hz) */
916 REAL8 f_ref, /**< reference GW frequency (Hz) */
917 REAL8 phiRef, /**< phase shift at reference frequency */
918 REAL8 distance, /**< distance of source (m) */
919 LALDict *LALparams /**< LAL dictionary with extra options */
920)
921{
922 LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO;
923 LALDict *XHMparams;
924 INT4 LALparams_In = 0;
925 LALValue *InputModeArray = NULL;
926
927 /* Read mode array from LAL dictionary */
928 if(LALparams != NULL)
929 {
930 LALparams_In = 1;
931 /* Check that the modes chosen are available for the model */
932 XLAL_CHECK(check_input_mode_array(LALparams) == XLAL_SUCCESS, XLAL_EFAULT, "Not available mode chosen.\n");
933
934 InputModeArray = XLALSimInspiralWaveformParamsLookupModeArray(LALparams);
935 }
936 else
937 {
938 LALparams = XLALCreateDict();
939 }
940
941
942 /* Create new LAL dictionary with the default mode-array of PhenomXHM.
943 Can not pass LALparams to this function because the mode array must be null,
944 and LALparams can have non-null mode array.
945 */
946 XHMparams = XLALCreateDict();
947 XHMparams = IMRPhenomXHM_setup_mode_array(XHMparams);
948 /* Read mode array from previous LAL dictionary */
949 LALValue *XHMModeArray = XLALSimInspiralWaveformParamsLookupModeArray(XHMparams);
950
951 /* If input LAL dictionary does not have mode array, setup to default XHM array */
952 if(InputModeArray == NULL)
953 {
954 InputModeArray = XLALSimInspiralWaveformParamsLookupModeArray(XHMparams);
955 }
956
957 INT4 length = 0;
958 COMPLEX16FrequencySeries *htilde22 = NULL;
959
960 /***** Loop over modes ******/
961 for (UINT4 ell = 2; ell <= L_MAX; ell++)
962 {
963 for (INT4 emm = -(INT4)ell; emm <= (INT4)ell; emm++)
964 {
965 /* Here I use two mode_arrays to check if the user asked for a mode that is not available in XHM and print an error message in such a case. */
966 if(XLALSimInspiralModeArrayIsModeActive(InputModeArray, ell, emm) !=1)
967 {
968 /* Skip mode if user did not specified it. */
969 continue;
970 }
971 if(XLALSimInspiralModeArrayIsModeActive(XHMModeArray, ell, emm) !=1)
972 {
973 /* Skip mode. This is a requested mode by the user that the model does not support and warning. */
974 XLAL_PRINT_ERROR("Mode (%i,%i) not available in IMRPhenomXHM", ell, emm);
975 continue;
976 }
977 //Variable to store the strain of only one (positive/negative) mode: h_lm
978 COMPLEX16FrequencySeries *htildelm = NULL;
979
980 // Read Multibanding threshold
982
983 /* Compute one mode */
984 if (thresholdMB == 0){ // No multibanding
985 XLALSimIMRPhenomXHMGenerateFDOneMode(&htildelm, m1_SI, m2_SI, S1z, S2z, ell, emm, distance, f_min, f_max, deltaF, phiRef, f_ref, LALparams);
986 }
987 else{ // With multibanding
988 if(ell==3 && abs(emm)==2){ // mode with mixing. htilde22 is not recycled here for flexibility, so instead we pass NULL.
989 XLALSimIMRPhenomXHMMultiBandOneModeMixing(&htildelm, htilde22, m1_SI, m2_SI, S1z, S2z, ell, emm, distance, f_min, f_max, deltaF, phiRef, f_ref, LALparams);
990 }
991 else{ // modes without mixing
992 XLALSimIMRPhenomXHMMultiBandOneMode(&htildelm, m1_SI, m2_SI, S1z, S2z, ell, emm, distance, f_min, f_max, deltaF, phiRef, f_ref, LALparams);
993 }
994 // If the 22 mode is active we will recycle for the mixing of the 32, we save it in another variable: htilde22.
995 if(ell==2 && emm==-2 && htildelm){
996 htilde22 = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, htildelm->data->length);
997 for(UINT4 idx = 0; idx < htildelm->data->length; idx++){
998 htilde22->data->data[idx] = htildelm->data->data[idx];
999 }
1000 }
1001 }
1002
1003 if (!(htildelm)){ XLAL_ERROR(XLAL_EFUNC); }
1004
1005 length = htildelm->data->length-1;
1006
1007
1008 XLALGPSAdd(&ligotimegps_zero, -1. / deltaF); /* coalesce at t=0 */
1009 COMPLEX16FrequencySeries *hlmall = NULL;
1010 hlmall = XLALCreateCOMPLEX16FrequencySeries("hlmall: mode with positive and negative freqs", &(htildelm->epoch), htildelm->f0, htildelm->deltaF, &(htildelm->sampleUnits), 2*length+1);
1011
1012 if(emm < 0){
1013 for(INT4 i=0; i<=length; i++)
1014 {
1015 hlmall->data->data[i+length] = htildelm->data->data[i];
1016 hlmall->data->data[i] = 0;
1017 }
1018 }
1019 else{
1020 for(INT4 i=0; i<=length; i++)
1021 {
1022 hlmall->data->data[i] = htildelm->data->data[length-i];
1023 hlmall->data->data[i+length] = 0;
1024 }
1025 }
1026
1027 // Add single mode to list
1028 *hlms = XLALSphHarmFrequencySeriesAddMode(*hlms, hlmall, ell, emm);
1029
1030
1031 // Free memory
1034 }
1035 } /* End loop over modes */
1037
1038 /* Add frequency array to SphHarmFrequencySeries */
1039 REAL8Sequence *freqs = XLALCreateREAL8Sequence(2*length+1);
1040 for (INT4 i = -length; i<=length; i++)
1041 {
1042 freqs->data[i+length] = i*deltaF;
1043 }
1045
1046
1047 /* Free memory */
1048 XLALDestroyValue(XHMModeArray);
1049 XLALDestroyDict(XHMparams);
1050
1051 if (LALparams_In == 0)
1052 {
1053 XLALDestroyDict(LALparams);
1054 }
1055 else
1056 {
1057 XLALDestroyValue(InputModeArray);
1058 }
1059
1060 return XLAL_SUCCESS;
1061
1062}
1063
1064
1066 REAL8Sequence **phase, /**< [out] FD waveform */
1067 const REAL8Sequence *freqs, /**< frequency array to evaluate model (positives) */
1068 UINT4 ell, /**< l index of the mode */
1069 INT4 emm, /**< m index of the mode */
1070 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
1071 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
1072 REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
1073 REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
1074 REAL8 distance, /**< Luminosity distance (m) */
1075 REAL8 phiRef, /**< Orbital phase at fRef (rad) */
1076 REAL8 fRef_In, /**< Reference frequency (Hz) */
1077 LALDict *lalParams /**< UNDOCUMENTED */
1078)
1079{
1080
1081 /* Variable to check correct calls to functions. */
1082 INT4 status = 0;
1083
1084 /* Sanity checks */
1085 if(*phase) { XLAL_CHECK(NULL != phase, XLAL_EFAULT); }
1086 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
1087 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
1088 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
1089 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
1090
1091 /*
1092 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
1093 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1094 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1095 - For mass ratios > 1000: throw a hard error that model is not valid.
1096 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1097
1098 */
1099 REAL8 mass_ratio;
1100 if(m1_SI > m2_SI)
1101 {
1102 mass_ratio = m1_SI / m2_SI;
1103 }
1104 else
1105 {
1106 mass_ratio = m2_SI / m1_SI;
1107 }
1108 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1109 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
1110 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1111
1112 /* Use an auxiliar laldict to not overwrite the input argument */
1113 LALDict *lalParams_aux;
1114 /* setup mode array */
1115 if (lalParams == NULL)
1116 {
1117 lalParams_aux = XLALCreateDict();
1118 }
1119 else{
1120 lalParams_aux = XLALDictDuplicate(lalParams);
1121 }
1122 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
1123 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
1124
1125 /* first check if (l,m) mode is 'activated' in the ModeArray */
1126 /* if activated then generate the mode, else skip this mode. */
1127 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1 )
1128 { /* skip mode */
1129 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
1131 } /* else: generate mode */
1132
1133 /* Get minimum and maximum frequencies. */
1134 REAL8 f_min_In = freqs->data[0];
1135 REAL8 f_max_In = freqs->data[freqs->length - 1];
1136
1137
1138 /* Initialize the useful powers of LAL_PI */
1140 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
1142 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
1143
1144
1145 /*
1146 Initialize IMRPhenomX waveform struct and perform sanity check.
1147 Passing deltaF = 0 tells us that freqs contains a frequency grid with non-uniform spacing.
1148 The function waveform start at lowest given frequency.
1149 */
1151 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
1152 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, 0.0, fRef_In, phiRef, f_min_In, f_max_In, distance, 0.0, lalParams_aux, PHENOMXDEBUG);
1153 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: failed.\n");
1154
1155
1156 // allocate qnm struct
1157 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
1159
1160 // Populate pWFHM
1162 IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams);
1163 LALFree(qnms);
1164
1165 /* Allocate coefficients of 22 mode */
1168 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
1169
1170 /* Allocate and initialize the PhenomXHM lm amplitude and phae coefficients struct */
1173
1174 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
1177
1178 /* Get coefficients for Amplitude and phase */
1179 if (pWFHM->MixingOn == 1) {
1180 // For mode with mixing we need the spheroidal coeffs of the 32 phase and the 22 amplitude coeffs.
1181 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
1183 }
1184 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
1185 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
1186
1187 IMRPhenomX_UsefulPowers powers_of_Mf;
1188 REAL8 Msec = pWF->M_sec; // Variable to transform Hz to Mf
1189
1190 *phase = XLALCreateREAL8Sequence(freqs->length);
1191
1192 for (UINT4 idx = 0; idx < freqs->length; idx++)
1193 {
1194 REAL8 Mf = Msec * freqs->data[idx];
1195 INT4 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
1196 if(initial_status != XLAL_SUCCESS)
1197 {
1198 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
1199 }
1200 else
1201 {
1202 ((*phase)->data)[idx] = IMRPhenomXHM_RD_Phase_AnsatzInt(Mf, &powers_of_Mf, pWFHM, pPhase);
1203 }
1204 }
1205
1206
1207 /* Free memory */
1208 LALFree(pWF);
1209 LALFree(pWFHM);
1210 LALFree(pPhase);
1211 LALFree(pPhase22);
1212 LALFree(pAmp);
1213 LALFree(pAmp22);
1214 XLALDestroyValue(ModeArray);
1215 XLALDestroyDict(lalParams_aux);
1216
1217
1218 return XLAL_SUCCESS;
1219}
1220
1221
1223 REAL8Sequence **amplitude, /**< [out] FD waveform */
1224 const REAL8Sequence *freqs, /**< frequency array to evaluate model (positives) */
1225 UINT4 ell, /**< l index of the mode */
1226 INT4 emm, /**< m index of the mode */
1227 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
1228 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
1229 REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
1230 REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
1231 REAL8 distance, /**< Luminosity distance (m) */
1232 REAL8 phiRef, /**< Orbital phase at fRef (rad) */
1233 REAL8 fRef_In, /**< Reference frequency (Hz) */
1234 LALDict *lalParams /**< UNDOCUMENTED */
1235)
1236{
1237
1238 /* Variable to check correct calls to functions. */
1239 INT4 status = 0;
1240
1241 /* Sanity checks */
1242 if(*amplitude) { XLAL_CHECK(NULL != amplitude, XLAL_EFAULT); }
1243 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
1244 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
1245 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
1246 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
1247
1248 /*
1249 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
1250 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1251 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1252 - For mass ratios > 1000: throw a hard error that model is not valid.
1253 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1254
1255 */
1256 REAL8 mass_ratio;
1257 if(m1_SI > m2_SI)
1258 {
1259 mass_ratio = m1_SI / m2_SI;
1260 }
1261 else
1262 {
1263 mass_ratio = m2_SI / m1_SI;
1264 }
1265 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1266 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
1267 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1268
1269 /* Use an auxiliar laldict to not overwrite the input argument */
1270 LALDict *lalParams_aux;
1271 /* setup mode array */
1272 if (lalParams == NULL)
1273 {
1274 lalParams_aux = XLALCreateDict();
1275 }
1276 else{
1277 lalParams_aux = XLALDictDuplicate(lalParams);
1278 }
1279 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
1280 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
1281
1282 /* first check if (l,m) mode is 'activated' in the ModeArray */
1283 /* if activated then generate the mode, else skip this mode. */
1284 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1 )
1285 { /* skip mode */
1286 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
1288 } /* else: generate mode */
1289
1290 /* Get minimum and maximum frequencies. */
1291 REAL8 f_min_In = freqs->data[0];
1292 REAL8 f_max_In = freqs->data[freqs->length - 1];
1293
1294
1295 /* Initialize the useful powers of LAL_PI */
1297 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
1299 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Failed to initialize useful powers of LAL_PI.");
1300
1301
1302 /*
1303 Initialize IMRPhenomX waveform struct and perform sanity check.
1304 Passing deltaF = 0 tells us that freqs contains a frequency grid with non-uniform spacing.
1305 The function waveform start at lowest given frequency.
1306 */
1308 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
1309 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, 0.0, fRef_In, phiRef, f_min_In, f_max_In, distance, 0.0, lalParams_aux, PHENOMXDEBUG);
1310 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: failed.\n");
1311
1312
1313 // allocate qnm struct
1314 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
1316
1317 // Populate pWFHM
1319 IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams);
1320 LALFree(qnms);
1321
1322 /* Allocate coefficients of 22 mode */
1325 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
1326
1327 /* Allocate and initialize the PhenomXHM lm amplitude and phae coefficients struct */
1330
1331 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
1334
1335 /* Get coefficients for Amplitude and phase */
1336 if (pWFHM->MixingOn == 1) {
1337 // For mode with mixing we need the spheroidal coeffs of the 32 phase and the 22 amplitude coeffs.
1338 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
1340 }
1341 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
1342 //FIXME: needed?
1343 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
1344
1345 IMRPhenomX_UsefulPowers powers_of_Mf;
1346 REAL8 Msec = pWF->M_sec; // Variable to transform Hz to Mf
1347
1348 *amplitude = XLALCreateREAL8Sequence(freqs->length);
1349
1350 for (UINT4 idx = 0; idx < freqs->length; idx++)
1351 {
1352 REAL8 Mf = Msec * freqs->data[idx];
1353 INT4 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
1354 if(initial_status != XLAL_SUCCESS)
1355 {
1356 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
1357 }
1358 else
1359 {
1360 ((*amplitude)->data)[idx] = IMRPhenomXHM_RD_Amp_Ansatz(&powers_of_Mf, pWFHM, pAmp) * pWFHM->Amp0;
1361 }
1362 }
1363
1364
1365 /* Free memory */
1366 LALFree(pWF);
1367 LALFree(pWFHM);
1368 LALFree(pPhase);
1369 LALFree(pPhase22);
1370 LALFree(pAmp);
1371 LALFree(pAmp22);
1372 XLALDestroyValue(ModeArray);
1373 XLALDestroyDict(lalParams_aux);
1374
1375
1376 return XLAL_SUCCESS;
1377}
1378
1379
1380/*********************************************/
1381/* */
1382/* MULTIMODE WAVEFORM */
1383/* */
1384/*********************************************/
1385
1386/** Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
1387
1388XLALSimIMRPhenomXHM calls the function for a single mode that can be XLALSimIMRPhenomXHMGenerateFDOneMode or XLALSimIMRPhenomXHMMultiBandOneMode,
1389depending on if the Multibanding is active or not.
1390
1391By default XLALSimIMRPhenomXHM is only used when the Multibanding is activated, since each mode has a different coarse frequency array and we can not recycle the array.
1392
1393This is just a wrapper of the function that actually carry out the calculations: IMRPhenomXHM_MultiMode2.
1394
1395*/
1396
1397/* Return hptilde, hctilde */
1399 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
1400 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
1401 REAL8 m1_SI, /**< mass of companion 1 (kg) */
1402 REAL8 m2_SI, /**< mass of companion 2 (kg) */
1403 REAL8 chi1L, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
1404 REAL8 chi2L, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
1405 REAL8 f_min, /**< Starting GW frequency (Hz) */
1406 REAL8 f_max, /**< End frequency; 0 defaults to Mf = 0.3 */
1407 REAL8 deltaF, /**< Sampling frequency (Hz) */
1408 REAL8 distance, /**< distance of source (m) */
1409 REAL8 inclination, /**< inclination of source (rad) */
1410 REAL8 phiRef, /**< reference orbital phase (rad) */
1411 REAL8 fRef_In, /**< Reference frequency */
1412 LALDict *lalParams /**<linked list containing the extra parameters */
1413)
1414{
1415 /* define and init return code for this function */
1416 int retcode;
1417
1418 /* Sanity checks on input parameters: check pointers, etc.
1419 More checks are done inside XLALSimIMRPhenomXHMGenerateFDOneMode/XLALSimIMRPhenomXHMMultiBandOneMode */
1420 XLAL_CHECK(NULL != hptilde, XLAL_EFAULT);
1421 XLAL_CHECK(NULL != hctilde, XLAL_EFAULT);
1422 XLAL_CHECK(*hptilde == NULL, XLAL_EFAULT);
1423 XLAL_CHECK(*hctilde == NULL, XLAL_EFAULT);
1424 XLAL_CHECK(distance > 0, XLAL_EDOM, "distance must be positive.\n");
1425 /*
1426 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
1427 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1428 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1429 - For mass ratios > 1000: throw a hard error that model is not valid.
1430 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1431
1432 */
1433 REAL8 mass_ratio;
1434 if(m1_SI > m2_SI)
1435 {
1436 mass_ratio = m1_SI / m2_SI;
1437 }
1438 else
1439 {
1440 mass_ratio = m2_SI / m1_SI;
1441 }
1442 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1443 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
1444 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1445
1446 /* Check that the modes chosen are available for the model */
1447 XLAL_CHECK(check_input_mode_array(lalParams) == XLAL_SUCCESS, XLAL_EFAULT, "Not available mode chosen.\n");
1448
1449
1450 /* Evaluate the model */
1451 retcode = IMRPhenomXHM_MultiMode(
1452 hptilde,
1453 hctilde,
1454 m1_SI,
1455 m2_SI,
1456 chi1L,
1457 chi2L,
1458 f_min,
1459 f_max,
1460 deltaF,
1461 distance,
1462 inclination,
1463 phiRef,
1464 fRef_In,
1465 lalParams
1466 );
1467 XLAL_CHECK(retcode == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_MultiMode failed in XLALSimIMRPhenomXHM.");
1468
1469 #if DEBUG == 1
1470 printf("\n******Leaving XLALSimIMRPhenomXHM*****\n");
1471 #endif
1472
1473 return retcode;
1474}
1475
1476/** Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
1477
1478XLALSimIMRPhenomXHM2 builds each mode explicitly in the loop over modes, recycling some common quantities between modes like
1479the frequency array, the powers of frequencies, structures, etc so it has less overhead than XLALSimIMRPhenomXHM.
1480
1481By default XLALSimIMRPhenomXHM2 is only used for the version without Multibanding.
1482
1483 This is just a wrapper of the function that actually carry out the calculations: IMRPhenomXHM_MultiMode2.
1484 */
1486 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
1487 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
1488 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
1489 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
1490 REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
1491 REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
1492 REAL8 f_min, /**< Starting GW frequency (Hz) */
1493 REAL8 f_max, /**< End frequency; 0 defaults to Mf = 0.3 */
1494 REAL8 deltaF, /**< Sampling frequency (Hz) */
1495 REAL8 distance, /**< Luminosity distance (m) */
1496 REAL8 inclination, /**< Inclination of the source */
1497 REAL8 phiRef, /**< Orbital phase at fRef (rad) */
1498 REAL8 fRef_In, /**< Reference frequency (Hz) */
1499 LALDict *lalParams /**< LAL Dictionary */
1500)
1501{
1502 UINT4 debug = DEBUG;
1503
1504 UINT4 status;
1505
1506 #if DEBUG == 1
1507 printf("\n*** IMRPhenomXHM2 ***\n");
1508 printf("fRef_In : %e\n",fRef_In);
1509 printf("m1_SI : %.16e\n",m1_SI);
1510 printf("m2_SI : %.16e\n",m2_SI);
1511 printf("chi1L : %.16e\n",chi1L);
1512 printf("chi2L : %.16e\n",chi2L);
1513 printf("f_min : %.16e \n", f_min);
1514 printf("Performing sanity checks...\n");
1515 #endif
1516
1517 /* Perform initial sanity checks */
1518 if(*hptilde) { XLAL_CHECK(NULL != hptilde, XLAL_EFAULT); }
1519 if(*hctilde) { XLAL_CHECK(NULL != hctilde, XLAL_EFAULT); }
1520 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
1521 if(deltaF <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n"); }
1522 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
1523 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
1524 if(f_min <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n"); }
1525 if(f_max < 0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n"); }
1526 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
1527 /*
1528 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
1529 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1530 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1531 - For mass ratios > 1000: throw a hard error that model is not valid.
1532 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1533
1534 */
1535 REAL8 mass_ratio;
1536 if(m1_SI > m2_SI)
1537 {
1538 mass_ratio = m1_SI / m2_SI;
1539 }
1540 else
1541 {
1542 mass_ratio = m2_SI / m1_SI;
1543 }
1544 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1545 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
1546 if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1547
1548 /* Check that the modes chosen are available for the model */
1549 XLAL_CHECK(check_input_mode_array(lalParams) == XLAL_SUCCESS, XLAL_EFAULT, "Not available mode chosen.\n");
1550
1551 /* If no reference frequency is given, set it to the starting gravitational wave frequency */
1552 REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
1553
1554
1555 #if DEBUG == 1
1556 printf("\nInitializing waveform struct...\n");
1557 #endif
1558
1559 /* Initialize the useful powers of LAL_PI */
1561 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
1562
1563 /* Initialize IMR PhenomX Waveform struct and check that it initialized correctly */
1565 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
1566 status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, inclination, lalParams, debug);
1567 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: failed.\n");
1568
1569
1570 /* Check that the frequency array will be consistent: fmin < fmax_prime */
1571 /* Return the closest power of 2 */
1572 size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
1573 /* Frequencies will be set using only the lower and upper bounds that we passed */
1574 size_t iStart = (size_t) (f_min / deltaF);
1575 size_t iStop = (size_t) (pWF->f_max_prime / deltaF);
1576 XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
1577 "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
1578
1579 /* Create a REAL8 frequency series.
1580 Use fLow, fHigh, deltaF to compute frequency sequence. Only pass the boundaries (fMin, f_max_prime). */
1582 freqs->data[0] = pWF->fMin;
1583 freqs->data[1] = pWF->f_max_prime;
1584
1585
1586 /* We now call the core IMRPhenomXHM_Multimode2 waveform generator. */
1587 status = IMRPhenomXHM_MultiMode2(hptilde, hctilde, freqs, pWF, lalParams);
1588 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_MultiMode2 failed to generate IMRPhenomXHM waveform.");
1589
1590 #if DEBUG == 1
1591 printf("\n\n **** Call to IMRPhenomXHM_MultiMode2 complete. **** \n\n");
1592 #endif
1593
1594
1595 /* Resize hptilde, hctilde */
1596 REAL8 lastfreq;
1597 if (pWF->f_max_prime < pWF->fMax)
1598 {
1599 /* The user has requested a higher f_max than Mf = fCut.
1600 Resize the frequency series to fill with zeros beyond the cutoff frequency. */
1601 lastfreq = pWF->fMax;
1602 XLAL_PRINT_WARNING("The input f_max = %.2f Hz is larger than the internal cutoff of Mf=0.3 (%.2f Hz). Array will be filled with zeroes between these two frequencies.\n", pWF->fMax, pWF->f_max_prime);
1603 }
1604 else{ // We have to look for a power of 2 anyway.
1605 lastfreq = pWF->f_max_prime;
1606 }
1607 // We want to have the length be a power of 2 + 1
1608 size_t n_full = NextPow2(lastfreq / deltaF) + 1;
1609 size_t n = (*hptilde)->data->length;
1610
1611 /* Resize the COMPLEX16 frequency series */
1612 *hptilde = XLALResizeCOMPLEX16FrequencySeries(*hptilde, 0, n_full);
1613 XLAL_CHECK (*hptilde, XLAL_ENOMEM, "Failed to resize h_+ COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
1614
1615 /* Resize the COMPLEX16 frequency series */
1616 *hctilde = XLALResizeCOMPLEX16FrequencySeries(*hctilde, 0, n_full);
1617 XLAL_CHECK (*hctilde, XLAL_ENOMEM, "Failed to resize h_x COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
1618
1619
1620 /* Free memory */
1621 LALFree(pWF);
1623
1624 return XLAL_SUCCESS;
1625}
1626
1627
1628/**
1629 * Returns hptilde and hctilde as a complex frequency series with entries exactly at the frequencies specified in
1630 * the REAL8Sequence *freqs (which can be unequally spaced). No zeros are added. Assumes positive frequencies.
1631 */
1632
1634 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
1635 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
1636 const REAL8Sequence *freqs, /**< Input Frequency series [Hz] */
1637 REAL8 m1_SI, /**< mass of companion 1 (kg) */
1638 REAL8 m2_SI, /**< mass of companion 2 (kg) */
1639 REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
1640 REAL8 chi2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
1641 REAL8 distance, /**< Distance of source (m) */
1642 REAL8 inclination, /**< inclination of source (rad) */
1643 REAL8 phiRef, /**< Orbital phase (rad) at reference frequency */
1644 REAL8 fRef_In, /**< Reference frequency (Hz) */
1645 LALDict *lalParams /**< LAL Dictionary struct */
1646 )
1647 {
1648 /* Variable to check correct calls to functions. */
1649 INT4 status;
1650
1651 /* Perform initial sanity checks */
1652 XLAL_CHECK(NULL != hptilde, XLAL_EFAULT, "Error: hptilde already defined. \n");
1653 XLAL_CHECK(NULL != hctilde, XLAL_EFAULT, "Error: hctilde already defined. \n");
1654 XLAL_CHECK(NULL != freqs, XLAL_EFAULT, "Error: Input freq array must be defined. \n");
1655 XLAL_CHECK(fRef_In >= 0, XLAL_EFUNC, "Error: fRef must be positive and greater than 0. \n");
1656 XLAL_CHECK(m1_SI > 0, XLAL_EFUNC, "Error: m1 must be positive and greater than 0. \n");
1657 XLAL_CHECK(m2_SI > 0, XLAL_EFUNC, "Error: m2 must be positive and greater than 0. \n");
1658 XLAL_CHECK(distance > 0, XLAL_EFUNC, "Error: Distance must be positive and greater than 0. \n");
1659
1660 /*
1661 Perform a basic sanity check on the region of the parameter space in which model is evaluated.
1662 Behaviour is as follows, consistent with the choices for IMRPhenomXAS/IMRPhenomXHM
1663 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1664 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1665 - For mass ratios > 1000: throw a hard error that model is not valid.
1666 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1667
1668 */
1669 REAL8 mass_ratio;
1670 if(m1_SI > m2_SI)
1671 {
1672 mass_ratio = m1_SI / m2_SI;
1673 }
1674 else
1675 {
1676 mass_ratio = m2_SI / m1_SI;
1677 }
1678 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1679 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
1680 if(fabs(chi1z) > 0.99 || fabs(chi2z) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1681
1682 /* If no reference frequency is given, set it to the starting gravitational wave frequency */
1683 REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In; //It is giving valgrind error, but it is not needed. f_ref = f_min in WaveformCache.c and SimInspiral.c.
1684
1685 /* Get minimum and maximum frequencies. */
1686 REAL8 f_min_In = freqs->data[0];
1687 REAL8 f_max_In = freqs->data[freqs->length - 1];
1688
1689 /*
1690 Passing deltaF = 0 implies that freqs is a frequency grid with non-uniform spacing.
1691 The function waveform then start at lowest given frequency.
1692 The Multibanding has to be switched off since it is built only for equally spaced frequency grid.
1693 */
1694 /* Use an auxiliar laldict to not overwrite the input argument */
1695 LALDict *lalParams_aux;
1696 /* setup mode array */
1697 if (lalParams == NULL)
1698 {
1699 lalParams_aux = XLALCreateDict();
1700 }
1701 else{
1702 lalParams_aux = XLALDictDuplicate(lalParams);
1703 }
1705 {
1706 XLAL_PRINT_WARNING("Warning: Function is aimed for non-uniform frequency grid, switching off Multibanding.");
1708 }
1709
1710 /* Initialize the useful powers of LAL_PI */
1712 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
1713
1714 /* Initialize IMRPhenomX waveform struct and perform sanity check. */
1716 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
1717 status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1z, chi2z, 0.0, fRef, phiRef, f_min_In, f_max_In, distance, inclination, lalParams_aux, DEBUG);
1718 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
1719
1720 /* Call the core IMRPhenomXHM waveform generator without multibanding. */
1721 status = IMRPhenomXHM_MultiMode2(hptilde, hctilde, freqs, pWF, lalParams_aux);
1722 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXPHM_hplushcross failed to generate IMRPhenomXPHM waveform.");
1723
1724 /* Free memory */
1725 LALFree(pWF);
1726 XLALDestroyDict(lalParams_aux);
1727
1728 return status;
1729 }
1730
1731/** @}
1732* @} **/
1733
1734
1735/* Core function of XLALSimIMRPhenomXHM, returns hptilde, hctilde corresponding to a sum of modes.
1736The default modes are 22, 21, 33, 32 and 44. It returns also the contribution of the corresponding negatives modes. */
1738 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
1739 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
1740 REAL8 m1_SI, /**< primary mass [kg] */
1741 REAL8 m2_SI, /**< secondary mass [kg] */
1742 REAL8 chi1z, /**< aligned spin of primary */
1743 REAL8 chi2z, /**< aligned spin of secondary */
1744 REAL8 f_min, /**< Starting GW frequency (Hz) */
1745 REAL8 f_max, /**< End frequency; 0 defaults to Mf = 0.3 */
1746 REAL8 deltaF, /**< Sampling frequency (Hz) */
1747 REAL8 distance, /**< distance of source (m) */
1748 REAL8 inclination, /**< inclination of source (rad) */
1749 REAL8 phiRef, /**< reference orbital phase (rad) */
1750 REAL8 fRef_In, /**< Reference frequency */
1751 LALDict *lalParams /**< LALDict struct */
1752)
1753{
1754 /* Set LIGOTimeGPS */
1755 LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
1756
1757 INT4 sym; /* sym will decide whether to add the -m mode (when equatorial symmetry is present) */
1758
1759 /* Use an auxiliar laldict to not overwrite the input argument */
1760 LALDict *lalParams_aux;
1761 /* setup mode array */
1762 if (lalParams == NULL)
1763 {
1764 lalParams_aux = XLALCreateDict();
1765 }
1766 else{
1767 lalParams_aux = XLALDictDuplicate(lalParams);
1768 }
1769 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
1770 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
1771
1772 /* At this point ModeArray should contain the list of modes
1773 and therefore if NULL then something is wrong and abort. */
1774 if (ModeArray == NULL)
1775 {
1776 XLAL_ERROR(XLAL_EDOM, "ModeArray is NULL when it shouldn't be. Aborting.\n");
1777 }
1778
1779 INT4 status = 0;
1780
1781 INT4 init = 0; //Variable to control initialization of hptilde and hctilde
1782
1783 /* When calling only the 32 mode, we need to call also the 22 for the mixing, but not sum it for hp, hc */
1784 INT4 add22 = 1;
1785
1786
1787 COMPLEX16FrequencySeries *htilde22 = NULL;
1788 INT4 posMode, negMode;
1789 /* Take input/default value for the threshold of the Multibanding. If = 0 then do not use Multibanding. */
1791
1792 /***** Loop over modes ******/
1793 for (UINT4 ell = 2; ell <= L_MAX; ell++)
1794 {
1795 for (UINT4 emm = 1; emm <= ell; emm++)
1796 { /* Loop over only positive m is intentional.
1797 The single mode function returns the negative mode h_l-m, and the positive is added automatically in IMRPhenomXHMFDAddMode. */
1798 /* First check if (l,m) mode is 'activated' in the ModeArray */
1799 /* if activated then generate the mode, else skip this mode. */
1800 posMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm);
1801 negMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -emm);
1802 if ( posMode != 1 && negMode != 1)
1803 { /* skip mode */
1804 continue;
1805 } /* else: generate mode */
1806 #if DEBUG == 1
1807 printf("\n Mode %i%i\n",ell, emm);
1808 #endif
1809
1810 // Variable to store the strain of only one (negative) mode: h_l-m
1811 COMPLEX16FrequencySeries *htildelm = NULL;
1812
1813
1814 if (resTest == 0){ // No multibanding
1815 XLALSimIMRPhenomXHMGenerateFDOneMode(&htildelm, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams_aux);
1816 }
1817 else{ // With multibanding
1818 if(ell==3 && emm==2){ // mode with mixing
1819 XLALSimIMRPhenomXHMMultiBandOneModeMixing(&htildelm, htilde22, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams_aux);
1820 }
1821 else{ // modes without mixing
1822 XLALSimIMRPhenomXHMMultiBandOneMode(&htildelm, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams_aux);
1823 }
1824 // If the 22 mode is active we will recycle for the mixing of the 32, we save it in another variable: htilde22.
1825 if(ell==2 && emm==2 && htildelm){
1826 htilde22 = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, htildelm->data->length);
1827 for(UINT4 idx = 0; idx < htildelm->data->length; idx++){
1828 htilde22->data->data[idx] = htildelm->data->data[idx];
1829 }
1830 }
1831 }
1832
1833 /**** For debugging ****/
1834 #if DEBUG == 1
1835 //Save mode l-m in file
1836 FILE *file;
1837 char fileSpec[40];
1838 sprintf(fileSpec, "simulation%i%i_MM.dat", ell,emm);
1839 printf("\nOutput file: %s\r\n",fileSpec);
1840 file = fopen(fileSpec,"w");
1841 REAL8 m2_SI_a, m1_SI_a, chi1z_a, chi2z_a;
1842 if(m1_SI < m2_SI){
1843 m2_SI_a = m1_SI;
1844 m1_SI_a = m2_SI;
1845 chi1z_a = chi2z;
1846 chi2z_a = chi1z;
1847 }
1848 else{
1849 m1_SI_a = m1_SI;
1850 m2_SI_a = m2_SI;
1851 chi1z_a = chi1z;
1852 chi2z_a = chi2z;
1853 }
1854 fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i Mtot = %.16f distance = %.16f\n", m1_SI_a/m2_SI_a, chi1z_a, chi2z_a, ell, emm, (m1_SI+m2_SI)/ LAL_MSUN_SI, distance/LAL_PC_SI/pow(10.,6));
1855 fprintf(file,"# Frequency (Hz) Real Imaginary\n");
1857 for(UINT4 idx = 0; idx < ((htildelm)->data->length); idx++)
1858 {
1859 data = ((htildelm)->data->data)[idx];
1860 fprintf(file, "%.16f %.16e %.16e\n", idx*deltaF, creal(data), cimag(data));
1861 }
1862 fclose(file);
1863 #endif
1864 /**** End debugging ****/
1865
1866
1867 if (!(htildelm)){ XLAL_ERROR(XLAL_EFUNC); }
1868
1869 /* We test for hypothetical m=0 modes */
1870 if (emm == 0)
1871 {
1872 sym = 0;
1873 }
1874 else
1875 {
1876 sym = 1;
1877 }
1878 /* Allocate hptilde and hctilde if they were not yet. */
1879 /* Taken from IMRPhenomHM */
1880 if( init == 0){
1881 /* Coalescence time is fixed to t=0, shift by overall length in time. Model is calibrated such that it peaks approx 500M before the end of the waveform, add this time to the epoch. */
1882 XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", deltaF);
1883 size_t n = (htildelm)->data->length;
1884 *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
1885 if (!(hptilde)){ XLAL_ERROR(XLAL_EFUNC);}
1886 memset((*hptilde)->data->data, 0, n * sizeof(COMPLEX16));
1887 XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
1888 *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
1889 if (!(hctilde)){ XLAL_ERROR(XLAL_EFUNC);}
1890 memset((*hctilde)->data->data, 0, n * sizeof(COMPLEX16));
1891 XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
1892 init = 1;
1893 }
1894 /* Skip 22 mode if it was only required for the mixing of the 32 */
1895 if(ell == 2 && emm == 2 && add22 == 0){
1897 }
1898 /* Add the hl-m mode to hptilde and hctilde. */
1899 else{ // According to LAL documentation the azimuthal angle phi = pi/2 - phiRef. This is not taken into account in PhenomD and that's why there is an dephasing of Pi/2 between PhenomD and SEOBNRv4
1900 if(posMode==1 && negMode!=1){
1901 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, emm, 0); // add only the positive mode
1902 }
1903 else if(posMode!=1 && negMode==1){
1904 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, -emm, 0); // add only the negative mode
1905 }
1906 else{
1907 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, emm, sym); // add both positive and negative modes
1908 }
1909 }
1911 }//Loop over emm
1912}//Loop over ell
1913XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_Multimode failed to generate IMRPhenomXHM waveform.");
1914
1915/* Free memory */
1917XLALDestroyValue(ModeArray);
1918XLALDestroyDict(lalParams_aux);
1919
1920#if DEBUG == 1
1921printf("\n******Leaving IMRPhenomXHM_MultiMode*****\n");
1922#endif
1923
1924return XLAL_SUCCESS;
1925}
1926
1927
1928
1929/* Core function of XLALSimIMRPhenomXHM2, returns hptilde, hctilde corresponding to a sum of modes.
1930The default modes are 22, 21, 33, 32 and 44 with the respective negatives ones. */
1932 COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
1933 COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
1934 const REAL8Sequence *freqs_In, /**< min and max frequency [Hz] */
1935 IMRPhenomXWaveformStruct *pWF, /**< waveform parameters */
1936 LALDict *lalParams /**< LALDict struct */
1937)
1938{
1939 #if DEBUG == 1
1940 printf("\n\n**** IMRPhenomXHM_MultiMode2 **** \n\n");
1941 #endif
1942
1943 /* Set LIGOTimeGPS */
1944 LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
1945
1946 /* Initialize useful powers of LAL_PI */
1948 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
1949
1950 /* Build the frequency array and initialize htildelm to the length of freqs. */
1951 REAL8Sequence *freqs;
1952 COMPLEX16FrequencySeries *htildelm;
1953 // offset is the number of frequency points between 0 and f_min.
1954 UINT4 offset = SetupWFArrays(&freqs, &htildelm, freqs_In, pWF, ligotimegps_zero);
1955
1956 UINT4 len = freqs->length;
1957
1958 #if DEBUG == 1
1959 printf("\n\nfstart, fend, lenfreqs lenhtildelm = %.16f %.16f %i %i\n\n", freqs->data[0], freqs->data[len-1], len, htildelm->data->length);
1960 #endif
1961
1962 // Allocate qnm struct, it contains ringdown and damping frequencies.
1963 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
1965
1966 UINT4 initial_status = XLAL_SUCCESS;
1967
1968 // Variable to transform Hz in adimensional frequencies Mf: Mf = Msec * Hz.
1969 REAL8 Msec = pWF->M_sec;
1970
1971 /* Transform the frequency array to adimensional frequencies to evaluate the model.
1972 Compute and array of the structure IMRPhenomX_UsefulPowers, with the useful powers of each frequency. */
1973 REAL8 *Mf = (REAL8 *)XLALMalloc(len * sizeof(REAL8));
1975
1976 for (UINT4 idx = 0; idx < len; idx++){
1977 Mf[idx] = Msec * freqs->data[idx];
1978 initial_status = IMRPhenomX_Initialize_Powers(&(powers_of_Mf[idx]), Mf[idx]);
1979 if(initial_status != XLAL_SUCCESS)
1980 {
1981 status = initial_status;
1982 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
1983 }
1984 }
1985
1986 INT4 sym = 1; /* sym will decide whether to add the m mode (when equatorial symmetry is present) */
1987
1988 /* Use an auxiliar laldict to not overwrite the input argument */
1989 LALDict *lalParams_aux;
1990 /* setup mode array */
1991 if (lalParams == NULL)
1992 {
1993 lalParams_aux = XLALCreateDict();
1994 }
1995 else{
1996 lalParams_aux = XLALDictDuplicate(lalParams);
1997 }
1998 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
1999 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
2000
2001 /* At this point ModeArray should contain the list of modes
2002 and therefore if NULL then something is wrong and abort. */
2003 if (ModeArray == NULL)
2004 {
2005 XLAL_ERROR(XLAL_EDOM, "ModeArray is NULL when it shouldn't be. Aborting.\n");
2006 }
2007
2008 /* Allocate hptilde and hctilde */
2009 /* Coalescence time is fixed to t=0, shift by overall length in time. */
2010 size_t n = (htildelm)->data->length;
2011 if (pWF->deltaF > 0){
2012 XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", pWF->deltaF);
2013 }
2014 *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
2015 if (!(hptilde)){ XLAL_ERROR(XLAL_EFUNC);}
2016 memset((*hptilde)->data->data, 0, n * sizeof(COMPLEX16)); // what is this for??
2017 XLALUnitMultiply(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit); // what does it do?
2018
2019 *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
2020 if (!(hctilde)){ XLAL_ERROR(XLAL_EFUNC);}
2021 memset((*hctilde)->data->data, 0, n * sizeof(COMPLEX16));
2022 XLALUnitMultiply(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
2023
2024 #if DEBUG == 1
2025 printf("\nlength htildelm = %zu\n", n);
2026 #endif
2027
2028 /******* Compute and add 22 Mode if active **********/
2029 COMPLEX16FrequencySeries *htilde22 = NULL;
2030 INT4 pos22, neg22;
2031 pos22 = XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, 2);
2032 neg22 = XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, -2);
2033 if (pos22 == 1 || neg22 == 1){
2034 #if DEBUG == 1
2035 printf("\n\nCalling IMRPhenomXASFrequencySequence...\n\n");
2036 #endif
2037 COMPLEX16FrequencySeries *htilde22tmp = NULL;
2038 XLALSimIMRPhenomXASFrequencySequence(&htilde22tmp, freqs, pWF->m1_SI, pWF->m2_SI, pWF->chi1L, pWF->chi2L, pWF->distance, pWF->phiRef_In, pWF->fRef, lalParams_aux);
2039 //If htilde22tmp is shorter than hptilde, need to resize
2040 htilde22 = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform", &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
2041 for(UINT4 idx = 0; idx < offset; idx++)
2042 {
2043 (htilde22->data->data)[idx] = 0.;
2044 }
2045 for(UINT4 idx = 0; idx < ((htilde22tmp)->data->length); idx++)
2046 {
2047 ((htilde22)->data->data)[idx+offset] = ((htilde22tmp)->data->data)[idx];
2048 }
2049 for(UINT4 idx = ((htilde22tmp)->data->length); idx < ((htildelm)->data->length) - offset; idx++)
2050 {
2051 (htilde22->data->data)[idx+offset] = 0.;
2052 }
2053 if(pos22==1 && neg22!=1){
2054 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, 2, 0); // add only the positive mode
2055 }
2056 else if(pos22!=1 && neg22==1){
2057 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, -2, 0); // add only the negative mode
2058 }
2059 else{
2060 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, 2, sym); // add both positive and negative modes
2061 }
2062
2063 #if DEBUG == 1
2064 //Save 22 mode in file
2065 printf("phifRef22=%f\n",pWF->phifRef);
2066 FILE *file22;
2067 char fileSpec22[40];
2068
2069 sprintf(fileSpec22, "simulation%i_MM2.dat", 22);
2070 printf("\nOutput file: %s\r\n",fileSpec22);
2071 file22 = fopen(fileSpec22,"w");
2072
2073 fprintf(file22,"# q = %.16f m1 = %.16f m2 = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->m1, pWF->m2, pWF->chi1L, pWF->chi2L, 22, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
2074 fprintf(file22,"# Frequency (Hz) Real Imaginary\n");
2075
2076 COMPLEX16 data22;
2077 for(UINT4 idx = 0; idx < ((htilde22)->data->length); idx++)
2078 {
2079 data22 = ((htilde22)->data->data)[idx];
2080 fprintf(file22, "%.16f %.16e %.16e\n", idx*pWF->deltaF, creal(data22), cimag(data22));
2081 }
2082 fclose(file22);
2083 printf("\n lenhtilde22 = %i\n", htilde22->data->length);
2084 #endif
2085
2087 } // End of 22 mode
2088
2089
2090 #if DEBUG == 1
2091 printf("\n\nlenfreqs lenhtildelm = %i %i\n\n", len, htildelm->data->length);
2092 #endif
2093
2094 // Initialize Amplitude and phase coefficients of the 22. pAmp22 will be filled only for the 32. pPhase22 is used for all the modes, that is why is computed outside the loop.
2097 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
2098
2099
2100 /****** Loop over higher modes ******/
2101 REAL8 amp, phi; // Amplitude and phase of the hlm mode
2102 INT4 minus1l, posMode, negMode;
2103 REAL8 Amp0;
2104 for (UINT4 ell = 2; ell <= L_MAX; ell++)
2105 {
2106 /* Multiply by (-1)^l to get the true h_l-m(f) */
2107 if(ell%2 != 0){
2108 minus1l = -1;
2109 }
2110 else{
2111 minus1l = 1;
2112 }
2113 Amp0 = minus1l * pWF->amp0; //Transform NR units to Physical units
2114
2115 for (INT4 emm = 1; emm < (INT4)ell + 1; emm++){
2116 /* Loop over only positive m is intentional. The single mode function returns the negative mode h_l-m, and the positive is added automatically in IMRPhenomXHMFDAddMode. */
2117 /* First check if (l,m) mode is 'activated' in the ModeArray */
2118 /* if activated then generate the mode, else skip this mode. */
2119 posMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm);
2120 negMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -emm);
2121 if ((posMode != 1 && negMode != 1) || (ell == 2 && abs(emm) == 2))
2122 { /* skip mode */
2123 continue;
2124 } /* else: generate mode */
2125
2126 /* We test for hypothetical m=0 modes */
2127 if (emm == 0)
2128 {
2129 sym = 0;
2130 }
2131 else
2132 {
2133 sym = 1;
2134 }
2135
2136 /* Now build the corresponding hlm mode */
2137
2138 // Populate pWFHM with useful parameters of each mode
2140 IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams_aux);
2141
2142
2143 // If mode is even and black holes are equal we skip this part and return an array of zeros.
2144 if(pWFHM->Ampzero==0){
2145
2146 #if DEBUG == 1
2147 printf("\n\nInitializing amplitude struct of %i...\n\n",pWFHM->modeTag);
2148 #endif
2149
2150 /* Allocate and initialize the PhenomXHM lm amplitude and phase coefficients struct */
2154 pPhase = XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
2157
2158 /* Get coefficients for Amplitude and Phase */
2159 if (pWFHM->MixingOn == 1) {
2160 // For the 32 we need the speroidal coefficients for the phase and the amplitude coefficients of the 22.
2161 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
2163 }
2164 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
2165 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams_aux);
2166
2167 #if DEBUG == 1
2168 printf("\n\n **** Amplitude and Phase struct initialized. **** \n\n");
2169 #endif
2170
2171 /* Loop over frequencies to generate waveform */
2172 /* With mode mixng */
2173 if(pWFHM->MixingOn==1){
2174 // If the 22 mode has been already computed we use it for the mixing of the 32.
2175 if(pos22 == 1 || neg22 == 1){
2176 for (UINT4 idx = 0; idx < len; idx++)
2177 {
2178 COMPLEX16 wf22 = htilde22->data->data[idx + offset]; //This will be rescaled inside SpheroidalToSphericalRecycle for the rotation
2179 amp = IMRPhenomXHM_Amplitude_ModeMixingRecycle(&powers_of_Mf[idx], wf22, pAmp, pPhase, pWFHM);
2180 phi = IMRPhenomXHM_Phase_ModeMixingRecycle(&powers_of_Mf[idx], wf22, pAmp, pPhase, pWFHM);
2181 /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2182 ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
2183 }
2184 }
2185 // If the 22 has not been computed, its ringdown part is computed internally using pAmp22 and pPhase22.
2186 else{
2187 for (UINT4 idx = 0; idx < len; idx++)
2188 {
2189 amp = IMRPhenomXHM_Amplitude_ModeMixing(&powers_of_Mf[idx], pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2190 phi = IMRPhenomXHM_Phase_ModeMixing(&powers_of_Mf[idx], pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2191 /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2192 ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
2193 }
2194 }
2195 } /* No mode mixing */
2196 else{
2197 for (UINT4 idx = 0; idx < len; idx++)
2198 {
2199 amp = IMRPhenomXHM_Amplitude_noModeMixing(&powers_of_Mf[idx], pAmp, pWFHM);
2200 phi = IMRPhenomXHM_Phase_noModeMixing(&powers_of_Mf[idx], pPhase, pWFHM, pWF);
2201 /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2202 ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
2203 }
2204 }/* End of loop over frequencies */
2205 /* In GetPhaseCoefficients we call IMRPhenomX_Phase_22_ConnectionCoefficients so the coefficients below are initialized,
2206 however every time a new mode is called we need to have these coefficients to be initially zero.*/
2207 pPhase22->C1Int = 0;
2208 pPhase22->C2Int = 0;
2209 pPhase22->C1MRD = 0;
2210 pPhase22->C2MRD = 0;
2211
2212 #if DEBUG == 1
2213 ParametersToFile(pWF, pWFHM, pAmp, pPhase);
2214 #endif
2215 /* Free memory */
2216 LALFree(pAmp);
2217 LALFree(pPhase);
2218 }
2219 // Return array of zeros if the mode is zero
2220 else{
2221 for (UINT4 idx = 0; idx < len; idx++)
2222 {
2223 ((htildelm)->data->data)[idx+offset] = 0.;
2224 }
2225 }// end Amp zero
2226
2227
2228 #if DEBUG == 1
2229 // Save the hlm mode into a file
2230 FILE *file;
2231 char fileSpec[40];
2232
2233 sprintf(fileSpec, "simulation%i_MM2.dat", pWFHM->modeTag);
2234 printf("\nOutput file: %s\r\n",fileSpec);
2235 file = fopen(fileSpec,"w");
2236
2237 fprintf(file,"# q = %.16f m1 = %.16f m2 = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->m1, pWF->m2, pWF->chi1L, pWF->chi2L, pWFHM->modeTag, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
2238 fprintf(file,"# Frequency (Hz) Amplitude Phase\n");
2239
2240 COMPLEX16 data0;
2241 for(UINT4 idx = 0; idx < htildelm->data->length; idx++)
2242 {
2243 data0 = ((htildelm)->data->data)[idx];
2244 fprintf(file, "%.16f %.16e %.16e\n", idx*pWF->deltaF, creal(data0), cimag(data0));
2245 }
2246 fclose(file);
2247 #endif
2248
2249 // Add the recent mode to hptilde and hctilde. beta is the azimuthal angle = pi/2 - phiRef, it is computed in IMRPhenomX_internals.c
2250 if(posMode==1 && negMode!=1){
2251 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, emm, 0); // add only the positive mode
2252 }
2253 else if(posMode!=1 && negMode==1){
2254 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, -emm, 0); // add only the negative mode
2255 }
2256 else{
2257 status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, emm, sym); // add both positive and negative modes
2258 }
2259 LALFree(pWFHM);
2260 }
2261 }// End loop of higher modes
2262
2263
2264 /* Free allocated memory */
2268 XLALDestroyValue(ModeArray);
2269 LALFree(powers_of_Mf);
2270 LALFree(pAmp22);
2271 LALFree(pPhase22);
2272 LALFree(qnms);
2273 LALFree(Mf);
2274 XLALDestroyDict(lalParams_aux);
2275
2276
2277 return status;
2278}
2279
2280
2281/* Function to sum one mode (htildelm) to hp/c tilde */
2283 COMPLEX16FrequencySeries *hptilde, /**<[out] hp series*/
2284 COMPLEX16FrequencySeries *hctilde, /**<[out] hc series */
2285 COMPLEX16FrequencySeries *htildelm, /**< hlm mode to add */
2286 REAL8 theta, /**< Inclination [rad] */
2287 REAL8 phi, /**< Azimuthal angle [rad]*/
2288 INT4 l, /**< l index of the lm mode */
2289 INT4 m, /**< m index of the lm mode */
2290 INT4 sym /**< Equatorial symmetry */
2291){
2292 COMPLEX16 Ystar, Ym;
2293 UINT4 j;
2294 COMPLEX16 hlm; /* helper variable that contains a single point of hlmtilde */
2295
2296 INT4 minus1l; /* (-1)^l */
2297 if (l % 2 !=0)
2298 {
2299 minus1l = -1;
2300 }
2301 else
2302 {
2303 minus1l = 1;
2304 }
2305
2306 Ym = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, -m);
2307
2308 if (sym)
2309 {
2310 /* Equatorial symmetry: add in -m and m mode */
2311 Ystar = conj(XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m));
2312 COMPLEX16 factorp = 0.5 * (Ym + minus1l * Ystar);
2313 COMPLEX16 factorc = I * 0.5 * ( Ym - minus1l * Ystar);
2314
2315 #if DEBUG == 1
2316 printf("\nfactorp = %.16e", cabs(factorp));
2317 printf("\nfactorc = %.16e",cabs(factorc));
2318 printf("\nhtildelm length = %i\n", htildelm->data->length);
2319 printf("\nhp/hc tilde length = %i %i\n", hptilde->data->length,hptilde->data->length);
2320 #endif
2321
2322 for (j = 0; j < htildelm->data->length; ++j) {
2323 hlm = htildelm->data->data[j];
2324 hptilde->data->data[j] += (factorp * hlm);
2325 hctilde->data->data[j] += (factorc * hlm);
2326 }
2327 }
2328 else // only positives or negative modes
2329 {
2330 COMPLEX16 Ylm, factorp, factorc;
2331 if (m >0){ // only m>0
2332 Ylm = conj(XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m));
2333 factorp = 0.5*minus1l*Ylm;
2334 factorc = -I*0.5*minus1l*Ylm;
2335 }
2336 else{ // only m<0
2337 Ylm = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m);
2338 factorp = 0.5*Ylm;
2339 factorc = I*0.5*Ylm;
2340 }
2341
2342 COMPLEX16* datap = hptilde->data->data;
2343 COMPLEX16* datac = hctilde->data->data;
2344
2345 for ( j = 0; j < htildelm->data->length; ++j ) {
2346 hlm = (htildelm->data->data[j]);
2347 datap[j] += factorp*hlm;
2348 datac[j] += factorc*hlm;
2349 }
2350 }
2351 return XLAL_SUCCESS;
2352}
2353
2354/** @addtogroup LALSimIMRPhenomX_c
2355* @{
2356*
2357* @name Routines for IMRPhenomXHM
2358* @{
2359*
2360* @author Cecilio García Quirós, Marta Colleoni, Sascha Husa
2361*
2362* @brief C code for IMRPhenomXHM phenomenological waveform model.
2363*
2364* This is an aligned-spin frequency domain model with subdomimant modes: 2|2|, 2|1|, 3|3|, 3|2|, 4|4| .
2365* See C.García-Quirós et al arXiv:2001.10914 for details. Any studies that use this waveform model should include
2366* a reference to this paper.
2367*
2368* @note The model was calibrated to mass-ratios from 1 to 1000.
2369* The calibration points will be given in forthcoming papers.
2370*
2371* @attention The model is usable outside this parameter range,
2372* and in tests to date gives sensible physical results,
2373* but conclusive statements on the physical fidelity of
2374* the model for these parameters await comparisons against further
2375* numerical-relativity simulations. For more information, see the review wiki
2376* under https://git.ligo.org/waveforms/reviews/imrphenomx/wikis/home.
2377* DCC link to the paper and supplementary material: https://dcc.ligo.org/P2000011-v2
2378*
2379* Waveform flags:
2380*
2381* PhenomXHMReleaseVersion: this flag was introduced after the recalibration of the higher modes amplitudes in 122022.
2382* The default value is 122022, pointing to the new release. The old release can be recovered setting this option to 122019.
2383* For future releases this flag will be updated.
2384*
2385* NOTE: The following flags are only intended for further model development and not of general interest to the user. Changes from the implemented default values (https://git.ligo.org/waveforms/reviews/imrphenomxhm-amplitude-recalibration/-/wikis/home) are generally not advised.
2386* IMRPhenomXHMInspiral(Intermediate)(Ringdown)Amp(Phase)FreqsVersion: controls the cutting frequencies between regions and the collocation points frequencies
2387* IMRPhenomXHMInspiral(Intermediate)(Ringdown)Amp(Phase)FitsVersion: controls the version of the parameter space fits for collocation points values and coefficients
2388* IMRPhenomXHMInspiral(Intermediate)(Ringdown)Amp(Phase)Version: controls the version of the ansatz. In the 122022 release the new format allows for more flexibility to choose the collocation points to be used
2389* The 122022 release does not modify the phases, so all the Phase flags point to the old value of PhaseVersion. Notice that the PhaseFreqs(Fits)Version flags cannot be modified through LALDict options.
2390**/
2391
2392/** Returns amplitude of one single mode in a custom frequency array.
2393 If the in-plane spin components are non-zero, this is the amplitude of the modified co-precessing mode,
2394 where the ringdown/damping frequencies corresponds to those of the precessing final spin.
2395*/
2397 REAL8Sequence **amplitude, /**< [out] FD amp */
2398 const REAL8Sequence *freqs, /**< Input Frequency Array (Hz) */
2399 UINT4 ell, /**< l index of the mode */
2400 INT4 emm, /**< m index of the mode */
2401 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
2402 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
2403 REAL8 S1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2404 REAL8 S1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2405 REAL8 S1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2406 REAL8 S2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2407 REAL8 S2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2408 REAL8 S2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2409 REAL8 distance, /**< Luminosity distance (m) */
2410 REAL8 phiRef, /**< Orbital amp at fRef (rad) */
2411 REAL8 fRef_In, /**< Reference frequency (Hz) */
2412 LALDict *lalParams /**< Extra params */
2413)
2414{
2415 UINT4 status;
2416
2417 /* Sanity checks */
2418 if(*amplitude) { XLAL_CHECK(NULL != amplitude, XLAL_EFAULT); }
2419 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
2420 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
2421 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
2422 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
2423 /*
2424 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
2425 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
2426 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
2427 - For mass ratios > 1000: throw a hard error that model is not valid.
2428 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
2429
2430 */
2431 REAL8 mass_ratio;
2432 if(m1_SI > m2_SI)
2433 {
2434 mass_ratio = m1_SI / m2_SI;
2435 }
2436 else
2437 {
2438 mass_ratio = m2_SI / m1_SI;
2439 }
2440 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
2441 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
2442 if(fabs(S1z) > 0.99 || fabs(S2z) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
2443
2444 /* Use an auxiliar laldict to not overwrite the input argument */
2445 LALDict *lalParams_aux;
2446 /* setup mode array */
2447 if (lalParams == NULL)
2448 {
2449 lalParams_aux = XLALCreateDict();
2450 }
2451 else{
2452 lalParams_aux = XLALDictDuplicate(lalParams);
2453 }
2454 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
2455 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
2456
2457 /* first check if (l,m) mode is 'activated' in the ModeArray */
2458 /* if activated then generate the mode, else skip this mode. */
2459 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1)
2460 { /* skip mode */
2461 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
2463 } /* else: generate mode */
2464 XLALDestroyValue(ModeArray);
2465
2466
2467 /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
2468 REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In;
2469
2470 /* Initialize the useful powers of LAL_PI */
2473 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
2474
2475 /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
2477 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
2478 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, S1z, S2z, 0., fRef, phiRef, freqs->data[0], freqs->data[freqs->length-1], distance, 0.0, lalParams_aux, DEBUG);
2479 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
2480
2481 /* If we have a precessing case, then update the final spin */
2482 if((S1x*S1x + S1y*S1y + S2x*S2x + S2y*S2y) > 0){
2483 /* Initialize IMRPhenomX Precession struct and check that it generated successfully. */
2485 pPrec = XLALMalloc(sizeof(IMRPhenomXPrecessionStruct));
2487 pWF,
2488 pPrec,
2489 m1_SI,
2490 m2_SI,
2491 S1x,
2492 S1y,
2493 S1z,
2494 S2x,
2495 S2y,
2496 S2z,
2497 lalParams_aux,
2499 );
2500 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetPrecessionVariables failed.\n");
2501 LALFree(pPrec);
2502 }
2503
2504
2505 //populate coefficients of 22 mode, to rotate to spherical
2508
2509 // Populate pWFHM
2511
2512 /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
2515
2516 REAL8 Amp0 = 0, amp = 0, Mf;
2517 IMRPhenomX_UsefulPowers powers_of_Mf;
2518
2519 if(ell ==2 && abs(emm) == 2){
2521 Amp0 = pWF->amp0;
2522 }
2523 else{
2524 // allocate qnm struct
2525 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
2527
2528 IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams_aux);
2529 LALFree(qnms);
2530
2531 if(pWFHM->Ampzero==0){
2532 Amp0 = pWFHM->Amp0;
2533
2534 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
2536
2537 /* Get coefficients for Amplitude and phase */
2538 if (pWFHM->MixingOn == 1) {
2540 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
2541 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
2543 }
2544 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
2545 }
2546 }
2547
2548 *amplitude = XLALCreateREAL8Sequence(freqs->length);
2549
2550 /* Loop over frequencies to generate waveform */
2551 for (UINT4 idx = 0; idx < freqs->length; idx++)
2552 {
2553 Mf = pWF->M_sec * freqs->data[idx];
2554 INT4 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf, Mf);
2555 if(initial_status != XLAL_SUCCESS)
2556 {
2557 status = initial_status;
2558 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2559 }
2560 else
2561 {
2562 if(ell == 2 && abs(emm) == 2){
2563 amp = IMRPhenomX_Amplitude_22(Mf, &powers_of_Mf, pAmp22, pWF);
2564 }
2565 else if (pWFHM->Ampzero==0){
2566 if(pWFHM->MixingOn==1){
2567 amp = IMRPhenomXHM_Amplitude_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2568 }
2569 else{
2570 amp = IMRPhenomXHM_Amplitude_noModeMixing(&powers_of_Mf, pAmp, pWFHM);
2571 }
2572 }
2573 ((*amplitude)->data)[idx] = Amp0 * amp;
2574 }
2575 }
2576
2577
2578 LALFree(pWFHM);
2579 LALFree(pWF);
2580 LALFree(pAmp22);
2581 LALFree(pAmp);
2582 LALFree(pPhase22);
2583 LALFree(pPhase);
2584 XLALDestroyDict(lalParams_aux);
2585
2586 return XLAL_SUCCESS;
2587}
2588
2589/** Returns phase of one single mode in a custom frequency array.
2590 If the in-plane spin components are non-zero, this is the phase of the modified co-precessing mode,
2591 where the ringdown/damping frequencies corresponds to those of the precessing final spin.
2592*/
2594 REAL8Sequence **phase, /**< [out] FD amp */
2595 const REAL8Sequence *freqs, /**< Input Frequency Array (Hz) */
2596 UINT4 ell, /**< l index of the mode */
2597 INT4 emm, /**< m index of the mode */
2598 REAL8 m1_SI, /**< Mass of companion 1 (kg) */
2599 REAL8 m2_SI, /**< Mass of companion 2 (kg) */
2600 REAL8 S1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2601 REAL8 S1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2602 REAL8 S1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
2603 REAL8 S2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2604 REAL8 S2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2605 REAL8 S2z, /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
2606 REAL8 distance, /**< Luminosity distance (m) */
2607 REAL8 phiRef, /**< Orbital amp at fRef (rad) */
2608 REAL8 fRef_In, /**< Reference frequency (Hz) */
2609 LALDict *lalParams /**< Extra params */
2610)
2611{
2612 UINT4 status;
2613
2614 /* Sanity checks */
2615 if(*phase) { XLAL_CHECK(NULL != phase, XLAL_EFAULT); }
2616 if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
2617 if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
2618 if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
2619 if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
2620 /*
2621 Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
2622 - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
2623 - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
2624 - For mass ratios > 1000: throw a hard error that model is not valid.
2625 - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
2626
2627 */
2628 REAL8 mass_ratio;
2629 if(m1_SI > m2_SI)
2630 {
2631 mass_ratio = m1_SI / m2_SI;
2632 }
2633 else
2634 {
2635 mass_ratio = m2_SI / m1_SI;
2636 }
2637 if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
2638 if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
2639 if(fabs(S1z) > 0.99 || fabs(S2z) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
2640
2641
2642 /* Use an auxiliar laldict to not overwrite the input argument */
2643 LALDict *lalParams_aux;
2644 /* setup mode array */
2645 if (lalParams == NULL)
2646 {
2647 lalParams_aux = XLALCreateDict();
2648 }
2649 else{
2650 lalParams_aux = XLALDictDuplicate(lalParams);
2651 }
2652 lalParams_aux = IMRPhenomXHM_setup_mode_array(lalParams_aux);
2653 LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
2654
2655 /* first check if (l,m) mode is 'activated' in the ModeArray */
2656 /* if activated then generate the mode, else skip this mode. */
2657 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1)
2658 { /* skip mode */
2659 XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
2661 } /* else: generate mode */
2662 XLALDestroyValue(ModeArray);
2663
2664
2665 /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
2666 REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In;
2667
2668 /* Initialize the useful powers of LAL_PI */
2671 XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
2672
2673 /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
2675 pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
2676 status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, S1z, S2z, 0, fRef, phiRef, freqs->data[0], freqs->data[freqs->length-1], distance, 0.0, lalParams_aux, DEBUG);
2677 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
2678
2679 /* If we have a precessing case, then update the final spin */
2680 if((S1x*S1x + S1y*S1y + S2x*S2x + S2y*S2y) > 0){
2681 /* Initialize IMRPhenomX Precession struct and check that it generated successfully. */
2683 pPrec = XLALMalloc(sizeof(IMRPhenomXPrecessionStruct));
2685 pWF,
2686 pPrec,
2687 m1_SI,
2688 m2_SI,
2689 S1x,
2690 S1y,
2691 S1z,
2692 S2x,
2693 S2y,
2694 S2z,
2695 lalParams_aux,
2697 );
2698 XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetPrecessionVariables failed.\n");
2699 LALFree(pPrec);
2700 }
2701
2702 /* Declare XHM waveform struct */
2704
2705 //populate coefficients of 22 mode, to rotate to spherical
2708 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
2709
2710 /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
2713
2714 REAL8 lina = 0, linb = 0, inveta=1./pWF->eta;
2715 if (ell == 2 && abs(emm) == 2){
2716 /* Initialize a struct containing useful powers of Mf at fRef */
2717 IMRPhenomX_UsefulPowers powers_of_MfRef;
2718 status = IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
2719 XLAL_CHECK(XLAL_SUCCESS == status, status, "IMRPhenomX_Initialize_Powers failed for MfRef.\n");
2720
2721 /* Linear time and phase shifts so that model peaks near t ~ 0 */
2722 lina = 0;
2723 /* Get phase connection coefficients */
2725 linb = IMRPhenomX_TimeShift_22(pPhase22, pWF);
2726 /* Calculate phase at reference frequency: phifRef = 2.0*phi0 + LAL_PI_4 + PhenomXPhase(fRef) */
2727 pWF->phifRef = -(inveta*IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF) + linb*pWF->MfRef + lina) + 2.0*pWF->phi0 + LAL_PI_4;
2728 }
2729 else{
2730 // allocate qnm struct
2731 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
2733 // Populate pWFHM
2734 IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams_aux);
2735 LALFree(qnms);
2736 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
2738
2739 /* Get coefficients for Amplitude and phase */
2740 if (pWFHM->MixingOn == 1) {
2741 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
2744 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
2745 }
2746 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams_aux);
2747 }
2748
2749 IMRPhenomX_UsefulPowers powers_of_Mf;
2750 REAL8 addpi = 0; // Add pi to the phase if (-1)^l is negative
2751
2752 /* Multiply by (-1)^l to get the true negative mode */
2753 if(ell%2 != 0){
2754 addpi = LAL_PI;
2755 }
2756
2757 *phase = XLALCreateREAL8Sequence(freqs->length);
2758
2759 REAL8 Mf, phi;
2760
2761 /* Loop over frequencies to generate waveform */
2762 for (UINT4 idx = 0; idx < freqs->length; idx++)
2763 {
2764 Mf = pWF->M_sec * freqs->data[idx];
2765 INT4 initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2766 if(initial_status != XLAL_SUCCESS)
2767 {
2768 status = initial_status;
2769 XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2770 }
2771 else
2772 {
2773 if (ell ==2 && abs(emm) == 2){
2774 phi = inveta*IMRPhenomX_Phase_22(Mf, &powers_of_Mf, pPhase22, pWF);
2775 phi += linb*Mf + lina + pWF->phifRef;
2776 }
2777 else{
2778 if(pWFHM->MixingOn==1){
2779 phi = IMRPhenomXHM_Phase_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2780 }
2781 else{
2782 phi = IMRPhenomXHM_Phase_noModeMixing(&powers_of_Mf, pPhase, pWFHM, pWF);
2783 }
2784 }
2785 ((*phase)->data)[idx] = phi + addpi;
2786 }
2787 }
2788
2789
2790 /* If the mode is positive, the wf is (-1)^l*conjugate(wf). For the phase this is translated in adding or not pi and changing the sign. */
2791 if(emm > 0){
2792 for (UINT4 idx = 0; idx < freqs->length; idx++)
2793 {
2794 ((*phase)->data)[idx] = addpi - ((*phase)->data)[idx];
2795 }
2796 }
2797
2798
2799 LALFree(pWFHM);
2800 LALFree(pWF);
2801 LALFree(pAmp22);
2802 LALFree(pAmp);
2803 LALFree(pPhase22);
2804 LALFree(pPhase);
2805 XLALDestroyDict(lalParams_aux);
2806
2807 return XLAL_SUCCESS;
2808}
2809
2810
2811
2812/* Compute XHM phase and phase derivative for a given Mf using the inputs as shown below. This function has been created to reduce code duplication in the PNR Coprecessing model. See IMRPhenomX_FullPhase_22 for the analagous XAS function. Both functions are designed to be used in in initialization routines, and not for evaluating the phase at many frequencies. We name this function "IMRPhenomXHM_Phase_for_initialization" becuase "IMRPhenomXHM_Phase" is already used in the multibanding code. */
2814 double *phase,
2815 double *dphase,
2816 double Mf,
2817 INT4 ell,
2818 INT4 emm,
2820 LALDict *lalParams
2821){
2822
2823 // Define an int to hold status values
2824 UINT4 status;
2825
2826 // allocate qnm struct
2827 QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
2829
2830 // Populate, pWFHM, the waveform struct for the non-prec HM moment
2832 IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams);
2833 LALFree(qnms);
2834
2835 /* Allocate coefficients of 22 mode */
2838 //
2839 IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
2840
2841 /* Allocate and initialize the PhenomXHM lm amplitude and phae coefficients struct */
2844
2845 /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
2848
2849 /* Get coefficients for Amplitude and phase */
2850 if (pWFHM->MixingOn == 1) {
2851 // For mode with mixing we need the spheroidal coeffs of the 32 phase and the 22 amplitude coeffs.
2852 GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
2854 }
2855 IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
2856 IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
2857
2858 // Compute XHM phase at Mf
2859
2860 //
2861 IMRPhenomX_UsefulPowers powers_of_Mf;
2862 status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2863
2864 //
2865 if(pWFHM->MixingOn==1){
2866 //
2867 *phase = IMRPhenomXHM_Phase_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2868 //
2869 *dphase = IMRPhenomXHM_dPhase_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2870 }
2871 else
2872 {
2873 //
2874 *phase = IMRPhenomXHM_Phase_noModeMixing(&powers_of_Mf, pPhase, pWFHM, pWF);
2875 //
2876 *dphase = IMRPhenomXHM_dPhase_noModeMixing(Mf, &powers_of_Mf, pPhase, pWFHM, pWF);
2877 }
2878
2879 //
2880 if(ell%2 != 0){
2881 *phase += LAL_PI;
2882 }
2883
2884 //
2885 *phase = fmod(*phase,2*LAL_PI);
2886 if ( *phase < 0 ){
2887 *phase += 2*LAL_PI;
2888 }
2889
2890 //
2891 LALFree(pWFHM);
2892 LALFree(pAmp);
2893 LALFree(pPhase);
2894 LALFree(pAmp22);
2895 LALFree(pPhase22);
2896
2897 //
2898 return status;
2899
2900}
2901
2902
2903/** @}
2904* @} **/
void XLALDestroyDict(LALDict *dict)
LALDict * XLALDictDuplicate(const LALDict *orig)
LALDict * XLALCreateDict(void)
#define LALFree(p)
static size_t NextPow2(const size_t n)
IMRPhenomX_UsefulPowers powers_of_lalpi
#define PHENOMXDEBUG
void IMRPhenomXHM_PNR_EnforceXHMPhaseAlignment(double *lina, double *linb, INT4 ell, INT4 emm, IMRPhenomXWaveformStruct *pWF, LALDict *lalParams)
int IMRPhenomXSetWaveformVariables(IMRPhenomXWaveformStruct *wf, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1L_In, const REAL8 chi2L_In, const REAL8 deltaF, const REAL8 fRef, const REAL8 phi0, const REAL8 f_min, const REAL8 f_max, const REAL8 distance, const REAL8 inclination, LALDict *LALParams, UNUSED const UINT4 debug)
double IMRPhenomX_TimeShift_22(IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
void IMRPhenomX_Phase_22_ConnectionCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
int IMRPhenomXGetAmplitudeCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
int IMRPhenomX_Initialize_Powers(IMRPhenomX_UsefulPowers *p, REAL8 number)
double IMRPhenomX_Phase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
int IMRPhenomXGetPhaseCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
INT4 check_input_mode_array(LALDict *lalParams)
double IMRPhenomX_Amplitude_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp, IMRPhenomXWaveformStruct *pWF)
int IMRPhenomXGetAndSetPrecessionVariables(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPrecessionStruct *pPrec, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1x, REAL8 chi1y, REAL8 chi1z, REAL8 chi2x, REAL8 chi2y, REAL8 chi2z, LALDict *lalParams, INT4 debug_flag)
Function to populate the IMRPhenomXPrecessionStruct:
static LALDict * IMRPhenomXHM_setup_mode_array(LALDict *lalParams)
int SetupWFArrays(REAL8Sequence **freqs, COMPLEX16FrequencySeries **htildelm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, LIGOTimeGPS ligotimegps_zero)
int IMRPhenomXHMGenerateFDOneMode(COMPLEX16FrequencySeries **htildelm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, UINT4 ell, UINT4 emm, LALDict *lalParams)
static int IMRPhenomXHM_MultiMode2(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, LALDict *lalParams)
static int IMRPhenomXHMFDAddMode(COMPLEX16FrequencySeries *hptilde, COMPLEX16FrequencySeries *hctilde, COMPLEX16FrequencySeries *hlmtilde, REAL8 theta, REAL8 phi, INT4 l, INT4 m, INT4 sym)
#define L_MAX
#define DEBUG
static int IMRPhenomXHM_MultiMode(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1z, REAL8 chi2z, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 distance, REAL8 inclination, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
IMRPhenomX_UsefulPowers powers_of_lalpiHM
REAL8 IMRPhenomXHM_Amplitude_ModeMixing(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22)
void IMRPhenomXHM_SetHMWaveformVariables(int ell, int emm, IMRPhenomXHMWaveformStruct *wf, IMRPhenomXWaveformStruct *wf22, QNMFits *qnms, LALDict *LALParams)
int ParametersToFile(IMRPhenomXWaveformStruct *pWF, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp, UNUSED IMRPhenomXHMPhaseCoefficients *pPhase)
double IMRPhenomXHM_dPhase_ModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22)
REAL8 IMRPhenomXHM_Phase_ModeMixingRecycle(IMRPhenomX_UsefulPowers *powers_of_Mf, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF)
void IMRPhenomXHM_GetAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22)
void IMRPhenomXHM_GetPhaseCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22, UNUSED LALDict *lalParams)
REAL8 IMRPhenomXHM_Amplitude_ModeMixingRecycle(IMRPhenomX_UsefulPowers *powers_of_Mf, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF)
REAL8 IMRPhenomXHM_Amplitude_noModeMixing(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMWaveformStruct *pWF)
void GetSpheroidalCoefficients(IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22)
void IMRPhenomXHM_FillAmpFitsArray(IMRPhenomXHMAmpCoefficients *pAmp)
void IMRPhenomXHM_FillPhaseFitsArray(IMRPhenomXHMPhaseCoefficients *pPhase)
REAL8 IMRPhenomXHM_Phase_noModeMixing(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, UNUSED IMRPhenomXWaveformStruct *pWF22)
double IMRPhenomXHM_dPhase_noModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, UNUSED IMRPhenomXWaveformStruct *pWF22)
REAL8 IMRPhenomXHM_Phase_ModeMixing(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22)
void IMRPhenomXHM_Initialize_QNMs(QNMFits *qnms)
static double IMRPhenomXHM_RD_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase)
static double IMRPhenomXHM_RD_Amp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp)
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
int XLALSimInspiralWaveformParamsInsertModeArray(LALDict *params, LALValue *value)
int XLALSimInspiralWaveformParamsInsertPhenomXHMThresholdMband(LALDict *params, REAL8 value)
REAL8 XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(LALDict *params)
void XLALDestroyValue(LALValue *value)
#define fprintf
int l
Definition: bh_qnmode.c:135
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
double theta
Definition: bh_sphwf.c:118
sigmaKerr data[0]
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)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define LAL_PI_2
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_PC_SI
#define LAL_PI_4
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
int XLALSimIMRPhenomXHMMultiBandOneMode(COMPLEX16FrequencySeries **htildelm, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emm, REAL8 distance, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Return htildelm, the waveform of one mode without mode-mixing.
INT4 IMRPhenomXHM_Phase_for_Initialization(double *phase, double *dphase, double Mf, INT4 ell, INT4 emm, IMRPhenomXWaveformStruct *pWF, LALDict *lalParams)
int XLALSimIMRPhenomXASGenerateFD(COMPLEX16FrequencySeries **htilde22, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Driver routine to calculate an IMRPhenomX aligned-spin, inspiral-merger-ringdown phenomenological wav...
int XLALSimIMRPhenomXHMFrequencySequence(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, const REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1z, REAL8 chi2z, REAL8 distance, REAL8 inclination, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns hptilde and hctilde as a complex frequency series with entries exactly at the frequencies spe...
int XLALSimIMRPhenomXHMModes(SphHarmFrequencySeries **hlms, REAL8 m1_SI, REAL8 m2_SI, REAL8 S1z, REAL8 S2z, REAL8 deltaF, REAL8 f_min, REAL8 f_max, REAL8 f_ref, REAL8 phiRef, REAL8 distance, LALDict *LALparams)
Function to obtain a SphHarmFrequencySeries with the individual modes h_lm.
int XLALSimIMRPhenomXHMGenerateFDOneMode(COMPLEX16FrequencySeries **htildelm, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emm, REAL8 distance, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns the Fourier domain strain of just one mode: h_lm.
int XLALSimIMRPhenomXHMFrequencySequenceOneMode(COMPLEX16FrequencySeries **htildelm, const REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emm, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Get the model evaluated in a prebuilt frequency array.
int XLALSimIMRPhenomXASFrequencySequence(COMPLEX16FrequencySeries **htilde22, const REAL8Sequence *freqs, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Compute waveform in LAL format at specified frequencies for the IMRPhenomX model.
int XLALSimIMRPhenomXHMPhase(REAL8Sequence **phase, const REAL8Sequence *freqs, UINT4 ell, INT4 emm, REAL8 m1_SI, REAL8 m2_SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns phase of one single mode in a custom frequency array.
int XLALSimIMRPhenomXHM(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 distance, REAL8 inclination, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
int XLALSimIMRPhenomXHM_SpheroidalPhase(REAL8Sequence **phase, const REAL8Sequence *freqs, UINT4 ell, INT4 emm, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
int XLALSimIMRPhenomXHMMultiBandOneModeMixing(COMPLEX16FrequencySeries **htildelm, COMPLEX16FrequencySeries *htilde22, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emm, REAL8 distance, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns htildelm the waveform of one mode that present mode-mixing.
int XLALSimIMRPhenomXHMAmplitude(REAL8Sequence **amplitude, const REAL8Sequence *freqs, UINT4 ell, INT4 emm, REAL8 m1_SI, REAL8 m2_SI, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns amplitude of one single mode in a custom frequency array.
int XLALSimIMRPhenomXHM_SpheroidalAmplitude(REAL8Sequence **amplitude, const REAL8Sequence *freqs, UINT4 ell, INT4 emm, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
int XLALSimIMRPhenomXHM2(COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 f_min, REAL8 f_max, REAL8 deltaF, REAL8 distance, REAL8 inclination, REAL8 phiRef, REAL8 fRef_In, LALDict *lalParams)
Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
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.
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 XLALSphHarmFrequencySeriesSetFData(SphHarmFrequencySeries *ts, REAL8Sequence *fdata)
Set the tdata member for all nodes in the list.
static const INT4 m
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
COMPLEX16 XLALSpinWeightedSphericalHarmonic(REAL8 theta, REAL8 phi, int s, int l, int m)
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,...)
#define XLAL_PRINT_WARNING(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_PRINT_ERROR(...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
string status
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8 * data
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23