LALSimulation  5.4.0.1-89842e6
LALSimIMRPhenomXHM_multiband.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Cecilio García Quirós, Sascha Husa
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  /* This code applies the multibanding technique described in arXiv:2001.10897 to the model IMRPhenomXHM described in arXiv:2001.10914. */
20 
21 #include <complex.h>
22 
23 #include <stdio.h>
24 #include <math.h>
25 
26 #include <gsl/gsl_spline.h>
27 
29 #include "LALSimIMRPhenomX.h"
30 
31 /*****************************************************/
32 /* */
33 /* MULTIBANDING GRIDS */
34 /* */
35 /*****************************************************/
36 
37 /* Build IMRPhenomXMultiBandingGridStruct object, equally-spaced grid */
39  REAL8 fSTART, /**< Starting frequency of the uniform bin **/
40  REAL8 fEND, /**< Ending frequency of the uniform bin **/
41  REAL8 mydf /**< Frequency spacing of the bin **/
42 ) {
43 
45 
46  REAL8 Deltaf, maxfreq;
47  INT4 nCoarseIntervals;
48 
49  Deltaf = fEND - fSTART;
50  nCoarseIntervals = (int)ceil(Deltaf/mydf);
51  maxfreq = fSTART + mydf * nCoarseIntervals;
52 
53  /* Model Version Parameters */
54  myGrid.debug = DEBUG;
55  myGrid.nIntervals = nCoarseIntervals;
56  myGrid.xStart = fSTART;
57  myGrid.xEndRequested = fEND;
58  myGrid.xEndFrom_xStart_dx = maxfreq;
59  myGrid.xMax = maxfreq;
60  myGrid.deltax = mydf;
61  myGrid.Length = nCoarseIntervals + 1;
62 
63  #if DEBUG == 1
64  printf("\nGridComp: fSTART = %.16f",fSTART);
65  printf("\nGridComp: xMax = %.16f",maxfreq);
66  printf("\nGridComp: Length = %i",nCoarseIntervals+1);
67  printf("\nGridComp: x0 = %e : x1 = %e : length = %d : mydf = %e\n", myGrid.xStart, myGrid.xMax, myGrid.Length, mydf);
68  #endif
69 
70  return myGrid;
71 }
72 
73 /* Build non equally-spaced coarse frequency grid */
75  REAL8 fstartIn, /**< Minimun frequency in NR unit s**/
76  REAL8 fend, /**< End of inspiral frequency bins **/
77  REAL8 MfLorentzianEnd, /**< Determines the last frequency bin **/
78  REAL8 Mfmax, /**< Maximun frequency in NR units **/
79  REAL8 evaldMf, /**< Spacing of the uniform frequency grid (NR units) **/
80  REAL8 dfpower, /**< decaying frequency power to estimate frequency spacing **/
81  REAL8 dfcoefficient, /**< multiplying factor to the estimate of the frequency spacing **/
82  IMRPhenomXMultiBandingGridStruct *allGrids, /**<[out] list of non-uniform frequency bins**/
83  REAL8 dfmerger, /**<[out] Spacing merger bin**/
84  REAL8 dfringdown /**<[out] Spacing ringdown bin**/
85 ){
86  // the df power law: df = dfcoefficient f^dfpower
87 
88  INT4 index, intdfRatio;
89  // Variables to control the subgrids to be computed
90  INT4 preComputeFirstGrid, nMergerGrid, nRingdownGrid, nDerefineInspiralGrids;
91 
92  /* Object to store information about one subgrid */
94  coarseGrid.xMax = fstartIn;
95 
96  REAL8 df0, FrequencyFactor=1, nextfSTART, origLogFreqFact;
97  REAL8 fSTART, mydf = evaldMf, fEND, fEndGrid0 = 0, fStartInspDerefinement, fEndInsp;
98 
99  /* Number of fine freq points between two coarse freq points */
100  /* The numerator of this quantity corresponds to eqs. 2.8, 2.9 in arXiv:2001.10897. */
101  REAL8 const dfRatio = dfcoefficient * pow(fstartIn, dfpower)/evaldMf;
102 
103  REAL8 df0original = dfRatio*evaldMf;
104  coarseGrid.deltax = df0original;
105 
106  #if DEBUG == 1
107  printf("\ndfcoefficient = %.16e", dfcoefficient);
108  printf("\nfstartIn = %.16e", fstartIn);
109  printf("\ndfpower = %.16e", dfpower);
110  printf("\nevaldMf = %.16e", evaldMf);
111  printf("\ndfRatio = %.16e\n", dfRatio);
112  #endif
113 
114  if (dfRatio < 1.0) {
115  /* User asks for a df that is coarser than one predicted by the multibanding criteria, so we take the users's df */
116  #if DEBUG == 1
117  printf("\n****Adjusting frequency factors!****\n");
118  #endif
119  preComputeFirstGrid = 1;
120  intdfRatio = 1;
121  df0 = evaldMf;
122  fEndGrid0 = pow(evaldMf/dfcoefficient,1./dfpower);
123  fStartInspDerefinement = fEndGrid0 + 2 * df0;
124  #if DEBUG == 1
125  printf("\nevaldMf = %.6f\n", fEndGrid0);
126  printf("\ndfcoefficient = %.6f\n", dfcoefficient);
127  printf("\ndfpower = %.6f\n", dfpower);
128  printf("\nfEndGrid0 = %.6f\n", fEndGrid0);
129  #endif
130  }
131  else {
132  #if DEBUG == 1
133  printf("proceed without preComputeFirstGrid!");
134  #endif
135  preComputeFirstGrid = 0;
136  intdfRatio = (int)floor(dfRatio);
137  fStartInspDerefinement = fstartIn;
138  }
139 
140  df0 = evaldMf * intdfRatio;
141 
142  #if DEBUG == 1
143  printf("\nintdfRatio = %d\n", intdfRatio);
144  printf("\nfStartInspDerefinement = %e\n", fStartInspDerefinement );
145  printf("\ndf0, df0original, evaldMf = %.6e %.6e %.6e\n", df0, df0original, evaldMf );
146  #endif
147 
148 
149  if (fStartInspDerefinement >= fend) {
150  fEndInsp = fStartInspDerefinement;
151  nDerefineInspiralGrids = 0;
152  }
153  else
154  {
155  // Compute the number of inspiral subgrids needed and the ending frequency
156  FrequencyFactor = pow(2., (1./dfpower));
157  origLogFreqFact = logbase(FrequencyFactor, fend/fStartInspDerefinement); // This is eq 2.40 in arXiv:2001.10897
158 
159  nDerefineInspiralGrids=(int)(ceil(origLogFreqFact));
160  fEndInsp = fStartInspDerefinement * pow(FrequencyFactor,nDerefineInspiralGrids); // estimate, could change due to boundary effects? maybe need one grid less
161 
162  #if DEBUG == 1
163  printf("FrequencyFactor, fend, fStartInspDerefinement, origLogFreqFact: %e : %e : %e :%e\n", FrequencyFactor, fend, fStartInspDerefinement, origLogFreqFact);
164  printf("df0/evaldMf = %e\n", df0/evaldMf);
165  printf("Factor in frequency between adjacent inspiral grids = %e\n", FrequencyFactor);
166  printf("Number of subgrids required = %d : unrounded = : %e\n", nDerefineInspiralGrids, origLogFreqFact);
167  #endif
168  }
169 
170  #if DEBUG == 1
171  printf("\nMfMECO = %.16e\n fEndInsp = %.16e\n MfLorentzianEnd = %.16e\n Mfmax = %.16e\n", fend, fEndInsp, MfLorentzianEnd, Mfmax);
172  #endif
173 
174  /* Adjust transition frequencies for special cases. */
175  if (fEndInsp + evaldMf >= MfLorentzianEnd) {
176  nMergerGrid = 0;
177  if (fEndInsp + evaldMf >= Mfmax) {
178  nRingdownGrid = 0;
179  } else {
180  nRingdownGrid = 1;
181  }
182  } else {
183  nMergerGrid = 1;
184  nRingdownGrid = 1;
185  if(MfLorentzianEnd > Mfmax){
186  nRingdownGrid = 0;
187  }
188  }
189 
190 
191  #if DEBUG == 1
192  printf("nMergerGrid = %d\n", nMergerGrid);
193  printf("nRingdownGrid = %d\n", nRingdownGrid);
194  printf("fStartInspDerefinement = %e\n", fStartInspDerefinement);
195  printf("fEndInsp = %e\n", fEndInsp);
196  #endif
197 
198 
199  // Precompute the first grid if needed
200  if (preComputeFirstGrid > 0) {
201 
202  mydf = evaldMf;
203  coarseGrid = XLALSimIMRPhenomXGridComp(fstartIn,fEndGrid0,mydf);
204 
205  allGrids[0] = coarseGrid;
206  allGrids[0].intdfRatio = 1;
207  #if DEBUG == 1
208  printf("\nAdding preComputeFirstGrid %i\n",preComputeFirstGrid);
209  printf("xStart: %.6f\n", allGrids[0].xStart);
210  printf("xEnd: %.6f\n", allGrids[0].xEndRequested);
211  printf("Length: %i\n", allGrids[0].Length);
212  printf("deltax: %.6e\n", allGrids[0].deltax);
213  printf("xMax: %.6f\n", allGrids[0].xMax);
214  #endif
215 
216  fStartInspDerefinement = coarseGrid.xMax;
217  df0 = 2*coarseGrid.deltax;
218  df0original = 2*df0original;
219  }
220 
221 
222  // Loop over inspiral derefinement grids
223  if (nDerefineInspiralGrids > 0) {
224  index = 0;
225  nextfSTART = fStartInspDerefinement;
226  #if DEBUG == 1
227  printf("nDerefineInspiralGrids before loop = %d\n", nDerefineInspiralGrids);
228  #endif
229 
230  while (index < nDerefineInspiralGrids) {
231  if(df0original < evaldMf){
232  #if DEBUG == 1
233  printf("\nAdjusting freq factors!!\n");
234  #endif
235  mydf = evaldMf;
236  intdfRatio = 1;
237  }
238  else{
239  intdfRatio = (int)floor(df0original/evaldMf);
240  mydf = evaldMf*intdfRatio;
241  }
242  if(index + preComputeFirstGrid == 0){
243  fSTART = nextfSTART;
244  }
245  else{
246  fSTART = nextfSTART + mydf;
247  }
248  fEND = fSTART * FrequencyFactor;
249 
250  #if DEBUG == 1
251  printf("\n(index, fSTART, fEND) = (%d, %e, %e, %e)\n", index + preComputeFirstGrid, fSTART, fEND, mydf);
252  #endif
253 
254  coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, fEND, mydf);
255 
256  #if DEBUG == 1
257  printf("xStart: %.16e\n", coarseGrid.xStart);
258  printf("xEnd: %.16e\n", coarseGrid.xEndRequested);
259  printf("Length: %i\n", coarseGrid.Length);
260  printf("deltax: %.16e\n", coarseGrid.deltax);
261  printf("mydf: %.16e\n", mydf);
262  printf("xMax: %.16e\n", coarseGrid.xMax);
263  printf("intdfRatio = %i\n", intdfRatio);
264  #endif
265 
266  df0original = 2*df0original;
267  //nextmydf = 2 * mydf;
268  nextfSTART = coarseGrid.xMax;
269 
270  allGrids[index + preComputeFirstGrid] = coarseGrid;
271  allGrids[index+preComputeFirstGrid].intdfRatio = intdfRatio;
272 
273  index = index + 1;
274  }
275  fEndInsp = coarseGrid.xMax;
276  }
277  else{
278  #if DEBUG == 1
279  printf("\nSkipping Inspiral Loop %i\n", nDerefineInspiralGrids);
280  #endif
281  if (preComputeFirstGrid > 0){
282  fEndInsp = coarseGrid.xMax;
283  }
284  }
285 
286  #if DEBUG == 1
287  printf("\nfStartInspDerefinement after loop = %e\n", fStartInspDerefinement);
288  printf("fEndInsp after loop = %e\n", fEndInsp);
289  printf("nDerefineInspiralGrids = %i\n", nDerefineInspiralGrids);
290  #endif
291 
292  // Add merger grid
293  if (nMergerGrid > 0) {
294  df0original = dfmerger; //check if the Delta_f given by the Lorentzian is smaller than at the beginning of the merger bin.
295  if(2*coarseGrid.deltax < dfmerger){
296  df0original = 2*coarseGrid.deltax;
297  }
298  if(df0original < evaldMf){
299  #if DEBUG == 1
300  printf("\nAdjusting freq factors!!\n");
301  #endif
302  mydf = evaldMf;
303  intdfRatio = 1;
304  }
305  else{
306  intdfRatio = (int)floor(df0original/evaldMf);
307  mydf = evaldMf*intdfRatio;
308  }
309  fSTART = fEndInsp + mydf;
310 
311  if(fEndInsp == fstartIn){
312  fSTART = fEndInsp;
313  }
314 
315  INT4 mergerIndex = 0;
316 
317  if(fSTART > MfLorentzianEnd){
318  nMergerGrid = 0;
319  #if DEBUG == 1
320  printf("\nNOT adding merger grid\n");
321  #endif
322  }
323  else{
324  coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, MfLorentzianEnd, mydf);
325  mergerIndex = preComputeFirstGrid + nDerefineInspiralGrids;
326 
327  df0original = 2*df0original;
328 
329  allGrids[mergerIndex] = coarseGrid;
330  allGrids[mergerIndex].intdfRatio = intdfRatio;
331 
332  #if DEBUG == 1
333  printf("\nadding merger grid\n");
334  printf("fSTART = %.6f\n", fSTART);
335  printf("fEND = %.6f\n", coarseGrid.xMax);
336  printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
337  printf("mydf = %.16e\n", mydf);
338  printf("mergerIndex = %i\n", mergerIndex);
339  printf("intdfRatio = %i\n", intdfRatio);
340  printf("# fine points float %.16f\n", allGrids[mergerIndex].deltax/evaldMf);
341  #endif
342  }
343 
344 
345  }
346 
347  // Add RD grid
348  if (nRingdownGrid > 0) {
349  df0original = dfringdown;
350  if(df0original < evaldMf){
351  #if DEBUG == 1
352  printf("\nAdjusting freq factors!!\n");
353  #endif
354  mydf = evaldMf;
355  intdfRatio = 1;
356  }
357  else{
358  intdfRatio = (int)floor(df0original/evaldMf);
359  mydf = evaldMf*intdfRatio;
360  }
361  fSTART = coarseGrid.xMax + mydf;
362  if(coarseGrid.xMax == fstartIn){
363  fSTART = fEndInsp;
364  }
365 
366  INT4 RDindex = 0;
367 
368  if(fSTART > Mfmax){
369  nRingdownGrid = 0;
370  #if DEBUG == 1
371  printf("\nNOT adding RD grid\n");
372  #endif
373  }
374  else{
375  coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, Mfmax, mydf);
376 
377  RDindex = preComputeFirstGrid + nDerefineInspiralGrids + nMergerGrid;
378 
379  df0original = 2*df0original;
380 
381  allGrids[RDindex] = coarseGrid;
382  allGrids[RDindex].intdfRatio = intdfRatio;
383 
384  #if DEBUG == 1
385  printf("\nadding RD grid\n");
386  printf("Mfmax = %e\n", Mfmax);
387  printf("fSTART = %.6f\n", fSTART);
388  printf("fEND = %.6f\n", coarseGrid.xMax);
389  printf("mydf = %.16e\n", mydf);
390  printf("RDIndex = %i\n", RDindex);
391  printf("intdfRatio = %i\n", intdfRatio);
392  printf("# fine points float %.16f\n", allGrids[RDindex].deltax/evaldMf);
393  #endif
394  }
395  }
396 
397  INT4 nGridsUsed = preComputeFirstGrid + nDerefineInspiralGrids + nMergerGrid+nRingdownGrid;
398  #if DEBUG == 1
399  printf("final grid length = %d\n", nGridsUsed);
400  printf("intdfRatio = %d\n", intdfRatio);
401  #endif
402 
403  return nGridsUsed;
404 }
405 
406 
408 {
409  REAL8 phase_coeff = 0, amp_coeff = 0;
410  if (pWFHM->MixingOn == 0){
411  phase_coeff = pPhase->alphaL;
412  }
413  else{
414  if (pWFHM->IMRPhenomXHMRingdownPhaseVersion == 122019){
415  phase_coeff = pPhase->alphaL_S;
416  }
417  else if(pWFHM->IMRPhenomXHMRingdownPhaseVersion == 122022) {
418  phase_coeff = pPhase->RDCoefficient[4];
419  }
420  }
421  amp_coeff = pAmp->RDCoefficient[1]/(pAmp->RDCoefficient[2]*pWFHM->fDAMP);
422  *dfmerger = deltaF_mergerBin(pWFHM->fDAMP, phase_coeff, resTest);
423  *dfringdown = deltaF_ringdownBin(pWFHM->fDAMP, phase_coeff, amp_coeff, resTest);
424 
425  XLAL_CHECK(*dfmerger > 0, XLAL_EFAULT, "dfmerger = %.6e. It must be > 0", *dfmerger);
426  XLAL_CHECK(*dfringdown > 0, XLAL_EFAULT, "dfringdown = %.6e. It must be > 0", *dfringdown);
427 
428  return XLAL_SUCCESS;
429 }
430 
431 /**
432  * @addtogroup LALSimIMRPhenomX_c
433  * @{
434  * @name Routines for IMRPhenomXHM Multibanding
435  * @{
436  *
437  */
438 
439 /*****************************************************/
440 /* */
441 /* MULTIBANDING WAVEFORMS */
442 /* */
443 /*****************************************************/
444 
445 /** Return htildelm, the waveform of one mode without mode-mixing.
446  e^(I phi) is interpolated with linear order and an iterative procedure.
447  Amplitude uses standard 1st (by default) or 3rd order interpolation with gsl. */
449  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
450  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
451  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
452  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
453  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
454  UINT4 ell, /**< l index of the mode */
455  INT4 emmIn, /**< m index of the mode */
456  REAL8 distance, /**< Luminosity distance (m) */
457  REAL8 f_min, /**< Starting GW frequency (Hz) */
458  REAL8 f_max, /**< End frequency; 0 defaults to Mf = \ref f_CUT */
459  REAL8 deltaF, /**< Sampling frequency (Hz) */
460  REAL8 phiRef, /**< Orbital phase at fRef (rad) */
461  REAL8 fRef_In, /**< Reference frequency (Hz) */
462  LALDict *lalParams /**< Extra params */
463 ){
464  UINT4 emm = abs(emmIn);
465  #if DEBUG == 1
466  printf("\nMode %i %i \n",ell,emm);
467  printf("fRef_In : %e\n",fRef_In);
468  printf("m1_SI : %e\n",m1_SI);
469  printf("m2_SI : %e\n",m2_SI);
470  printf("chi1L : %e\n",chi1L);
471  printf("chi2L : %e\n\n",chi2L);
472  printf("Performing sanity checks...\n");
473  #endif
474 
475  /* Sanity checks */
476  if(*htildelm) { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT); }
477  if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
478  if(deltaF <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n"); }
479  if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
480  if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
481  if(f_min <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n"); }
482  if(f_max < 0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n"); }
483  if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
484  /*
485  Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
486  - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
487  - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
488  - For mass ratios > 1000: throw a hard error that model is not valid.
489  - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
490 
491  */
492  REAL8 mass_ratio;
493  if(m1_SI > m2_SI)
494  {
495  mass_ratio = m1_SI / m2_SI;
496  }
497  else
498  {
499  mass_ratio = m2_SI / m1_SI;
500  }
501  if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
502  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
503  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
504 
505 
506  #if DEBUG == 1
507  printf("\n**********************************************************************\n");
508  printf("\n* IMRPhenomXHMMultiBandOneMode %i%i *\n", ell, emm);
509  printf("\n**********************************************************************\n");
510  printf("\nm1, m2, chi1, chi2 %.16f %.16f %.16f %.16f\n", m1_SI/LAL_MSUN_SI, m2_SI/LAL_MSUN_SI, chi1L, chi2L);
511  #endif
512 
513 
514  /* When mode does not vanishes */
515  int debug = DEBUG;
516 
517  // Define two powers of pi to avoid clashes between PhenomX and PhenomXHM files.
519  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
521  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PIHM.");
522 
523  /* Initialize IMRPhenomX Waveform struct and check that it initialized correctly */
525  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
526  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef_In, phiRef, f_min, f_max, distance, 0.0, lalParams, debug);
527  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
528 
529 
530  status = IMRPhenomXHMMultiBandOneMode(htildelm, pWF, ell, emm, lalParams);
531  XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHMMultiBandOneMode failed to generate IMRPhenomXHM waveform.");
532 
533  INT4 offset = (size_t) (pWF->fMin / deltaF);
534 
535  if(emmIn>0){
536  /* (-1)^l */
537  INT4 minus1l = 1;
538  if (ell % 2 !=0){
539  minus1l = -1;
540  }
541  #if DEBUG == 1
542  printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
543  #endif
544  for(UINT4 idx=offset; idx<(*htildelm)->data->length; idx++){
545  (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
546  }
547  }
548 
549  REAL8 lastfreq;
550  /* Resize htildelm if needed */
551  if (pWF->f_max_prime < pWF->fMax)
552  { /* The user has requested a higher f_max than Mf = fCut.
553  Resize the frequency series to fill with zeros beyond the cutoff frequency. */
554  lastfreq = pWF->fMax;
555  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);
556  }
557  else{ // We have to look for a power of 2 anyway. Without MBAND this step is already satisfied
558  lastfreq = pWF->f_max_prime;
559  }
560  // We want to have the length be a power of 2 + 1
561  size_t n_full = NextPow2(lastfreq / deltaF) + 1;
562  size_t n = (*htildelm)->data->length;
563 
564  /* Resize the COMPLEX16 frequency series */
565  *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
566  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->fCut, n_full, pWF->fMax );
567  XLALUnitMultiply(&((*htildelm)->sampleUnits), &((*htildelm)->sampleUnits), &lalSecondUnit);
568 
569  LALFree(pWF);
570 
571  return status;
572 
573 }
574 /** @}
575  @} **/
576 
577 
579  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform **/
580  IMRPhenomXWaveformStruct *pWF, /**< Waveform structure 22 mode **/
581  UINT4 ell, /**< First index (l,m) mode **/
582  UINT4 emm, /**< Second incex (l,m) mode **/
583  LALDict *lalParams /**< LAL dictionary **/
584 )
585 {
586  /* Set LIGOTimeGPS */
587  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
588 
589  REAL8 deltaF = pWF->deltaF;
590  pWF->deltaF = 0; // Needed for SetupWFArraysReal function, if not introduces an extra offset in amplitude and phase.
591 
592  /* Check that the frequency array will be consistent: fmin < fmax_prime */
593  /* Return the closest power of 2 */
594  size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
595  /* Frequencies will be set using only the lower and upper bounds that we passed */
596  size_t iStart = (size_t) (pWF->fMin / deltaF);
597  size_t iStop = (size_t) (pWF->f_max_prime / deltaF) + 1;
598  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
599  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
600 
601  #if DEBUG == 1
602  printf("\n***********************\n");
603  printf("pWF->fMin, deltaF, iStart = %.16e %.16e %zu", pWF->fMin, deltaF, iStart);
604  printf("\n***********************\n");
605  #endif
606 
607 
608  size_t offset = iStart;
609 
610 
611  /* If it is odd mode with equal black holes then return array of zeros 0 */
612  if(pWF->q == 1 && pWF->chi1L == pWF->chi2L && emm%2!=0){ // Mode zero
613  *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, iStop);
614  for(unsigned int idx = 0; idx < iStop; idx++){
615  ((*htildelm)->data->data)[idx] = 0.;
616  }
617 
618  return XLAL_SUCCESS;
619  }
620 
621  /** Mode non-zero **/
622 
623 
624  /* Final grid spacing, adimensional (NR) units */
625  REAL8 evaldMf = XLALSimIMRPhenomXUtilsHztoMf(deltaF, pWF->Mtot);
626 
627  /* Threshold for the Multibanding. It is a measure of how restrictive it is. Smaller value implies stronger restriction, more points where evaluate the model. */
629  XLAL_CHECK(resTest > 0, XLAL_EDOM, "Multibanding threshold must be > 0.");
631  #if DEBUG == 1
632  printf("\n***** MBAND = %i, resTest = %.16f, ampIntorder = %i\n", MBAND, resTest, ampinterpolorder);
633  #endif
634  /* Variable for the Multibanding criteria */
635  REAL8 dfpower = 11./6.;
636  REAL8 dfcoefficient = 8. * sqrt(3./5.) * LAL_PI * powers_of_lalpi.m_one_sixth * sqrt(2.)*cbrt(2) /(cbrt(emm)*emm) * sqrt(resTest * pWF->eta);
637  /* Variables for the coarse frequency grid */
638  REAL8 Mfmin = XLALSimIMRPhenomXUtilsHztoMf(iStart*deltaF, pWF->Mtot);
640  REAL8 MfMECO, MfLorentzianEnd;
641  REAL8 dfmerger = 0., dfringdown = 0.;//, relerror = 0.001;
642 
643 
645  //Initialize pWFHM, pAmp(22), pPhase(22) and pass to the functions. No l, m needed
646  //populate coefficients of 22 mode, to rotate to spherical
649  IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
650 
651 
652  /* Setup for NRTidal testing */
653  NRTidal_version_type NRTidal_version;
654  /* Set tidal version */
655  NRTidal_version=IMRPhenomX_SetTidalVersion(lalParams);
656  /* initialise tidal corrections to phasing*/
657  if(NRTidal_version!=NoNRT_V){ IMRPhenomXGetTidalPhaseCoefficients(pWF,pPhase22,NRTidal_version);
658  }
659 
660  /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
663 
664  if(ell == 2 && emm ==2){
665  MfMECO = pWF->fMECO;
666  #if DEBUG == 1
667  printf("\nfRING = %e\n",pWF->fRING);
668  printf("fDAMP = %e\n",pWF->fDAMP);
669  printf("alphaL22 = %.16e", pPhase22->cLovfda/pWF->eta);
670  #endif
671  MfLorentzianEnd = pWF->fRING + 2*pWF->fDAMP;
673  dfmerger = deltaF_mergerBin(pWF->fDAMP, pPhase22->cLovfda/pWF->eta, resTest);
674  dfringdown = deltaF_ringdownBin(pWF->fDAMP, pPhase22->cLovfda/pWF->eta, pAmp22->gamma2/(pAmp22->gamma3*pWF->fDAMP),resTest);
675  }
676  else{
677  // allocate qnm struct
678  QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
680  // Populate pWFHM
681  IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF,qnms,lalParams);
682  LALFree(qnms);
683 
684  /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
687 
688  /* Get coefficients for Amplitude and phase */
689  IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
690  IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
691 
692  MfMECO = pWFHM->fMECOlm;
693  MfLorentzianEnd = pWFHM->fRING + 2*pWFHM->fDAMP;
694  #if DEBUG == 1
695  printf("\nfRING = %e\n",pWFHM->fRING);
696  printf("fDAMP = %e\n",pWFHM->fDAMP);
697  printf("alphaL = %.16e", pPhase->alphaL);
698  #endif
699  deltaF_MergerRingdown(&dfmerger, &dfringdown, resTest, pWFHM, pAmp, pPhase);
700  }
701 
702  /* Allocate memory for the list of grids. The number of grids must be less than lengthallGrids. */
703  UINT4 lengthallGrids = 20;
705 
706  if (allGrids == NULL)
707  {
708  #if DEBUG == 1
709  printf("Malloc of allGrids failed!\n");
710  #endif
711  return -1;
712  }
713 
714  #if DEBUG == 1
715  printf("\nMfmin = %.6f\n", Mfmin);
716  printf("MfMECO = %.6f\n", MfMECO);
717  printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
718  printf("Mfmax = %.6f\n", Mfmax);
719  printf("evaldMf = %.6e\n", evaldMf);
720  printf("dfpower = %.6e\n", dfpower);
721  printf("dfcoefficient = %.6e\n", dfcoefficient);
722  printf("dfmerger = %.6e\n", dfmerger);
723  printf("dfringdown = %.6e\n", dfringdown);
724  #endif
725 
726  /* Compute the coarse frequency array. It is stored in a list of grids. */
727  UINT4 nGridsUsed = XLALSimIMRPhenomXMultibandingGrid(Mfmin, MfMECO, MfLorentzianEnd, Mfmax, evaldMf, dfpower, dfcoefficient, allGrids, dfmerger, dfringdown);
728 
729  #if DEBUG == 1
730  printf("allGrids[1].Length = %i\n", allGrids[0].Length);
731  #endif
732 
733  /* Number of fine frequencies per coarse interval in every coarse grid */
734  INT4 mydfRatio[lengthallGrids];
735  /* Actual number of subgrids to be used. We allocated more than needed. */
736  UINT4 actualnumberofGrids = 0;
737  /* Length of coarse frequency array */
738  UINT4 lenCoarseArray = 0;
739 
740  /* Transform the coarse frequency array to 1D array. */
741  // Take only the subgrids needed
742  for(UINT4 kk = 0; kk < nGridsUsed; kk++){
743  lenCoarseArray = lenCoarseArray + allGrids[kk].Length;
744  actualnumberofGrids++;
745 
746  mydfRatio[kk] = allGrids[kk].intdfRatio;
747 
748  #if DEBUG == 1
749  printf("\nkk = %i\n",kk);
750  printf("xStart: %.6e\n", allGrids[kk].xStart);
751  printf("xEnd: %.6e\n", allGrids[kk].xEndRequested);
752  printf("Length: %i\n", allGrids[kk].Length);
753  printf("deltax, Hz: %.6e %.6e\n", allGrids[kk].deltax, XLALSimIMRPhenomXUtilsMftoHz(allGrids[kk].deltax, pWF->Mtot));
754  printf("evaldMf, Hz: %.6e %.6e\n", evaldMf, XLALSimIMRPhenomXUtilsMftoHz(evaldMf, pWF->Mtot));
755  printf("xMax: %.16e\n", allGrids[kk].xMax);
756  printf("Mfmax: %.16e\n", Mfmax);
757  printf("# fine points %i\n", mydfRatio[kk]);
758  printf("# fine points float %.16f\n", allGrids[kk].deltax/evaldMf);
759  #endif
760 
761  if(allGrids[kk].xMax + evaldMf >= Mfmax){
762  break;
763  }
764  }
765 
766  // Add extra points to the coarse grid if the last freq is lower than Mfmax
767  while(allGrids[actualnumberofGrids-1].xMax < Mfmax){
768  allGrids[actualnumberofGrids-1].xMax = allGrids[actualnumberofGrids-1].xMax + allGrids[actualnumberofGrids-1].deltax;
769  allGrids[actualnumberofGrids-1].Length = allGrids[actualnumberofGrids-1].Length + 1;
770  lenCoarseArray++;
771  }
772 
773  #if DEBUG == 1
774  if(ell==2 && emm==2){
775  printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWF->fDAMP, pWF->Mtot));
776  }else{
777  printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWFHM->fDAMP, pWF->Mtot));
778  }
779  printf("actualnumberofGrids = %i\n", actualnumberofGrids);
780  printf("lenCoarseArray = %i\n", lenCoarseArray);
781  printf("Last grid.xMax = %.16f", allGrids[actualnumberofGrids-1].xMax);
782  #endif
783 
784  // Transform coarse frequency array to 1D vector
785  REAL8 *IntLawpoints = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
786  UINT4 lenIntLawpoints = 0;
787 
788  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
789  for(INT4 ll = 0; ll < allGrids[kk].Length; ll++){
790  IntLawpoints[lenIntLawpoints] = (allGrids[kk].xStart + allGrids[kk].deltax*ll);
791  lenIntLawpoints++;
792  }
793  }
794  /* End of coarse frequency array. */
795 
796  #if DEBUG == 1
797  printf("\n******** Coarse frequencies array done ********* \n");
798  printf("\nlenIntLawpoints, coarse[0], coarse[-1], Mfmax, M_sec = %i %.16e %.16e %.16e %.16e\n",lenIntLawpoints, IntLawpoints[0], IntLawpoints[lenIntLawpoints-1], Mfmax, pWF->M_sec);
799  #endif
800 
801  /* IntLawpoints stores the adimensional frequencies (Mf) */
802  /* coarseFreqs will store the same frequency array but in Hz */
803  /* Allocate memory for frequency array and terminate if this fails */
804  REAL8Sequence *coarseFreqs;
805  coarseFreqs = XLALCreateREAL8Sequence(lenCoarseArray);
806  if (!coarseFreqs) {XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); }
807 
808  /* Populate frequency array */
809  #if DEBUG == 1
810  printf("\n***** Coarse freqs *****\n");
811  #endif
812  REAL8 divis = 1./pWF->M_sec;
813  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
814  {
815  coarseFreqs->data[ii] = IntLawpoints[ii]*divis;
816  }
817  #if DEBUG == 1
818  printf("\nFirst/Last Coarse freqs *****%.16e %.16e\n", coarseFreqs->data[0], coarseFreqs->data[coarseFreqs->length-1]);
819  #endif
820 
821  /* Next we will compute amplitude and phase of one mode in the coarse frequency array. */
822 
823  REAL8FrequencySeries *amplitude, *phase;
824 
825  /** Compute 22 using PhenomX functions **/
826  // This is copied from IMRPhenomXASGenerateFD.
827  if(ell == 2 && emm ==2){
828  #if DEBUG == 1
829  printf("\n** Computing Amplitude and Phase of PhenomX %i **********\n", lenCoarseArray);
830  #endif
831 
832  amplitude = XLALCreateREAL8FrequencySeries("amplitude22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,coarseFreqs->length);
833  phase = XLALCreateREAL8FrequencySeries("phase22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,coarseFreqs->length);
834 
836 
837  /* Initialize a struct containing useful powers of Mf at fRef */
838  IMRPhenomX_UsefulPowers powers_of_MfRef;
839  int status = IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
840  XLAL_CHECK(XLAL_SUCCESS == status, status, "IMRPhenomX_Initialize_Powers failed for MfRef.\n");
841 
842 
843  /* Linear time and phase shifts so that model peaks near t ~ 0 */
844  REAL8 lina = 0;
846  double linb=IMRPhenomX_TimeShift_22(pPhase22, pWF);
847 
848  REAL8Sequence *phi_tidal = NULL;
849  REAL8Sequence *amp_tidal = NULL;
850  REAL8Sequence *planck_taper = NULL;
851 
852  /* Set matter parameters (set to zero in pWF if NRTidal additions are not turned on) */
853  REAL8 lambda1 = pWF->lambda1;
854  REAL8 lambda2 = pWF->lambda2;
855 
856  REAL8 f_final=Mfmax/pWF->M_sec;
857 
858  REAL8 f_merger = XLALSimNRTunedTidesMergerFrequency(pWF->Mtot, pWF->kappa2T, pWF->q);
859  if(f_merger<f_final)
860  f_final = f_merger;
861  double phiTfRef = 0.;
862 
863  // correct for time and phase shifts due to tidal phase
864  if(NRTidal_version!=NoNRT_V){
865 
866  IMRPhenomX_UsefulPowers powers_of_ffinal;
867  REAL8 Mf_final = f_final*pWF->M_sec;
868  status = IMRPhenomX_Initialize_Powers(&powers_of_ffinal,Mf_final);
869  XLAL_CHECK(XLAL_SUCCESS == status, status, "IMRPhenomX_Initialize_Powers failed for f_final.\n");
870  REAL8 dphi_fmerger=1/pWF->eta*IMRPhenomX_dPhase_22(Mf_final, &powers_of_ffinal, pPhase22, pWF)+linb-IMRPhenomX_TidalPhaseDerivative(&powers_of_ffinal, pWF, pPhase22, NRTidal_version);
871  REAL8 tshift = -dphi_fmerger;
872  linb+=tshift;
873  phiTfRef = -IMRPhenomX_TidalPhase(&powers_of_MfRef, pWF, pPhase22, NRTidal_version);
874 
875  }
876 
877 
878  // Calculate IMRPhenomX phase at reference frequency
879  REAL8 phiref22 = -1./pWF->eta*IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF)- phiTfRef - linb*pWF->MfRef - lina + 2.0*pWF->phi0 + LAL_PI_4;
880 
881  if (NRTidal_version!=NoNRT_V) {
882  int ret = 0;
883  UINT4 L_fCut = coarseFreqs->length;
884  phi_tidal = XLALCreateREAL8Sequence(L_fCut);
885  amp_tidal = XLALCreateREAL8Sequence(L_fCut);
886  planck_taper = XLALCreateREAL8Sequence(L_fCut);
887  /* Get FD tidal phase correction and amplitude factor */
888  ret = XLALSimNRTunedTidesFDTidalPhaseFrequencySeries(phi_tidal, amp_tidal, planck_taper, coarseFreqs, pWF->m1_SI, pWF->m2_SI, lambda1, lambda2, NRTidal_version);
889  XLAL_CHECK(XLAL_SUCCESS == ret, ret, "XLALSimNRTunedTidesFDTidalPhaseFrequencySeries Failed.");
890  }
891  if (NRTidal_version==NoNRT_V) {
892 
893  for(UINT4 kk = 0; kk < (coarseFreqs)->length; kk++)
894  {
895 
896  REAL8 Mff = coarseFreqs->data[kk]*pWF->M_sec;
897  IMRPhenomX_UsefulPowers powers_of_f;
898  IMRPhenomX_Initialize_Powers(&powers_of_f,Mff);
899  amplitude->data->data[kk] = IMRPhenomX_Amplitude_22(Mff, &powers_of_f, pAmp22, pWF) * pWF->amp0;
900  phase->data->data[kk] = 1./pWF->eta*IMRPhenomX_Phase_22(Mff, &powers_of_f, pPhase22, pWF) + linb*Mff + lina + phiref22;
901  }
902  }
903  else{
904 
905  REAL8 pfaN = 3./(128.*pWF->m1*pWF->m2);
906 
907  for(UINT4 kk = 0; kk < (coarseFreqs)->length; kk++)
908  {
909 
910  REAL8 phaseTidal = phi_tidal->data[kk];
911  double ampTidal = amp_tidal->data[kk];
912  double window = planck_taper->data[kk];
913 
914  REAL8 Mff = coarseFreqs->data[kk]*pWF->M_sec;
915  IMRPhenomX_UsefulPowers powers_of_f;
916  IMRPhenomX_Initialize_Powers(&powers_of_f,Mff);
917  /* Add spin-induced quadrupole moment terms to tidal phasing */
918  /* 2PN terms */
919  phaseTidal += pfaN * pPhase22->c2PN_tidal* powers_of_lalpi.m_one_third * powers_of_f.m_one_third;
920  /* 3PN terms */
921  phaseTidal += pfaN * pPhase22->c3PN_tidal* powers_of_lalpi.one_third * powers_of_f.one_third;
922  /* 3.5PN terms are only in NRTidalv2 */
923  if (NRTidal_version == NRTidalv2_V) {
924  phaseTidal += pfaN * pPhase22->c3p5PN_tidal * powers_of_lalpi.two_thirds * powers_of_f.two_thirds;
925  }
926  /* Reconstruct waveform with NRTidal terms included: h(f) = [A(f) + A_tidal(f)] * Exp{I [phi(f) - phi_tidal(f)]} * window(f) */
927  REAL8 amp=IMRPhenomX_Amplitude_22(Mff, &powers_of_f, pAmp22, pWF);
928  amplitude->data->data[kk] = (amp + 2*sqrt(1./5.)*powers_of_lalpi.sqrt * ampTidal) * window * pWF->amp0;
929 
930  phase->data->data[kk] =1./pWF->eta*IMRPhenomX_Phase_22(Mff, &powers_of_f, pPhase22, pWF) + linb*Mff + lina + phiref22 - phaseTidal;
931 
932  }
933  //end of loop
934 
935  }
936 
937 
938  XLALDestroyREAL8Sequence(phi_tidal);
939  XLALDestroyREAL8Sequence(amp_tidal);
940  XLALDestroyREAL8Sequence(planck_taper);
941 
942 
943  }
944  /** Higher modes **/
945  else{
946 
947  #if DEBUG == 1
948  printf("\n******* Computing Coarse Amplitude And Phase ****************\n");
949  #endif
950  /* Compute coarse amplitude and phase */
951  IMRPhenomXHM_Amplitude(&amplitude, coarseFreqs, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
952  IMRPhenomXHM_Phase(&phase, coarseFreqs, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
953  }
954 
955  #if DEBUG == 1
956  printf("\n******* Computed Coarse Amp and Phase **************** %i\n", coarseFreqs->length);
957  #endif
958 
959  /* Transform the REAL8FrequencySeries to vector since gsl uses vectors for the interpolation.
960  gsl is only used for the amplitude but to keep the code more symmetric we transform also the phase. */
961  REAL8 *ILamplm = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
962  REAL8 *ILphaselm = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
963 
964  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
965  {
966  ILamplm[ii] = ((amplitude)->data->data)[ii];
967  ILphaselm[ii] = ((phase)->data->data)[ii];
968  }
969 
970  #if DEBUG == 1
971  //Save coarse amplitude and phase in file
972  FILE *file0;
973  char fileSpec0[40];
974  sprintf(fileSpec0, "coarseamplitude%i%i.dat", ell,emm);
975  printf("\nOutput file: %s\r\n",fileSpec0);
976  file0 = fopen(fileSpec0,"w");
977  fprintf(file0,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
978  FILE *file3;
979  char fileSpec3[40];
980  sprintf(fileSpec3, "coarsephase%i%i.dat", ell,emm);
981  printf("\nOutput file: %s\r\n",fileSpec3);
982  file3 = fopen(fileSpec3,"w");
983  fprintf(file3,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
984  for(UINT4 idx = 0; idx < lenCoarseArray; idx++)
985  {
986  fprintf(file0, "%.16f %.16e \n", coarseFreqs->data[idx], ILamplm[idx]);
987  fprintf(file3, "%.16f %.16e \n", coarseFreqs->data[idx], ILphaselm[idx]);
988  }
989  fclose(file0);
990  fclose(file3);
991  #endif
992 
993  /* Free allocated memory */
996  XLALDestroyREAL8Sequence(coarseFreqs);
997 
998  /***** Linear Interpolation of e^(I*phi) with the iterative procedure *****/
999 
1000  /* Estimation of the length of the fineGrid */
1001  INT4 lenWF = 0;
1002 
1003  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
1004  lenWF = lenWF + (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk];
1005  #if DEBUG == 1
1006  printf("\nmydfRatio[%i] = %i %i %i", kk, mydfRatio[kk],allGrids[kk].Length, (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk]);
1007  printf("\nlenWF = %i\n\n", lenWF);
1008  #endif
1009  }
1010 
1011  // Variable to control the number of coarse points we have used
1012  int pointsPrecessedSoFar = 0;
1013 
1014  /* Allocate memory for the complex exponential and the fine equally-spaced frequency array */
1015  COMPLEX16 *expphi = (COMPLEX16*)XLALMalloc(lenWF*sizeof(COMPLEX16));
1016  if (expphi == NULL){
1017  return -1;
1018  }
1019 
1020  REAL8 *finefreqs = (REAL8*)XLALMalloc(lenWF*sizeof(REAL8));
1021  if (finefreqs == NULL){
1022  return -1;
1023  }
1024 
1025  UINT4 count = 0; // Variable to track the point being filled in the fine frequency grid
1026 
1027  /* Loop over allgrids */
1028  bool stop = false;
1029  for (UINT4 i = 0; i<actualnumberofGrids && !stop; i++){
1030  #if DEBUG == 1
1031  printf("\ni = %i\n", i);
1032  #endif
1033 
1034  UINT4 lcoarseGrid = allGrids[i].Length;
1035  if(lcoarseGrid == 0){
1036  break;
1037  }
1038 
1039  /* Linear Interpolation and iteration, here I get fineGridResult */
1040  if(i==actualnumberofGrids-1){
1041  lcoarseGrid--;
1042  }
1043 
1044  REAL8 Omega, phi0, Mfhere = 0, Mfnext = 0;
1045  COMPLEX16 h0, Q;
1046 
1047  /* Loop over the coarse points of a subgrid */
1048  for(UINT4 j = 0; j < lcoarseGrid && !stop ; j++){
1049  Mfhere = IntLawpoints[pointsPrecessedSoFar + j];
1050  Mfnext = IntLawpoints[pointsPrecessedSoFar + j + 1];
1051 
1052  INT4 ratio;
1053  // If we are in the last coarse point of a sublist we use the number of fine points of the next subgrid.
1054  if(j==lcoarseGrid-1 && i < actualnumberofGrids-1){
1055  ratio = mydfRatio[i+1];
1056  }
1057  else{
1058  ratio = mydfRatio[i];
1059  }
1060  if(Mfnext + evaldMf >= Mfmax){
1061  double dratio = (Mfmax - Mfhere)/evaldMf + 1;
1062  ratio = (int) dratio;
1063  int roundratio = round((Mfmax - Mfhere)/evaldMf) + 1;
1064  if(fabs(dratio-roundratio) < 0.0001) ratio = roundratio; //To get the correct rounded integer
1065  /* Break the loop if you overpass the maximun frequency */
1066  stop = true;
1067  #if DEBUG == 1
1068  printf("\nMfmax, Mfhere, evaldMf, ratio, lastfreqHz= %.16f %.16f %.16f %i %.16e\n", Mfmax, Mfhere, evaldMf, ratio, XLALSimIMRPhenomXUtilsMftoHz(Mfhere+(ratio-1)*evaldMf,pWF->Mtot) );
1069  #endif
1070  }
1071 
1072  /********************************************/
1073  /* Inner Loop: linear interpolation */
1074  /********************************************/
1075  UINT4 jjdx = j + pointsPrecessedSoFar;
1076  if(jjdx < lenCoarseArray){
1077  Omega = (ILphaselm[jjdx+ 1] - ILphaselm[jjdx])/(IntLawpoints[jjdx + 1] - IntLawpoints[jjdx]);
1078  }
1079  else{
1080  Omega = (ILphaselm[jjdx] - ILphaselm[jjdx -1])/(IntLawpoints[jjdx] - IntLawpoints[jjdx -1]);
1081  }
1082  phi0 = ILphaselm[jjdx];
1083 
1084  h0 = cexp(I*phi0);
1085  Q = cexp(I*evaldMf*Omega);
1086 
1087  finefreqs[count] = Mfhere;
1088  expphi[count] = h0;
1089  count++;
1090 
1091  /* This loop carry out the eq. 2.32 in arXiv:2001.10897 */
1092  for(int kk = 1; kk < ratio; kk++){ // Compute finefreqs and fine expphi
1093  finefreqs[count] = Mfhere + evaldMf*kk;
1094  expphi[count] = Q*expphi[count-1];
1095  count++;
1096  }
1097 
1098  }
1099  pointsPrecessedSoFar = pointsPrecessedSoFar + lcoarseGrid;
1100  }// End loop over ILgrids. count should be aprox = to lenWF
1101 
1102  #if DEBUG == 1
1103  printf("\ncount = %i\n", count);
1104  #endif
1105 
1106  #if DEBUG == 1
1107  printf("\n******* Interpolate Amplitude **********\n");
1108  #endif
1109 
1110  /*** Interpolation and evaluation in fineFreqs of the amplitude ***/
1111  REAL8 *fineAmp = (REAL8*)XLALMalloc(count * sizeof(REAL8));
1112  interpolateAmplitude(fineAmp, IntLawpoints, ILamplm, finefreqs, lenCoarseArray, count, ampinterpolorder);
1113 
1114  /**** Build the waveform ****/
1115  // Due to round of erros, the last freq may be greater Mfmax. The difference should be less than the frequency step.
1116  // Remove that extra frequency point
1117  while(finefreqs[count-1] > Mfmax){
1118  count--;
1119  }
1120  #if DEBUG == 1
1121  printf("\n******* Building Waveform 2**********\n");
1122  printf("\nfinefreqs[0]Hz = %.16f\n", finefreqs[0]/pWF->M_sec);
1123  printf("\nfinefreqs[%i]Hz = %.16f\n", count-1, finefreqs[count-1]/pWF->M_sec);
1124  printf("Mfmax in Hz = %.16f\n", Mfmax/pWF->M_sec);
1125  printf("count, offset = %i %zu\n", count-1, offset);
1126  printf("Mfmaxtheory = %.16f\n", (count-1+offset)*deltaF);
1127  #endif
1128 
1129  /* Intialize FrequencySeries for htildelm */
1130  while(count+offset > iStop){ count--; }
1131  size_t n = iStop;
1132  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);
1133  *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
1134 
1135  for(int idx = 0; idx < (int) offset; idx++){
1136  ((*htildelm)->data->data)[idx] = 0.;
1137  }
1138 
1139  /* (-1)^l */
1140  INT4 minus1l;
1141  if (ell % 2 !=0){
1142  minus1l = -1;
1143  }
1144  else{
1145  minus1l = +1;
1146  }
1147 
1148  for(UINT4 idx = 0; idx < count; idx++){
1149  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
1150  ((*htildelm)->data->data)[idx + offset] = minus1l * fineAmp[idx] * expphi[idx];
1151  }
1152 
1153  /* Sometimes rounding error can make that count+offset < iStop, meaning that we have computed less points than those we are gonna output,
1154  here we make sure that all the elements of htildelm are initialized and we put the extra point(s) to 0. */
1155  for(UINT4 idx = count-1; idx < iStop-offset; idx++){
1156  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
1157  ((*htildelm)->data->data)[idx + offset] = 0.;
1158  }
1159 
1160  /* Free allocated memory */
1161  LALFree(pAmp);
1162  LALFree(pAmp22);
1163  LALFree(pPhase);
1164  LALFree(pPhase22);
1165 
1166 
1167  #if DEBUG == 1
1168  //Save hlm in file
1169  FILE *file;
1170  char fileSpec[40];
1171  sprintf(fileSpec, "simulation%i%i_Multiband.dat", ell,emm);
1172  printf("\nOutput file: %s\r\n",fileSpec);
1173  file = fopen(fileSpec,"w");
1174  fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
1175  fprintf(file,"# Frequency (Hz) Real Imaginary\n");
1176  COMPLEX16 data;
1177  for(UINT4 idx = 0; idx < count; idx++)
1178  {
1179  data = expphi[idx];
1180  fprintf(file, "%.16f %.16e %.16e\n", (idx+offset)*deltaF, creal(data), cimag(data));
1181  }
1182  fclose(file);
1183  #endif
1184 
1185  #if DEBUG == 1
1186  //Save fine amplitude and freq array in file
1187  FILE *file2;
1188  char fileSpec2[40];
1189  sprintf(fileSpec2, "amplitude%i%i_fine.dat", ell,emm);
1190  printf("\nOutput file: %s\r\n",fileSpec2);
1191  file2 = fopen(fileSpec2,"w");
1192  fprintf(file2,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
1193  printf("\ncount, count + offset, len htildelm = %i %i %i\n", count, (int)(count + offset), (*htildelm)->data->length);
1194  for(UINT4 idx = 0; idx < count; idx++)
1195  {
1196  fprintf(file2, "%.16f %.16f %.16e\n", finefreqs[idx], (idx+offset)*evaldMf, fineAmp[idx]);
1197  }
1198  fclose(file2);
1199  #endif
1200 
1201  /* Free allocated memory */
1202  LALFree(expphi);
1203  LALFree(finefreqs);
1204  LALFree(allGrids);
1205  LALFree(fineAmp);
1206  LALFree(pWFHM);
1207  LALFree(ILamplm);
1208  LALFree(ILphaselm);
1209  LALFree(IntLawpoints);
1210 
1211  return XLAL_SUCCESS;
1212 }
1213 
1214 
1215 /** @addtogroup LALSimIMRPhenomX_c
1216 * @{
1217 * @name Routines for IMRPhenomXHM Multibanding
1218 * @{
1219 * @author Cecilio García Quirós, Sascha Husa
1220 *
1221 * @brief C code for applying Multibanding to IMRPhenomXHM_Multimode
1222 *
1223 * This is a technique to make the evaluation of waveform models faster by evaluating the model
1224 * in a coarser non-uniform grid and interpolate this to the final fine uniform grid.
1225 * We apply this technique to the fourier domain model IMRPhenomXHM as described in this paper: https://arxiv.org/abs/2001.10897
1226 *
1227 * Multibanding flags:
1228 * ThresholdMband: Determines the strength of the Multibanding algorithm.
1229 * The lower this value is, the slower is the evaluation but more accurate is the final waveform compared to the one without multibanding.
1230 * - 0.001: DEFAULT value
1231 * - 0: switch off the multibanding
1232 *
1233 * AmpInterpol: Determines the gsl interpolation order for the amplitude.
1234 * - 1: linear interpolation (DEFAULT)
1235 * - 3: cubic interpolation
1236 *
1237 */
1238 
1239 /** Returns htildelm the waveform of one mode that present mode-mixing.
1240 The multibanding is applied to the spherical part (inspiral and intermediate) and to the spheroidal part (ringdown).
1241 Both are interpolated and evaluated in the fine frequency grid and the ringdown part is rotated back to spherical */
1243  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
1244  COMPLEX16FrequencySeries *htilde22, /**< Precomputed FD waveform of dominant mode */
1245  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
1246  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
1247  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
1248  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
1249  UINT4 ell, /**< l index of the mode */
1250  INT4 emmIn, /**< m index of the mode */
1251  REAL8 distance, /**< Luminosity distance (m) */
1252  REAL8 f_min, /**< Starting GW frequency (Hz) */
1253  REAL8 f_max, /**< End frequency; 0 defaults to Mf = \ref f_CUT */
1254  REAL8 deltaF, /**< Sampling frequency (Hz) */
1255  REAL8 phiRef, /**< Orbital phase at fRef (rad) */
1256  REAL8 fRef_In, /**< Reference frequency (Hz) */
1257  LALDict *lalParams /**< Extra params */
1258 ){
1259  UINT4 emm = abs(emmIn);
1260  #if DEBUG == 1
1261  printf("\nMode %i %i \n",ell,emm);
1262  printf("fRef_In : %e\n",fRef_In);
1263  printf("m1_SI : %e\n",m1_SI);
1264  printf("m2_SI : %e\n",m2_SI);
1265  printf("chi1L : %e\n",chi1L);
1266  printf("chi2L : %e\n\n",chi2L);
1267  printf("Performing sanity checks...\n");
1268  #endif
1269 
1270  /* Sanity checks */
1271  if(*htildelm) { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT); }
1272  if(fRef_In < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
1273  if(deltaF <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n"); }
1274  if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
1275  if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
1276  if(f_min <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n"); }
1277  if(f_max < 0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n"); }
1278  if(distance < 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
1279  /*
1280  Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
1281  - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
1282  - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
1283  - For mass ratios > 1000: throw a hard error that model is not valid.
1284  - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
1285 
1286  */
1287  REAL8 mass_ratio;
1288  if(m1_SI > m2_SI)
1289  {
1290  mass_ratio = m1_SI / m2_SI;
1291  }
1292  else
1293  {
1294  mass_ratio = m2_SI / m1_SI;
1295  }
1296  if(mass_ratio > 20.0 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
1297  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
1298  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
1299 
1300  #if DEBUG == 1
1301  printf("\n**********************************************************************\n");
1302  printf("\n* IMRPhenomXHMMultiBandOneModeMixing %i%i *\n", ell, emm);
1303  printf("\n**********************************************************************\n");
1304  printf("\nm1, m2, chi1, chi2, f_min, f_max, deltaF %.16f %.16f %.16f %.16f %.16f %.16f %.16f\n", m1_SI/LAL_MSUN_SI, m2_SI/LAL_MSUN_SI, chi1L, chi2L, f_min, f_max, deltaF);
1305  if(htilde22 == NULL){
1306  printf("*** 22 mode not computed before ***\n\n");
1307  }
1308  #endif
1309 
1310  if(htilde22 == NULL){
1311  XLALPrintWarning("The input 22 waveform is NULL and will be computed internally. This produces a very small difference in the ringdown part respect to when the multibanded 22 waveform is passed in as an argument.\n ");
1312  }
1313 
1314 
1315  int debug = DEBUG;
1316 
1317  // Define two powers of pi to avoid clashes between PhenomX and PhenomXHM files.
1319  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
1321  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PIHM.");
1322 
1323  /* Initialize IMRPhenomX Waveform struct and check that it initialized correctly */
1325  pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
1326  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef_In, phiRef, f_min, f_max, distance, 0.0, lalParams, debug);
1327  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
1328 
1329 
1330  //int offset = IMRPhenomXHMMultiBandOneModeMixing(htildelm, htilde22, pWF, ell, emm, lalParams);
1331  status = IMRPhenomXHMMultiBandOneModeMixing(htildelm, htilde22, pWF, ell, emm, lalParams);
1332  XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHMMultiBandOneModeMixing failed to generate IMRPhenomXHM waveform.");
1333 
1334  INT4 offset = (size_t) (pWF->fMin / deltaF);
1335 
1336  if(emmIn>0){
1337  /* (-1)^l */
1338  INT4 minus1l = 1;
1339  if (ell % 2 != 0){
1340  minus1l = -1;
1341  }
1342  #if DEBUG == 1
1343  printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
1344  #endif
1345  for(UINT4 idx=offset; idx<(*htildelm)->data->length; idx++){
1346  (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
1347  }
1348  }
1349 
1350  REAL8 lastfreq;
1351  /* Resize htildelm if needed */
1352  if (pWF->f_max_prime < pWF->fMax)
1353  { /* The user has requested a higher f_max than Mf = fCut.
1354  Resize the frequency series to fill with zeros beyond the cutoff frequency. */
1355  lastfreq = pWF->fMax;
1356  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);
1357  }
1358  else{ // We have to look for a power of 2 anyway. Without MBAND this step is already satisfied
1359  lastfreq = pWF->f_max_prime;
1360  }
1361  // We want to have the length be a power of 2 + 1
1362  size_t n_full = NextPow2(lastfreq / deltaF) + 1;
1363  size_t n = (*htildelm)->data->length;
1364 
1365  /* Resize the COMPLEX16 frequency series */
1366  *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
1367  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->fCut, n_full, pWF->fMax );
1368  XLALUnitMultiply(&((*htildelm)->sampleUnits), &((*htildelm)->sampleUnits), &lalSecondUnit);
1369 
1370  LALFree(pWF);
1371 
1372  return status;
1373 
1374 }
1375 
1376 /** @}
1377 * @}
1378 */
1379 
1380 
1382  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
1383  COMPLEX16FrequencySeries *htilde22, /**< Recycle the 22 mode if previously computed **/
1384  IMRPhenomXWaveformStruct *pWF, /**< Structure of 22 mode **/
1385  UINT4 ell, /**< First index (l,m) mode **/
1386  UINT4 emm, /**< Second incex (l,m) mode **/
1387  LALDict *lalParams /**< LAL dictionary **/
1388 )
1389 {
1390  /* Set LIGOTimeGPS */
1391  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
1392 
1393  REAL8 deltaF = pWF->deltaF;
1394  pWF->deltaF = 0; // Needed for SetupWFArraysReal function, if not introduces an extra offset in amplitude and phase.
1395 
1396  /* Check that the frequency array will be consistent: fmin < fmax_prime */
1397  /* Return the closest power of 2 */
1398  size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
1399  /* Frequencies will be set using only the lower and upper bounds that we passed */
1400  size_t iStart = (size_t) (pWF->fMin / deltaF);
1401  size_t iStop = (size_t) (pWF->f_max_prime / deltaF) + 1;
1402  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
1403  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
1404 
1405  // Allocate qnm struct
1406  QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
1408 
1409  // Populate pWFHM with useful parameters of each mode
1411  IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF,qnms, lalParams);
1412  LALFree(qnms);
1413 
1414  /* Final grid spacing, adimensional (NR) units */
1415  REAL8 evaldMf = XLALSimIMRPhenomXUtilsHztoMf(deltaF, pWF->Mtot);
1416 
1417  /* Threshold for the Multibanding. It is a measure of how restrictive it is. Smaller value implies stronger restriction, more points where evaluate the model. */
1419  XLAL_CHECK(resTest > 0, XLAL_EDOM, "Multibanding threshold must be > 0.");
1421  #if DEBUG == 1
1422  printf("\n***** MBAND = %i, resTest = %.16f, ampIntorder = %i\n", MBAND, resTest, ampinterpolorder);
1423  #endif
1424  /* Variable for the Multibanding criteria */
1425  REAL8 dfpower = 11./6.;
1426  REAL8 dfcoefficient = 8. * sqrt(3./5.) * LAL_PI * powers_of_lalpi.m_one_sixth * sqrt(2.)*cbrt(2) /(cbrt(emm)*emm) * sqrt(resTest * pWF->eta);
1427  /* Variables for the coarse frequency grid */
1428  REAL8 Mfmin = XLALSimIMRPhenomXUtilsHztoMf(iStart*deltaF, pWF->Mtot);
1429  REAL8 Mfmax = XLALSimIMRPhenomXUtilsHztoMf(pWF->f_max_prime, pWF->Mtot);
1430  REAL8 MfMECO = pWFHM->fMECOlm; // Separate the inspiral grid from the merger grid
1431  REAL8 MfLorentzianEnd = pWFHM->fRING + 2*pWFHM->fDAMP; // Separate the merger grid from the ringdown grid
1432  REAL8 dfmerger = 0., dfringdown = 0.;
1433 
1434  //Initialize pWFHM, pAmp(22), pPhase(22) and pass to the functions. No l, m needed
1435  //populate coefficients of 22 mode, to rotate to spherical
1438  IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
1439  //IMRPhenomX_Phase_22_ConnectionCoefficients(pWF,pPhase22);//ceci where should this go? discontinuity
1440 
1441  /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
1444 
1445  /* Initialize the PhenomXHM lm phase and amp coefficients struct */
1448 
1449  /* Get coefficients for Amplitude and phase */
1450  GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
1452 
1453  IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
1454  IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
1455 
1456  deltaF_MergerRingdown(&dfmerger, &dfringdown, resTest, pWFHM, pAmp, pPhase);
1457 
1458  #if DEBUG == 1
1459  printf("f_min = %.6f, Mfmin = %.6f\n", pWF->fMin, Mfmin);
1460  printf("f_max = %.6f, f_max_prime = %.6f, Mfmax = %.6f\n", pWF->fMax, pWF->f_max_prime, Mfmax);
1461  printf("\nfRING = %e\n",pWFHM->fRING);
1462  printf("fDAMP = %e\n",pWFHM->fDAMP);
1463  printf("\nMfmin = %.6f\n", Mfmin);
1464  printf("MfMECO = %.6f\n", MfMECO);
1465  printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
1466  printf("Mfmax = %.6f\n", Mfmax);
1467  printf("evaldMf = %.6e\n", evaldMf);
1468  printf("dfpower = %.6e\n", dfpower);
1469  printf("dfcoefficient = %.6e\n", dfcoefficient);
1470  printf("dfmerger = %.6e\n", dfmerger);
1471  printf("dfringdown = %.6e\n", dfringdown);
1472  printf("alphaL_S = %.16e\n", pPhase->alphaL_S);
1473  #endif
1474 
1475  /* Allocate memory for the list of grids. The number of grids must be less than lengthallGrids. */
1476  UINT4 lengthallGrids = 20;
1478 
1479  if (allGrids == NULL)
1480  {
1481  #if DEBUG == 1
1482  printf("Malloc of allGrids failed!\n");
1483  #endif
1484  return -1;
1485  }
1486 
1487  /* Compute the coarse frequency array. It is stored in a list of grids. */
1488  UINT4 nGridsUsed = XLALSimIMRPhenomXMultibandingGrid(Mfmin, MfMECO, MfLorentzianEnd, Mfmax, evaldMf, dfpower, dfcoefficient, allGrids, dfmerger, dfringdown);
1489 
1490  #if DEBUG == 1
1491  printf("allGrids[0].Length = %i\n", allGrids[0].Length);
1492  #endif
1493 
1494  /* Number of fine frequencies per coarse interval in every coarse grid */
1495  INT4 mydfRatio[lengthallGrids];
1496  /* Actual number of subgrids to be used. We allocated more than needed. */
1497  UINT4 actualnumberofGrids = 0;
1498  /* Length of coarse frequency array */
1499  UINT4 lenCoarseArray = 0;
1500 
1501  /* Transform the coarse frequency array to 1D array. */
1502  // Take only the subgrids needed
1503  for(UINT4 kk = 0; kk < nGridsUsed; kk++){
1504  lenCoarseArray = lenCoarseArray + allGrids[kk].Length;
1505  actualnumberofGrids++;
1506 
1507  mydfRatio[kk] = allGrids[kk].intdfRatio;
1508 
1509  #if DEBUG == 1
1510  printf("\nkk = %i\n",kk);
1511  printf("xStart: %.16e\n", allGrids[kk].xStart);
1512  printf("xEnd: %.16e\n", allGrids[kk].xEndRequested);
1513  printf("Length: %i\n", allGrids[kk].Length);
1514  printf("deltax: %.16e\n", allGrids[kk].deltax);
1515  printf("evaldMf: %.16e\n", evaldMf);
1516  printf("xMax: %.16e\n", allGrids[kk].xMax);
1517  printf("# fine points %i\n", mydfRatio[kk]);
1518  printf("Last grid.xMax = %.16f\n", allGrids[actualnumberofGrids-1].xMax);
1519  #endif
1520 
1521  if(allGrids[kk].xMax + evaldMf >= Mfmax){
1522  break;
1523  }
1524  }
1525 
1526  // Add extra points to the coarse grid if the last freq is lower than Mfmax
1527  while(allGrids[actualnumberofGrids-1].xMax < Mfmax){
1528  allGrids[actualnumberofGrids-1].xMax = allGrids[actualnumberofGrids-1].xMax + allGrids[actualnumberofGrids-1].deltax;
1529  allGrids[actualnumberofGrids-1].Length = allGrids[actualnumberofGrids-1].Length + 1;
1530  lenCoarseArray++;
1531  }
1532 
1533  #if DEBUG == 1
1534  printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWFHM->fDAMP, pWF->Mtot));
1535  printf("\nactualnumberofGrids = %i\n", actualnumberofGrids);
1536  printf("lenCoarseArray = %i\n", lenCoarseArray);
1537  printf("Last grid.xMax = %.16f", allGrids[actualnumberofGrids-1].xMax);
1538  #endif
1539 
1540  // Transform coarse frequency array to 1D vector
1541  REAL8 *IntLawpoints = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
1542  UINT4 lenIntLawpoints = 0;
1543 
1544  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
1545  for(INT4 ll = 0; ll < allGrids[kk].Length; ll++){
1546  IntLawpoints[lenIntLawpoints] = (allGrids[kk].xStart + allGrids[kk].deltax*ll);
1547  lenIntLawpoints++;
1548  }
1549  }
1550 
1551 
1552 
1553  /* End of coarse frequency array. */
1554 
1555  #if DEBUG == 1
1556  printf("\n******** Coarse frequencies array done ********* \n");
1557  printf("\nlenIntLawpoints, coarse[0], coarse[-1], Mfmax, M_sec = %i %.16e %.16e %.16e %.16e\n",lenIntLawpoints, IntLawpoints[0], IntLawpoints[lenIntLawpoints-1], Mfmax, pWF->M_sec);
1558  #endif
1559 
1560  /* IntLawpoints stores the adimensional frequencies (Mf) */
1561  /* coarseFreqs will store the same frequency array but in Hz */
1562  /* Allocate memory for frequency array and terminate if this fails */
1563  REAL8Sequence *coarseFreqs;
1564  coarseFreqs = XLALCreateREAL8Sequence(lenCoarseArray);
1565  if (!coarseFreqs) { XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); }
1566 
1567  /* Populate frequency array */
1568  #if DEBUG == 1
1569  printf("\n***** Coarse freqs *****\n");
1570  #endif
1571  REAL8 divis = 1./pWF->M_sec;
1572  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
1573  {
1574  coarseFreqs->data[ii] = IntLawpoints[ii]*divis;
1575  }
1576  #if DEBUG == 1
1577  printf("\nFirst/Last Coarse freqs *****%.16f %.16f\n", coarseFreqs->data[0], coarseFreqs->data[coarseFreqs->length-1]);
1578  #endif
1579 
1580  /* Next we will compute amplitude and phase of one mode in the coarse frequency array. For that we need to split the frequency array in the spherical and spheroidal part. */
1581  /* We will compute 2 waveforms: one in the spherical part and another in the spheroidal. */
1582 
1583  #if DEBUG == 1
1584  printf("\n******* Splitting spherical/spheroidal coarseFreqs %i****************\n",lenCoarseArray);
1585  #endif
1586 
1587 
1588  REAL8 *IntLawpointsS = (REAL8*)XLALMalloc(lenCoarseArray*sizeof(REAL8));
1589  REAL8 *IntLawpointsSS = (REAL8*)XLALMalloc(lenCoarseArray*sizeof(REAL8));
1590 
1591  double MfRDcutMin, MfRDcutMax;
1592  if(pPhase->fPhaseMatchIM < pAmp->fAmpMatchIM){
1593  MfRDcutMin = pPhase->fPhaseMatchIM;
1594  MfRDcutMax = pAmp->fAmpMatchIM;
1595  }else{
1596  MfRDcutMin = pAmp->fAmpMatchIM;
1597  MfRDcutMax = pPhase->fPhaseMatchIM;
1598  }
1599 
1600  #if DEBUG == 1
1601  printf("\nMfRDcutMin = %.16f, MfRDcutMax = %.16f, lastcoarseArray = %.16f\n", MfRDcutMin, MfRDcutMax, IntLawpoints[lenCoarseArray-1]);
1602  #endif
1603 
1604  /* Compute the coarse frequencies in the spherical and in the spheroidal part. */
1605 
1606  unsigned int lencoarseS = 0, lencoarseSS = 0, enter = 0;
1607  for(UINT4 idx = 0; idx < lenCoarseArray; idx++){
1608  double ff = IntLawpoints[idx];
1609  if(ff > MfRDcutMin){
1610  if(lencoarseSS < 1 && lencoarseS>0){ // This numbers tells how many points we add to spherical after MfRDcutMin and how many to spheroidal before MfRDcutMin
1611  IntLawpointsSS[lencoarseSS] = IntLawpointsS[lencoarseS-1];
1612  lencoarseSS++;
1613 
1614  if(idx == lenCoarseArray-1){
1615  IntLawpointsS[lencoarseS] = ff;
1616  lencoarseS++;
1617  }
1618  }
1619  IntLawpointsSS[lencoarseSS] = ff;
1620  lencoarseSS++;
1621 
1622  if(idx < lenCoarseArray-1 && IntLawpoints[idx+1] < MfRDcutMax){
1623  IntLawpointsS[lencoarseS] = ff;
1624  lencoarseS++;
1625  }
1626  if(idx < lenCoarseArray-1 && IntLawpoints[idx+1] > MfRDcutMax && enter<2){
1627  IntLawpointsS[lencoarseS] = ff;
1628  lencoarseS++;
1629  enter++;
1630  }
1631  }
1632  else{
1633  IntLawpointsS[lencoarseS] = ff;
1634  lencoarseS++;
1635  }
1636  }
1637 
1638  #if DEBUG == 1
1639  printf("\n******* Coarse Freqs Spherical/Spheroidal ****************\n");
1640  printf("%i ", lencoarseS);
1641  printf("%i ", lencoarseSS);
1642  #endif
1643 
1644  /* Transform spherical and spheroidal frequencies to Hz */
1645  REAL8Sequence *coarseFreqsS = XLALCreateREAL8Sequence(lencoarseS);
1646  REAL8Sequence *coarseFreqsSS = XLALCreateREAL8Sequence(lencoarseSS);
1647  for (UINT4 ii = 0; ii < lencoarseS; ii++)
1648  {
1649  coarseFreqsS->data[ii] = IntLawpointsS[ii]/pWF->M_sec;
1650  }
1651  for (UINT4 ii = 0; ii < lencoarseSS; ii++)
1652  {
1653  coarseFreqsSS->data[ii] = IntLawpointsSS[ii]/pWF->M_sec;
1654  }
1655 
1656 
1657  #if DEBUG == 1
1658  printf("\n******* Computing Coarse Phase and Amp ****************\n");
1659  printf("%i ", coarseFreqsS->length);
1660  printf("%i ", coarseFreqsSS->length);
1661  #endif
1662 
1663  /* Compute coarse amplitude and phase in the spherical and spheroidal part */
1664  /* Declare amplitude and phase variables */
1665  REAL8FrequencySeries *amplitude, *phase;
1666  REAL8FrequencySeries *phaseSS, *amplitudeSS;
1667 
1668 
1669  if(lencoarseS > ampinterpolorder){
1670  IMRPhenomXHM_Phase(&phase, coarseFreqsS, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
1671  IMRPhenomXHM_Amplitude(&amplitude, coarseFreqsS, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
1672  }
1673  if(lencoarseSS > ampinterpolorder){
1674  IMRPhenomXHM_PhaseMixing(&phaseSS, coarseFreqsSS, pWF, pWFHM, pPhase);
1675  IMRPhenomXHM_AmplitudeMixing(&amplitudeSS, coarseFreqsSS, pWF, pWFHM, pAmp, pPhase);
1676  #if DEBUG == 1
1677  printf("\nLength@phaseSS = %i\n",phaseSS->data->length);
1678  #endif
1679  }
1680 
1681 
1682 
1683  #if DEBUG == 1
1684  printf("\n******* Computed Coarse Amp and Phase **************** %i\n", coarseFreqs->length);
1685  #endif
1686 
1687  /* Transform the REAL8FrequencySeries to vector since gsl uses vectors for the interpolation.
1688  gsl is only used for the amplitude but to keep the code more symmetric we transform also the phase. */
1689  REAL8 *ILamplm = (REAL8*)XLALMalloc(lencoarseS * sizeof(REAL8));
1690  REAL8 *ILphaselm = (REAL8*)XLALMalloc(lencoarseS * sizeof(REAL8));
1691  REAL8 *ILamplmSS = (REAL8*)XLALMalloc(lencoarseSS * sizeof(REAL8));
1692  REAL8 *ILphaselmSS = (REAL8*)XLALMalloc(lencoarseSS * sizeof(REAL8));
1693 
1694  if(lencoarseS > ampinterpolorder){
1695  for (UINT4 ii = 0; ii < lencoarseS; ii++)
1696  {
1697  ILamplm[ii] = ((amplitude)->data->data)[ii];
1698  ILphaselm[ii] = ((phase)->data->data)[ii];
1699  }
1700  }
1701  if(lencoarseSS > ampinterpolorder){
1702  for (UINT4 ii = 0; ii < lencoarseSS; ii++)
1703  {
1704  ILamplmSS[ii] = ((amplitudeSS)->data->data)[ii];
1705  ILphaselmSS[ii] = ((phaseSS)->data->data)[ii];
1706  }
1707  }
1708 
1709  #if DEBUG == 1
1710  if(lencoarseS > ampinterpolorder) printf("\nLast spherical phases %.16f %.16f", ILphaselm[lencoarseS-2], ILphaselm[lencoarseS-1]);
1711  if(lencoarseSS > ampinterpolorder) printf("\nLast spherical freqs %.16f %.16f", IntLawpoints[lencoarseS-2], IntLawpoints[lencoarseS-1]);
1712  #endif
1713 
1714  #if DEBUG == 1
1715  //Save coarse amplitude and phase (spherical and spheroidal) in file
1716  FILE *file0;
1717  char fileSpec0[40];
1718  sprintf(fileSpec0, "coarseamplitude%i%i.dat", ell,emm);
1719  printf("\nOutput file: %s\r\n",fileSpec0);
1720  file0 = fopen(fileSpec0,"w");
1721  fprintf(file0,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
1722  FILE *file3;
1723  char fileSpec3[40];
1724  sprintf(fileSpec3, "coarsephase%i%i.dat", ell,emm);
1725  printf("\nOutput file: %s\r\n",fileSpec3);
1726  file3 = fopen(fileSpec3,"w");
1727  fprintf(file3,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
1728  for(UINT4 idx = 0; idx < (UINT4)lencoarseS && lencoarseS>ampinterpolorder; idx++)
1729  {
1730  fprintf(file0, "%.16f %.16e \n", coarseFreqsS->data[idx], ILamplm[idx]);
1731  fprintf(file3, "%.16f %.16e \n", coarseFreqsS->data[idx]*pWF->M_sec, ILphaselm[idx]);
1732  }
1733  fprintf(file3, "\n\n");
1734  if(lencoarseSS > ampinterpolorder){
1735  for(UINT4 idx = 0; idx < (UINT4)lencoarseSS && lencoarseSS>ampinterpolorder; idx++)
1736  {
1737  fprintf(file0, "%.16f %.16e \n", coarseFreqsSS->data[idx], ILamplmSS[idx]);
1738  fprintf(file3, "%.16f %.16e \n", coarseFreqsSS->data[idx]*pWF->M_sec, ILphaselmSS[idx]);
1739  }
1740  }
1741  fclose(file0);
1742  fclose(file3);
1743  #endif
1744 
1745  /* Free allocated memory */
1746  if(lencoarseS > ampinterpolorder){
1749  }
1750  if(lencoarseSS > ampinterpolorder){
1752  XLALDestroyREAL8FrequencySeries(amplitudeSS);
1753  }
1754  XLALDestroyREAL8Sequence(coarseFreqs);
1755  XLALDestroyREAL8Sequence(coarseFreqsS);
1756  XLALDestroyREAL8Sequence(coarseFreqsSS);
1757 
1758 
1759  /***** Linear Interpolation of e^(I*phi) with the iterative procedure *****/
1760 
1761  /* Estimation of the length of the fineGrid */
1762  INT4 lenWF = 0;
1763 
1764  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
1765  lenWF = lenWF + (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk];
1766  #if DEBUG == 1
1767  printf("\nmydfRatio[%i] = %i %i %i", kk, mydfRatio[kk],allGrids[kk].Length, (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk]);
1768  printf("\nlenWF = %i", lenWF);
1769  #endif
1770  }
1771 
1772  // Variable to control the number of coarse points we have used
1773  int pointsPrecessedSoFar = 0;
1774 
1775  /* Allocate memory for the complex exponential and the fine equally-spaced frequency array */
1776  COMPLEX16 *expphi = (COMPLEX16*)XLALMalloc(lenWF*sizeof(COMPLEX16));
1777  if (expphi == NULL) {
1778  return -1;
1779  }
1780 
1781  REAL8 *finefreqs = (REAL8*)XLALMalloc(lenWF*sizeof(REAL8));
1782  if (finefreqs == NULL){
1783  return -1;
1784  }
1785 
1786  UINT4 count = 0; // Variable to track the point being filled in the fine frequency grid
1787  UINT4 coarsecount = 0; // Variable to track the point used in the coarse frequency grid
1788  UINT4 RDcutMin = 0, RDcutMax = 0; // Variables to know where to separate the fine spherical and spheroidal part. RDcutMin is for the phase and RDcutMax for the amplitude.
1789  COMPLEX16 Q32 = 0;
1790  INT4 lenRD = round((Mfmax - MfRDcutMin)/evaldMf) + 3; //+3 to be safe and no run out of memory because of rounding erros
1791  if(lenRD <= 0) {
1792  lenRD = 1;
1793  }
1794 
1795  /* After the rotation from spheroidal to spherical we will have to add a linear part to the phase of the 32. This part is also computed using Multibanding. */
1796  COMPLEX16 *linear32 = (COMPLEX16*)XLALMalloc( lenRD * sizeof(COMPLEX16));
1797 
1798  /* Loop over allgrids */
1799  bool stop = false;
1800  for (UINT4 i = 0; i<actualnumberofGrids && !stop; i++){
1801  #if DEBUG == 1
1802  printf("\ni = %i\n", i);
1803  #endif
1804 
1805 
1806  /* Compute mydfRatio */
1807  UINT4 lcoarseGrid = allGrids[i].Length;
1808  if(lcoarseGrid == 0){
1809  break;
1810  }
1811 
1812  /* Linear Interpolation and iteration */
1813  if(i==actualnumberofGrids-1){
1814  lcoarseGrid--;
1815  }
1816 
1817  REAL8 Omega, phi0, Mfhere = 0, Mfnext=0;
1818  COMPLEX16 h0, Q;
1819 
1820  /* Loop over the coarse points of a subgrid */
1821  for(UINT4 j = 0; j < lcoarseGrid && !stop; j++){
1822  Mfhere = IntLawpoints[pointsPrecessedSoFar + j];
1823  Mfnext = IntLawpoints[pointsPrecessedSoFar + j + 1] ;
1824 
1825  INT4 ratio;
1826  // If we are in the last coarse point of a sublist we use the number of fine points of the next subgrid.
1827  if(j==lcoarseGrid-1 && i < actualnumberofGrids-1){
1828  ratio = mydfRatio[i+1];
1829  }
1830  else{
1831  ratio = mydfRatio[i];
1832  }
1833  if(Mfnext + evaldMf >= Mfmax){
1834  double dratio = (Mfmax - Mfhere)/evaldMf + 1;
1835  ratio = (int) dratio;
1836  int roundratio = round((Mfmax - Mfhere)/evaldMf) + 1;
1837  if(fabs(dratio-roundratio) < 0.0001) ratio = roundratio; // To get the correct rounded integer
1838  /* Break the loop if you overpass the maximun frequency */
1839  stop = true;
1840  #if DEBUG == 1
1841  printf("\nMfmax, Mfhere, evaldMf, ratio= %.16f %.16f %.16f %i\n", Mfmax, Mfhere, evaldMf, ratio);
1842  #endif
1843  }
1844 
1845  /********************************************/
1846  /* Inner Loop: linear interpolation */
1847  /********************************************/
1848  /**** Spheroidal part ****/
1849  if(Mfhere > MfRDcutMin && lencoarseSS > ampinterpolorder) {
1850  if(RDcutMin == 0 ){
1851  MfRDcutMin = Mfhere;
1852  RDcutMin = count;
1853  linear32[0] = cexp( I * (pPhase->C1RD*Mfhere+pPhase->CRD + pPhase->deltaphiLM));
1854  Q32 = cexp( I * evaldMf * (pPhase->C1RD));
1855  #if DEBUG == 1
1856  printf("\n*** Starting spheroidal part ****\n");
1857  printf("Mfhere, MfRDcutMin, RDcutMin = %.16e %.16e %i\n", Mfhere, MfRDcutMin, RDcutMin);
1858  #endif
1859  if(lencoarseS <= ampinterpolorder){
1860  coarsecount++; //When the coarse array does not have spherical part.
1861  }
1862  }
1863 
1864  INT4 jdx = pointsPrecessedSoFar + j - coarsecount + 1;
1865 
1866  phi0 = ILphaselmSS[jdx];
1867 
1868  if(jdx < (int)lencoarseSS-1){
1869  Omega = (ILphaselmSS[ jdx + 1] - ILphaselmSS[jdx])/(IntLawpoints[pointsPrecessedSoFar + j + 1] - IntLawpoints[pointsPrecessedSoFar + j]);
1870  }
1871  else{
1872  Omega = (ILphaselmSS[jdx] - ILphaselmSS[jdx - 1])/(IntLawpoints[pointsPrecessedSoFar + j] - IntLawpoints[pointsPrecessedSoFar + j -1]);
1873  }
1874 
1875  if(pWFHM->IMRPhenomXHMReleaseVersion == 122019 && Mfhere > pAmp->fAmpMatchIM && RDcutMax < 1){
1876  RDcutMax = count;
1877  }
1878  if(pWFHM->IMRPhenomXHMReleaseVersion != 122019 && Mfhere > MfRDcutMax && RDcutMax < 1){
1879  RDcutMax = count;
1880  }
1881  }
1882  /**** Spherical part ****/
1883  else{
1884  UINT4 jjdx = j + pointsPrecessedSoFar;
1885  if(jjdx < lencoarseS-1){
1886  Omega = (ILphaselm[jjdx+ 1] - ILphaselm[jjdx])/(IntLawpoints[jjdx + 1] - IntLawpoints[jjdx]);
1887  }
1888  else{
1889  Omega = (ILphaselm[jjdx] - ILphaselm[jjdx -1])/(IntLawpoints[jjdx] - IntLawpoints[jjdx -1]);
1890 
1891  }
1892  phi0 = ILphaselm[jjdx];
1893  coarsecount++;
1894  }
1895 
1896  h0 = cexp(I*phi0);
1897  Q = cexp(I*evaldMf*Omega);
1898 
1899  if(RDcutMin == 0 && lencoarseS>ampinterpolorder){ // Spherical part
1900  finefreqs[count] = Mfhere;
1901  expphi[count] = h0;
1902  count++;
1903  /* This loop carry out the eq. 2.32 in arXiv:2001.10897 */
1904  for(int kk = 1; kk < ratio; kk++){ // Compute finefreqs and fine expphi
1905  finefreqs[count] = Mfhere + evaldMf*kk;
1906  expphi[count] = Q*expphi[count-1];
1907  count++;
1908  }
1909  }
1910  else{ // Spheroidal part
1911  finefreqs[count] = Mfhere;
1912  expphi[count] = h0;
1913  linear32[count - RDcutMin +1] = Q32*linear32[count - RDcutMin ];
1914  count++;
1915  /* This loop carry out the eq. 2.32 in arXiv:2001.10897 but for spheroidals */
1916  for(int kk = 1; kk < ratio; kk++){ // Compute finefreqs and fine expphi
1917  finefreqs[count] = Mfhere + evaldMf*kk;
1918  expphi[count] = Q*expphi[count-1];
1919  linear32[count - RDcutMin +1] = Q32*linear32[count - RDcutMin ];
1920  count++;
1921  }
1922  }
1923  }
1924  pointsPrecessedSoFar = pointsPrecessedSoFar + lcoarseGrid;
1925  }// End loop over ILgrids. count should be aprox = to lenWF
1926 
1927  if(RDcutMin == 0){
1928  RDcutMin = count;
1929  }
1930  if(lencoarseS <= ampinterpolorder){
1931  RDcutMin = 0;
1932  }
1933  if(RDcutMax == 0){
1934  RDcutMax = count;
1935  }
1936 
1937 
1938  #if DEBUG == 1
1939  printf("\nTheory and practice (should not be equal) %i %i \n", lencoarseS, coarsecount );
1940  printf("\n******* Interpolate Amplitude **********\n");
1941  #endif
1942 
1943  /*** Interpolation and evaluation in fineFreqs of the amplitude ***/
1944  REAL8 *fineAmp = (REAL8*)XLALMalloc(count * sizeof(REAL8));
1945  REAL8 *fineAmpSS = (REAL8*)XLALMalloc(count * sizeof(REAL8));
1946 
1947  interpolateAmplitudeMixing(fineAmp, fineAmpSS, IntLawpointsS, IntLawpointsSS, ILamplm, ILamplmSS, finefreqs, lencoarseS, lencoarseSS, count, RDcutMin, RDcutMax, ampinterpolorder);
1948 
1949 
1950  /**** Build the waveform ****/
1951  size_t offset = iStart;
1952 
1953  #if DEBUG ==1
1954  printf("\nfinefreqs[0], evaldMf, quotient, offset = %.16e %.16e %.16e %zu\n", finefreqs[0], evaldMf, finefreqs[0]/evaldMf, offset);
1955  #endif
1956 
1957  // Due to round of erros, the last freq may be greater Mfmax. The difference should be less than the frequency step.
1958  // Remove that extra frequency point
1959  while(finefreqs[count-1] > Mfmax){
1960  count--;
1961  if(RDcutMin>count) RDcutMin = count;
1962  if(RDcutMax>count) RDcutMax = count;
1963  }
1964 
1965  /* Intialize FrequencySeries for htildelm */
1966  while(count + offset > iStop){ count--;}
1967  size_t n = iStop;
1968  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);
1969  //XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF + 500*pWF->Mtot*LAL_MTSUN_SI), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df + 500M with df = %g.", deltaF);
1970  *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
1971  for(int idx = 0; idx < (int) offset; idx++){
1972  ((*htildelm)->data->data)[idx] = 0.;
1973  }
1974 
1975  /* Sometimes rounding error can make that count+offset < iStop, meaning that we have computed less points than those we are gonna output,
1976  here we make sure that all the elements of htildelm are initialized and we put the extra point(s) to 0. */
1977  for(UINT4 idx = count-1; idx < iStop-offset; idx++){
1978  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
1979  ((*htildelm)->data->data)[idx + offset] = 0.;
1980  }
1981 
1982  #if DEBUG == 1
1983  printf("\n**** pPhase->fPhaseMatchIM, pPhase->fAmpMatchIM, MfRDcutMin = %.16f %.16f %.16f \n",pPhase->fPhaseMatchIM, pAmp->fAmpMatchIM, MfRDcutMin);
1984  printf("\ncount RDcutMin RDcutMax: %i %i %i\n", count, RDcutMin, RDcutMax);
1985  printf("\nMfRDcutMin MfRDcutMax: %.6f %.6f\n", MfRDcutMin, MfRDcutMax);
1986  //Save lm in file
1987  FILE *file5;
1988  char fileSpec5[40];
1989  sprintf(fileSpec5, "sphericalfine%i%i.dat", ell,emm);
1990  printf("\nOutput file: %s\r\n",fileSpec5);
1991  file5 = fopen(fileSpec5,"w");
1992  fprintf(file5,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
1993  fprintf(file5,"# Frequency (Hz) Fine Spherical Phase \n");
1994  //Save lm in file
1995  FILE *file6;
1996  char fileSpec6[40];
1997  sprintf(fileSpec6, "spheroidalfine%i%i.dat", ell,emm);
1998  printf("\nOutput file: %s\r\n",fileSpec6);
1999  file6 = fopen(fileSpec6,"w");
2000  fprintf(file6,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
2001  fprintf(file6,"# Frequency (Hz) Fine Spheroidal Phase \n");
2002  #endif
2003 
2004  /* (-1)^l */
2005  INT4 minus1l;
2006  if (ell % 2 != 0)
2007  minus1l = -1;
2008  else
2009  minus1l = +1;
2010 
2011  /******** Spherical part **********/
2012  #if DEBUG == 1
2013  printf("\nRDcutMin = %i", RDcutMin);
2014  #endif
2015  for(UINT4 idx = 0; idx < RDcutMin; idx++){
2016  COMPLEX16 data5 = minus1l * fineAmp[idx] * expphi[idx];
2017  ((*htildelm)->data->data)[idx + offset] = data5;
2018  #if DEBUG == 1
2019  fprintf(file5, "%.16f %.16e %.16e\n",(idx + offset)*deltaF, creal(data5), cimag(data5));
2020  #endif
2021  }
2022  #if DEBUG ==1
2023  fclose(file5);
2024  #endif
2025 
2026 
2027  /********** Rotate Spheroidal part ******************/
2028  // Compute htilde22 for the ringdown part if the 22 mode was not computed before.
2029  COMPLEX16FrequencySeries *htilde22tmp = NULL;
2030 
2031  if(htilde22 == NULL && count>RDcutMin){
2032  REAL8Sequence *freqs = XLALCreateREAL8Sequence(count - RDcutMin);
2033  #if DEBUG == 1
2034  printf("\nBuilding RD 22 mode\n");
2035  printf("\nlen@freqs, RDcutMin, count = %i %i %i\n", freqs->length, RDcutMin, count);
2036  #endif
2037  for(UINT4 idx = RDcutMin; idx < count; idx++){
2038  freqs->data[idx-RDcutMin] = finefreqs[idx]/pWF->M_sec;
2039  }
2040  int return_code = IMRPhenomXASGenerateFD(
2041  &htilde22tmp,
2042  freqs,
2043  pWF,
2044  lalParams
2045  );
2046  XLAL_CHECK(return_code == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXASGenerateFD failed to generate IMRPhenomX waveform.");
2047 
2048  XLALDestroyREAL8Sequence(freqs);
2049  }
2050  else{
2051  htilde22tmp = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,count-RDcutMin);
2052  for(UINT4 idx = RDcutMin; idx < count; idx++){
2053  htilde22tmp->data->data[idx - RDcutMin] = htilde22->data->data[idx + offset];
2054  }
2055  }
2056 
2057 
2058 
2059  COMPLEX16 shift32 = 0;
2060 
2061  #if DEBUG == 1
2062  printf("\nLength@htilde22, count, RDcutMin, RDcutMax, offset %i %i %i %i %zu\n",htilde22tmp->data->length, (int)(count+offset), RDcutMin, RDcutMax, offset);
2063  #endif
2064  for(UINT4 idx = RDcutMin; idx < count; idx++){
2065  double Mf = finefreqs[idx];
2066  IMRPhenomX_UsefulPowers powers_of_f;
2067  IMRPhenomX_Initialize_Powers(&powers_of_f, Mf);
2068  //22 waveform complete (without rescaling)
2069  //COMPLEX16 wf22 = htilde22->data->data[idx + offset];
2070  COMPLEX16 wf22 = htilde22tmp->data->data[idx - RDcutMin];
2071  //32 waveform in spheroidal
2072  REAL8 amplm = fineAmpSS[idx-RDcutMin] * pWFHM->Amp0;
2073  if (pWFHM->IMRPhenomXHMRingdownAmpVersion == 0) amplm *= powers_of_f.m_seven_sixths;
2074  COMPLEX16 expphilm = expphi[idx];
2075  //Rotation to spherical with Berti's coefficients
2076  shift32 = linear32[idx-RDcutMin];
2077  COMPLEX16 sphericalWF_32 = (conj(pWFHM->mixingCoeffs[2])*wf22 + conj(pWFHM->mixingCoeffs[3])*amplm*expphilm)*shift32;
2078  COMPLEX16 data;
2079 
2080  // Use spheroidal phase but spherical amplitude
2081  if(Mf < pAmp->fAmpMatchIM){
2082  data = sphericalWF_32/cabs(sphericalWF_32) * fineAmp[idx];
2083  }
2084  // Use spheroidal amp but spherical phase. Case when fAmpMatchIM < fPhaseMatchIM.
2085  // For the 122019 release the phase freq was always lower than the amp freq so this case was not necessary
2086  // In fact, that is not completely true, in IMRPhenomXHM_Intermediate_CollocPtsFreqs the phase cutting freq for the 122019 is pushed
2087  // to higher frequencies for EMRI and negative s1z and it can be higher than the cutting freq for the amplitude.
2088  // In that case, the 122019 release extrapolated the spheroidal phase to lower frequencies.
2089  else if(Mf < pPhase->fPhaseMatchIM && pWFHM->IMRPhenomXHMReleaseVersion != 122019){
2090  // This part does not use Multibanding for the phase. The spherical phase is only interpolated up to RDcutMin (fAmpMatchIM)
2091  // This is not using Multibanding for the phase. The spherical phase is only interpolated up to RDcutMin (fAmpMatchIM)
2092  COMPLEX16 myphase = cexp(I * IMRPhenomXHM_Phase_ModeMixing(&powers_of_f, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF));
2093  data = cabs(sphericalWF_32) * myphase;
2094  }
2095  // Use spheroidal amplitude and phase
2096  else{
2097  data = sphericalWF_32;
2098  }
2099  ((*htildelm)->data->data)[idx + offset] = data * minus1l;
2100  #if DEBUG == 1
2101  data = ((*htildelm)->data->data)[idx + offset];
2102  fprintf(file6, "%.16f %.16e %.16e\n",(idx + offset)*deltaF, creal(data), cimag(data));
2103  #endif
2104  }
2105  #if DEBUG == 1
2106  fclose(file6);
2107  #endif
2108 
2109  /* Free allocated memory */
2111  LALFree(pAmp);
2112  LALFree(pAmp22);
2113  LALFree(pPhase);
2114  LALFree(pPhase22);
2115  LALFree(linear32);
2116 
2117 
2118  #if DEBUG == 1
2119  printf("\n******* Building Waveform 2**********\n");
2120  printf("\nfinefreqs[0]Hz = %.16f\n", finefreqs[0]/pWF->M_sec);
2121  printf("\nfinefreqs[%i]Hz = %.16f\n", count-1, finefreqs[count-1]/pWF->M_sec);
2122  printf("Mfmax in Hz = %.16f\n", Mfmax/pWF->M_sec);
2123  printf("count-1, offset = %i %zu\n", count-1, offset);
2124  printf("Mfmaxtheory = %.16f\n", (count-1+offset)*deltaF);
2125  printf("\nlength@htildelm, count+offset = %i %zu", (*htildelm)->data->length, count+offset);
2126  printf("\nf_max_prime = %.16e", pWF->f_max_prime);
2127  printf("\nlastfreq true = %.16e", (*htildelm)->data->length * deltaF);
2128  printf("\nlastfreq true = %.16e %.16e", creal((*htildelm)->data->data[count-1]), cimag((*htildelm)->data->data[count-1]));
2129  #endif
2130 
2131 
2132  #if DEBUG == 1
2133  //Save hlm mode in file
2134  FILE *file;
2135  char fileSpec[40];
2136  sprintf(fileSpec, "simulation%i%i_Multiband.dat", ell,emm);
2137  printf("\nOutput file: %s\r\n",fileSpec);
2138  file = fopen(fileSpec,"w");
2139  fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->m1_SI/pWF->m2_SI, pWF->chi1L, pWF->chi2L, ell, emm);
2140  fprintf(file,"# Frequency (Hz) Real Imaginary\n");
2141  COMPLEX16 data;
2142  for(UINT4 idx = 0; idx < ((*htildelm)->data->length); idx++)
2143  {
2144  data = ((*htildelm)->data->data)[idx];
2145  fprintf(file, "%.16f %.16e %.16e\n", idx*deltaF, creal(data), cimag(data));
2146  }
2147  fclose(file);
2148  #endif
2149 
2150  #if DEBUG == 1
2151  //Save fine amplitude and freq array in file
2152  FILE *file2;
2153  char fileSpec2[40];
2154  sprintf(fileSpec2, "amplitude%i%i_fine.dat", ell,emm);
2155  printf("\nOutput file: %s\r\n",fileSpec2);
2156  file2 = fopen(fileSpec2,"w");
2157  fprintf(file2,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->m1_SI/pWF->m2_SI, pWF->chi1L, pWF->chi2L, ell, emm);
2158  for(UINT4 idx = 0; idx < RDcutMax && lencoarseS>ampinterpolorder; idx++)
2159  {
2160  fprintf(file2, "%.16f %.16e\n", finefreqs[idx], fineAmp[idx]);
2161  }
2162  fclose(file2);
2163  #endif
2164 
2165  /* Free allocated memory */
2166  LALFree(expphi);
2167  LALFree(finefreqs);
2168  LALFree(allGrids);
2169  LALFree(fineAmp);
2170  LALFree(fineAmpSS);
2171  LALFree(pWFHM);
2172  LALFree(ILamplm);
2173  LALFree(ILamplmSS);
2174  LALFree(ILphaselm);
2175  LALFree(ILphaselmSS);
2176  LALFree(IntLawpoints);
2177  LALFree(IntLawpointsS);
2178  LALFree(IntLawpointsSS);
2179 
2180  return XLAL_SUCCESS;
2181 }
2182 
2183 
2184 /**************************************/
2185 /* INTERPOLATING FUNCTIONS */
2186 /**************************************/
2187 
2188 /* Interpolate the 2D array [coarseFreqs, coarseAmp] and evaluate in finefreqs */
2189 /* Interpolation uses third order */
2191  double *fineAmp, /**<[out] amplitude in the fine uniform grid **/
2192  double coarsefreqs[], /**< non-uniform frequency array**/
2193  double coarseAmp[], /**< amplitude in the non-uniform frequency array **/
2194  double finefreqs[], /**< uniform fine frequency grid**/
2195  int lengthCoarse, /**< length of non-uniform freq array **/
2196  int lengthFine, /**< length of uniform fine freq array **/
2197  int ampinterpolorder /**< order of the gsl interpolation **/
2198 ){
2199 
2200  #if DEBUG == 1
2201  printf("\n****Building interpolants*****\n");
2202  printf("Number of points to interpolate = %i\r\n", lengthCoarse);
2203  #endif
2204 
2205  gsl_interp_accel *acc = gsl_interp_accel_alloc();
2206  gsl_spline *spline;
2207  switch(ampinterpolorder){
2208  case 1:{
2209  spline = gsl_spline_alloc(gsl_interp_linear, lengthCoarse);
2210  break;
2211  }
2212  case 3:{
2213  spline = gsl_spline_alloc(gsl_interp_cspline, lengthCoarse);
2214  break;
2215  }
2216  default:{spline = gsl_spline_alloc(gsl_interp_cspline, lengthCoarse);}
2217  }
2218  gsl_spline_init(spline, coarsefreqs, coarseAmp, lengthCoarse);
2219 
2220  #if DEBUG == 1
2221  printf("\n****Loop for fine freqs*****\n");
2222  #endif
2223 
2224  for(INT4 kk = 0; kk < lengthFine; kk++){
2225  if(finefreqs[kk] < coarsefreqs[0] || finefreqs[kk] > coarsefreqs[lengthCoarse-1]){
2226  #if DEBUG == 1
2227  printf("\nOut of coarse range: coarse[0], coarse[-1] fine[%i] %.16e %.16e %.16e\n", kk, coarsefreqs[0], coarsefreqs[lengthCoarse-1], finefreqs[kk]);
2228  #endif
2229  fineAmp[kk] = fineAmp[kk-1];
2230  }
2231  else{
2232  fineAmp[kk] = gsl_spline_eval(spline, finefreqs[kk], acc);
2233  }
2234  }
2235  #if DEBUG == 1
2236  printf("\n****Free memory*****\n");
2237  #endif
2238  /* Free memory */
2239  gsl_spline_free(spline);
2240  gsl_interp_accel_free(acc);
2241 
2242  return 0;
2243 
2244 }
2245 
2246 /* Do 2 interpolations, one in the spherical regime and other in the spheroidal. */
2248  double *fineAmp, /**<[out] spherical amplitude in the fine uniform grid **/
2249  double *fineAmpSS, /**<[out] spheroidal amplitude in the fine uniform grid **/
2250  double coarsefreqs[], /**< non-uniform frequency array**/
2251  double coarsefreqsSS[], /**< non-uniform frequency array spheroidal **/
2252  double coarseAmp[], /**< amplitude in the non-uniform frequency array **/
2253  double coarseAmpSS[], /**< spheroidal amplitude in the non-uniform frequency array **/
2254  double finefreqs[], /**< uniform fine frequency grid**/
2255  int lengthCoarse, /**< length of non-uniform freq array **/
2256  int lengthCoarseSS, /**< length of non-uniform freq array Sphroidal **/
2257  int lengthFine, /**< length of uniform fine freq array **/
2258  int sphericalfinecount, /**< length of spherical fine grid **/
2259  int sphericalfinecountMax, /**< length of spherical fine grid **/
2260  int ampinterpolorder /**< order of interpolation **/
2261 )
2262 {
2263  int spheroidalfinecount = lengthFine - sphericalfinecount;
2264 
2265  REAL8 *sphericalfineFreqs = (REAL8*)XLALMalloc(sphericalfinecountMax * sizeof(REAL8));
2266  REAL8 *spheroidalfineFreqs = (REAL8*)XLALMalloc(spheroidalfinecount * sizeof(REAL8));
2267 
2268  for(int i = 0; i < sphericalfinecountMax; i++){
2269  sphericalfineFreqs[i] = finefreqs[i];
2270  }
2271  for(int i = 0; i < spheroidalfinecount; i++){
2272  spheroidalfineFreqs[i] = finefreqs[i + sphericalfinecount];
2273  }
2274 
2275  if(lengthCoarse > ampinterpolorder) interpolateAmplitude(fineAmp, coarsefreqs, coarseAmp, sphericalfineFreqs, lengthCoarse, sphericalfinecountMax, ampinterpolorder);
2276  if(lengthCoarseSS > ampinterpolorder) interpolateAmplitude(fineAmpSS, coarsefreqsSS, coarseAmpSS, spheroidalfineFreqs, lengthCoarseSS, spheroidalfinecount, ampinterpolorder);
2277 
2278  #if DEBUG == 1
2279  //Save lm in file
2280  FILE *file2;
2281  char fileSpec2[40];
2282  sprintf(fileSpec2, "amplitude%i%i_fineSS.dat", 3,2);
2283  printf("\nOutput file: %s\r\n",fileSpec2);
2284  file2 = fopen(fileSpec2,"w");
2285  REAL8 data2;
2286  for(long int idx = 0; idx < spheroidalfinecount; idx++)
2287  {
2288  data2 = fineAmpSS[idx]; // uninitialised value
2289  fprintf(file2, "%.16f %.16e\n", finefreqs[ sphericalfinecount + idx], data2);
2290  }
2291  fclose(file2);
2292  #endif
2293 
2294  LALFree(sphericalfineFreqs);
2295  LALFree(spheroidalfineFreqs);
2296 
2297  return 0;
2298 
2299 }
2300 
2301 
2302 /****************************************/
2303 /* */
2304 /* AUXILIARY FUNCTIONS */
2305 /* */
2306 /****************************************/
2307 
2308 /* Set up frequency array and frequency series for amplitude or phase */
2309 // We pass it the coarse frequency array so it just initialize amplitude or phase.
2311  REAL8Sequence **freqs, /**<[out] Frequency array to evaluate model **/
2312  REAL8FrequencySeries **amphase, /**<[out] Initialize amplitude or phase with the length of freqs **/
2313  const REAL8Sequence *freqs_In, /**< Input frequency array or fmin, fmax **/
2314  IMRPhenomXWaveformStruct *pWF, /**< Structure of the 22 mode **/
2315  LIGOTimeGPS ligotimegps_zero /**< Needed to initialize amphase **/
2316 ){
2317 
2318  /* Inherit minimum and maximum frequencies to generate wavefom from input frequency grid */
2319  double f_min = freqs_In->data[0];
2320  double f_max = freqs_In->data[freqs_In->length - 1];
2321 
2322  /* Size of array */
2323  size_t npts = 0;
2324 
2325  /* Index shift between freqs and the frequency series */
2326  UNUSED UINT4 offset = 0;
2327 
2328  #if DEBUG == 1
2329  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
2330  #endif
2331 
2332  /* If deltaF is non-zero then we need to generate a uniformly sampled frequency grid of spacing deltaF. Start at f = 0. */
2333  if(pWF->deltaF > 0)
2334  {
2335  #if DEBUG == 1
2336  printf("\n******* deltaF > 0 ************\n");
2337  #endif
2338  /* Return the closest power of 2 */
2339  npts = NextPow2(f_max / pWF->deltaF) + 1;
2340 
2341  /* Debug information */
2342  if(pWF->debug)
2343  {
2344  #if DEBUG == 1
2345  printf("npts = %zu\n",npts);
2346  printf("fMin = %.4f\n",f_min);
2347  printf("fMax = %.4f\n",f_max);
2348  printf("dF = %.4f\n",pWF->deltaF);
2349  #endif
2350  }
2351 
2352  /* Coalescence time is fixed to t=0, shift by overall length in time. */
2353  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);
2354  #if DEBUG == 1
2355  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
2356  #endif
2357  /* Initialize the htilde frequency series */
2358  *amphase = XLALCreateREAL8FrequencySeries("amphase: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,npts);
2359  /* Check that frequency series generated okay */
2360  XLAL_CHECK(*amphase,XLAL_ENOMEM,"Failed to allocate REAL8FrequencySeries of length %zu for f_max = %f, deltaF = %g.\n",npts,f_max,pWF->deltaF);
2361 
2362  /* Frequencies will be set using only the lower and upper bounds that we passed */
2363  size_t iStart = (size_t) (f_min / pWF->deltaF);
2364  size_t iStop = (size_t) (f_max / pWF->deltaF) + 1;
2365 
2366  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
2367  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
2368  #if DEBUG == 1
2369  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
2370  #endif
2371  /* Allocate memory for frequency array and terminate if this fails */
2372  (*freqs) = XLALCreateREAL8Sequence(iStop - iStart);
2373  #if DEBUG == 1
2374  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
2375  #endif
2376  if (!(*freqs))
2377  {
2378  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
2379  }
2380  #if DEBUG == 1
2381  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
2382  #endif
2383  /* Populate frequency array */
2384  for (UINT4 i = iStart; i < iStop; i++)
2385  {
2386  (*freqs)->data[i-iStart] = i * pWF->deltaF;
2387  }
2388  offset = iStart;
2389  }
2390  else
2391  {
2392  #if DEBUG == 1
2393  printf("\n******* deltaF = 0 ************\n");
2394  #endif
2395  /* freqs is a frequency grid with non-uniform spacing, so we start at the lowest given frequency */
2396  npts = freqs_In->length;
2397  *amphase = XLALCreateREAL8FrequencySeries("amphase: FD waveform, 22 mode", &ligotimegps_zero, f_min, pWF->deltaF, &lalStrainUnit, npts);
2398 
2399  XLAL_CHECK (*amphase, XLAL_ENOMEM, "Failed to allocated waveform REAL8FrequencySeries of length %zu from sequence.", npts);
2400 
2401  offset = 0;
2402  (*freqs) = XLALCreateREAL8Sequence(freqs_In->length);
2403 
2404  /* Allocate memory for frequency array and terminate if this fails */
2405  if (!(*freqs))
2406  {
2407  XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
2408  }
2409 
2410  /* Populate frequency array */
2411  for (UINT4 i = 0; i < freqs_In->length; i++)
2412  {
2413  (*freqs)->data[i] = freqs_In->data[i];
2414  }
2415  }//end freqs
2416  memset((*amphase)->data->data, 0, npts * sizeof(REAL8));
2417  XLALUnitMultiply(&((*amphase)->sampleUnits), &((*amphase)->sampleUnits), &lalSecondUnit);
2418 
2419  return offset;
2420 }
2421 
2422 
2423 /** Functions to compute coarse amplitude and phase **/
2424 
2425 /* Spherical amplitude evaluated in an input frequency array */
2427  REAL8FrequencySeries **amplm, /**<[out] amplitude of hlm mode **/
2428  const REAL8Sequence *freqs_In, /**< Frequency array to evaluate model or fmin, fmax **/
2429  IMRPhenomXWaveformStruct *pWF, /**< Structure of the 22 mode **/
2430  IMRPhenomXAmpCoefficients *pAmp22, /**< Amplitude coefficients 22 */
2431  IMRPhenomXPhaseCoefficients *pPhase22, /**< Phase coefficients 22 */
2432  IMRPhenomXHMWaveformStruct *pWFHM, /**< waveform parameters lm mode */
2433  IMRPhenomXHMAmpCoefficients *pAmp, /**< Amplitude coefficients lm */
2434  IMRPhenomXHMPhaseCoefficients *pPhase /**< Phase coefficients 22 */
2435 )
2436 {
2437 
2438  #if DEBUG == 1
2439  printf("\n **** IMRPhenomXHM_Amplitude **** \n");
2440  printf("\nf_min, f_max = %.16e %.16e\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
2441  #endif
2442 
2443  /* Set LIGOTimeGPS */
2444  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
2445 
2446  int status = 0;
2447  REAL8Sequence *freqs;
2448  UINT4 offset = SetupWFArraysReal(&freqs, amplm, freqs_In, pWF, ligotimegps_zero);
2449 
2450  #if DEBUG == 1
2451  printf("\n***Length@freqs, offset %i %i",freqs_In->length,offset);
2452  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
2453  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
2454  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
2455  #endif
2456 
2457  if(pWFHM->Ampzero==0){
2458  IMRPhenomX_UsefulPowers powers_of_Mf;
2459  UINT4 initial_status = XLAL_SUCCESS;
2460  REAL8 Msec = pWF->M_sec;
2461  REAL8 amp;
2462 
2463  /* Loop over frequencies to generate waveform */
2464  if(pWFHM->MixingOn==1){
2465  for (UINT4 idx = 0; idx < freqs->length; idx++)
2466  {
2467  REAL8 Mf = Msec * freqs->data[idx];
2468  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2469  if(initial_status != XLAL_SUCCESS)
2470  {
2471  status = initial_status;
2472  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2473  }
2474  else
2475  {
2476  amp = IMRPhenomXHM_Amplitude_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2477  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2478  ((*amplm)->data->data)[idx+offset] = pWFHM->Amp0 * amp;
2479  }
2480  }
2481  }
2482  else{
2483  for (UINT4 idx = 0; idx < freqs->length; idx++)
2484  {
2485  REAL8 Mf = Msec * freqs->data[idx];
2486  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2487  if(initial_status != XLAL_SUCCESS)
2488  {
2489  status = initial_status;
2490  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2491  }
2492  else
2493  {
2494  amp = IMRPhenomXHM_Amplitude_noModeMixing(&powers_of_Mf, pAmp, pWFHM);
2495  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2496  ((*amplm)->data->data)[idx+offset] = pWFHM->Amp0 * amp;
2497  }
2498  }
2499  }
2500  }
2501  /* Free allocated memory */
2502  XLALDestroyREAL8Sequence(freqs);
2503 
2504  return status;
2505 }
2506 
2507 
2508 /* Ringdown amplitude ansatz evaluated in an input frequency array */
2510  REAL8FrequencySeries **amplm, /**<[out] amplitude of hlm mode **/
2511  const REAL8Sequence *freqs_In, /**< Frequency array to evaluate model or fmin, fmax **/
2512  IMRPhenomXWaveformStruct *pWF, /**< Structure of the 22 mode **/
2513  IMRPhenomXHMWaveformStruct *pWFHM, /**< waveform parameters lm mode */
2514  IMRPhenomXHMAmpCoefficients *pAmp, /**< Amplitude coefficients lm */
2515  UNUSED IMRPhenomXHMPhaseCoefficients *pPhase /**< Phase coefficients 22 */
2516 )
2517 {
2518  #if DEBUG == 1
2519  printf("\n **** IMRPhenomXHM_Amplitude **** \n");
2520  #endif
2521 
2522  /* Set LIGOTimeGPS */
2523  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
2524 
2525  int status = 0;
2526  REAL8Sequence *freqs;
2527  UINT4 offset = SetupWFArraysReal(&freqs, amplm, freqs_In, pWF, ligotimegps_zero);
2528 
2529  #if DEBUG == 1
2530  printf("\n***Length@freqs, offset %i %i",freqs_In->length,offset);
2531  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
2532  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
2533  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
2534  #endif
2535 
2536 
2537  /* Loop over frequencies to generate waveform */
2538  if(pWFHM->Ampzero==0){
2539  IMRPhenomX_UsefulPowers powers_of_Mf;
2540  UINT4 initial_status = XLAL_SUCCESS;
2541  REAL8 Msec = pWF->M_sec;
2542  REAL8 amp;
2543 
2544  for (UINT4 idx = 0; idx < freqs->length; idx++)
2545  {
2546  REAL8 Mf = Msec * freqs->data[idx];
2547  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2548  if(initial_status != XLAL_SUCCESS)
2549  {
2550  status = initial_status;
2551  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2552  }
2553  else
2554  {
2555  amp = IMRPhenomXHM_RD_Amp_Ansatz(&powers_of_Mf, pWFHM, pAmp);
2556  if (pWFHM->IMRPhenomXHMRingdownAmpVersion == 0) amp *= pWF->ampNorm;
2557  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2558  ((*amplm)->data->data)[idx+offset] = amp;
2559  }
2560  }
2561  }
2562  /* Free allocated memory */
2563  XLALDestroyREAL8Sequence(freqs);
2564 
2565  return status;
2566 
2567 }
2568 
2569 /* Spherical phase evaluated in an input frequency array */
2571  REAL8FrequencySeries **phaselm, /**<[out] phase of hlm mode **/
2572  const REAL8Sequence *freqs_In, /**< Frequency array to evaluate model or fmin, fmax **/
2573  IMRPhenomXWaveformStruct *pWF, /**< Structure of the 22 mode **/
2574  IMRPhenomXAmpCoefficients *pAmp22, /**< Amplitude coefficients 22 */
2575  IMRPhenomXPhaseCoefficients *pPhase22, /**< Phase coefficients 22 */
2576  IMRPhenomXHMWaveformStruct *pWFHM, /**< waveform parameters lm mode */
2577  IMRPhenomXHMAmpCoefficients *pAmp, /**< Amplitude coefficients lm */
2578  IMRPhenomXHMPhaseCoefficients *pPhase /**< Phase coefficients 22 */
2579 )
2580 {
2581  #if DEBUG == 1
2582  printf("\n **** IMRPhenomXHM_Phase **** \n");
2583  #endif
2584 
2585  /* Set LIGOTimeGPS */
2586  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
2587 
2588  int status = 0;
2589  REAL8Sequence *freqs;
2590  UINT4 offset = SetupWFArraysReal(&freqs, phaselm, freqs_In, pWF, ligotimegps_zero);
2591 
2592  #if DEBUG == 1
2593  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
2594  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
2595  #endif
2596 
2597  if(pWFHM->Ampzero==0){
2598  IMRPhenomX_UsefulPowers powers_of_Mf;
2599  UINT4 initial_status = XLAL_SUCCESS;
2600  REAL8 Msec = pWF->M_sec;
2601  REAL8 phi;
2602 
2603  /* Loop over frequencies to generate waveform */
2604  if(pWFHM->MixingOn==1){
2605  //double twopi_m1=1./(2.*LAL_PI);
2606  UINT4 enter = 1;
2607  REAL8 Mf = Msec * freqs->data[0];
2608  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2609  if(initial_status != XLAL_SUCCESS)
2610  {
2611  status = initial_status;
2612  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2613  }
2614  else
2615  {
2616  //REAL8 phiprevious = 0;
2617  for (UINT4 idx = 0; idx < freqs->length; idx++)
2618  {
2619  Mf = Msec * freqs->data[idx];
2620  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2621  if(initial_status != XLAL_SUCCESS)
2622  {
2623  status = initial_status;
2624  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2625  }
2626  else
2627  {
2628  phi = IMRPhenomXHM_Phase_ModeMixing(&powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
2629  /* Only the first coarse point in the RD needs the unwrapping.
2630  If we remove the enter condition we would get a nice and smooth coarse phase up to pAmp->fAmpMatchIM. */
2631  if(Mf > pPhase->fPhaseMatchIM && idx>0 && enter == 1){
2632  #if DEBUG == 1
2633  printf("\nExtrapolating intermediate phase out of its range for one point\n");
2634  #endif
2635  phi = IMRPhenomXHM_Inter_Phase_AnsatzInt(Mf, &powers_of_Mf, pWFHM, pPhase);
2636  phi = phi + pPhase->deltaphiLM;
2637  //phi = phi+2.*LAL_PI*round((phiprevious-phi)*twopi_m1);
2638  enter = 0;
2639  }
2640  //phiprevious = phi;
2641  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2642  ((*phaselm)->data->data)[idx+offset] = phi;
2643  }
2644  }
2645  }
2646  }
2647  else{
2648  /* Loop over frequencies to generate waveform */
2649  for (UINT4 idx = 0; idx < freqs->length; idx++)
2650  {
2651  REAL8 Mf = Msec * freqs->data[idx];
2652  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2653  if(initial_status != XLAL_SUCCESS)
2654  {
2655  status = initial_status;
2656  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2657  }
2658  else
2659  {
2660  phi = IMRPhenomXHM_Phase_noModeMixing(&powers_of_Mf, pPhase, pWFHM, pWF);
2661  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2662  ((*phaselm)->data->data)[idx+offset] = phi;
2663  }
2664  }
2665  }
2666  }
2667  /* Free allocated memory */
2668  XLALDestroyREAL8Sequence(freqs);
2669 
2670  return status;
2671 }
2672 
2673 
2674 /* Ringdown phase ansatz evaluated in an input frequency array */
2676  REAL8FrequencySeries **phaselm, /**<[out] phase of hlm mode **/
2677  const REAL8Sequence *freqs_In, /**< Frequency array to evaluate model or fmin, fmax **/
2678  IMRPhenomXWaveformStruct *pWF, /**< Structure of the 22 mode **/
2679  IMRPhenomXHMWaveformStruct *pWFHM, /**< waveform parameters lm mode */
2680  IMRPhenomXHMPhaseCoefficients *pPhase /**< Phase coefficients 22 */
2681 )
2682 {
2683  #if DEBUG == 1
2684  printf("\n **** IMRPhenomXHM_PhaseMixing **** \n");
2685  #endif
2686 
2687  /* Set LIGOTimeGPS */
2688  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
2689 
2690  int status = 0;
2691  REAL8Sequence *freqs;
2692  UINT4 offset = SetupWFArraysReal(&freqs, phaselm, freqs_In, pWF, ligotimegps_zero);
2693 
2694  #if DEBUG == 1
2695  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
2696  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
2697  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
2698  #endif
2699 
2700  if(pWFHM->Ampzero==0){
2701  IMRPhenomX_UsefulPowers powers_of_Mf;
2702  UINT4 initial_status = XLAL_SUCCESS;
2703  REAL8 Msec = pWF->M_sec;
2704  REAL8 phi;
2705 
2706  /* Loop over frequencies to generate waveform */
2707  for (UINT4 idx = 0; idx < freqs->length; idx++)
2708  {
2709  REAL8 Mf = Msec * freqs->data[idx];
2710  initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
2711  if(initial_status != XLAL_SUCCESS)
2712  {
2713  status = initial_status;
2714  XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
2715  }
2716  else
2717  {
2718  phi = IMRPhenomXHM_RD_Phase_AnsatzInt(Mf, &powers_of_Mf, pWFHM, pPhase);
2719  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
2720  ((*phaselm)->data->data)[idx+offset] = phi;
2721  }
2722  }
2723  }
2724  /* Free allocated memory */
2725  XLALDestroyREAL8Sequence(freqs);
2726 
2727  return status;
2728 }
2729 
2730 /* Log function */
2731 static double logbase(double base, double x) {
2732  return (log(x) / log(base));
2733 }
2734 
2735 /* Right hand of eq. 2.27 in arXiv:2001.10897. */
2736 static double deltaF_mergerBin(REAL8 fdamp, REAL8 alpha4, REAL8 abserror)
2737 {
2738  double aux = sqrt(sqrt(3.)*3);
2739  return 4. * fdamp * sqrt(abserror/fabs(alpha4)) / aux;
2740 }
2741 
2742 /* Correspond to eqs. 2.28 and 2.31 in arXiv:2001.10897 */
2743 static double deltaF_ringdownBin(REAL8 fdamp, REAL8 alpha4, REAL8 LAMBDA, REAL8 abserror){
2744  double dfphase = 5*fdamp*sqrt(abserror*0.5/fabs(alpha4));
2745  double dfamp = sqrt(2*abserror)/fabs(LAMBDA);
2746  if (dfphase <= dfamp){
2747  return dfphase;
2748  }
2749  else{
2750  return dfamp;
2751  }
2752 }
2753 
2754 // static double deltaF_ringdownBinAmp(REAL8 fdamp, REAL8 lambda, REAL8 sigma, REAL8 relerror){
2755 // return sqrt(sqrt(24.*relerror))*sigma*fdamp/lambda;
2756 // }
#define LALFree(p)
int XLALSimNRTunedTidesFDTidalPhaseFrequencySeries(const REAL8Sequence *phi_tidal, const REAL8Sequence *amp_tidal, const REAL8Sequence *planck_taper, const REAL8Sequence *fHz, REAL8 m1_SI, REAL8 m2_SI, REAL8 lambda1, REAL8 lambda2, NRTidal_version_type NRTidal_version)
Function to call the frequency domain tidal correction over an array of input frequencies.
double XLALSimNRTunedTidesMergerFrequency(const REAL8 mtot_MSUN, const REAL8 kappa2T, const REAL8 q)
compute the merger frequency of a BNS system.
static size_t NextPow2(const size_t n)
static double fdamp(double eta, double chi1, double chi2, double finspin)
fdamp is the complex part of the ringdown frequency 1508.07250 figure 9
IMRPhenomX_UsefulPowers powers_of_lalpi
int IMRPhenomXASGenerateFD(COMPLEX16FrequencySeries **htilde22, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, LALDict *lalParams)
#define DEBUG
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)
NRTidal_version_type IMRPhenomX_SetTidalVersion(LALDict *lalParams)
double IMRPhenomX_TimeShift_22(IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
REAL8 IMRPhenomX_TidalPhaseDerivative(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase, NRTidal_version_type NRTidal_version)
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)
void IMRPhenomXGetTidalPhaseCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase, NRTidal_version_type NRTidal_version)
REAL8 IMRPhenomX_TidalPhase(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase, NRTidal_version_type NRTidal_version)
int IMRPhenomXGetPhaseCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
double IMRPhenomX_dPhase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
double IMRPhenomX_Amplitude_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp, IMRPhenomXWaveformStruct *pWF)
#define MBAND
IMRPhenomX_UsefulPowers powers_of_lalpiHM
static double IMRPhenomXHM_Inter_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase)
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)
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_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)
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 deltaF_ringdownBin(REAL8 fdamp, REAL8 alpha4, REAL8 LAMBDA, REAL8 abserror)
static int interpolateAmplitudeMixing(double *fineAmp, double *fineAmpSS, double coarsefreqs[], double coarsefreqsSS[], double coarseAmp[], double coarseAmpSS[], double finefreqs[], int lengthCoarse, int lengthCoarseSS, int lengthFine, int sphericalfinecount, int sphericalfinecountMax, int ampinterpolorder)
INT4 XLALSimIMRPhenomXMultibandingGrid(REAL8 fstartIn, REAL8 fend, REAL8 MfLorentzianEnd, REAL8 Mfmax, REAL8 evaldMf, REAL8 dfpower, REAL8 dfcoefficient, IMRPhenomXMultiBandingGridStruct *allGrids, REAL8 dfmerger, REAL8 dfringdown)
INT4 deltaF_MergerRingdown(REAL8 *dfmerger, REAL8 *dfringdown, REAL8 resTest, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase)
static double logbase(double base, double x)
static int IMRPhenomXHM_AmplitudeMixing(REAL8FrequencySeries **amplm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp, UNUSED IMRPhenomXHMPhaseCoefficients *pPhase)
static int interpolateAmplitude(double *fineAmp, double coarsefreqs[], double coarseAmp[], double finefreqs[], int lengthCoarse, int lengthFine, int ampinterpolorder)
static int IMRPhenomXHM_PhaseMixing(REAL8FrequencySeries **phaselm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase)
static int SetupWFArraysReal(REAL8Sequence **freqs, REAL8FrequencySeries **amphase, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, LIGOTimeGPS ligotimegps_zero)
IMRPhenomXMultiBandingGridStruct XLALSimIMRPhenomXGridComp(REAL8 fSTART, REAL8 fEND, REAL8 mydf)
static double deltaF_mergerBin(REAL8 fdamp, REAL8 alpha4, REAL8 abserror)
static int IMRPhenomXHM_Amplitude(REAL8FrequencySeries **amplm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase)
Functions to compute coarse amplitude and phase.
static int IMRPhenomXHM_Phase(REAL8FrequencySeries **phaselm, const REAL8Sequence *freqs_In, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase)
int IMRPhenomXHMMultiBandOneModeMixing(COMPLEX16FrequencySeries **htildelm, COMPLEX16FrequencySeries *htilde22, IMRPhenomXWaveformStruct *pWF, UINT4 ell, UINT4 emm, LALDict *lalParams)
int IMRPhenomXHMMultiBandOneMode(COMPLEX16FrequencySeries **htildelm, IMRPhenomXWaveformStruct *pWF, UINT4 ell, UINT4 emm, LALDict *lalParams)
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)
REAL8 XLALSimIMRPhenomXUtilsHztoMf(REAL8 fHz, REAL8 Mtot_Msun)
Convert from frequency in Hz to geometric frequency.
REAL8 XLALSimIMRPhenomXUtilsMftoHz(REAL8 Mf, REAL8 Mtot_Msun)
Convert from geometric frequency to Hz.
REAL8 XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(LALDict *params)
INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMAmpInterpolMB(LALDict *params)
#define fprintf
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
const double Q
sigmaKerr data[0]
REAL8FrequencySeries * XLALCreateREAL8FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
COMPLEX16FrequencySeries * XLALResizeCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series, int first, size_t length)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALDestroyREAL8FrequencySeries(REAL8FrequencySeries *series)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_PI_4
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
NRTidal_version_type
Definition: LALSimIMR.h:80
@ NoNRT_V
special case for PhenomPv2 BBH baseline
Definition: LALSimIMR.h:85
@ NRTidalv2_V
version NRTidalv2: https://arxiv.org/abs/1905.06011
Definition: LALSimIMR.h:82
int XLALSimIMRPhenomXHMMultiBandOneMode(COMPLEX16FrequencySeries **htildelm, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emmIn, 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.
int XLALSimIMRPhenomXHMMultiBandOneModeMixing(COMPLEX16FrequencySeries **htildelm, COMPLEX16FrequencySeries *htilde22, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, UINT4 ell, INT4 emmIn, 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.
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
const LALUnit lalStrainUnit
const LALUnit lalSecondUnit
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
#define XLAL_PRINT_INFO(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_WARNING(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list x
string status
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8 RDCoefficient[N_MAX_COEFFICIENTS_AMPLITUDE_RING]
REAL8 RDCoefficient[N_MAX_COEFFICIENTS_PHASE_RING+3]
REAL8Sequence * data
REAL8 * data
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23