LALInspiral 5.0.3.1-eeff03c
LALEOBNonQCCorrection.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2010 Craig Robinson
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
21/**
22 * \author Craig Robinson
23 *
24 * \brief More recent versions of the EOB model, such as EOBNR_v2, utilise
25 * a non-quasicircular correction to bring the peak of the EOB frequency
26 * into agreement with that of NR simulations. This file contains the functions
27 * used to calculate these NQC corrections. The fits to NR peak amplitude,
28 * frequency, and their derivatives, are taken from Pan et al, arXiv:1106.1021v1 [gr-qc].
29 *
30 */
31
32#include <math.h>
33
34#include <lal/XLALGSL.h>
35#include <lal/LALInspiral.h>
36#include <lal/LALEOBNRv2Waveform.h>
37
38#include <gsl/gsl_vector.h>
39#include <gsl/gsl_matrix.h>
40#include <gsl/gsl_spline.h>
41#include <gsl/gsl_linalg.h>
42
43
45{
46 switch ( l )
47 {
48 case 2:
49 if ( m == 2 )
50 {
51 return 0.0;
52 }
53 else if ( m == 1 )
54 {
55 return 10.67 - 41.41 * eta + 76.1 * eta*eta;
56 }
57 else
58 {
60 }
61 break;
62 case 3:
63 if ( m == 3 )
64 {
65 return 3.383 + 3.847 * eta + 8.979 * eta * eta;
66 }
67 else
68 {
70 }
71 break;
72 case 4:
73 if ( m == 4 )
74 {
75 return 5.57 - 49.86 * eta + 154.3 * eta * eta;
76 }
77 else
78 {
80 }
81 break;
82 case 5:
83 if ( m == 5 )
84 {
85 return 6.693 - 34.47 * eta + 102.7 * eta*eta;
86 }
87 else
88 {
90 }
91 break;
92 default:
94 break;
95 }
96}
97
98static inline
100{
101 switch ( l )
102 {
103 case 2:
104 if ( m == 2 )
105 {
106 return eta * ( 1.422 + 0.3013 * eta + 1.246 * eta * eta );
107 }
108 else if ( m == 1 )
109 {
110 return eta * sqrt( 1.0 - 4. * eta ) * (0.4832 - 0.01032 * eta);
111 }
112 else
113 {
115 }
116 break;
117 case 3:
118 if ( m == 3 )
119 {
120 return eta * sqrt(1.-4.*eta) * ( 0.5761 - 0.09638 * eta + 2.715*eta*eta );
121 }
122 else
123 {
125 }
126 break;
127 case 4:
128 if ( m == 4 )
129 {
130 return eta * (0.354 - 1.779 * eta + 2.834 * eta*eta );
131 }
132 else
133 {
135 }
136 break;
137 case 5:
138 if ( m == 5 )
139 {
140 return eta * sqrt(1.-4.*eta) * ( 0.1353 - 0.1485 * eta );
141 }
142 else
143 {
145 }
146 break;
147 default:
149 break;
150 }
151}
152
153static inline
155{
156 switch ( l )
157 {
158 case 2:
159 if ( m == 2 )
160 {
161 return -0.01 * eta * ( 0.1679 + 1.44 * eta - 2.001 * eta * eta );
162 }
163 else if ( m == 1 )
164 {
165 return -0.01 * eta * sqrt(1.-4.*eta) * (0.1867 + 0.6094 * eta );
166 }
167 else
168 {
170 }
171 break;
172 case 3:
173 if ( m == 3 )
174 {
175 return -0.01 * eta * sqrt(1.-4.*eta) * (0.2518 - 0.8145*eta + 5.731*eta*eta);
176 }
177 else
178 {
180 }
181 break;
182 case 4:
183 if ( m == 4 )
184 {
185 return -0.01 * eta * (0.1813 - 0.9935 * eta + 1.858 * eta * eta );
186 }
187 else
188 {
190 }
191 break;
192 case 5:
193 if ( m == 5 )
194 {
195 return -0.01 * eta * sqrt(1.-4.*eta) * ( 0.09051 - 0.1604 * eta );
196 }
197 else
198 {
200 }
201 break;
202 default:
204 break;
205 }
206}
207
208static inline
210{
211 switch ( l )
212 {
213 case 2:
214 if ( m == 2 )
215 {
216 return 0.2733 + 0.2316 * eta + 0.4463 * eta * eta;
217 }
218 else if ( m == 1 )
219 {
220 return 0.2907 - 0.08338 * eta + 0.587 * eta*eta;
221 }
222 else
223 {
225 }
226 break;
227 case 3:
228 if ( m == 3 )
229 {
230 return 0.4539 + 0.5376 * eta + 1.042 * eta*eta;
231 }
232 else
233 {
235 }
236 break;
237 case 4:
238 if ( m == 4 )
239 {
240 return 0.6435 - 0.05103 * eta + 2.216 * eta*eta;
241 }
242 else
243 {
245 }
246 break;
247 case 5:
248 if ( m == 5 )
249 {
250 return 0.8217 + 0.2346 * eta + 2.599 * eta*eta;
251 }
252 else
253 {
255 }
256 break;
257 default:
259 break;
260 }
261}
262
263static inline
265{
266 switch ( l )
267 {
268 case 2:
269 if ( m == 2 )
270 {
271 return 0.005862 + 0.01506 * eta + 0.02625 * eta * eta;
272 }
273 else if ( m == 1 )
274 {
275 return 0.00149 + 0.09197 * eta - 0.1909 * eta*eta;
276 }
277 else
278 {
280 }
281 break;
282 case 3:
283 if ( m == 3 )
284 {
285 return 0.01074 + 0.0293 * eta + 0.02066 * eta*eta;
286 }
287 else
288 {
290 }
291 break;
292 case 4:
293 if ( m == 4 )
294 {
295 return 0.01486 + 0.08529 * eta - 0.2174 * eta * eta;
296 }
297 else
298 {
300 }
301 break;
302 case 5:
303 if ( m == 5 )
304 {
305 return 0.01775 + 0.09801 * eta - 0.1686 * eta*eta;
306 }
307 else
308 {
310 }
311 break;
312 default:
314 break;
315 }
316}
317
318
319/**
320 * For the 2,2 mode, there are fits available for the NQC coefficients.
321 * This function provides the values of these coefficients, so the
322 * correction can be used in the dynamics prior to finding the more
323 * accurate NQC values later on.
324 */
326 INT4 l,
327 INT4 m,
328 REAL8 eta
329 )
330{
331
332 if ( !coeffs )
333 {
335 }
336
337 if ( l != 2 || m != 2 )
338 {
339 XLALPrintError( "Mode %d,%d is not supported by this function.\n", l, m );
341 }
342
343 /* All NQC coefficients are set to zero here */
344 /* including coeffs->a4 that is not used in EOBNRv2 */
345 memset( coeffs, 0, sizeof( *coeffs ) );
346
347 coeffs->a1 = -4.55919 + 18.761 * eta - 24.226 * eta*eta;
348 coeffs->a2 = 37.683 - 201.468 * eta + 324.591 * eta*eta;
349 coeffs->a3 = - 39.6024 + 228.899 * eta - 387.222 * eta * eta;
350
351 return XLAL_SUCCESS;
352}
353
354
356 COMPLEX16 * restrict nqc,
357 REAL8Vector * restrict values,
358 const REAL8 omega,
359 EOBNonQCCoeffs * restrict coeffs
360 )
361
362{
363
364 REAL8 rOmega, rOmegaSq;
365 REAL8 r, p;
366
367 REAL8 mag, phase;
368
369
370 r = values->data[0];
371 p = values->data[2];
372
373 rOmega = r * omega;
374 rOmegaSq = rOmega*rOmega;
375
376 /* In EOBNRv2, coeffs->a4 is set to zero */
377 /* through XLALSimIMREOBGetCalibratedNQCCoeffs() */
378 /* and XLALSimIMREOBCalculateNQCCoefficients() */
379 mag = 1. + (p*p / rOmegaSq) * ( coeffs->a1
380 + coeffs->a2 / r + coeffs->a3 / (r*sqrt(r))
381 + coeffs->a4 / (r*r) );
382
383 phase = coeffs->b1 * p / rOmega + coeffs->b2 * p*p*p/rOmega;
384
385 *nqc = crect( mag * cos(phase), mag * sin(phase) );
386
387 return XLAL_SUCCESS;
388
389}
390
391
393 REAL8Vector * restrict amplitude,
394 REAL8Vector * restrict phase,
395 REAL8Vector * restrict q1,
396 REAL8Vector * restrict q2,
397 REAL8Vector * restrict q3,
398 REAL8Vector * restrict p1,
399 REAL8Vector * restrict p2,
400 INT4 l,
401 INT4 m,
402 REAL8 timePeak,
403 REAL8 deltaT,
404 REAL8 eta,
405 EOBNonQCCoeffs * restrict coeffs )
406{
407
408 UINT4 i;
409
410 /* For gsl permutation stuff */
411
412 int signum;
413
414 REAL8Vector * restrict time = NULL;
415
416 /* Since the vectors we actually want are q etc * A, we will have to generate them here */
417 REAL8Vector *q1LM = NULL;
418 REAL8Vector *q2LM = NULL;
419 REAL8Vector *q3LM = NULL;
420
421 REAL8 a, aDot, aDDot;
422 REAL8 omega, omegaDot;
423
424 REAL8 nra, nraDDot;
425 REAL8 nromega, nromegaDot;
426
427 REAL8 nrDeltaT, nrTimePeak;
428
429 /* Stuff for finding numerical derivatives */
430 gsl_spline *spline = NULL;
431 gsl_interp_accel *acc = NULL;
432
433 /* Matrix stuff for calculating coefficients */
434 gsl_matrix *qMatrix = NULL, *pMatrix = NULL;
435 gsl_vector *aCoeff = NULL, *bCoeff = NULL;
436
437 gsl_vector *amps = NULL, *omegaVec = NULL;
438
439 gsl_permutation *perm1 = NULL, *perm2 = NULL;
440
441 /* All NQC coefficients are set to zero here */
442 /* including coeffs->a4 that is not used in EOBNRv2 */
443 memset( coeffs, 0, sizeof( EOBNonQCCoeffs ) );
444
445 /* Populate the time vector */
446 /* It is okay to assume initial t = 0 */
447 time = XLALCreateREAL8Vector( q1->length );
448 q1LM = XLALCreateREAL8Vector( q1->length );
449 q2LM = XLALCreateREAL8Vector( q2->length );
450 q3LM = XLALCreateREAL8Vector( q3->length );
451
452 /* Populate vectors as necessary */
453 for ( i = 0; i < time->length; i++ )
454 {
455 time->data[i] = i * deltaT;
456 q1LM->data[i] = q1->data[i] * amplitude->data[i];
457 q2LM->data[i] = q2->data[i] * amplitude->data[i];
458 q3LM->data[i] = q3->data[i] * amplitude->data[i];
459 }
460
461 /* Allocate all the memory we need */
463 /* a stuff */
464 qMatrix = gsl_matrix_alloc( 3, 3 );
465 aCoeff = gsl_vector_alloc( 3 );
466 amps = gsl_vector_alloc( 3 );
467 perm1 = gsl_permutation_alloc( 3 );
468
469 /* b stuff */
470 pMatrix = gsl_matrix_alloc( 2, 2 );
471 bCoeff = gsl_vector_alloc( 2 );
472 omegaVec = gsl_vector_alloc( 2 );
473 perm2 = gsl_permutation_alloc( 2 );
474 );
475
476 if ( !qMatrix || !aCoeff || !amps || !pMatrix || !bCoeff || !omegaVec )
477 {
478 gsl_matrix_free( qMatrix );
479 gsl_vector_free( amps );
480 gsl_vector_free( aCoeff );
481 gsl_permutation_free( perm1 );
482 gsl_matrix_free( pMatrix );
483 gsl_vector_free( omegaVec );
484 gsl_vector_free( bCoeff );
485 gsl_permutation_free( perm2 );
491 }
492
493 /* The time we want to take as the peak time depends on l and m */
494 /* Calculate the adjustment we need to make here */
495 nrDeltaT = XLALGetNRPeakDeltaT( l, m, eta );
496 if ( XLAL_IS_REAL8_FAIL_NAN( nrDeltaT ) )
497 {
499 }
500
501 nrTimePeak = timePeak + nrDeltaT;
502
503 /* We are now in a position to use the interp stuff to calculate the derivatives we need */
504 /* We will start with the quantities used in the calculation of the a coefficients */
505 spline = gsl_spline_alloc( gsl_interp_cspline, amplitude->length );
506 acc = gsl_interp_accel_alloc();
507
508 /* Q1 */
509 gsl_spline_init( spline, time->data, q1LM->data, q1LM->length );
510 gsl_matrix_set( qMatrix, 0, 0, gsl_spline_eval( spline, nrTimePeak, acc ) );
511 gsl_matrix_set( qMatrix, 1, 0, gsl_spline_eval_deriv( spline, nrTimePeak, acc ) );
512 gsl_matrix_set( qMatrix, 2, 0, gsl_spline_eval_deriv2( spline, nrTimePeak, acc ) );
513
514 /* Q2 */
515 gsl_spline_init( spline, time->data, q2LM->data, q2LM->length );
516 gsl_interp_accel_reset( acc );
517 gsl_matrix_set( qMatrix, 0, 1, gsl_spline_eval( spline, nrTimePeak, acc ) );
518 gsl_matrix_set( qMatrix, 1, 1, gsl_spline_eval_deriv( spline, nrTimePeak, acc ) );
519 gsl_matrix_set( qMatrix, 2, 1, gsl_spline_eval_deriv2( spline, nrTimePeak, acc ) );
520
521 /* Q3 */
522 gsl_spline_init( spline, time->data, q3LM->data, q3LM->length );
523 gsl_interp_accel_reset( acc );
524 gsl_matrix_set( qMatrix, 0, 2, gsl_spline_eval( spline, nrTimePeak, acc ) );
525 gsl_matrix_set( qMatrix, 1, 2, gsl_spline_eval_deriv( spline, nrTimePeak, acc ) );
526 gsl_matrix_set( qMatrix, 2, 2, gsl_spline_eval_deriv2( spline, nrTimePeak, acc ) );
527
528 /* Amplitude */
529 gsl_spline_init( spline, time->data, amplitude->data, amplitude->length );
530 gsl_interp_accel_reset( acc );
531 a = gsl_spline_eval( spline, nrTimePeak, acc );
532 aDot = gsl_spline_eval_deriv( spline, nrTimePeak, acc );
533 aDDot = gsl_spline_eval_deriv2( spline, nrTimePeak, acc );
534
535 nra = GetNRPeakAmplitude( l, m, eta );
536 nraDDot = GetNRPeakADDot( l, m, eta );
537
538 if ( XLAL_IS_REAL8_FAIL_NAN( nra ) || XLAL_IS_REAL8_FAIL_NAN( nraDDot ) )
539 {
541 }
542
543 gsl_vector_set( amps, 0, nra - a );
544 gsl_vector_set( amps, 1, - aDot );
545 gsl_vector_set( amps, 2, nraDDot - aDDot );
546
547 /* We have now set up all the stuff to calculate the a coefficients */
548 /* So let us do it! */
549 gsl_linalg_LU_decomp( qMatrix, perm1, &signum );
550 gsl_linalg_LU_solve( qMatrix, perm1, amps, aCoeff );
551
552 /* Now we (should) have calculated the a values. Now we can do the b values */
553
554 /* P1 */
555 gsl_spline_init( spline, time->data, p1->data, p1->length );
556 gsl_interp_accel_reset( acc );
557 gsl_matrix_set( pMatrix, 0, 0, - gsl_spline_eval_deriv( spline, nrTimePeak, acc ) );
558 gsl_matrix_set( pMatrix, 1, 0, - gsl_spline_eval_deriv2( spline, nrTimePeak, acc ) );
559
560 /* P2 */
561 gsl_spline_init( spline, time->data, p2->data, p2->length );
562 gsl_interp_accel_reset( acc );
563 gsl_matrix_set( pMatrix, 0, 1, - gsl_spline_eval_deriv( spline, nrTimePeak, acc ) );
564 gsl_matrix_set( pMatrix, 1, 1, - gsl_spline_eval_deriv2( spline, nrTimePeak, acc ) );
565
566 /* Phase */
567 gsl_spline_init( spline, time->data, phase->data, phase->length );
568 gsl_interp_accel_reset( acc );
569 omega = gsl_spline_eval_deriv( spline, nrTimePeak, acc );
570 omegaDot = gsl_spline_eval_deriv2( spline, nrTimePeak, acc );
571
572 /* Since the phase can be decreasing, we need to take care not to have a -ve frequency */
573 if ( omega * omegaDot > 0.0 )
574 {
575 omega = fabs( omega );
576 omegaDot = fabs( omegaDot );
577 }
578 else
579 {
580 omega = fabs( omega );
581 omegaDot = - fabs( omegaDot );
582 }
583
584 nromega = GetNRPeakOmega( l, m, eta );
585 nromegaDot = GetNRPeakOmegaDot( l, m, eta );
586
587 if ( XLAL_IS_REAL8_FAIL_NAN( nromega ) || XLAL_IS_REAL8_FAIL_NAN( nromegaDot ) )
588 {
590 }
591
592 gsl_vector_set( omegaVec, 0, nromega - omega );
593 gsl_vector_set( omegaVec, 1, nromegaDot - omegaDot );
594
595 /* And now solve for the b coefficients */
596 gsl_linalg_LU_decomp( pMatrix, perm2, &signum );
597 gsl_linalg_LU_solve( pMatrix, perm2, omegaVec, bCoeff );
598
599 /* We can now populate the coefficients structure */
600 coeffs->a1 = gsl_vector_get( aCoeff, 0 );
601 coeffs->a2 = gsl_vector_get( aCoeff, 1 );
602 coeffs->a3 = gsl_vector_get( aCoeff, 2 );
603 coeffs->b1 = gsl_vector_get( bCoeff, 0 );
604 coeffs->b2 = gsl_vector_get( bCoeff, 1 );
605
606 /* Free memory and exit */
607 gsl_matrix_free( qMatrix );
608 gsl_vector_free( amps );
609 gsl_vector_free( aCoeff );
610 gsl_permutation_free( perm1 );
611
612 gsl_matrix_free( pMatrix );
613 gsl_vector_free( omegaVec );
614 gsl_vector_free( bCoeff );
615 gsl_permutation_free( perm2 );
616
617 gsl_spline_free( spline );
618 gsl_interp_accel_free( acc );
619
624
625 return XLAL_SUCCESS;
626}
static REAL8 GetNRPeakADDot(INT4 l, INT4 m, REAL8 eta)
int XLALCalculateNQCCoefficients(REAL8Vector *restrict amplitude, REAL8Vector *restrict phase, REAL8Vector *restrict q1, REAL8Vector *restrict q2, REAL8Vector *restrict q3, REAL8Vector *restrict p1, REAL8Vector *restrict p2, INT4 l, INT4 m, REAL8 timePeak, REAL8 deltaT, REAL8 eta, EOBNonQCCoeffs *restrict coeffs)
static REAL8 GetNRPeakAmplitude(INT4 l, INT4 m, REAL8 eta)
int XLALEOBNonQCCorrection(COMPLEX16 *restrict nqc, REAL8Vector *restrict values, const REAL8 omega, EOBNonQCCoeffs *restrict coeffs)
static REAL8 GetNRPeakOmega(INT4 l, INT4 m, REAL8 eta)
static REAL8 GetNRPeakOmegaDot(INT4 l, INT4 m, REAL8 eta)
#define XLAL_CALLGSL(statement)
int l
double i
#define crect(re, im)
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
REAL8 XLALGetNRPeakDeltaT(INT4 l, INT4 m, REAL8 eta)
More recent versions of the EOB model, such as EOBNR_v2, utilise a non-quasicircular correction to br...
int XLALGetCalibratedNQCCoeffs(EOBNonQCCoeffs *coeffs, INT4 l, INT4 m, REAL8 eta)
For the 2,2 mode, there are fits available for the NQC coefficients.
static const INT4 r
static const INT4 m
static const INT4 a
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_IS_REAL8_FAIL_NAN(val)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EINVAL
p
REAL8 * data
double deltaT