Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-8a6b96f
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRNRWaveforms.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2015 Ian Harry, Patricia Schmidt, Riccardo Sturani
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#include <stdio.h>
21#include <stdlib.h>
22#include <math.h>
23#include <complex.h>
24#include <time.h>
25#include <stdbool.h>
26#include <alloca.h>
27#include <libgen.h>
28
29#ifdef __GNUC__
30#define UNUSED __attribute__ ((unused))
31#else
32#define UNUSED
33#endif
34
35#include <gsl/gsl_errno.h>
36#include <gsl/gsl_bspline.h>
37#include <gsl/gsl_blas.h>
38#include <gsl/gsl_min.h>
39#include <gsl/gsl_spline.h>
40#include <lal/Units.h>
41#include <lal/SeqFactories.h>
42#include <lal/LALConstants.h>
43#include <lal/XLALError.h>
44#include <lal/FrequencySeries.h>
45#include <lal/Date.h>
46#include <lal/StringInput.h>
47#include <lal/Sequence.h>
48#include <lal/LALStdio.h>
49#include <lal/FileIO.h>
50
51#include <lal/LALSimInspiral.h>
52#include <lal/LALSimIMR.h>
53#include <lal/LALConfig.h>
54#include <lal/SphericalHarmonics.h>
55#include <lal/LALSimInspiralPrecess.h>
56
57#include <lal/H5FileIO.h>
58
60
62 UNUSED LALH5File* file,
63 UNUSED REAL8 fRef
64)
65{
66 #ifndef LAL_HDF5_ENABLED
67 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
68 #else
69 gsl_vector *omega_w_vec = NULL;
70 LALH5File *omega_group = NULL;
71 REAL8 min_fref, lowest_arr_fref;
72 if (fRef > 0)
73 {
74 /* This is the declared f_lower (using 1MSUN total mass) */
75 XLALH5FileQueryScalarAttributeValue(&min_fref, file, "f_lower_at_1MSUN");
76 /* This is the lowest f_lower in the Omega-vs-time array */
77 omega_group = XLALH5GroupOpen(file, "Omega-vs-time");
78 ReadHDF5RealVectorDataset(omega_group, "Y", &omega_w_vec);
79 XLALH5FileClose(omega_group);
80 lowest_arr_fref = gsl_vector_get(omega_w_vec, 0);
81 lowest_arr_fref = lowest_arr_fref / (LAL_MTSUN_SI * LAL_PI);
82 gsl_vector_free(omega_w_vec);
83 /* First, is fRef smaller than min_fref?
84 * Allow some float-precision slop */
85 if (fRef < 0.9999 * min_fref)
86 {
87 XLAL_ERROR(XLAL_EINVAL, "The supplied reference frequency is lower than the start frequency of the waveform. Start frequency (scaled by total mass) is %e and supplied fRef (scaled by total mass) is %e.\n", min_fref, fRef);
88 }
89 /* The Omega array may not quite extend to the minimum fRef, if that
90 * happens, fall back on the attribute values. */
91 if (fRef < lowest_arr_fref)
92 {
93 fRef = -1;
94 }
95 }
96 return fRef;
97 #endif
98}
99
101 UNUSED LALH5File* file,
102 UNUSED REAL8 fRef
103)
104{
105 #ifndef LAL_HDF5_ENABLED
106 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
107 #else
108 /* NOTE: This is an internal function, it is expected that fRef is scaled
109 * to correspond to the fRef with a total mass of 1 solar mass */
110 LALH5File *curr_group = NULL;
111 gsl_vector *omega_t_vec = NULL;
112 gsl_vector *omega_w_vec = NULL;
113 gsl_interp_accel *acc;
114 gsl_spline *spline;
115 REAL8 ref_time;
116 curr_group = XLALH5GroupOpen(file, "Omega-vs-time");
117 ReadHDF5RealVectorDataset(curr_group, "X", &omega_t_vec);
118 ReadHDF5RealVectorDataset(curr_group, "Y", &omega_w_vec);
119 XLALH5FileClose(curr_group);
120 acc = gsl_interp_accel_alloc();
121 spline = gsl_spline_alloc(gsl_interp_cspline, omega_w_vec->size);
122 INT4 status = gsl_spline_init(spline, omega_w_vec->data, omega_t_vec->data,
123 omega_t_vec->size);
124 XLAL_CHECK(status == GSL_SUCCESS, XLAL_FAILURE, "Failed gsl_spline_init evaluation. Probably omega_w is not monotonically increasing.\n");
125 ref_time = gsl_spline_eval(spline, fRef * (LAL_MTSUN_SI * LAL_PI), acc);
126 if ( isnan(ref_time) ){
127 XLAL_ERROR(XLAL_FAILURE, "Interpolation error: gsl_spline_eval returning nan\n");
128 }
129 gsl_vector_free(omega_t_vec);
130 gsl_vector_free(omega_w_vec);
131 gsl_spline_free(spline);
132 gsl_interp_accel_free(acc);
133 return ref_time;
134 #endif
135}
136
138 UNUSED LALH5File* file, /**< Pointer to HDF5 file */
139 UNUSED const char *groupName, /**< Name of group in HDF file */
140 UNUSED REAL8 ref_point /**< Point at which to evaluate */
141 )
142{
143 #ifndef LAL_HDF5_ENABLED
144 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
145 #else
146 LALH5File *curr_group = NULL;
147 gsl_vector *curr_t_vec = NULL;
148 gsl_vector *curr_y_vec = NULL;
149 gsl_interp_accel *acc;
150 gsl_spline *spline;
151 REAL8 ret_val;
152 curr_group = XLALH5GroupOpen(file, groupName);
153 ReadHDF5RealVectorDataset(curr_group, "X", &curr_t_vec);
154 ReadHDF5RealVectorDataset(curr_group, "Y", &curr_y_vec);
155 XLALH5FileClose(curr_group);
156 acc = gsl_interp_accel_alloc();
157 spline = gsl_spline_alloc(gsl_interp_cspline, curr_t_vec->size);
158 INT4 status = gsl_spline_init(spline, curr_t_vec->data, curr_y_vec->data,
159 curr_t_vec->size);
160 XLAL_CHECK(status == GSL_SUCCESS, XLAL_FAILURE, "Failed gsl_spline_init evaluation. Probably omega_w is not monotonically increasing.\n");
161 ret_val = gsl_spline_eval(spline, ref_point, acc);
162 if ( isnan(ret_val) ){
163 XLAL_ERROR(XLAL_FAILURE, "Interpolation error: gsl_spline_eval returning nan. Group name %s\n", groupName);
164 }
165 gsl_vector_free(curr_t_vec);
166 gsl_vector_free(curr_y_vec);
167 gsl_spline_free (spline);
168 gsl_interp_accel_free (acc);
169 return ret_val;
170 #endif
171}
172
173/* Everything needs to be declared as unused in case HDF is not enabled. */
175 UNUSED REAL8 *S1x, /**< [out] Dimensionless spin1x in LAL frame */
176 UNUSED REAL8 *S1y, /**< [out] Dimensionless spin1y in LAL frame */
177 UNUSED REAL8 *S1z, /**< [out] Dimensionless spin1z in LAL frame */
178 UNUSED REAL8 *S2x, /**< [out] Dimensionless spin2x in LAL frame */
179 UNUSED REAL8 *S2y, /**< [out] Dimensionless spin2y in LAL frame */
180 UNUSED REAL8 *S2z, /**< [out] Dimensionless spin2z in LAL frame */
181 UNUSED REAL8 fRef, /**< Reference frequency */
182 UNUSED REAL8 mTot, /**< Total mass */
183 UNUSED LALH5File* file /**< Pointer to HDF5 file */
184)
185{
186 #ifndef LAL_HDF5_ENABLED
187 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
188 #else
189 REAL8 nrSpin1x, nrSpin1y, nrSpin1z, nrSpin2x, nrSpin2y, nrSpin2z;
190 REAL8 ln_hat_x, ln_hat_y, ln_hat_z, n_hat_x, n_hat_y, n_hat_z, n_norm;
191 REAL8 pos1x, pos1y, pos1z, pos2x, pos2y, pos2z;
192 REAL8 ref_time;
193 INT8 nr_file_format;
194 /* We'll work by always using mTot = 1 */
195 fRef = fRef * mTot;
196
197 XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
198 if ((nr_file_format < 2) && (fRef > 0))
199 {
200 /* Supplying a fRef > 0 indicates that the user actually wants to use
201 * fRef. If this is not possible, because the file format is < 2, then
202 * the code will fail. */
203 XLAL_ERROR(XLAL_EINVAL, "This NR file is format 1. Only formats 2 and above support the use of reference frequency. For formats < 2 give the reference frequency as 0 or -1 to indicate that the start of the waveform should be used as the reference.");
204 }
205
206 /* Check if fRef is possible given inputs */
208
209 if (fRef <= 0)
210 {
211 XLALH5FileQueryScalarAttributeValue(&nrSpin1x, file, "spin1x");
212 XLALH5FileQueryScalarAttributeValue(&nrSpin1y, file, "spin1y");
213 XLALH5FileQueryScalarAttributeValue(&nrSpin1z, file, "spin1z");
214 XLALH5FileQueryScalarAttributeValue(&nrSpin2x, file, "spin2x");
215 XLALH5FileQueryScalarAttributeValue(&nrSpin2y, file, "spin2y");
216 XLALH5FileQueryScalarAttributeValue(&nrSpin2z, file, "spin2z");
217
218 XLALH5FileQueryScalarAttributeValue(&ln_hat_x , file, "LNhatx");
219 XLALH5FileQueryScalarAttributeValue(&ln_hat_y , file, "LNhaty");
220 XLALH5FileQueryScalarAttributeValue(&ln_hat_z , file, "LNhatz");
221
222 XLALH5FileQueryScalarAttributeValue(&n_hat_x , file, "nhatx");
223 XLALH5FileQueryScalarAttributeValue(&n_hat_y , file, "nhaty");
224 XLALH5FileQueryScalarAttributeValue(&n_hat_z , file, "nhatz");
225 }
226 else
227 {
228 /* This will be real slow if done many times!
229 * One speed issue is we create the spline for *all* points, but only
230 * evaluate at a single point. */
231
232 /* First interpolate between time and freq to get a reference time */
234 REAL8 fminNR;
235 XLALH5FileQueryScalarAttributeValue(&fminNR, file, "f_lower_at_1MSUN");
236 XLAL_CHECK( ref_time!=XLAL_FAILURE, XLAL_FAILURE, "Error computing reference time. Try setting fRef equal to the f_low given by the NR simulation (%.16f Hz) or to a value <=0 to deactivate fRef for a non-precessing simulation.\n", fminNR/mTot);
237
238 /* Now use ref_time to get spins, LN and nhat */
240 (file, "spin1x-vs-time", ref_time);
242 (file, "spin1y-vs-time", ref_time);
244 (file, "spin1z-vs-time", ref_time);
246 (file, "spin2x-vs-time", ref_time);
248 (file, "spin2y-vs-time", ref_time);
250 (file, "spin2z-vs-time", ref_time);
252 (file, "LNhatx-vs-time", ref_time);
254 (file, "LNhaty-vs-time", ref_time);
256 (file, "LNhatz-vs-time", ref_time);
257 /* Would have been easier if we could store n_hat directly!! */
259 (file, "position1x-vs-time", ref_time);
261 (file, "position1y-vs-time", ref_time);
263 (file, "position1z-vs-time", ref_time);
265 (file, "position2x-vs-time", ref_time);
267 (file, "position2y-vs-time", ref_time);
269 (file, "position2z-vs-time", ref_time);
270 n_hat_x = pos1x - pos2x;
271 n_hat_y = pos1y - pos2y;
272 n_hat_z = pos1z - pos2z;
273 n_norm = sqrt(n_hat_x*n_hat_x + n_hat_y*n_hat_y + n_hat_z*n_hat_z);
274 n_hat_x = n_hat_x / n_norm;
275 n_hat_y = n_hat_y / n_norm;
276 n_hat_z = n_hat_z / n_norm;
277 }
278
279 *S1x = nrSpin1x * n_hat_x + nrSpin1y * n_hat_y + nrSpin1z * n_hat_z;
280 *S1y = nrSpin1x * (-ln_hat_z * n_hat_y + ln_hat_y * n_hat_z)
281 + nrSpin1y * (ln_hat_z * n_hat_x - ln_hat_x * n_hat_z)
282 + nrSpin1z * (-ln_hat_y * n_hat_x + ln_hat_x * n_hat_y) ;
283 *S1z = nrSpin1x * ln_hat_x + nrSpin1y * ln_hat_y + nrSpin1z * ln_hat_z;
284
285 *S2x = nrSpin2x * n_hat_x + nrSpin2y * n_hat_y + nrSpin2z * n_hat_z;
286 *S2y = nrSpin2x * (-ln_hat_z * n_hat_y + ln_hat_y * n_hat_z)
287 + nrSpin2y * (ln_hat_z * n_hat_x - ln_hat_x * n_hat_z)
288 + nrSpin2z * (-ln_hat_y * n_hat_x + ln_hat_x * n_hat_y);
289 *S2z = nrSpin2x * ln_hat_x + nrSpin2y * ln_hat_y + nrSpin2z * ln_hat_z;
290
291 return XLAL_SUCCESS;
292 #endif
293}
294
296 UNUSED REAL8Vector** output, /**< Returned vector uncompressed */
297 UNUSED LALH5File* pointer, /**< Pointer to HDF5 file */
298 UNUSED REAL8 totalMass, /**< Total mass of system for scaling */
299 UNUSED REAL8 startTime, /**< Start time of veturn vector */
300 UNUSED size_t length, /**< Length of returned vector */
301 UNUSED REAL8 deltaT, /**< Sample rate of returned vector */
302 UNUSED const char *keyName /**< Name of vector to uncompress */
303 )
304{
305 #ifndef LAL_HDF5_ENABLED
306 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
307 #else
308 UINT4 idx;
309 size_t comp_data_length;
310 REAL8 massTime;
311 gsl_interp_accel *acc;
312 gsl_spline *spline;
313 gsl_vector *knotsVector, *dataVector;
314 LALH5File *group = XLALH5GroupOpen(pointer, keyName);
315 knotsVector=dataVector=NULL;
316
317 ReadHDF5RealVectorDataset(group, "X", &knotsVector);
318 ReadHDF5RealVectorDataset(group, "Y", &dataVector);
319 XLALH5FileClose(group);
320
321 *output = XLALCreateREAL8Vector(length);
322
323 comp_data_length = dataVector->size;
324 /* SPLINE STUFF */
325 acc = gsl_interp_accel_alloc();
326 spline = gsl_spline_alloc(gsl_interp_cspline, comp_data_length);
327 INT4 status = gsl_spline_init(spline, knotsVector->data, dataVector->data,
328 comp_data_length);
329 XLAL_CHECK(status == GSL_SUCCESS, XLAL_FAILURE, "Failed gsl_spline_init evaluation. Probably omega_w is not monotonically increasing.\n");
330
331 for (idx = 0; idx < length; idx++)
332 {
333 massTime = (startTime + idx*deltaT) / (totalMass * LAL_MTSUN_SI);
334 /* This if statement is used to catch the case where massTime at idx=0
335 * ends up at double precision smaller than the first point in the
336 * interpolation. In this case set it back to exactly the first point.
337 * Sanity checking that we are not trying to use data below the
338 * interpolation range is done elsewhere.
339 */
340 if ((idx == 0) && (massTime < knotsVector->data[0]))
341 {
342 massTime = knotsVector->data[0];
343 }
344 (*output)->data[idx] = gsl_spline_eval(spline, massTime, acc);
345 }
346
347 gsl_vector_free(knotsVector);
348 gsl_vector_free(dataVector);
349 gsl_spline_free (spline);
350 gsl_interp_accel_free (acc);
351
352 return XLAL_SUCCESS;
353 #endif
354}
355
357 UNUSED REAL8 *theta, /**< Returned inclination angle of source */
358 UNUSED REAL8 *psi, /**< Returned azimuth angle of source */
359 UNUSED REAL8 *calpha, /**< Returned cosine of the polarisation angle */
360 UNUSED REAL8 *salpha, /**< Returned sine of the polarisation angle */
361 UNUSED LALH5File* filepointer, /**< Pointer to NR HDF5 file */
362 UNUSED const REAL8 inclination, /**< Inclination of source */
363 UNUSED const REAL8 phi_ref, /**< Orbital reference phase*/
364 UNUSED REAL8 fRef /**< Reference frequency */
365 )
366{
367 #ifndef LAL_HDF5_ENABLED
368 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
369 #else
370
371 /* Compute the angles necessary to rotate from the intrinsic NR source frame
372 * into the LAL frame. See DCC-T1600045 for details.
373 */
374
375 /* Attribute declarations go in here */
376 /* Declarations */
377 REAL8 orb_phase, ln_hat_x, ln_hat_y, ln_hat_z, ln_hat_norm, ref_time;
378 REAL8 n_hat_x, n_hat_y, n_hat_z, n_hat_norm;
379 REAL8 pos1x, pos1y, pos1z, pos2x, pos2y, pos2z;
380 REAL8 r_x, r_y, r_z, r_norm;
381 REAL8 corb_phase, sorb_phase, sinclination, cinclination;
382 REAL8 ln_cross_n_x, ln_cross_n_y, ln_cross_n_z, ln_cross_n_norm;
383 REAL8 z_wave_x, z_wave_y, z_wave_z, z_wave_norm;
384 REAL8 stheta, ctheta, spsi, cpsi, theta_hat_x, theta_hat_y, theta_hat_z;
385 REAL8 psi_hat_x, psi_hat_y, psi_hat_z;
386 REAL8 n_dot_theta, ln_cross_n_dot_theta, n_dot_psi, ln_cross_n_dot_psi;
387 REAL8 y_val;
388
389 fRef = XLALSimInspiralNRWaveformCheckFRef(filepointer, fRef);
390
391 /* Following section IV of DCC-T1600045
392 * Step 1: Define Phi = phiref
393 */
394 orb_phase = phi_ref;
395
396 /* Step 2: Compute Zref
397 * 2.1: Compute LN_hat from file. LN_hat = direction of orbital ang. mom.
398 * 2.2: Compute n_hat from file.
399 * n_hat = direction from object 2 to object 1
400 */
401
402 if (fRef > 0)
403 {
405 fRef);
406 XLAL_CHECK( ref_time!=XLAL_FAILURE, XLAL_FAILURE, "Error computing reference time. Try setting fRef equal to the f_low given by the NR simulation or to a value <=0 to deactivate fRef for a non-precessing simulation.\n");
408 (filepointer, "LNhatx-vs-time", ref_time);
410 (filepointer, "LNhaty-vs-time", ref_time);
412 (filepointer, "LNhatz-vs-time", ref_time);
413 /* Would have been easier if we could store n_hat directly!! */
415 (filepointer, "position1x-vs-time", ref_time);
417 (filepointer, "position1y-vs-time", ref_time);
419 (filepointer, "position1z-vs-time", ref_time);
421 (filepointer, "position2x-vs-time", ref_time);
423 (filepointer, "position2y-vs-time", ref_time);
425 (filepointer, "position2z-vs-time", ref_time);
426 r_x = pos1x - pos2x;
427 r_y = pos1y - pos2y;
428 r_z = pos1z - pos2z;
429 r_norm=sqrt(r_x*r_x+ r_y*r_y + r_z*r_z);
430 n_hat_x=r_x/r_norm;
431 n_hat_y=r_y/r_norm;
432 n_hat_z=r_z/r_norm;
433 }
434 else
435 {
436 XLALH5FileQueryScalarAttributeValue(&ln_hat_x , filepointer, "LNhatx");
437 XLALH5FileQueryScalarAttributeValue(&ln_hat_y , filepointer, "LNhaty");
438 XLALH5FileQueryScalarAttributeValue(&ln_hat_z , filepointer, "LNhatz");
439 XLALH5FileQueryScalarAttributeValue(&n_hat_x , filepointer, "nhatx");
440 XLALH5FileQueryScalarAttributeValue(&n_hat_y , filepointer, "nhaty");
441 XLALH5FileQueryScalarAttributeValue(&n_hat_z , filepointer, "nhatz");
442 }
443
444 ln_hat_norm = sqrt(ln_hat_x * ln_hat_x + ln_hat_y * ln_hat_y + ln_hat_z * ln_hat_z);
445
446 if (fabs(ln_hat_norm - 1) > 0.001)
447 {
448 XLAL_PRINT_ERROR("ln_hat_mag = %.16f\n", ln_hat_norm);
449 XLAL_ERROR(XLAL_EDOM, "The size of the LN hat vector in the supplied HDF file is not equal to unity");
450 }
451
452 ln_hat_x = ln_hat_x / ln_hat_norm;
453 ln_hat_y = ln_hat_y / ln_hat_norm;
454 ln_hat_z = ln_hat_z / ln_hat_norm;
455
456 n_hat_norm = sqrt(n_hat_x * n_hat_x + n_hat_y * n_hat_y + n_hat_z * n_hat_z);
457
458 if (fabs(n_hat_norm - 1) > 0.001)
459 {
460 XLAL_PRINT_ERROR("n_hat_mag = %.16f\n", n_hat_norm);
461 XLAL_ERROR(XLAL_EDOM, "The size of the n hat vector in the supplied HDF file is not equal to unity");
462 }
463
464 n_hat_x = n_hat_x / n_hat_norm;
465 n_hat_y = n_hat_y / n_hat_norm;
466 n_hat_z = n_hat_z / n_hat_norm;
467
468 /* 2.3: Compute Z in the lal wave frame */
469
470 corb_phase = cos(orb_phase);
471 sorb_phase = sin(orb_phase);
472 sinclination = sin(inclination);
473 cinclination = cos(inclination);
474
475 ln_cross_n_x = ln_hat_y * n_hat_z - ln_hat_z * n_hat_y;
476 ln_cross_n_y = ln_hat_z * n_hat_x - ln_hat_x * n_hat_z;
477 ln_cross_n_z = ln_hat_x * n_hat_y - ln_hat_y * n_hat_x;
478
479 ln_cross_n_norm = sqrt(ln_cross_n_x*ln_cross_n_x + ln_cross_n_y*ln_cross_n_y + ln_cross_n_z*ln_cross_n_z);
480 ln_cross_n_x = ln_cross_n_x / ln_cross_n_norm;
481 ln_cross_n_y = ln_cross_n_y / ln_cross_n_norm;
482 ln_cross_n_z = ln_cross_n_z / ln_cross_n_norm;
483
484 if (fabs(ln_cross_n_norm - 1) > 0.001)
485 {
486 XLAL_PRINT_ERROR("ln_cross_n mag = %.16f\n", ln_cross_n_norm);
487 XLAL_ERROR(XLAL_EDOM, "The size of the LN x n vector computed here is not equal to unity. This shouldn't be possible, please email lalsimulation developers.");
488 }
489
490 z_wave_x = sinclination * (sorb_phase * n_hat_x + corb_phase * ln_cross_n_x);
491 z_wave_y = sinclination * (sorb_phase * n_hat_y + corb_phase * ln_cross_n_y);
492 z_wave_z = sinclination * (sorb_phase * n_hat_z + corb_phase * ln_cross_n_z);
493
494 z_wave_x += cinclination * ln_hat_x;
495 z_wave_y += cinclination * ln_hat_y;
496 z_wave_z += cinclination * ln_hat_z;
497
498 z_wave_norm = sqrt(z_wave_x * z_wave_x + z_wave_y * z_wave_y + z_wave_z * z_wave_z);
499
500 z_wave_x = z_wave_x / z_wave_norm;
501 z_wave_y = z_wave_y / z_wave_norm;
502 z_wave_z = z_wave_z / z_wave_norm;
503
504 if (fabs(z_wave_norm - 1) > 0.001)
505 {
506 XLAL_PRINT_ERROR("Z mag = %.16f\n", z_wave_norm);
507 XLAL_ERROR(XLAL_EDOM, "The size of the Z vector computed here is not equal to unity. This shouldn't be possible, please email lalsimulation developers.");
508 }
509
510 /* Step 3.1: Extract theta and psi from Z in the lal wave frame
511 * NOTE: Theta can only run between 0 and pi, so no problem with arccos here
512 */
513
514 *theta = acos(z_wave_z);
515
516 /* Degenerate if Z_wave[2] == 1. In this case just choose psi randomly,
517 * the choice will be cancelled out by alpha correction (I hope!)
518 */
519
520 if(fabs(z_wave_z - 1.0 ) < 0.000001)
521 {
522 *psi = 0.5;
523 }
524 else
525 {
526 /* psi can run between 0 and 2pi, but only one solution works for x and y */
527 /* Possible numerical issues if z_wave_x = sin(theta) */
528 if(fabs(z_wave_x / sin(*theta)) > 1.)
529 {
530 if(fabs(z_wave_x / sin(*theta)) < 1.00001)
531 {
532 if((z_wave_x * sin(*theta)) < 0.)
533 {
534 *psi = LAL_PI;
535 }
536 else
537 {
538 *psi = 0.;
539 }
540 }
541 else
542 {
543 XLAL_PRINT_ERROR("z_wave_x = %.16f\n", z_wave_x);
544 XLAL_PRINT_ERROR("sin(theta) = %.16f\n", sin(*theta));
545 XLAL_ERROR(XLAL_EDOM, "Z_x cannot be bigger than sin(theta). Please email lalsimulation developers.");
546 }
547 }
548 else
549 {
550 *psi = acos(z_wave_x / sin(*theta));
551 }
552 y_val = sin(*psi) * sin(*theta);
553 /* If z_wave[1] is negative, flip psi so that sin(psi) goes negative
554 * while preserving cos(psi) */
555 if( z_wave_y < 0.)
556 {
557 *psi = 2 * LAL_PI - *psi;
558 y_val = sin(*psi) * sin(*theta);
559 }
560 if( fabs(y_val - z_wave_y) > 0.005)
561 {
562 XLAL_PRINT_ERROR("orb_phase = %.16f\n", orb_phase);
563 XLAL_PRINT_ERROR("y_val = %.16f, z_wave_y = %.16f, fabs(y_val - z_wave_y) = %.16f\n", y_val, z_wave_y, fabs(y_val - z_wave_y));
564 XLAL_ERROR(XLAL_EDOM, "Something's wrong in Ian's math. Tell him he's an idiot!");
565 }
566 }
567
568 /* 3.2: Compute the vectors theta_hat and psi_hat */
569
570 stheta = sin(*theta);
571 ctheta = cos(*theta);
572 spsi = sin(*psi);
573 cpsi = cos(*psi);
574
575 theta_hat_x = cpsi * ctheta;
576 theta_hat_y = spsi * ctheta;
577 theta_hat_z = - stheta;
578
579 psi_hat_x = -spsi;
580 psi_hat_y = cpsi;
581 psi_hat_z = 0.0;
582
583 /* Step 4: Compute sin(alpha) and cos(alpha) */
584
585 n_dot_theta = n_hat_x * theta_hat_x + n_hat_y * theta_hat_y + n_hat_z * theta_hat_z;
586 ln_cross_n_dot_theta = ln_cross_n_x * theta_hat_x + ln_cross_n_y * theta_hat_y + ln_cross_n_z * theta_hat_z;
587 n_dot_psi = n_hat_x * psi_hat_x + n_hat_y * psi_hat_y + n_hat_z * psi_hat_z;
588 ln_cross_n_dot_psi = ln_cross_n_x * psi_hat_x + ln_cross_n_y * psi_hat_y + ln_cross_n_z * psi_hat_z;
589
590 *salpha = corb_phase * n_dot_theta - sorb_phase * ln_cross_n_dot_theta;
591 *calpha = corb_phase * n_dot_psi - sorb_phase * ln_cross_n_dot_psi;
592
593 /* Step 5: Also useful to keep the source frame vectors as defined in
594 * equation 16 of Harald's document.
595 */
596
597 /*
598 * x_source_hat[0] = corb_phase * n_hat_x - sorb_phase * ln_cross_n_x;
599 * x_source_hat[1] = corb_phase * n_hat_y - sorb_phase * ln_cross_n_y;
600 * x_source_hat[2] = corb_phase * n_hat_z - sorb_phase * ln_cross_n_z;
601 * y_source_hat[0] = sorb_phase * n_hat_x + corb_phase * ln_cross_n_x;
602 * y_source_hat[1] = sorb_phase * n_hat_y + corb_phase * ln_cross_n_y;
603 * y_source_hat[2] = sorb_phase * n_hat_z + corb_phase * ln_cross_n_z;
604 * z_source_hat[0] = ln_hat_x;
605 * z_source_hat[1] = ln_hat_y;
606 * z_source_hat[2] = ln_hat_z;
607 */
608
609 return XLAL_SUCCESS;
610 #endif
611}
612
614 UNUSED REAL8 *S1x, /**< [out] Dimensionless spin1x in LAL frame */
615 UNUSED REAL8 *S1y, /**< [out] Dimensionless spin1y in LAL frame */
616 UNUSED REAL8 *S1z, /**< [out] Dimensionless spin1z in LAL frame */
617 UNUSED REAL8 *S2x, /**< [out] Dimensionless spin2x in LAL frame */
618 UNUSED REAL8 *S2y, /**< [out] Dimensionless spin2y in LAL frame */
619 UNUSED REAL8 *S2z, /**< [out] Dimensionless spin2z in LAL frame */
620 UNUSED REAL8 fRef, /**< Reference frequency */
621 UNUSED REAL8 mTot, /**< Total mass */
622 UNUSED const char *NRDataFile /**< Location of NR HDF file */
623)
624{
625 #ifndef LAL_HDF5_ENABLED
626 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
627 #else
629 file = XLALH5FileOpen(NRDataFile, "r");
630 if (file == NULL)
631 {
632 XLAL_ERROR(XLAL_EIO, "NR SIMULATION DATA FILE %s NOT FOUND.\n",
633 NRDataFile);
634 }
636 S2y, S2z, fRef, mTot,
637 file);
639 return XLAL_SUCCESS;
640 #endif
641}
642
643
644/* Everything needs to be declared as unused in case HDF is not enabled. */
645
647 UNUSED SphHarmTimeSeries **Hlms, /**< OUTPUT */
648 UNUSED LIGOTimeGPS *epoch, /**< OUTPUT */
649 UNUSED UINT4 *length, /**< OUTPUT */
650 UNUSED REAL8 deltaT, /**< sampling interval (s) */
651 UNUSED REAL8 m1, /**< mass of companion 1 (solar units) */
652 UNUSED REAL8 m2, /**< mass of companion 2 (solar units) */
653 UNUSED REAL8 r, /**< distance of source (m) */
654 UNUSED REAL8 fStart, /**< start GW frequency (Hz) */
655 UNUSED REAL8 fRef, /**< reference GW frequency (Hz) */
656 UNUSED REAL8 s1x, /**< initial value of S1x */
657 UNUSED REAL8 s1y, /**< initial value of S1y */
658 UNUSED REAL8 s1z, /**< initial value of S1z */
659 UNUSED REAL8 s2x, /**< initial value of S2x */
660 UNUSED REAL8 s2y, /**< initial value of S2y */
661 UNUSED REAL8 s2z, /**< initial value of S2z */
662 UNUSED LALH5File* file, /**< pointer to location of NR HDF file */
663 UNUSED LALValue* ModeArray /**< Container for the ell and m modes to generate. To generate all available modes pass NULL */
664 )
665{
666#ifndef LAL_HDF5_ENABLED
667 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
668#else
669 /* Declarations */
670 UINT4 curr_idx, nr_file_format;
671 INT4 model, modem;
672 size_t array_length;
673 REAL8 nrEta;
674 REAL8 S1x = 0, S1y = 0, S1z = 0, S2x = 0, S2y = 0, S2z = 0;
675 REAL8 Mflower, time_start_M, time_start_s, time_end_M, time_end_s;
676 REAL8 est_start_time;
677 REAL8 distance_scale_fac;
679 SphHarmTimeSeries *hlms_tmp=NULL;
680
681 /* These keys follow a strict formulation and cannot be longer than 11
682 * characters */
683 char amp_key[30];
684 char phase_key[31];
685 gsl_vector *tmpVector=NULL;
686 LALH5File *group;
687 LIGOTimeGPS tmpEpoch = LIGOTIMEGPSZERO;
688 REAL8Vector *curr_amp, *curr_phase;
689
690 /* Sanity checks on physical parameters passed to waveform
691 * generator to guarantee consistency with NR data file.
692 */
694 if (fabs((m1 * m2) / pow((m1 + m2),2.0) - nrEta) > 1E-3)
695 {
696 XLAL_ERROR(XLAL_EDOM, "MASSES (%e and %e) ARE INCONSISTENT WITH THE MASS RATIO OF THE NR SIMULATION (eta=%e).\n", m1, m2, nrEta);
697 }
698
699 /* Read spin metadata, L_hat, n_hat from HDF5 metadata and make sure
700 * the ChooseTDWaveform() input values are consistent with the data
701 * recorded in the metadata of the HDF5 file.
702 * PS: This assumes that the input spins are in the LAL frame!
703 */
705 &S2x, &S2y, &S2z,
706 fRef, m1+m2, file);
707 XLAL_CHECK(xlalErrno == 0, XLAL_EFUNC, "XLALSimInspiralNRWaveformGetSpinsFromHDF5FilePointer() failed");
708
709 if (fabs(S1x - s1x) > 1E-3)
710 {
711 XLAL_ERROR(XLAL_EDOM, "SPIN1X IS INCONSISTENT WITH THE NR SIMULATION.\n");
712 }
713
714 if (fabs(S1y - s1y) > 1E-3)
715 {
716 XLAL_ERROR(XLAL_EDOM, "SPIN1Y IS INCONSISTENT WITH THE NR SIMULATION.\n");
717 }
718
719 if (fabs(S1z - s1z) > 1E-3)
720 {
721 XLAL_ERROR(XLAL_EDOM, "SPIN1Z IS INCONSISTENT WITH THE NR SIMULATION.\n");
722 }
723
724 if (fabs(S2x - s2x) > 1E-3)
725 {
726 XLAL_ERROR(XLAL_EDOM, "SPIN2X IS INCONSISTENT WITH THE NR SIMULATION.\n");
727 }
728
729 if (fabs(S2y - s2y) > 1E-3)
730 {
731 XLAL_ERROR(XLAL_EDOM, "SPIN2Y IS INCONSISTENT WITH THE NR SIMULATION.\n");
732 }
733
734 if (fabs(S2z - s2z) > 1E-3)
735 {
736 XLAL_ERROR(XLAL_EDOM, "SPIN2Z IS INCONSISTENT WITH THE NR SIMULATION.\n");
737 }
738
739
740 /* First estimate the length of time series that is needed.
741 * Demand that 22 mode that is present and use that to figure this out
742 */
743
744 XLALH5FileQueryScalarAttributeValue(&Mflower, file, "f_lower_at_1MSUN");
745 /* Figure out start time of data */
746 group = XLALH5GroupOpen(file, "amp_l2_m2");
747 ReadHDF5RealVectorDataset(group, "X", &tmpVector);
748 XLALH5FileClose(group);
749 time_start_M = (REAL8)(gsl_vector_get(tmpVector, 0));
750 time_end_M = (REAL8)(gsl_vector_get(tmpVector, tmpVector->size - 1));
751 gsl_vector_free(tmpVector);
752 time_start_s = time_start_M * (m1 + m2) * LAL_MTSUN_SI;
753 time_end_s = time_end_M * (m1 + m2) * LAL_MTSUN_SI;
754
755 /* We don't want to return the *entire* waveform if it will be much longer
756 * than the specified f_lower. Therefore guess waveform length using
757 * the SEOBNR_ROM function and add 10% for safety.
758 * FIXME: Is this correct for precessing waveforms?
759 */
760
761 /* We allow fstart to be fractionally lower than expected to
762 * try and catch rounding errors
763 */
764 if (fStart * (1 + 1E-5) < Mflower / (m1 + m2))
765 {
766 XLAL_ERROR(XLAL_EDOM, "WAVEFORM IS NOT LONG ENOUGH TO REACH f_low. \
767 fStart = %e, Mflower = %e, Mflower / (m1 + m2)) = %e",
768 fStart, Mflower, Mflower / (m1 + m2));
769 }
770
771 XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
772 if (nr_file_format > 1)
773 {
774 if (XLALSimInspiralNRWaveformCheckFRef(file, fStart * (m1+m2)) > 0)
775 {
776 /* Can use Omega array to get start time */
777 est_start_time = XLALSimInspiralNRWaveformGetRefTimeFromRefFreq(file, fStart * (m1+m2));
778 REAL8 fminNR;
779 XLALH5FileQueryScalarAttributeValue(&fminNR, file, "f_lower_at_1MSUN");
780 XLAL_CHECK( est_start_time!=XLAL_FAILURE, XLAL_FAILURE, "Error computing starting time. Try setting f_low equal to the f_low given by the NR simulation (%.16f Hz)\n",fminNR/(m1+m2));
781 est_start_time = est_start_time * (m1 + m2) * LAL_MTSUN_SI;
782 }
783 else
784 {
785 /* This is the potential weird case where Omega-vs-time does not start
786 * at precisely the same time as flower_at_1MSUN. This gap should be
787 * small, so just use the full waveform here.
788 */
789 est_start_time = time_start_s;
790 }
791 }
792 else
793 {
794 /* Fall back on SEOBNR chirp time estimate */
795 XLALSimIMRSEOBNRv4ROMTimeOfFrequency(&est_start_time, fStart, m1 * LAL_MSUN_SI, m2 * LAL_MSUN_SI, s1z, s2z);
796 est_start_time = (-est_start_time) * 1.1;
797 }
798
799 if (est_start_time > time_start_s)
800 {
801 /* Restrict start time of waveform */
802 time_start_s = est_start_time;
803 time_start_M = time_start_s / ((m1 + m2) * LAL_MTSUN_SI);
804 }
805
806 array_length = (UINT4)(ceil( (time_end_s - time_start_s) / deltaT));
807 *length=array_length;
808
809 /* Create the return time series, use arbitrary epoch here. We set this
810 * properly later. */
811 XLALGPSAdd(&tmpEpoch, time_start_s);
812 *epoch=tmpEpoch;
813
814 /* Create the distance scale factor */
815 distance_scale_fac = (m1 + m2) * LAL_MRSUN_SI / r;
816
817 /* Generate the waveform */
818 /* NOTE: We assume that for a given ell mode, all m modes are present */
819 INT4 NRLmax;
820
822
823 INT4 modearray_needs_destroying=0;
824 if ( ModeArray == NULL )
825 {/* Default behaviour: Generate all modes upto NRLmax */
826 modearray_needs_destroying=1;
827 ModeArray = XLALSimInspiralCreateModeArray();
828 for (int ell=2; ell<=NRLmax; ell++)
829 {
831 }
832 }
833 /* else Use the ModeArray given */
834 hlm=XLALCreateCOMPLEX16TimeSeries("hlm",&tmpEpoch,0.0,deltaT,&lalStrainUnit,array_length);
835 memset(hlm->data->data, 0, array_length * sizeof(COMPLEX16));
836
837 for (model=2; model < (NRLmax + 1) ; model++)
838 {
839 for (modem=-model; modem < (model+1); modem++)
840 {
841
842 /* first check if (l,m) mode is 'activated' in the ModeArray */
843 /* if activated then generate the mode, else skip this mode. */
844 if (XLALSimInspiralModeArrayIsModeActive(ModeArray, model, modem) != 1)
845 {
846 XLAL_PRINT_INFO("SKIPPING model = %i modem = %i\n", model, modem);
847 continue;
848 }
849 XLAL_PRINT_INFO("generating model = %i modem = %i\n", model, modem);
850
851 snprintf(amp_key, sizeof(amp_key), "amp_l%d_m%d", model, modem);
852 snprintf(phase_key, sizeof(phase_key), "phase_l%d_m%d", model, modem);
853
854 /* Check that both groups exist */
855 if (XLALH5FileCheckGroupExists(file, amp_key) == 0)
856 {
857 continue;
858 }
859 if (XLALH5FileCheckGroupExists(file, phase_key) == 0)
860 {
861 continue;
862 }
863
864 /* Get amplitude and phase from file */
866 time_start_s, array_length, deltaT, amp_key);
868 time_start_s, array_length, deltaT, phase_key);
869
870 for (curr_idx = 0; curr_idx < array_length; curr_idx++)
871 {
872 hlm->data->data[curr_idx]= (curr_amp->data[curr_idx]*cos(curr_phase->data[curr_idx]) + I*curr_amp->data[curr_idx]*sin(curr_phase->data[curr_idx]) ) * distance_scale_fac;
873 }
874 /* Note that the hlm built here do not respect the LAL convention
875 * the function XLALSimIMRNRWaveformGetHlm will perform the pi/2 rotation
876 * necessary to bring the in the right frame.
877 * See https://dcc.ligo.org/LIGO-T1900080 for details.
878 */
879 hlms_tmp=XLALSphHarmTimeSeriesAddMode(hlms_tmp,hlm,model,modem);
880 XLALDestroyREAL8Vector(curr_amp);
881 XLALDestroyREAL8Vector(curr_phase);
882 }
883 }
885 if (modearray_needs_destroying)
886 XLALDestroyValue(ModeArray);
887
888 *Hlms=hlms_tmp;
889
890 return XLAL_SUCCESS;
891#endif
892}
893
894/* Everything needs to be declared as unused in case HDF is not enabled. */
896 UNUSED REAL8TimeSeries **hplus, /**< Output h_+ vector */
897 UNUSED REAL8TimeSeries **hcross, /**< Output h_x vector */
898 UNUSED REAL8 phiRef, /**< orbital phase at reference pt. */
899 UNUSED REAL8 inclination, /**< inclination angle */
900 UNUSED REAL8 deltaT, /**< sampling interval (s) */
901 UNUSED REAL8 m1_SI, /**< mass of companion 1 (kg) */
902 UNUSED REAL8 m2_SI, /**< mass of companion 2 (kg) */
903 UNUSED REAL8 r, /**< distance of source (m) */
904 UNUSED REAL8 fStart, /**< start GW frequency (Hz) */
905 UNUSED REAL8 fRef, /**< reference GW frequency (Hz) */
906 UNUSED REAL8 s1x, /**< initial value of S1x */
907 UNUSED REAL8 s1y, /**< initial value of S1y */
908 UNUSED REAL8 s1z, /**< initial value of S1z */
909 UNUSED REAL8 s2x, /**< initial value of S2x */
910 UNUSED REAL8 s2y, /**< initial value of S2y */
911 UNUSED REAL8 s2z, /**< initial value of S2z */
912 UNUSED const char *NRDataFile, /**< Location of NR HDF file */
913 UNUSED LALValue* ModeArray /**< Container for the ell and m modes to generate. To generate all available modes pass NULL */
914 )
915{
916#ifndef LAL_HDF5_ENABLED
917 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
918#else
919 /* Declarations */
920 UINT4 curr_idx, array_length, nr_file_format;
921 INT4 model, modem, NRLmax;
922 REAL8 m1,m2;
923 REAL8 theta, psi, calpha, salpha;
924 REAL8 fRef_pass=fRef;
925 COMPLEX16 curr_ylm, tmp;
926 COMPLEX16TimeSeries *curr_hlm=NULL;
927 REAL8TimeSeries *hplus_corr;
928 REAL8TimeSeries *hcross_corr;
929
930 /* These keys follow a strict formulation and cannot be longer than 11
931 * characters */
932 LALH5File *file=NULL;
933 LIGOTimeGPS tmpEpoch = LIGOTIMEGPSZERO;
934 SphHarmTimeSeries *tmp_Hlms=NULL;
935
936 /* Use solar masses for units. NR files will use
937 * solar masses as well, so easier for that conversion
938 */
939 m1 = m1_SI / LAL_MSUN_SI;
940 m2 = m2_SI / LAL_MSUN_SI;
941
942 file = XLALH5FileOpen(NRDataFile, "r");
943 if (file == NULL)
944 {
945 XLAL_ERROR(XLAL_EIO, "NR SIMULATION DATA FILE %s NOT FOUND.\n", NRDataFile);
946 }
947
948 XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
949 if (nr_file_format < 2)
950 {
951 XLALPrintInfo("This NR file is format %d. Only formats 2 and above support the use of reference frequency. For formats < 2 the reference frequency always corresponds to the start of the waveform.", nr_file_format);
952 fRef_pass = -1;
953 }
954 INT4 err_code = XLALSimIMRNRWaveformGetModes(&tmp_Hlms,&tmpEpoch,&array_length, \
955 deltaT, m1, m2, r, fStart, fRef_pass, \
956 s1x,s1y,s1z,s2x,s2y,s2z, \
957 file, ModeArray);
958 if (err_code!=XLAL_SUCCESS)
960
961 /* Compute correct angles for hplus and hcross following LAL convention. */
962
963 theta = psi = calpha = salpha = 0.;
965 &salpha, file, inclination, phiRef, fRef_pass*(m1+m2));
967
968 *hplus = XLALCreateREAL8TimeSeries("H_PLUS", &tmpEpoch, 0.0, deltaT,
969 &lalStrainUnit, array_length );
970 *hcross = XLALCreateREAL8TimeSeries("H_CROSS", &tmpEpoch, 0.0, deltaT,
971 &lalStrainUnit, array_length );
972
973 hplus_corr = XLALCreateREAL8TimeSeries("H_PLUS", &tmpEpoch, 0.0, deltaT,
974 &lalStrainUnit, array_length );
975 hcross_corr = XLALCreateREAL8TimeSeries("H_CROSS", &tmpEpoch, 0.0, deltaT,
976 &lalStrainUnit, array_length );
977 for (curr_idx = 0; curr_idx < array_length; curr_idx++)
978 {
979 hplus_corr->data->data[curr_idx] = 0.0;
980 hcross_corr->data->data[curr_idx] = 0.0;
981 }
982
983 NRLmax=XLALSphHarmTimeSeriesGetMaxL(tmp_Hlms);
984
985 for (model=2; model < (NRLmax + 1) ; model++)
986 {
987 for (modem=-model; modem < (model+1); modem++)
988 {
989 curr_ylm = XLALSpinWeightedSphericalHarmonic(theta, psi, -2, model, modem);
990 curr_hlm = XLALSphHarmTimeSeriesGetMode(tmp_Hlms, model, modem);
991 if (curr_hlm) {
992 for (curr_idx = 0; curr_idx < array_length; curr_idx++)
993 {
994 tmp=curr_hlm->data->data[curr_idx]*curr_ylm;
995 hplus_corr->data->data[curr_idx] += creal(tmp);
996 hcross_corr->data->data[curr_idx] -= cimag(tmp);
997 }
998 }
999 }
1000 }
1002
1003 /* Correct for the "alpha" angle as given in T1500606 or arxiv:1703.01076
1004 * to translate from the NR wave frame to LAL wave-frame.
1005 *
1006 * Helper time series needed.
1007 */
1008
1009 for (curr_idx = 0; curr_idx < array_length; curr_idx++)
1010 {
1011 (*hplus)->data->data[curr_idx] =
1012 (calpha*calpha - salpha*salpha) * hplus_corr->data->data[curr_idx]
1013 - 2.0*calpha*salpha * hcross_corr->data->data[curr_idx];
1014
1015 (*hcross)->data->data[curr_idx] =
1016 + 2.0*calpha*salpha * hplus_corr->data->data[curr_idx]
1017 + (calpha*calpha - salpha*salpha) * hcross_corr->data->data[curr_idx];
1018 }
1019
1020 XLALDestroyREAL8TimeSeries(hplus_corr);
1021 XLALDestroyREAL8TimeSeries(hcross_corr);
1022
1023 return XLAL_SUCCESS;
1024#endif
1025}
1026
1027/* Everything needs to be declared as unused in case HDF is not enabled. */
1029 UNUSED REAL8 deltaT, /**< sampling interval (s) */
1030 UNUSED REAL8 m1_SI, /**< mass of companion 1 (kg) */
1031 UNUSED REAL8 m2_SI, /**< mass of companion 2 (kg) */
1032 UNUSED REAL8 r, /**< distance of source (m) */
1033 UNUSED REAL8 fStart, /**< start GW frequency (Hz) */
1034 UNUSED REAL8 fRef, /**< reference GW frequency (Hz) */
1035 UNUSED REAL8 s1x, /**< initial value of S1x */
1036 UNUSED REAL8 s1y, /**< initial value of S1y */
1037 UNUSED REAL8 s1z, /**< initial value of S1z */
1038 UNUSED REAL8 s2x, /**< initial value of S2x */
1039 UNUSED REAL8 s2y, /**< initial value of S2y */
1040 UNUSED REAL8 s2z, /**< initial value of S2z */
1041 UNUSED const char *NRDataFile, /**< Location of NR HDF file */
1042 UNUSED LALValue* ModeArray /**< Container for the ell and m modes to generate. To generate all available modes pass NULL */
1043 )
1044{
1045#ifndef LAL_HDF5_ENABLED
1046 XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
1047#else
1048 /* Declarations */
1049 UINT4 curr_idx, array_length, nr_file_format;
1050 INT4 model, modem, NRLmax;
1051 REAL8 m1,m2;
1052 REAL8 theta, psi, calpha, salpha;
1053 REAL8 fRef_pass=fRef;
1054 COMPLEX16TimeSeries *tmp_hlm=NULL;
1055 SphHarmTimeSeries *tmp_Hlms=NULL;
1056 LALH5File *file;
1057 LIGOTimeGPS tmpEpoch = LIGOTIMEGPSZERO;
1058
1059 /* Use solar masses for units. NR files will use
1060 * solar masses as well, so easier for that conversion
1061 */
1062 m1 = m1_SI / LAL_MSUN_SI;
1063 m2 = m2_SI / LAL_MSUN_SI;
1064
1065 file = XLALH5FileOpen(NRDataFile, "r");
1066 if (file == NULL)
1067 {
1068 XLAL_ERROR(XLAL_EIO, "NR SIMULATION DATA FILE %s NOT FOUND.\n", NRDataFile);
1069 }
1070
1071 XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
1072 if (nr_file_format < 2)
1073 {
1074 XLALPrintInfo("This NR file is format %d. Only formats 2 and above support the use of reference frequency. For formats < 2 the reference frequency always corresponds to the start of the waveform.", nr_file_format);
1075 fRef_pass = -1;
1076 }
1077
1078 INT4 err_code = XLALSimIMRNRWaveformGetModes(&tmp_Hlms,&tmpEpoch,&array_length, \
1079 deltaT, m1, m2, r, fStart, fRef_pass, \
1080 s1x,s1y,s1z,s2x,s2y,s2z, \
1081 file, ModeArray);
1082 if (err_code!=XLAL_SUCCESS)
1084
1085 /* Compute correct angles for hplus and hcross following LAL convention. */
1086
1087 psi = calpha = salpha = 0.;
1089 &salpha, file, 0., 0., fRef_pass*(m1+m2));
1091
1092 NRLmax= XLALSphHarmTimeSeriesGetMaxL(tmp_Hlms);
1093 COMPLEX16 facm=-1;
1094 for (model=2; model < (NRLmax + 1) ; model++)
1095 {
1096 for (modem=-model; modem < (model+1); modem++)
1097 {
1098 tmp_hlm=XLALSphHarmTimeSeriesGetMode(tmp_Hlms,model,modem);
1099 if (tmp_hlm) {
1100 for (curr_idx = 0; curr_idx < array_length; curr_idx++)
1101 tmp_hlm->data->data[curr_idx]*=facm;
1102 *Hlms=XLALSphHarmTimeSeriesAddMode(*Hlms,tmp_hlm,model,modem);
1103 }
1104 facm*=I;
1105 }
1106 facm=1./facm;
1107 }
1109
1110 /* Correct for the "alpha" angle as given in T1500606 or arxiv:1703.01076
1111 * to translate from the NR wave frame to LAL wave-frame.
1112 */
1113
1114 REAL8TimeSeries *alphats = XLALCreateREAL8TimeSeries("alpha", &tmpEpoch, 0.0, deltaT, &lalDimensionlessUnit, array_length );
1115 REAL8TimeSeries *thetats = XLALCreateREAL8TimeSeries("theta", &tmpEpoch, 0.0, deltaT, &lalDimensionlessUnit, array_length );
1116 REAL8TimeSeries *psits = XLALCreateREAL8TimeSeries("tpsi", &tmpEpoch, 0.0, deltaT, &lalDimensionlessUnit, array_length );
1117 REAL8 alpha=atan2(salpha,calpha);
1118
1119 for (curr_idx = 0; curr_idx < array_length; curr_idx++) {
1120 alphats->data->data[curr_idx] = alpha;
1121 thetats->data->data[curr_idx] =-theta;
1122 psits->data->data[curr_idx] =-psi;
1123 }
1124
1125 err_code=XLALSimInspiralPrecessionRotateModes(*Hlms,alphats,thetats,psits);
1126 if (err_code!=XLAL_SUCCESS)
1131
1132 return XLAL_SUCCESS;
1133#endif
1134}
struct tagLALH5File LALH5File
int XLALSimIMRSEOBNRv4ROMTimeOfFrequency(REAL8 *t, REAL8 frequency, REAL8 m1SI, REAL8 m2SI, REAL8 chi1, REAL8 chi2)
Compute the 'time' elapsed in the ROM waveform from a given starting frequency until the ringdown.
static UNUSED REAL8 XLALSimInspiralNRWaveformGetInterpValueFromGroupAtPoint(UNUSED LALH5File *file, UNUSED const char *groupName, UNUSED REAL8 ref_point)
int XLALSimInspiralNRWaveformGetSpinsFromHDF5File(UNUSED REAL8 *S1x, UNUSED REAL8 *S1y, UNUSED REAL8 *S1z, UNUSED REAL8 *S2x, UNUSED REAL8 *S2y, UNUSED REAL8 *S2z, UNUSED REAL8 fRef, UNUSED REAL8 mTot, UNUSED const char *NRDataFile)
INT4 XLALSimInspiralNRWaveformGetHplusHcross(UNUSED REAL8TimeSeries **hplus, UNUSED REAL8TimeSeries **hcross, UNUSED REAL8 phiRef, UNUSED REAL8 inclination, UNUSED REAL8 deltaT, UNUSED REAL8 m1_SI, UNUSED REAL8 m2_SI, UNUSED REAL8 r, UNUSED REAL8 fStart, UNUSED REAL8 fRef, UNUSED REAL8 s1x, UNUSED REAL8 s1y, UNUSED REAL8 s1z, UNUSED REAL8 s2x, UNUSED REAL8 s2y, UNUSED REAL8 s2z, UNUSED const char *NRDataFile, UNUSED LALValue *ModeArray)
static UNUSED REAL8 XLALSimInspiralNRWaveformGetRefTimeFromRefFreq(UNUSED LALH5File *file, UNUSED REAL8 fRef)
static UNUSED UINT4 XLALSimInspiralNRWaveformGetDataFromHDF5File(UNUSED REAL8Vector **output, UNUSED LALH5File *pointer, UNUSED REAL8 totalMass, UNUSED REAL8 startTime, UNUSED size_t length, UNUSED REAL8 deltaT, UNUSED const char *keyName)
INT4 XLALSimInspiralNRWaveformGetHlms(UNUSED SphHarmTimeSeries **Hlms, UNUSED REAL8 deltaT, UNUSED REAL8 m1_SI, UNUSED REAL8 m2_SI, UNUSED REAL8 r, UNUSED REAL8 fStart, UNUSED REAL8 fRef, UNUSED REAL8 s1x, UNUSED REAL8 s1y, UNUSED REAL8 s1z, UNUSED REAL8 s2x, UNUSED REAL8 s2y, UNUSED REAL8 s2z, UNUSED const char *NRDataFile, UNUSED LALValue *ModeArray)
static UNUSED INT4 XLALSimIMRNRWaveformGetModes(UNUSED SphHarmTimeSeries **Hlms, UNUSED LIGOTimeGPS *epoch, UNUSED UINT4 *length, UNUSED REAL8 deltaT, UNUSED REAL8 m1, UNUSED REAL8 m2, UNUSED REAL8 r, UNUSED REAL8 fStart, UNUSED REAL8 fRef, UNUSED REAL8 s1x, UNUSED REAL8 s1y, UNUSED REAL8 s1z, UNUSED REAL8 s2x, UNUSED REAL8 s2y, UNUSED REAL8 s2z, UNUSED LALH5File *file, UNUSED LALValue *ModeArray)
static UNUSED UINT4 XLALSimInspiralNRWaveformGetSpinsFromHDF5FilePointer(UNUSED REAL8 *S1x, UNUSED REAL8 *S1y, UNUSED REAL8 *S1z, UNUSED REAL8 *S2x, UNUSED REAL8 *S2y, UNUSED REAL8 *S2z, UNUSED REAL8 fRef, UNUSED REAL8 mTot, UNUSED LALH5File *file)
static UNUSED REAL8 XLALSimInspiralNRWaveformCheckFRef(UNUSED LALH5File *file, UNUSED REAL8 fRef)
static UNUSED UINT4 XLALSimInspiralNRWaveformGetRotationAnglesFromH5File(UNUSED REAL8 *theta, UNUSED REAL8 *psi, UNUSED REAL8 *calpha, UNUSED REAL8 *salpha, UNUSED LALH5File *filepointer, UNUSED const REAL8 inclination, UNUSED const REAL8 phi_ref, UNUSED REAL8 fRef)
Auxiliary functions for SEOBNRv1/v2 reduced order modeling codes in LALSimIMRSEOBNRv2ROMDoubleSpin....
void XLALDestroyValue(LALValue *value)
double theta
Definition: bh_sphwf.c:118
void XLALH5FileClose(LALH5File UNUSED *file)
LALH5File * XLALH5GroupOpen(LALH5File UNUSED *file, const char UNUSED *name)
int XLALH5FileQueryScalarAttributeValue(void UNUSED *value, LALH5File UNUSED *file, const char UNUSED *key)
LALH5File * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
int XLALH5FileCheckGroupExists(const LALH5File UNUSED *file, const char UNUSED *name)
#define LAL_MSUN_SI
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
#define LIGOTIMEGPSZERO
double complex COMPLEX16
double REAL8
int64_t INT8
uint32_t UINT4
int32_t INT4
int XLALSimInspiralPrecessionRotateModes(SphHarmTimeSeries *h_lm, REAL8TimeSeries *alpha, REAL8TimeSeries *beta, REAL8TimeSeries *gam)
Takes in the h_lm spherical harmonic decomposed modes and rotates the modes by Euler angles alpha,...
int XLALSimInspiralModeArrayIsModeActive(LALValue *modes, unsigned l, int m)
LALValue * XLALSimInspiralCreateModeArray(void)
Create a LALValue pointer to store the mode array.
LALValue * XLALSimInspiralModeArrayActivateAllModesAtL(LALValue *modes, unsigned l)
COMPLEX16TimeSeries * XLALSphHarmTimeSeriesGetMode(SphHarmTimeSeries *ts, UINT4 l, INT4 m)
Get the time series of a waveform's (l,m) spherical harmonic mode from a SphHarmTimeSeries linked lis...
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.
UINT4 XLALSphHarmTimeSeriesGetMaxL(SphHarmTimeSeries *ts)
Get the largest l index of any mode in the SphHarmTimeSeries linked list.
void XLALDestroySphHarmTimeSeries(SphHarmTimeSeries *ts)
Delete list from current pointer to the end of the list.
static const INT4 r
COMPLEX16 XLALSpinWeightedSphericalHarmonic(REAL8 theta, REAL8 phi, int s, int l, int m)
void XLALDestroyCOMPLEX16TimeSeries(COMPLEX16TimeSeries *series)
COMPLEX16TimeSeries * XLALCreateCOMPLEX16TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
REAL8TimeSeries * XLALCreateREAL8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
const LALUnit lalStrainUnit
const LALUnit lalDimensionlessUnit
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
#define XLAL_PRINT_INFO(...)
#define xlalErrno
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_ERROR(...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
string status
double alpha
Definition: sgwb.c:106
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8Sequence * data
REAL8 * data
Structure to carry a collection of spherical harmonic modes in COMPLEX16 time series.
LIGOTimeGPS epoch
Definition: unicorn.c:20
char output[FILENAME_MAX]
Definition: unicorn.c:26
double deltaT
Definition: unicorn.c:24