LALSimulation  5.4.0.1-89842e6
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 
60 #include "LALSimIMRPhenomXHM_qnm.h"
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
72 static LALDict *IMRPhenomXHM_setup_mode_array(LALDict *lalParams);
73 
74 /*
75 * Helper function to multiple hlm with Ylm.
76 * Adapted from LALSimIMREOBNRv2HMROMUtilities.c
77 */
78 static 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 */
91 static 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 */
109 static 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 */
122 static 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 */
142  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 2);
143  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 1);
144  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, 3);
145  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, 2);
146  XLALSimInspiralModeArrayActivateMode(ModeArray, 4, 4);
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 
153  XLALSimInspiralWaveformParamsInsertModeArray(lalParams, ModeArray);
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.
282 Notice than even when the specified frequencies are positives, the m>0 only lives in the negative frequencies regime.
283 With 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).
284 In the contrary, h_l-m is zero for negative frequencies and only lives for positive frequencies.
285 This 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 
335  UINT4 status;
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 */
417  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
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  */
864  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
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  }
1044  XLALSphHarmFrequencySeriesSetFData(*hlms, freqs);
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 
1388 XLALSimIMRPhenomXHM calls the function for a single mode that can be XLALSimIMRPhenomXHMGenerateFDOneMode or XLALSimIMRPhenomXHMMultiBandOneMode,
1389 depending on if the Multibanding is active or not.
1390 
1391 By 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 
1393 This 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 
1478 XLALSimIMRPhenomXHM2 builds each mode explicitly in the loop over modes, recycling some common quantities between modes like
1479 the frequency array, the powers of frequencies, structures, etc so it has less overhead than XLALSimIMRPhenomXHM.
1480 
1481 By 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);
1622  XLALDestroyREAL8Sequence(freqs);
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.
1736 The 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");
1856  COMPLEX16 data;
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){
1896  status = XLAL_SUCCESS;
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
1913 XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_Multimode failed to generate IMRPhenomXHM waveform.");
1914 
1915 /* Free memory */
1917 XLALDestroyValue(ModeArray);
1918 XLALDestroyDict(lalParams_aux);
1919 
1920 #if DEBUG == 1
1921 printf("\n******Leaving IMRPhenomXHM_MultiMode*****\n");
1922 #endif
1923 
1924 return XLAL_SUCCESS;
1925 }
1926 
1927 
1928 
1929 /* Core function of XLALSimIMRPhenomXHM2, returns hptilde, hctilde corresponding to a sum of modes.
1930 The 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 */
2152  pAmp = XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
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 */
2267  XLALDestroyREAL8Sequence(freqs);
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,
2498  PHENOMXDEBUG
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,
2696  PHENOMXDEBUG
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(LALDict *old)
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)
int XLALSimInspiralWaveformParamsInsertModeArray(LALDict *params, LALValue *value)
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
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 * XLALResizeCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series, int first, size_t length)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
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.
LALValue * XLALSimInspiralCreateModeArray(void)
Create a LALValue pointer to store the mode array.
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralModeArrayActivateMode(LALValue *modes, unsigned l, int m)
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