LALSimulation  5.4.0.1-fe68b98
LALSimIMRPhenomTHM.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Hector Estelles
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with with program; see the file COPYING. If not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  */
19 
20 /* Standard LAL */
21 #include <lal/Sequence.h>
22 #include <lal/Date.h>
23 #include <lal/Units.h>
24 #include <lal/XLALError.h>
25 
26 /* LAL datatypes and constants */
27 #include <lal/LALDatatypes.h>
28 #include <lal/LALStdlib.h>
29 #include <lal/LALConstants.h>
30 
31 /* Time series, frequency series and spherical harmonics */
32 #include <lal/TimeSeries.h>
33 #include <lal/TimeFreqFFT.h>
34 #include <lal/SphericalHarmonics.h>
35 #include <lal/LALSimSphHarmMode.h>
36 #include <lal/FrequencySeries.h>
37 
38 /* LALSimulation */
39 #include <lal/LALSimIMR.h>
40 #include <lal/LALSimInspiral.h>
41 
42 /* Standard C */
43 #include <math.h>
44 #include <complex.h>
45 #include <stdbool.h>
46 
47 /* Link IMRPhenomTHM routines */
50 #include "LALSimIMRPhenomTHM.h"
51 
52 /* *********** ALIGNED SPIN IMR MULTIMODE PHENOMENOLOGICAL TIME DOMAIN WAVEFORM MODEL: IMRPhenomTHM *********** */
53 
54 /* EXTERNAL ROUTINES */
55 
56 /**
57  * @addtogroup LALSimIMRPhenomT_c
58  * @brief Routines to produce IMRPhenomT-family of phenomenological inspiral-merger-ringdown waveforms.
59  * These are time-domain models for compact binaries at comparable and extreme mass ratios, tuned to numerical-relativity simulations.
60  *
61  * - IMRPhenomT: model for the 22 mode of non-precessing binaries. Model concept together with precession was published in https://arxiv.org/abs/2004.08302.
62  * Although an updated version together with the higher mode extension is under the DCC: https://dcc.ligo.org/LIGO-P2000524.
63  * - IMRPhenomTHM: model with subdominant harmonics for non-precessing binaries. DCC link: https://dcc.ligo.org/LIGO-P2000524.
64  * - IMRPhenomTP: model for precessing binaries. Twisted-up version of IMRPhenomT. Original concept: https://arxiv.org/abs/2004.08302.
65  * - IMRPhenomTPHM: model for precessing binaries including higher harmonics. Twisted-up version of IMRPhenomTHM.
66  *
67  *
68  * @review IMRPhenomT(HM) has been review by Maria Haney, Jacob Lange, Jonathan Thompson and Eleanor Hamilton. Review wiki: https://git.ligo.org/waveforms/reviews/phenomt/-/wikis/home.
69  * IMRPhenomTP(HM) are being reviewed by the same team under the same wiki page.
70  *
71  *
72  */
73 
74  /**
75  * @addtogroup LALSimIMRPhenomT_c
76  * @{
77  *
78  * @name Routines for IMRPhenomT
79  * @{
80  *
81  * @author Héctor Estellés
82  *
83  * @brief C code for the IMRPhenomT phenomenological waveform model
84  *
85  *
86  *
87  */
88 
89 /**
90  * Routine to compute time domain polarisations for IMRPhenomT model. It returns two real time series for the plus and the cross polarisations,
91  * constructed with the modes (l,m)=(2,2), (2,-2).
92  */
93 
95  REAL8TimeSeries **hp, /**< [out] TD waveform for plus polarisation */
96  REAL8TimeSeries **hc, /**< [out] TD waveform for cross polarisation */
97  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
98  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
99  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
100  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
101  REAL8 distance, /**< Luminosity distance (m) */
102  REAL8 inclination, /**< inclination of source (rad) */
103  REAL8 deltaT, /**< sampling interval (s) */
104  REAL8 fmin, /**< starting GW frequency (Hz) */
105  REAL8 fRef, /**< reference GW frequency (Hz) */
106  REAL8 phiRef, /**< reference orbital phase (rad) */
107  LALDict *lalParams /**< LAL dictionary containing accessory parameters */
108  )
109 {
110 
111  INT4 status;
112 
113  /* Use an auxiliar laldict to not overwrite the input argument */
114  LALDict *lalParams_aux;
115  /* setup mode array */
116  if (lalParams == NULL)
117  {
118  lalParams_aux = XLALCreateDict();
119  }
120  else{
121  lalParams_aux = XLALDictDuplicate(lalParams);
122  }
123  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
124 
125  /* Check if an mode array is NULL and then populate it with the (2,2) and (2,-2) modes. */
126  if(ModeArray==NULL)
127  {
128  ModeArray = XLALSimInspiralCreateModeArray();
129  /* Activate (2,2) and (2,-2) modes*/
130  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 2);
131  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
132  /* Insert ModeArray into lalParams */
133  XLALSimInspiralWaveformParamsInsertModeArray(lalParams_aux, ModeArray);
134  XLALDestroyValue(ModeArray);
135  }
136 
137  UINT4 only22 = 1; /* Internal flag for mode array check */
138 
139  /* Compute modes dominant modes */
140  SphHarmTimeSeries *hlms = NULL;
141  status = LALSimIMRPhenomTHM_Modes(&hlms, m1_SI, m2_SI, chi1L, chi2L, distance, deltaT, fmin, fRef, phiRef, lalParams_aux, only22);
142  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: Internal function LALSimIMRPhenomTHM_Modes has failed producing the modes.");
143 
144  /* Obtain length and epoch from modes (they are the same for all the modes) */
145  INT4 length = hlms->mode->data->length;
146  LIGOTimeGPS epoch = hlms->mode->epoch;
147 
148  /* Auxiliary time series for setting the polarisations to zero */
149  REAL8TimeSeries *hplus = XLALCreateREAL8TimeSeries ("hplus", &epoch, 0.0, deltaT, &lalStrainUnit,length);
150  REAL8TimeSeries *hcross = XLALCreateREAL8TimeSeries ("hcross", &epoch, 0.0, deltaT, &lalStrainUnit,length);
151  memset( hplus->data->data, 0, hplus->data->length * sizeof(REAL8) );
152  memset( hcross->data->data, 0, hcross->data->length * sizeof(REAL8) );
153 
154  /* Add the modes to the polarisations using lalsim routines.
155  Negative modes are explicitely passed, instead of using the symmetry flag */
156 
157  SphHarmTimeSeries *hlms_temp = hlms;
158  while ( hlms_temp )
159  {
160  XLALSimAddMode(hplus, hcross, hlms_temp->mode, inclination, LAL_PI/2. - phiRef, hlms_temp->l, hlms_temp->m, 0);
161  hlms_temp = hlms_temp->next;
162  }
163 
164  /* Point the output pointers to the relevant time series */
165  (*hp) = hplus;
166  (*hc) = hcross;
167 
168  /* Destroy intermediate time series */
170  XLALDestroySphHarmTimeSeries(hlms_temp);
171 
172  /* Destroy lalParams_aux. */
173  XLALDestroyDict(lalParams_aux);
174 
175 
176  return status;
177 }
178 
179 /** @} */
180 /**
181 * @name Routines for IMRPhenomTHM
182 * @{
183 *
184 * @author Héctor Estellés
185 *
186 * @brief C code for the IMRPhenomTHM phenomenological waveform model
187 *
188 * IMRPhenomTHM is a phenomenological model in the time domain for aligned-spin binary black hole coalescences, calibrated to Numerical Relativity simulations for
189 * comparable mass ratio and Teukolsky waveforms for extreme mass ratio. The model produces IMR waveforms for the Spin-Weighted Spherical Harmonic modes (l,m)=(2,2), (2,1), (3,3), (4,4) and (5,5),
190 * obtaining the corresponding negative m modes by symmetry.
191 *
192 * For selecting a particular list of modes to be returned or to be employed in the polarisations construction, the user can follow the usual procedure:
193 * - Create a mode array object with lalsimulation.SimInspiralCreateModeArray
194 * - Activate the desired modes with lalsim.SimInspiralModeArrayActivateMode
195 * - Insert the mode array into a LAL dictionary with lalsim.SimInspiralWaveformParamsInsertModeArray
196 * - Pass the LAL ditionary to ChooseTDWaveform or ChooseTDModes.
197 * For a user specified mode array, only the implemented modes in the model will be computed.
198 *
199 * User option for selecting (2,2) phase and frequency reconstruction through LAL parameter PhenomTHMInspiralVersion. Default (0) will reconstruct with
200 * only 1 inspiral region modelled by TaylorT3 with the merger time parameter tt0 set to 0 and additional higher order terms.
201 * Non-default will provide an early inspiral region for imensionless PN time parameter theta<0.33, constructed with pure TaylorT3 (without higher orders) with tt0 calibrated
202 * across parameter space. Both options maintained for code historical reasons, but not clear benefit from non-default option was found.
203 *
204 * Model has been calibrated to 531 BBH non-precessing NR simulations from the
205 * last release of the SXS Catalog (https://iopscience.iop.org/article/10.1088/1361-6382/ab34e2), additional BAM NR simulations at q=4, q=8 and q=18, and numerical Teukolsky waveforms placed at q=200 and q=1000. Calibration procedure has followed the
206 * hierarchical data-driven fitting approach (Xisco Jimenez-Forteza et al https://arxiv.org/abs/1611.00332) using the symmetric mass ratio eta, dimensionless effective spin Shat=(m1^2*chi1+m2^2*chi2)/(m1^2+m2^2)
207 * and spin difference dchi=chi1-chi2. Supplementary material for the fits of the various collocation points
208 * and phenomenological coefficients is available at https://git.ligo.org/waveforms/reviews/phenomt/-/tree/master/SupplementaryMaterial/Fits3DPhenomTHM.
209 *
210 */
211 
212 /**
213  * Routine to compute time domain polarisations for IMRPhenomTHM model. It returns two real time series for the plus and the cross polarisations,
214  * constructed with the modes specified in lalParams that correspond to included modes in the model: (l,m)=(2,2), (2,1), (3,3), (4,4) and (5,5) and
215  * the corresponding negative m modes.
216  */
217 
219  REAL8TimeSeries **hp, /**< [out] TD waveform for plus polarisation */
220  REAL8TimeSeries **hc, /**< [out] TD waveform for cross polarisation */
221  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
222  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
223  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
224  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
225  REAL8 distance, /**< Luminosity distance (m) */
226  REAL8 inclination, /**< inclination of source (rad) */
227  REAL8 deltaT, /**< sampling interval (s) */
228  REAL8 fmin, /**< starting GW frequency (Hz) */
229  REAL8 fRef, /**< reference GW frequency (Hz) */
230  REAL8 phiRef, /**< reference orbital phase (rad) */
231  LALDict *lalParams /**< LAL dictionary containing accessory parameters */
232  )
233 {
234 
235  int status;
236 
237  /* Sanity checks pointers. */
238  XLAL_CHECK(NULL != hp, XLAL_EFAULT);
239  XLAL_CHECK(NULL != hc, XLAL_EFAULT);
240  XLAL_CHECK(*hp == NULL, XLAL_EFAULT);
241  XLAL_CHECK(*hc == NULL, XLAL_EFAULT);
242 
243  UINT4 only22 = 0; /* Internal flag for mode array check */
244 
245  /* Compute modes (if a subset of modes is desired, it should be passed through lalParams) */
246  SphHarmTimeSeries *hlms = NULL;
247  status = LALSimIMRPhenomTHM_Modes(&hlms, m1_SI, m2_SI, chi1L, chi2L, distance, deltaT, fmin, fRef, phiRef, lalParams, only22);
248  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: Internal function LALSimIMRPhenomTHM_Modes has failed producing the modes.");
249 
250  /* Obtain length and epoch from modes (they are the same for all the modes) */
251  INT4 length = hlms->mode->data->length;
252  LIGOTimeGPS epoch = hlms->mode->epoch;
253 
254  /* Auxiliary time series for setting the polarisations to zero */
255  REAL8TimeSeries *hplus = XLALCreateREAL8TimeSeries ("hplus", &epoch, 0.0, deltaT, &lalStrainUnit,length);
256  REAL8TimeSeries *hcross = XLALCreateREAL8TimeSeries ("hcross", &epoch, 0.0, deltaT, &lalStrainUnit,length);
257  memset( hplus->data->data, 0, hplus->data->length * sizeof(REAL8) );
258  memset( hcross->data->data, 0, hcross->data->length * sizeof(REAL8) );
259 
260  /* Add the modes to the polarisations using lalsim routines.
261  Negative modes are explicitely passed, instead of using the symmetry flag */
262 
263  SphHarmTimeSeries *hlms_temp = hlms;
264  while ( hlms_temp )
265  {
266  XLALSimAddMode(hplus, hcross, hlms_temp->mode, inclination, LAL_PI/2. - phiRef, hlms_temp->l, hlms_temp->m, 0);
267  hlms_temp = hlms_temp->next;
268  }
269 
270  /* Point the output pointers to the relevant time series */
271  (*hp) = hplus;
272  (*hc) = hcross;
273 
274  /* Destroy intermediate time series */
276  XLALDestroySphHarmTimeSeries(hlms_temp);
277 
278  return status;
279 }
280 
281 /**
282  * Routine to compute time domain Spin-Weighted Spherical Harmonic modes for IMRPhenomTHM model. It returns a SphHarmTimeSeries structure, with complex time series for each mode generated.
283  */
284 
286  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
287  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
288  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
289  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
290  REAL8 distance, /**< Luminosity distance (m) */
291  REAL8 deltaT, /**< sampling interval (s) */
292  REAL8 fmin, /**< starting GW frequency (Hz) */
293  REAL8 fRef, /**< reference GW frequency (Hz) */
294  REAL8 phiRef, /**< reference orbital phase (rad) */
295  LALDict *lalParams /**< LAL dictionary containing accessory parameters */
296  )
297 {
298 
299  INT4 status;
300 
301  UINT4 only22 = 0; /* Internal flag for mode array check */
302 
303  /* Compute modes (if a subset of modes is desired, it should be passed through lalParams */
304  SphHarmTimeSeries *hlms = NULL;
305  status = LALSimIMRPhenomTHM_Modes(&hlms, m1_SI, m2_SI, chi1L, chi2L, distance, deltaT, fmin, fRef, phiRef, lalParams, only22);
306  XLAL_CHECK_NULL(status != XLAL_FAILURE, XLAL_EFUNC, "Error: Internal function LALSimIMRPhenomTHM_Modes has failed producing the modes.");
307 
308  return hlms;
309 }
310 
311 /** @} */
312 /** @} */
313 
314 /*
315  * Internal routine to compute time domain Spin-Weighted Spherical Harmonic modes for IMRPhenomTHM model. It returns a SphHarmTimeSeries structure, with complex time series for each mode generated.
316  */
317 
319  SphHarmTimeSeries **hlms, /**< [out] Time domain modes */
320  REAL8 m1_SI, /**< Mass of companion 1 (kg) */
321  REAL8 m2_SI, /**< Mass of companion 2 (kg) */
322  REAL8 chi1L, /**< Dimensionless aligned spin of companion 1 */
323  REAL8 chi2L, /**< Dimensionless aligned spin of companion 2 */
324  REAL8 distance, /**< Luminosity distance (m) */
325  REAL8 deltaT, /**< sampling interval (s) */
326  REAL8 fmin, /**< starting GW frequency (Hz) */
327  REAL8 fRef, /**< reference GW frequency (Hz) */
328  REAL8 phiRef, /**< reference orbital phase (rad) */
329  LALDict *lalParams, /**< LAL dictionary containing accessory parameters */
330  UINT4 only22 /** Internal flag for mode array check */
331  )
332 {
333 
334  /* Pointers sanity check */
335  XLAL_CHECK(NULL != hlms, XLAL_EFAULT);
336  XLAL_CHECK(*hlms == NULL, XLAL_EFAULT);
337 
338  /* Sanity checks */
339  if(fRef < 0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n"); }
340  if(deltaT <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n"); }
341  if(m1_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n"); }
342  if(m2_SI <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n"); }
343  if(fmin <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n"); }
344  if(distance <= 0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n"); }
345 
346  /* Check that the modes chosen are available for the model. Included ones are (2,2), (2,1), (3,3), (4,4) and (5,5) and corresponding negative m ones.
347  If only22=1, then checks that only (2,2) (2,-2) are included for dominant mode approximant */
348 
349  if(only22==0)
350  {
351  XLAL_CHECK(check_input_mode_array_THM(lalParams) == XLAL_SUCCESS, XLAL_EFAULT, "Not available mode chosen.\n");
352  }
353  else if(only22==1)
354  {
355  XLAL_CHECK(check_input_mode_array_22_THM(lalParams) == XLAL_SUCCESS, XLAL_EFAULT, "Not available mode chosen.\n");
356  }
357 
358  /*
359  Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
360  - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
361  - For 200 > mass ratio > 20 and spins <= 0.9: print a warning message that model can be pathological.
362  - For mass ratios > 200: throw a hard error that model is not valid.
363  - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
364 
365  */
366  REAL8 mass_ratio;
367  if(m1_SI > m2_SI)
368  {
369  mass_ratio = m1_SI / m2_SI;
370  }
371  else
372  {
373  mass_ratio = m2_SI / m1_SI;
374  }
375  if(mass_ratio > 20.0 && chi1L < 0.9 && m2_SI/LAL_MSUN_SI >= 0.5 ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
376  if(mass_ratio > 20.0 && (chi1L >= 0.9 || m2_SI/LAL_MSUN_SI < 0.5) ) { XLAL_PRINT_INFO("Warning: Model can be pathological at these parameters."); }
377  if(mass_ratio > 200. && fabs(mass_ratio - 200) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 200."); } // The 1e-12 is to avoid rounding errors
378  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
379 
380  INT4 status;
381 
382  /* Use an auxiliar laldict to not overwrite the input argument */
383  LALDict *lalParams_aux;
384  /* setup mode array */
385  if (lalParams == NULL)
386  {
387  lalParams_aux = XLALCreateDict();
388  }
389  else{
390  lalParams_aux = XLALDictDuplicate(lalParams);
391  }
392  lalParams_aux = IMRPhenomTHM_setup_mode_array(lalParams_aux);
393  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams_aux);
394 
395  /* Initialise waveform struct and phase/frequency struct for the 22, needed for any mode */
396 
398  pWF = XLALMalloc(sizeof(IMRPhenomTWaveformStruct));
399  status = IMRPhenomTSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, distance, deltaT, fmin, fRef, phiRef, lalParams_aux);
400  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: Internal function IMRPhenomTSetWaveformVariables has failed.");
401 
402 
403  IMRPhenomTPhase22Struct *pPhase;
404  pPhase = XLALMalloc(sizeof(IMRPhenomTPhase22Struct));
406  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: Internal function IMRPhenomTSetPhase22Coefficients has failed.");
407 
408  /* Length of the required sequence and length of the different inspiral regions of the 22 phase. */
409  size_t length = pPhase->wflength;
410  size_t length_insp_early = pPhase->wflength_insp_early;
411  size_t length_insp_late = pPhase->wflength_insp_late;
412  size_t length_insp = length_insp_early + length_insp_late;
413 
414  /*Initialize time */
415  REAL8 t, thetabar, theta, w22, ph22;
416  REAL8 factheta = pow(5.0,1./8);
417 
418  /* Initialize REAL8 sequences for storing the phase, frequency and PN expansion parameter x of the 22 */
419  REAL8Sequence *phi22 = NULL;
420  REAL8Sequence *xorb = NULL;
421  xorb = XLALCreateREAL8Sequence(length);
422  phi22 = XLALCreateREAL8Sequence(length);
423 
424 
425  /* Compute 22 phase and x=(0.5*omega_22)^(2/3), needed for all modes.
426  Depending on the inspiral region, theta is defined with a fitted t0 parameter or with t0=0. */
427 
428  if(pWF->inspVersion!=0) // If reconstruction is non-default, this will compute frequency, phase and PN expansion parameter x from TaylorT3 with fitted t0 for the early inspiral region-
429  {
430  for(UINT4 jdx = 0; jdx < length_insp_early; jdx++)
431  {
432  t = pPhase->tmin + jdx*pWF->dtM;
433 
434  thetabar = pow(pWF->eta*(pPhase->tt0-t),-1./8);
435 
436  theta = factheta*thetabar;
437 
438  w22 = IMRPhenomTomega22(t, theta, pWF, pPhase);
439  xorb->data[jdx] = pow(0.5*w22,2./3);
440 
441  ph22 = IMRPhenomTPhase22(t, thetabar, pWF, pPhase);
442 
443  phi22->data[jdx] = ph22;
444  }
445 
446  for(UINT4 jdx = length_insp_early; jdx < length_insp; jdx++) // For times later than the early-late inspiral boundary, it computes phase, frequency and x with the extended TaylorT3 (with tt0=0)
447  {
448  t = pPhase->tmin + jdx*pWF->dtM;
449 
450  thetabar = pow(-pWF->eta*t,-1./8);
451 
452  theta = factheta*thetabar;
453 
454  w22 = IMRPhenomTomega22(t, theta, pWF, pPhase);
455  xorb->data[jdx] = pow(0.5*w22,2./3);
456 
457  ph22 = IMRPhenomTPhase22(t, thetabar, pWF, pPhase);
458 
459  phi22->data[jdx] = ph22;
460  }
461  }
462 
463  else // If default reconstruction, only one inspiral region with extended TaylorT3 (with tt0=0) is employed up to the inspiral-merger boundary time
464  {
465  for(UINT4 jdx = 0; jdx < length_insp; jdx++)
466  {
467  t = pPhase->tmin + jdx*pWF->dtM;
468 
469  thetabar = pow(-pWF->eta*t,-1./8);
470 
471  theta = factheta*thetabar;
472 
473  w22 = IMRPhenomTomega22(t, theta, pWF, pPhase);
474  xorb->data[jdx] = pow(0.5*w22,2./3);
475 
476  ph22 = IMRPhenomTPhase22(t, thetabar, pWF, pPhase);
477 
478  phi22->data[jdx] = ph22;
479  }
480 
481  }
482 
483  /* During the 22 phase merger region, phase and x are also computed because the higher modes end the inspiral at a fixed time,
484  which can occur later than the end of the 22 inspiral. */
485  for(UINT4 jdx = length_insp; jdx < length; jdx++)
486  {
487  t = pPhase->tmin + jdx*pWF->dtM;
488 
489  w22 = IMRPhenomTomega22(t, 0.0, pWF, pPhase);
490  xorb->data[jdx] = pow(0.5*w22,2./3);
491 
492  ph22 = IMRPhenomTPhase22(t, 0.0, pWF, pPhase);
493 
494  phi22->data[jdx] = ph22;
495  }
496 
497  /***** Loop over modes ******/
498 
499  INT4 posMode, negMode;
500 
501  for (UINT4 ell = 2; ell <= 5; ell++)
502  {
503  for (UINT4 emm = 1; emm <= ell; emm++)
504  { /* Loop over only positive m is intentional.*/
505 
506  posMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm);
507  negMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -emm);
508  if ( posMode != 1 && negMode != 1)
509  { /* skip mode */
510  continue;
511  } /* else: generate mode */
512 
513  COMPLEX16TimeSeries *tmp_mode = NULL;
514 
515  status = LALSimIMRPhenomTHM_OneMode(&tmp_mode, pWF, pPhase, phi22, xorb, ell, emm);
516 
517  if(posMode==1) /* Modes are generated only for positive m. If positive m is requested, simply add to the SphHarmTimeSeries structure */
518  {
519  *hlms = XLALSphHarmTimeSeriesAddMode(*hlms, tmp_mode, ell, emm);
520  }
521 
522  if(negMode==1) /* If negative m is requested, transform from positive m mode using symmetry property for aligned spin systems */
523  {
524  for(UINT4 jdx = 0; jdx < length; jdx++)
525  {
526  ((*tmp_mode).data)->data[jdx] = pow(-1,ell)*conj(((*tmp_mode).data)->data[jdx]);
527  }
528  *hlms = XLALSphHarmTimeSeriesAddMode(*hlms, tmp_mode, ell, -emm);
529  }
530 
531  XLALDestroyCOMPLEX16TimeSeries(tmp_mode); /* Destroy temporary structure once the desired mode is added */
532  }
533 
534  }
535 
536  /*Free structures and destroy sequences and dict */
537  XLALDestroyValue(ModeArray);
538  LALFree(pPhase);
539  LALFree(pWF);
540 
542 
544 
545  XLALDestroyDict(lalParams_aux);
546 
547  return status;
548 }
549 
550 /* Internal function for generating one mode. See section II of PhenomTHM paper for details on mode construction: https://dcc.ligo.org/DocDB/0172/P2000524/001/PhenomTHM_SH-3.pdf */
551 
553  COMPLEX16TimeSeries **hlm, /**< [out] Time domain waveform of the requested (l,m) mode */
554  IMRPhenomTWaveformStruct *pWF, /**< Waveform structure */
555  IMRPhenomTPhase22Struct *pPhase, /**< 22 phase and frequency structure */
556  REAL8Sequence *phase22, /**< Values of the 22 phase for the waveform time array */
557  REAL8Sequence *xorb, /**< Values of the 22 frequency for the waveform time array */
558  UINT4 ell, /**< l value of the requested mode */
559  UINT4 emm /**< m value of the requested mode */
560  )
561 {
562 
563  /* Sanity checks were performed in XLALSimIMRPhenomTHM_Modes, from which this function is called. */
564  UINT4 status;
565 
566  /*Length of the required sequence. Read it from 22 phase structure. */
567  size_t length = pPhase->wflength;
568 
569  /*Declare time, amplitude and phase */
570  REAL8 t;
571 
572  COMPLEX16 amplm;
573  UNUSED REAL8 philm;
574 
575  /* Set LIGOTimeGPS */
576  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
577  XLALGPSAdd(&ligotimegps_zero, pPhase->tminSec); /* By model construction, this implies that the 22 amplitude peaks exactly at t=0 */
578 
579  /* Initialize time series for mode */
580  *hlm = XLALCreateCOMPLEX16TimeSeries("hlm: TD waveform",&ligotimegps_zero,0.0,pWF->deltaT,&lalStrainUnit,length);
581 
582  /* Initialize variables for 22 phase and frequency */
583  REAL8 x = 0.0;
584  UNUSED REAL8 phi22 = 0.0;
585  UNUSED COMPLEX16 expPhi;
586  COMPLEX16 wf;
587 
588  /* phiref0 is the value of the 22 phase at the reference frequency, which will be substracted in order to impose the chosen orbital reference phase */
589  REAL8 thetabarRef = pow(-pPhase->tRef*pWF->eta,-1./8);
590  REAL8 phiref0 = IMRPhenomTPhase22(pPhase->tRef, thetabarRef, pWF, pPhase);
591 
592  IMRPhenomTHMAmpStruct *pAmplm;
593  pAmplm = XLALMalloc(sizeof(IMRPhenomTHMAmpStruct));
594  status = IMRPhenomTSetHMAmplitudeCoefficients(ell,emm, pAmplm, pPhase, pWF);
595  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomTSetHMAmplitudeCoefficients failed for %d,%d.\n",ell,emm);
596 
597  /* For l=2, m=2 mode, phase already computed. Amplitude is computed in absolute value since we don't want the complex phase contribution in the 22 (frequency is already calibrated in the inspiral) */
598  if(ell==2 && emm==2)
599  {
600  /* Loop over time */
601  /* Mode construction, see equation 2 of THM paper https://dcc.ligo.org/DocDB/0172/P2000524/001/PhenomTHM_SH-3.pdf */
602  for(UINT4 jdx = 0; jdx < length; jdx++)
603  {
604  t = pPhase->tmin + jdx*pWF->dtM;
605  x = (xorb)->data[jdx];
606  amplm = pWF->ampfac*cabs(IMRPhenomTHMAmp(t, x, pAmplm));
607 
608  phi22 = (phase22)->data[jdx] - phiref0;
609  wf = amplm*cexp(-I*phi22);
610 
611  ((*hlm)->data->data)[jdx] = wf;
612  }
613  }
614 
615  else if(emm%2 != 0 && pWF->delta<1E-10 && fabs(pWF->chi1L-pWF->chi2L)<1E-10) // This is for not computing odd modes in the equal BH limit. Instead, they are set to 0 directly.
616  {
617 
618  memset( (*hlm)->data->data, 0.0, (*hlm)->data->length * sizeof(COMPLEX16) );
619 
620  }
621 
622  else // Higher modes
623  {
624  /* Initialize phase struct for desired mode */
625 
626  IMRPhenomTHMPhaseStruct *pPhaselm;
627  pPhaselm = XLALMalloc(sizeof(IMRPhenomTHMPhaseStruct));
628  status = IMRPhenomTSetHMPhaseCoefficients(ell,emm, pPhaselm, pPhase, pAmplm, pWF);
629  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomTSetHMPhaseCoefficients failed for %d,%d.\n",ell,emm);
630 
631  /* Phase offset, as explained in eq 13 of PhenomTHM paper (https://dcc.ligo.org/DocDB/0172/P2000524/001/PhenomTHM_SH-3.pdf). */
632 
633  REAL8 phoff = 0.0; // Constant phase offset employed for rotating PN amplitudes so much of the content is real.
634  if(ell==2 && emm==1)
635  {
636  phoff = 0.5*LAL_PI;
637  }
638  else if(ell==3 && emm==3)
639  {
640  phoff = -0.5*LAL_PI;
641  }
642  else if(ell==5 && emm==5)
643  {
644  phoff = 0.5*LAL_PI;
645  }
646  else if(ell==4 && emm==4)
647  {
648  phoff = LAL_PI;
649  }
650 
651  /* Loop over time */
652  for(UINT4 jdx = 0; jdx < length; jdx++)
653  {
654 
655  t = pPhase->tmin + jdx*pWF->dtM;
656  x = (xorb)->data[jdx]; // 22 frequency, needed for evaluating inspiral amplitude
657  amplm = pWF->ampfac*IMRPhenomTHMAmp(t, x, pAmplm);
658 
659  phi22 = (phase22)->data[jdx]; // 22 phase, needed for rescaling lm inspiral phase
660 
661  philm = IMRPhenomTHMPhase(t, phi22, pPhaselm,pAmplm) - (emm/2.0)*phiref0 - phoff; // Phase construction
662  wf = amplm*cexp(-I*philm); /* Mode construction. Note than amplitude is now complex during the inspiral, which will contribute to the phase of the mode */
663 
664  ((*hlm)->data->data)[jdx] = wf;
665 
666  }
667  LALFree(pPhaselm);
668 
669  }
670 
671  LALFree(pAmplm);
672 
673  return status;
674 }
675 
676 /* Wrapper function for adding higher modes to the ModeArray, almost identical to IMRPhenomXHM_setup_mode_array */
677 
678 LALDict *IMRPhenomTHM_setup_mode_array(LALDict *lalParams)
679 {
680  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
681 
682  /* If the mode array is empty, populate using a default choice of modes */
683  if (ModeArray == NULL)
684  {
685  /* Default behaviour */
686  XLAL_PRINT_INFO("Using default modes for IMRPhenomTHM.\n");
687  ModeArray = XLALSimInspiralCreateModeArray();
688 
689 
690  /* IMRPhenomTHM has the following calibrated modes.*/
691  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 2);
692  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 1);
693  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, 3);
694  XLALSimInspiralModeArrayActivateMode(ModeArray, 4, 4);
695  XLALSimInspiralModeArrayActivateMode(ModeArray, 5, 5);
696  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
697  XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -1);
698  XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -3);
699  XLALSimInspiralModeArrayActivateMode(ModeArray, 4, -4);
700  XLALSimInspiralModeArrayActivateMode(ModeArray, 5, -5);
701 
702  XLALSimInspiralWaveformParamsInsertModeArray(lalParams, ModeArray);
703  }
704  else {XLAL_PRINT_INFO("Using custom modes for PhenomTHM.\n"); }
705  XLALDestroyValue(ModeArray);
706 
707  return lalParams;
708 }
709 
710 /* Function for checking if input mode array has supported modes by the model. Ported from IMRPhenomXHM, with modifications in the supported modes. */
711 INT4 check_input_mode_array_THM(LALDict *lalParams)
712 {
713  UINT4 flagTrue = 0;
714 
715  if(lalParams == NULL) return XLAL_SUCCESS;
716 
717  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
718 
719  if(ModeArray!=NULL)
720  {
721  INT4 larray[5] = {2, 2, 3, 4, 5};
722  INT4 marray[5] = {2, 1, 3, 4, 5};
723 
724  for(INT4 ell=2; ell<=LAL_SIM_L_MAX_MODE_ARRAY; ell++)
725  {
726  for(INT4 emm=0; emm<=ell; emm++)
727  {
728  if(XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm)==1 || XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -1*emm)==1)
729  {
730  for(UINT4 idx=0; idx<5; idx++)
731  {
732  if(ell==larray[idx] && abs(emm)==marray[idx])
733  {
734  flagTrue = 1;
735  }
736  }
737  // If flagTrue !=1 means that the input mode array has a mode that is not supported by the model.
738  if(flagTrue!=1){
739  XLALPrintError ("Mode (%d,%d) is not available by the model.\n", ell, emm);
740  XLALDestroyValue(ModeArray);
741  return XLAL_FAILURE;
742  }
743  flagTrue = 0;
744  }
745  }//End loop over emm
746  }//End loop over ell
747  }//End of if block
748 
749  XLALDestroyValue(ModeArray);
750 
751  return XLAL_SUCCESS;
752 }
753 
754 /* Function for checking if input mode array has supported modes by the model. Ported from IMRPhenomXHM, with modifications in the supported modes. In this cases, for IMRPhenomT, only 22 and 2-2 modes are supported. */
756 {
757  UINT4 flagTrue = 0;
758 
759  if(lalParams == NULL) return XLAL_SUCCESS;
760 
761  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
762 
763  if(ModeArray!=NULL)
764  {
765  for(INT4 ell=2; ell<=LAL_SIM_L_MAX_MODE_ARRAY; ell++)
766  {
767  for(INT4 emm=0; emm<=ell; emm++)
768  {
769  if(XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm)==1 || XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -1*emm)==1)
770  {
771 
772  if(ell==2 && abs(emm)==2)
773  {
774  flagTrue = 1;
775  }
776 
777  // If flagTrue !=1 means that the input mode array has a mode that is not supported by the model.
778  if(flagTrue!=1){
779  XLALPrintError ("Mode (%d,%d) is not available by the model.\n", ell, emm);
780  XLALDestroyValue(ModeArray);
781  return XLAL_FAILURE;
782  }
783  flagTrue = 0;
784  }
785  }//End loop over emm
786  }//End loop over ell
787  }//End of if block
788 
789  XLALDestroyValue(ModeArray);
790 
791  return XLAL_SUCCESS;
792 }
void XLALDestroyDict(LALDict *dict)
LALDict * XLALDictDuplicate(LALDict *old)
LALDict * XLALCreateDict(void)
#define LALFree(p)
INT4 check_input_mode_array_THM(LALDict *lalParams)
int LALSimIMRPhenomTHM_OneMode(COMPLEX16TimeSeries **hlm, IMRPhenomTWaveformStruct *pWF, IMRPhenomTPhase22Struct *pPhase, REAL8Sequence *phase22, REAL8Sequence *xorb, UINT4 ell, UINT4 emm)
INT4 check_input_mode_array_22_THM(LALDict *lalParams)
int LALSimIMRPhenomTHM_Modes(SphHarmTimeSeries **hlms, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 deltaT, REAL8 fmin, REAL8 fRef, REAL8 phiRef, LALDict *lalParams, UINT4 only22)
LALDict * IMRPhenomTHM_setup_mode_array(LALDict *lalParams)
double IMRPhenomTomega22(REAL8 t, REAL8 theta, IMRPhenomTWaveformStruct *pWF, IMRPhenomTPhase22Struct *pPhase)
int IMRPhenomTSetHMAmplitudeCoefficients(int l, int m, IMRPhenomTHMAmpStruct *pAmp, IMRPhenomTPhase22Struct *pPhase, IMRPhenomTWaveformStruct *wf)
COMPLEX16 IMRPhenomTHMAmp(REAL8 t, UNUSED REAL8 x, IMRPhenomTHMAmpStruct *pAmp)
int IMRPhenomTSetPhase22Coefficients(IMRPhenomTPhase22Struct *pPhase, IMRPhenomTWaveformStruct *wf)
double IMRPhenomTHMPhase(REAL8 t, REAL8 phiInsp, IMRPhenomTHMPhaseStruct *pPhaseHM, UNUSED IMRPhenomTHMAmpStruct *pAmpHM)
int IMRPhenomTSetWaveformVariables(IMRPhenomTWaveformStruct *wf, const REAL8 m1_SI, const REAL8 m2_SI, const REAL8 chi1L_In, const REAL8 chi2L_In, const REAL8 distance, const REAL8 deltaT, const REAL8 fmin, const REAL8 fRef, const REAL8 phiRef, LALDict *lalParams)
int IMRPhenomTSetHMPhaseCoefficients(int l, int m, IMRPhenomTHMPhaseStruct *pPhaseHM, IMRPhenomTPhase22Struct *pPhase, IMRPhenomTHMAmpStruct *pAmplm, IMRPhenomTWaveformStruct *wf)
double IMRPhenomTPhase22(REAL8 t, REAL8 thetabar, IMRPhenomTWaveformStruct *pWF, IMRPhenomTPhase22Struct *pPhase)
int XLALSimInspiralWaveformParamsInsertModeArray(LALDict *params, LALValue *value)
LALValue * XLALSimInspiralWaveformParamsLookupModeArray(LALDict *params)
void XLALDestroyValue(LALValue *value)
double e
Definition: bh_ringdown.c:117
double theta
Definition: bh_sphwf.c:118
sigmaKerr data[0]
#define LAL_MSUN_SI
#define LAL_PI
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
int XLALSimIMRPhenomTHM(REAL8TimeSeries **hp, REAL8TimeSeries **hc, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 inclination, REAL8 deltaT, REAL8 fmin, REAL8 fRef, REAL8 phiRef, LALDict *lalParams)
Routine to compute time domain polarisations for IMRPhenomTHM model.
SphHarmTimeSeries * XLALSimIMRPhenomTHM_Modes(REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 deltaT, REAL8 fmin, REAL8 fRef, REAL8 phiRef, LALDict *lalParams)
Routine to compute time domain Spin-Weighted Spherical Harmonic modes for IMRPhenomTHM model.
int XLALSimIMRPhenomT(REAL8TimeSeries **hp, REAL8TimeSeries **hc, REAL8 m1_SI, REAL8 m2_SI, REAL8 chi1L, REAL8 chi2L, REAL8 distance, REAL8 inclination, REAL8 deltaT, REAL8 fmin, REAL8 fRef, REAL8 phiRef, LALDict *lalParams)
Routine to compute time domain polarisations for IMRPhenomT model.
#define LAL_SIM_L_MAX_MODE_ARRAY
Maximum L spherical harmonic mode that is supported in Mode Array.
LALValue * XLALSimInspiralCreateModeArray(void)
Create a LALValue pointer to store the mode array.
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralModeArrayActivateMode(LALValue *modes, unsigned l, int m)
int XLALSimAddMode(REAL8TimeSeries *hplus, REAL8TimeSeries *hcross, COMPLEX16TimeSeries *hmode, REAL8 theta, REAL8 phi, int l, int m, int sym)
Multiplies a mode h(l,m) by a spin-2 weighted spherical harmonic to obtain hplus - i hcross,...
SphHarmTimeSeries * XLALSphHarmTimeSeriesAddMode(SphHarmTimeSeries *appended, const COMPLEX16TimeSeries *inmode, UINT4 l, INT4 m)
Prepend a node to a linked list of SphHarmTimeSeries, or create a new head.
void XLALDestroySphHarmTimeSeries(SphHarmTimeSeries *ts)
Delete list from current pointer to the end of the list.
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX16TimeSeries(COMPLEX16TimeSeries *series)
COMPLEX16TimeSeries * XLALCreateCOMPLEX16TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
const LALUnit lalStrainUnit
#define XLAL_PRINT_INFO(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_NULL(assertion,...)
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
list x
string status
COMPLEX16Sequence * data
REAL8Sequence * data
REAL8 * data
Structure to carry a collection of spherical harmonic modes in COMPLEX16 time series.
struct tagSphHarmTimeSeries * next
next pointer
COMPLEX16TimeSeries * mode
The sequences of sampled data.
INT4 m
Node submode m
UINT4 l
Node mode l
LIGOTimeGPS epoch
Definition: unicorn.c:20
double deltaT
Definition: unicorn.c:24