Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimIMRPhenomUtils.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017 Sebastian Khan
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 * \author Sebastian Khan
22 *
23 * \file
24 *
25 * \brief External (SWIG'd) Auxiliary functions for phenomenological model development
26 *
27 * Helper functions for phenomenological waveform models
28 * Can be used through python SWIG wrapping
29 * NOTE: The convention for naming functions in there is to use
30 * the prefix 'XLALSimPhenom_'
31 */
32
33#include <lal/LALSimIMRPhenomUtils.h>
35#include <lal/LALSimIMR.h>
36#include <lal/SphericalHarmonics.h>
37
38// /**
39// * Example how to write an external XLAL phenom function
40// */
41// void XLALSimPhenomUtilsTest(){
42// printf("Hello! I am the XLALSimPhenomUtilsTest function\n");
43// }
44
45/**
46 * Convert from geometric frequency to frequency in Hz
47 */
49 REAL8 Mf, /**< Geometric frequency */
50 REAL8 Mtot_Msun /**< Total mass in solar masses */
51)
52{
53 return Mf / (LAL_MTSUN_SI * Mtot_Msun);
54}
55
56/**
57 * Convert from frequency in Hz to geometric frequency
58 */
60 REAL8 fHz, /**< Frequency in Hz */
61 REAL8 Mtot_Msun /**< Total mass in solar masses */
62)
63{
64 return fHz * (LAL_MTSUN_SI * Mtot_Msun);
65}
66
67/**
68 * compute the frequency domain amplitude pre-factor
69 */
71 REAL8 Mtot_Msun, /**< total mass in solar masses */
72 REAL8 distance /**< distance (m) */
73)
74{
75 return Mtot_Msun * LAL_MRSUN_SI * Mtot_Msun * LAL_MTSUN_SI / distance;
76}
77
78/**
79 * Wrapper for final-spin formula based on:
80 * - IMRPhenomD's FinalSpin0815() for aligned spins.
81 *
82 * We use their convention m1>m2
83 * and put <b>all in-plane spin on the larger BH</b>.
84 *
85 * In the aligned limit return the FinalSpin0815 value.
86 *
87 * Function should reproduce
88 * the function FinalSpinIMRPhenomD_all_in_plane_spin_on_larger_BH
89 */
91 const REAL8 m1, /**< Mass of companion 1 (solar masses) */
92 const REAL8 m2, /**< Mass of companion 2 (solar masses) */
93 const REAL8 chi1_l, /**< Aligned spin of BH 1 */
94 const REAL8 chi2_l, /**< Aligned spin of BH 2 */
95 const REAL8 chip /**< Dimensionless spin in the orbital plane */
96)
97{
98 const REAL8 M = m1 + m2;
99
100 REAL8 af_parallel, q_factor;
101 if (m1 >= m2)
102 {
103 q_factor = m1 / M;
104 af_parallel = XLALSimIMRPhenomDFinalSpin(m1, m2, chi1_l, chi2_l);
105 }
106 else
107 {
108 q_factor = m2 / M;
109 af_parallel = XLALSimIMRPhenomDFinalSpin(m1, m2, chi1_l, chi2_l);
110 }
111
112 REAL8 Sperp = chip * q_factor * q_factor;
113 REAL8 af = copysign(1.0, af_parallel) * sqrt(Sperp * Sperp + af_parallel * af_parallel);
114 return af;
115}
116
117/**
118 * Helper function used in PhenomHM and PhenomPv3HM
119 * Returns the final mass from the fit used in PhenomD
120 */
122 REAL8 m1, /**< mass of primary in solar masses */
123 REAL8 m2, /**< mass of secondary in solar masses */
124 REAL8 chi1z, /**< aligned-spin component on primary */
125 REAL8 chi2z /**< aligned-spin component on secondary */
126)
127{
128 int retcode = 0;
130 &m1,
131 &m2,
132 &chi1z,
133 &chi2z);
135 XLAL_SUCCESS == retcode,
137 "PhenomInternal_AlignedSpinEnforcePrimaryIsm1 failed");
138 REAL8 Mtot = m1 + m2;
139 REAL8 eta = m1 * m2 / (Mtot * Mtot);
140 return (1.0 - PhenomInternal_EradRational0815(eta, chi1z, chi2z));
141}
142
143/**
144 * Wrapper for final-spin formula based on:
145 * - IMRPhenomD's FinalSpin0815() for aligned spins.
146 *
147 * We use their convention m1>m2
148 * and use all in-plane spin components to determine the final spin magnitude.
149 *
150 * In the aligned limit return the FinalSpin0815 value.
151 */
153 const REAL8 m1, /**< Mass of companion 1 (solar masses) */
154 const REAL8 m2, /**< Mass of companion 2 (solar masses) */
155 const REAL8 chi1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
156 const REAL8 chi1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
157 const REAL8 chi1z, /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
158 const REAL8 chi2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
159 const REAL8 chi2y, /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
160 const REAL8 chi2z /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
161)
162{
163
164 const REAL8 M = (m1 + m2) * XLALSimPhenomUtilsIMRPhenomDFinalMass(m1, m2, chi1z, chi2z);
165
166 REAL8 af_parallel, primary_q_factor, secondary_q_factor;
167 if (m1 >= m2)
168 {
169 primary_q_factor = m1 / M;
170 secondary_q_factor = m2 / M;
171 af_parallel = XLALSimIMRPhenomDFinalSpin(m1, m2, chi1z, chi2z);
172 }
173 else
174 {
175 primary_q_factor = m2 / M;
176 secondary_q_factor = m1 / M;
177 af_parallel = XLALSimIMRPhenomDFinalSpin(m1, m2, chi1z, chi2z);
178 }
179
180 REAL8 S1perp = sqrt(chi1x * chi1x + chi1y * chi1y) * primary_q_factor * primary_q_factor;
181 REAL8 S2perp = sqrt(chi2x * chi2x + chi2y * chi2y) * secondary_q_factor * secondary_q_factor;
182 REAL8 Sperp = S1perp + S2perp;
183 REAL8 af = copysign(1.0, af_parallel) * sqrt(Sperp * Sperp + af_parallel * af_parallel);
184 return af;
185}
186
187/**
188 * Function to compute the effective precession parameter chi_p (1408.1810)
189 */
191 const REAL8 m1, /**< Mass of companion 1 (solar masses) */
192 const REAL8 m2, /**< Mass of companion 2 (solar masses) */
193 const REAL8 s1x, /**< x-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
194 const REAL8 s1y, /**< y-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
195 const REAL8 s2x, /**< x-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
196 const REAL8 s2y /**< y-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
197)
198{
199 XLAL_CHECK(m1 > 0, XLAL_EDOM, "m1 must be positive.\n");
200 XLAL_CHECK(m2 > 0, XLAL_EDOM, "m2 must be positive.\n");
201 XLAL_CHECK(fabs(s1x * s1x + s1y * s1y) <= 1.0, XLAL_EDOM, "|S1_perp/m1^2| must be <= 1.\n");
202 XLAL_CHECK(fabs(s2x * s2x + s2y * s2y) <= 1.0, XLAL_EDOM, "|S2_perp/m2^2| must be <= 1.\n");
203
204 const REAL8 m1_2 = m1 * m1;
205 const REAL8 m2_2 = m2 * m2;
206
207 /* Magnitude of the spin projections in the orbital plane */
208 const REAL8 S1_perp = m1_2 * sqrt(s1x * s1x + s1y * s1y);
209 const REAL8 S2_perp = m2_2 * sqrt(s2x * s2x + s2y * s2y);
210
211 const REAL8 A1 = 2 + (3 * m2) / (2 * m1);
212 const REAL8 A2 = 2 + (3 * m1) / (2 * m2);
213 const REAL8 ASp1 = A1 * S1_perp;
214 const REAL8 ASp2 = A2 * S2_perp;
215 const REAL8 num = (ASp2 > ASp1) ? ASp2 : ASp1;
216 const REAL8 den = (m2 > m1) ? A2 * m2_2 : A1 * m1_2;
217 const REAL8 chip = num / den;
218
219 return chip;
220}
221
223{
225 memset(p, 0, sizeof(IMRPhenomPv3HMYlmStruct));
226
227 // for each ell mode we make an array from -ell ... ell
228 // of spherical harmonics and their complex conjugate
229 // ylm[0] = ylm
230 // ylm[1] = conj(ylm)
231
232 int midx=0;
233
234 if (ell == 2)
235 {
236 midx=0;
237 for (int m = -ell ; m<=ell; m++){
238 p->Ylm2[0][midx] = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, ell, m);
239 p->Ylm2[1][midx] = conj(p->Ylm2[0][midx]);
240 midx++;
241 }
242
243 }
244 else if (ell == 3)
245 {
246 midx = 0;
247 for (int m = -ell; m <= ell; m++)
248 {
249 p->Ylm3[0][midx] = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, ell, m);
250 p->Ylm3[1][midx] = conj(p->Ylm3[0][midx]);
251 midx++;
252 }
253 }
254 else if (ell == 4)
255 {
256 midx = 0;
257 for (int m = -ell; m <= ell; m++)
258 {
259 p->Ylm4[0][midx] = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, ell, m);
260 p->Ylm4[1][midx] = conj(p->Ylm4[0][midx]);
261 midx++;
262 }
263 }
264 else
265 {
266 XLAL_PRINT_ERROR("ell = %i mode not possible. Returning NULL\n", ell);
267 XLALFree(p);
268 p = NULL;
269 }
270
271 return p;
272}
273
274// IMRPhenomPv3HMAlphaStruct *XLALSimIMRPhenomPv3HMComputeAlphaElements(UINT4 ell, REAL8 alpha)
276{
277 // IMRPhenomPv3HMAlphaStruct *p = XLALMalloc(sizeof(IMRPhenomPv3HMAlphaStruct));
278 // memset(p, 0, sizeof(IMRPhenomPv3HMAlphaStruct));
279
280 // for each ell mode we make an array from -ell ... ell
281 // and compute the following
282 // [ cexp(I * m * alpha) for m in [-ell ... ell] ]
283 if (*p == NULL)
284 {
286 }
287
288
289 COMPLEX16 cexp_i_alpha = cexp(+I * alpha);
290 COMPLEX16 cexp_2i_alpha = cexp_i_alpha * cexp_i_alpha;
291 COMPLEX16 cexp_mi_alpha = 1.0 / cexp_i_alpha;
292 COMPLEX16 cexp_m2i_alpha = cexp_mi_alpha * cexp_mi_alpha;
293
294 COMPLEX16 cexp_3i_alpha = 0.;
295 COMPLEX16 cexp_m3i_alpha = 0.;
296 COMPLEX16 cexp_4i_alpha = 0.;
297 COMPLEX16 cexp_m4i_alpha = 0.;
298
299 if (ell == 2)
300 {
301
302 (*p)->alpha2[0] = cexp_m2i_alpha;
303 (*p)->alpha2[1] = cexp_mi_alpha;
304 (*p)->alpha2[2] = 1.0;
305 (*p)->alpha2[3] = cexp_i_alpha;
306 (*p)->alpha2[4] = cexp_2i_alpha;
307
308 }
309 else if (ell == 3)
310 {
311 cexp_3i_alpha = cexp_2i_alpha * cexp_i_alpha;
312 cexp_m3i_alpha = cexp_m2i_alpha * cexp_mi_alpha;
313
314 (*p)->alpha3[0] = cexp_m3i_alpha;
315 (*p)->alpha3[1] = cexp_m2i_alpha;
316 (*p)->alpha3[2] = cexp_mi_alpha;
317 (*p)->alpha3[3] = 1.0;
318 (*p)->alpha3[4] = cexp_i_alpha;
319 (*p)->alpha3[5] = cexp_2i_alpha;
320 (*p)->alpha3[6] = cexp_3i_alpha;
321 }
322 else if (ell == 4)
323 {
324 cexp_3i_alpha = cexp_2i_alpha * cexp_i_alpha;
325 cexp_m3i_alpha = cexp_m2i_alpha * cexp_mi_alpha;
326 cexp_4i_alpha = cexp_3i_alpha * cexp_i_alpha;
327 cexp_m4i_alpha = cexp_m3i_alpha * cexp_mi_alpha;
328
329 (*p)->alpha4[0] = cexp_m4i_alpha;
330 (*p)->alpha4[1] = cexp_m3i_alpha;
331 (*p)->alpha4[2] = cexp_m2i_alpha;
332 (*p)->alpha4[3] = cexp_mi_alpha;
333 (*p)->alpha4[4] = 1.0;
334 (*p)->alpha4[5] = cexp_i_alpha;
335 (*p)->alpha4[6] = cexp_2i_alpha;
336 (*p)->alpha4[7] = cexp_3i_alpha;
337 (*p)->alpha4[8] = cexp_4i_alpha;
338 }
339 else
340 {
341 XLAL_ERROR(XLAL_EFUNC, "ell = %i mode not possible.\n", ell);
342 // XLAL_ERROR_NULL(XLAL_EINVAL, "ell = %i mode not possible.\n", ell);
343 }
344
345 return XLAL_SUCCESS;
346}
347
348/**
349 * computes the wigner-d elements for -beta in batches.
350 * mprime - only takes positive values as the negative values are added
351 * automatically according to the symmetry
352 * d^{ell}_{-m',-m} = (-1)^{m'+m} d^{ell}_{m',m}.
353 */
354// IMRPhenomPv3HMWignderStruct *XLALSimIMRPhenomPv3HMComputeWignerdElements(UNUSED UINT4 ell, UNUSED INT4 mprime, UNUSED REAL8 b)
356{
357 if (*p == NULL)
358 {
360 }
361
362 REAL8 b2 = 2. * b;
363 REAL8 cosb = cos(b);
364 REAL8 cos2b = cos(b2);
365 REAL8 sinb = sin(b);
366
367 REAL8 b3 = 0.;
368 REAL8 cos2b_over_two = 0.;
369 REAL8 cos3b = 0.;
370
371 REAL8 cosb_over_two = cosb * ONE_OVER_TWO;
372 REAL8 cos2b_fac_1 = cos2b * ONE_OVER_EIGHT + THREE_OVER_EIGHT;
373 REAL8 cosb_minus_1 = cosb - 1.0;
374 REAL8 cosb_plus_1 = cosb + 1.0;
375
376 REAL8 sinb_over_two = sinb * ONE_OVER_TWO;
377
378 if (ell == 2 && mprime == 2)
379 {
380 //mprime == 2
381 (*p)->d22[0][0] = -cosb_over_two + cos2b_fac_1; //m=-2
382 (*p)->d22[0][1] = cosb_minus_1 * sinb_over_two; //m=-1
383 (*p)->d22[0][2] = SQRT_6 * (1. - cos2b) * ONE_OVER_EIGHT; //m=0
384 (*p)->d22[0][3] = -cosb_plus_1 * sinb_over_two; //m=1
385 (*p)->d22[0][4] = cosb_over_two + cos2b_fac_1; //m=2
386
387 //mprime == -2
388 (*p)->d22[1][0] = (*p)->d22[0][4];
389 (*p)->d22[1][1] = -(*p)->d22[0][3];
390 (*p)->d22[1][2] = (*p)->d22[0][2];
391 (*p)->d22[1][3] = -(*p)->d22[0][1];
392 (*p)->d22[1][4] = (*p)->d22[0][0];
393 }
394 else if (ell == 2 && mprime == 1)
395 {
396 REAL8 sin2b = sin(2.*b);
397 cos2b_over_two = cos2b * ONE_OVER_TWO;
398
399 //mprime == 1
400 (*p)->d21[0][0] = cosb_minus_1 * sinb_over_two; //m=-2
401 (*p)->d21[0][1] = cosb_over_two - cos2b_over_two; //m=-1
402 (*p)->d21[0][2] = -SQRT_6 * sin2b * ONE_OVER_FOUR; //m=0
403 (*p)->d21[0][3] = cosb_over_two + cos2b_over_two; //m=1
404 (*p)->d21[0][4] = cosb_plus_1 * sinb_over_two; //m=2
405
406 //mprime == -1
407 (*p)->d21[1][0] = -(*p)->d21[0][4];
408 (*p)->d21[1][1] = (*p)->d21[0][3];
409 (*p)->d21[1][2] = -(*p)->d21[0][2];
410 (*p)->d21[1][3] = (*p)->d21[0][1];
411 (*p)->d21[1][4] = -(*p)->d21[0][0];
412 }
413 else if (ell == 3 && mprime == 3)
414 {
415 b3 = 3. * b;
416
417 cos3b = cos(b3);
418 REAL8 sin2b = sin(2. * b);
419 REAL8 sin3b = sin(b3);
420
421 REAL8 FIFTEEN_OVER_32_cosb = FIFTEEN_OVER_32 * cosb;
422 REAL8 THREE_OVER_16_cos2b = THREE_OVER_16 * cos2b;
423 REAL8 ONE_OVER_32_cos3b = ONE_OVER_32 * cos3b;
424 REAL8 THREE_OVER_16_cos2b_plus_5_OVER_16 = THREE_OVER_16_cos2b + FIVE_OVER_16;
425
426 REAL8 FIVE_sinb = 5.0 * sinb;
427 REAL8 FOUR_sin2b = 4.0 * sin2b;
428 REAL8 FIFTEEN_OVER_32_cosb_plus_ONE_OVER_32_cos3b = FIFTEEN_OVER_32_cosb + ONE_OVER_32_cos3b;
429 REAL8 FIVE_sinb_plus_sin3b = FIVE_sinb + sin3b;
430 REAL8 FOUR_sin2b_sq = -4. * (cos2b - 1.) * ONE_OVER_TWO; // pow(sin(b), 2.0) = -(cos2b - 1.)/2.;
431 REAL8 cosb_m_cos3b = cosb - cos3b;
432
433 //mprime == 3
434 (*p)->d33[0][0] = -(FIFTEEN_OVER_32_cosb_plus_ONE_OVER_32_cos3b - THREE_OVER_16_cos2b_plus_5_OVER_16); //m=-3
435 (*p)->d33[0][1] = mSQRT_6_OVER_32 * (FIVE_sinb_plus_sin3b - FOUR_sin2b); //m=-2
436 (*p)->d33[0][2] = mSQRT_15_OVER_32 * (cosb_m_cos3b - FOUR_sin2b_sq); //m=-1
437 (*p)->d33[0][3] = SQRT_5_OVER_16 * (-3.0 * sinb + sin3b); //m=0
438 (*p)->d33[0][4] = SQRT_15_OVER_32 * (cosb_m_cos3b + FOUR_sin2b_sq); //m=1
439 (*p)->d33[0][5] = mSQRT_6_OVER_32 * (FIVE_sinb_plus_sin3b + FOUR_sin2b); //m=2
440 (*p)->d33[0][6] = FIFTEEN_OVER_32_cosb_plus_ONE_OVER_32_cos3b + THREE_OVER_16_cos2b_plus_5_OVER_16; //m=3
441
442 //mprime == -3
443 (*p)->d33[1][0] = (*p)->d33[0][6];
444 (*p)->d33[1][1] = -(*p)->d33[0][5];
445 (*p)->d33[1][2] = (*p)->d33[0][4];
446 (*p)->d33[1][3] = -(*p)->d33[0][3];
447 (*p)->d33[1][4] = (*p)->d33[0][2];
448 (*p)->d33[1][5] = -(*p)->d33[0][1];
449 (*p)->d33[1][6] = (*p)->d33[0][0];
450 }
451 else if (ell == 3 && mprime == 2)
452 {
453
454 b2 = 2. * b;
455 b3 = 3. * b;
456 REAL8 FOUR_sin2b = 4.0 * sin(b2);
457 REAL8 FIVE_sinb = 5.0 * sinb;
458 REAL8 sin3b = sin(b3);
459 cos3b = cos(b3);
460
461 cos2b_over_two = cos2b * ONE_OVER_TWO;
462
463 REAL8 FIVE_sinb_sin3b = FIVE_sinb + sin3b;
464
465 REAL8 FIVE_OVER_16_cosb = FIVE_OVER_16 * cosb;
466 REAL8 THREE_OVER_16_cos3b = THREE_OVER_16 * cos3b;
467 REAL8 FIVE_OVER_16_cosb_p_THREE_OVER_16_cos3b = FIVE_OVER_16_cosb + THREE_OVER_16_cos3b;
468
469 REAL8 THREE_sin3b = 3.0 * sin3b;
470 REAL8 sinb_m_THREE_sin3b = sinb - THREE_sin3b;
471
472 //mprime == 2
473 (*p)->d32[0][0] = SQRT_6_OVER_32 * (FOUR_sin2b - FIVE_sinb_sin3b); //m=-3
474 (*p)->d32[0][1] = FIVE_OVER_16_cosb_p_THREE_OVER_16_cos3b - cos2b_over_two; //m=-2
475 (*p)->d32[0][2] = mSQRT_10_OVER_32 * (sinb_m_THREE_sin3b + FOUR_sin2b); //m=-1
476 (*p)->d32[0][3] = SQRT_30_OVER_16 * (cosb - cos3b); //m=0
477 (*p)->d32[0][4] = SQRT_10_OVER_32 * (sinb_m_THREE_sin3b - FOUR_sin2b); //m=1
478 (*p)->d32[0][5] = FIVE_OVER_16_cosb_p_THREE_OVER_16_cos3b + cos2b_over_two; //m=2
479 (*p)->d32[0][6] = SQRT_6_OVER_32 * (FIVE_sinb_sin3b + FOUR_sin2b); //m=3
480
481 //mprime == -2
482 (*p)->d32[1][0] = -(*p)->d32[0][6];
483 (*p)->d32[1][1] = (*p)->d32[0][5];
484 (*p)->d32[1][2] = -(*p)->d32[0][4];
485 (*p)->d32[1][3] = (*p)->d32[0][3];
486 (*p)->d32[1][4] = -(*p)->d32[0][2];
487 (*p)->d32[1][5] = (*p)->d32[0][1];
488 (*p)->d32[1][6] = -(*p)->d32[0][0];
489 }
490 else if (ell == 4 && mprime == 4)
491 {
492 b2 = 2. * b;
493 b3 = 3. * b;
494 REAL8 b4 = 4. * b;
495
496 cos3b = cos(b3);
497 REAL8 cos4b = cos(b4);
498
499 REAL8 sin2b = sin(b2);
500 REAL8 sin3b = sin(b3);
501 REAL8 sin4b = sin(b4);
502
503 REAL8 SEVEN_OVER_16_cosb = SEVEN_OVER_16 * cosb;
504
505 REAL8 cos3b_OVER_16 = cos3b * ONE_OVER_16;
506
507 REAL8 sinb_14 = 14.0 * sinb;
508 REAL8 sin2b_14 = 14.0 * sin2b;
509
510 REAL8 sin3b_6 = 6.0 * sin3b;
511
512 REAL8 sin2b_14_p_sin4b = sin2b_14 + sin4b;
513 REAL8 sinb_14_p_sin3b_6 = sinb_14 + sin3b_6;
514
515 // using sin(x)**4 = 1./8. * (3. - 4*cos(2.*x) + cos(4.*x))
516 REAL8 sin_pow_4 = ONE_OVER_EIGHT * (3. - 4.*cos2b + cos4b);
517 REAL8 two_sin_pow_4 = 2.0 * sin_pow_4;
518
519 // using sin(x)**2 = -0.5 * (cos(2.*x) - 1)
520 REAL8 sin_pow_2 = -ONE_OVER_TWO * (cos2b - 1.0);
521 REAL8 four_sin_pow_2 = 4.0 * sin_pow_2;
522 REAL8 four_sin_pow_2_m_two_sin_pow_4 = four_sin_pow_2 - two_sin_pow_4;
523
524 // sin(x)**3 = (3*sin(x) - sin(3*x))/4.
525 REAL8 four_sin_pow_3_cosb = (3.*sinb - sin3b) * cosb;
526
527 //3.0 * sin(b) + sin(3.0 * b)
528 REAL8 sin3b_m_sinb_3 = sin3b - 3. * sinb;
529
530 //mprime == 4
531 (*p)->d44[0][0] = -SEVEN_OVER_16_cosb + SEVEN_OVER_32 * cos2b - cos3b_OVER_16 + cos(b4) * ONE_OVER_128 + THIRTYFIVE_OVER_128; //m=-4
532 (*p)->d44[0][1] = mSQRT_2_OVER_64 * (sinb_14_p_sin3b_6 - sin2b_14_p_sin4b); //m=-3
533 (*p)->d44[0][2] = SQRT_7_OVER_16 * (four_sin_pow_2_m_two_sin_pow_4 - cosb + cos3b); //m=-2
534 (*p)->d44[0][3] = SQRT_14_OVER_32 * (four_sin_pow_3_cosb + sin3b_m_sinb_3); //m=-1
535 (*p)->d44[0][4] = SQRT_70_16 * sin_pow_4; //m=0
536 (*p)->d44[0][5] = SQRT_14_OVER_32 * (sin3b_m_sinb_3 - four_sin_pow_3_cosb); //m=1
537 (*p)->d44[0][6] = SQRT_7_OVER_16 * (four_sin_pow_2_m_two_sin_pow_4 + cosb - cos3b); //m=2
538 (*p)->d44[0][7] = mSQRT_2_OVER_64 * (sinb_14_p_sin3b_6 + sin2b_14_p_sin4b); //m=3
539 (*p)->d44[0][8] = sin_pow_4 * ONE_OVER_16 - sin_pow_2 * ONE_OVER_TWO + SEVEN_OVER_16 * cosb + cos3b * ONE_OVER_16 + ONE_OVER_TWO; //m=4
540
541 //mprime == -4
542 (*p)->d44[1][0] = (*p)->d44[0][8];
543 (*p)->d44[1][1] = -(*p)->d44[0][7];
544 (*p)->d44[1][2] = (*p)->d44[0][6];
545 (*p)->d44[1][3] = -(*p)->d44[0][5];
546 (*p)->d44[1][4] = (*p)->d44[0][4];
547 (*p)->d44[1][5] = -(*p)->d44[0][3];
548 (*p)->d44[1][6] = (*p)->d44[0][2];
549 (*p)->d44[1][7] = -(*p)->d44[0][1];
550 (*p)->d44[1][8] = (*p)->d44[0][0];
551 }
552 else if (ell == 4 && mprime == 3)
553 {
554 b2 = 2. * b;
555 b3 = 3. * b;
556 REAL8 b4 = 4. * b;
557
558 cos3b = cos(b3);
559 REAL8 cos4b = cos(b4);
560
561 REAL8 sin2b = sin(b2);
562 REAL8 sin3b = sin(b3);
563 REAL8 sin4b = sin(b4);
564
565 REAL8 sinb_14 = 14.0 * sinb;
566 REAL8 sin2b_14 = 14.0 * sin2b;
567
568 REAL8 sin3b_6 = 6. * sin3b;
569 REAL8 sin3b_3 = 3. * sin3b;
570
571 REAL8 cosb_3 = 3. * cosb;
572 REAL8 cos2b_2 = 2. * cos2b;
573 REAL8 cos3b_3 = 3. * cos3b;
574 REAL8 cos4b_2 = 2. * cos4b;
575
576 REAL8 cosb_3_m_cos3b_3 = cosb_3 - cos3b_3;
577
578 REAL8 sin2b_14_p_sin4b = sin2b_14 + sin4b;
579 REAL8 sinb_14_p_sin3b_6 = sinb_14 + sin3b_6;
580
581 REAL8 cosb_7_OVER_32 = SEVEN_OVER_32 * cosb;
582 REAL8 cos2b_7_OVER_16 = SEVEN_OVER_16 * cos2b;
583
584 REAL8 cos3b_9_OVER_32 = NINE_OVER_32 * cos3b;
585
586 REAL8 cos4b_OVER_16 = cos4b * ONE_OVER_16;
587
588 REAL8 cosb_7_OVER_32_p_cos3b_9_OVER_32 = cosb_7_OVER_32 + cos3b_9_OVER_32;
589 REAL8 cos2b_7_OVER_16_p_cos4b_OVER_16 = cos2b_7_OVER_16 + cos4b_OVER_16;
590
591 REAL8 sin2b_2 = 2.0 * sin2b;
592
593 REAL8 sin2b_2_p_sin4b = sin2b_2 + sin4b;
594
595 // sin(x)**3 = (3*sin(x) - sin(3*x))/4.
596 REAL8 sin_pow_3_cosb = (3. * sinb - sin3b) * cosb * ONE_OVER_FOUR;
597
598 //mprime == 3
599 (*p)->d43[0][0] = mSQRT_2_OVER_64 * (sinb_14_p_sin3b_6 - sin2b_14_p_sin4b); //m=-4
600 (*p)->d43[0][1] = cosb_7_OVER_32_p_cos3b_9_OVER_32 - cos2b_7_OVER_16_p_cos4b_OVER_16; //m=-3
601 (*p)->d43[0][2] = SQRT_14_OVER_32 * (sin3b_3 - sinb - sin2b_2_p_sin4b); //m=-2
602 (*p)->d43[0][3] = SQRT_7_OVER_32 * (cosb_3_m_cos3b_3 - cos2b_2 + cos4b_2); //m=-1
603 (*p)->d43[0][4] = -SQRT_35_OVER_4 * sin_pow_3_cosb; //m=0
604 (*p)->d43[0][5] = SQRT_7_OVER_32 * (cosb_3_m_cos3b_3 + cos2b_2 - cos4b_2); //m=1
605 (*p)->d43[0][6] = SQRT_14_OVER_32 * (sinb - sin3b_3 - sin2b_2_p_sin4b); //m=2
606 (*p)->d43[0][7] = cosb_7_OVER_32_p_cos3b_9_OVER_32 + cos2b_7_OVER_16_p_cos4b_OVER_16; //m=3
607 (*p)->d43[0][8] = SQRT_2_OVER_64 * (sinb_14_p_sin3b_6 + sin2b_14_p_sin4b); //m=4
608
609 //mprime == -3
610 (*p)->d43[1][0] = -(*p)->d43[0][8];
611 (*p)->d43[1][1] = (*p)->d43[0][7];
612 (*p)->d43[1][2] = -(*p)->d43[0][6];
613 (*p)->d43[1][3] = (*p)->d43[0][5];
614 (*p)->d43[1][4] = -(*p)->d43[0][4];
615 (*p)->d43[1][5] = (*p)->d43[0][3];
616 (*p)->d43[1][6] = -(*p)->d43[0][2];
617 (*p)->d43[1][7] = (*p)->d43[0][1];
618 (*p)->d43[1][8] = -(*p)->d43[0][0];
619 }
620 else
621 {
622 XLAL_ERROR(XLAL_EFUNC, "ell = %i, mprime = %i modes not possible.\n", ell, mprime);
623 }
624
625 return XLAL_SUCCESS;
626};
627
628
629/**
630 * Hard coded expressions for relevant Wignerd matrix elements.
631 * Only certain elements are coded up.
632 * These were obtained using sympy and cross checked numerically
633 * against the LAL XLALWignerdMatrix function
634 */
636 REAL8 *wig_d, /**< [out] element of Wignerd Matrix */
637 UINT4 ell, /**< spherical harmonics ell mode */
638 INT4 mprime, /**< spherical harmonics m prime mode */
639 INT4 mm, /**< spherical harmonics m mode */
640 REAL8 b /**< beta angle (rad) */
641)
642{
643 // There is alot of symmetry here so can optimise this futher
644 REAL8 ans = 0.;
645 REAL8 fac = 1.;
646
647 /* to get negative mprime we use the symmetry
648 d^{\ell}_{-m',-m} = (-1)^{m'+m} d^{\ell}_{m',m}
649 */
650 if (mprime < 0)
651 {
652 fac = pow(-1., mm + mprime);
653 mm *= -1;
654 }
655
656 if (ell == 2)
657 {
658 // mprime should be the modes included in the co-precessing model
659 if (abs(mprime) == 2)
660 {
661 if (mm == -2)
662 {
663 // ell =2, mprime=2, mm = -2
664 ans = -cos(b) / 2.0 + cos(2.0 * b) / 8.0 + 3.0 / 8.0;
665 }
666 if (mm == -1)
667 {
668 // ell =2, mprime=2, mm = -1
669 ans = (cos(b) - 1.0) * sin(b) / 2.0;
670 }
671 if (mm == 0)
672 {
673 // ell =2, mprime=2, mm = 0
674 ans = sqrt(6.0) * pow(sin(b), 2.0) / 4.0;
675 }
676 if (mm == 1)
677 {
678 // ell =2, mprime=2, mm = 1
679 ans = -(cos(b) + 1.0) * sin(b) / 2.0;
680 }
681 if (mm == 2)
682 {
683 // ell =2, mprime=2, mm = 2
684 ans = cos(b) / 2.0 + cos(2.0 * b) / 8.0 + 3.0 / 8.0;
685 }
686 }
687 if (abs(mprime) == 1)
688 {
689 if (mm == -2)
690 {
691 // ell =2, mprime=1, mm = -2
692 ans = (cos(b) - 1.0) * sin(b) / 2.0;
693 }
694 if (mm == -1)
695 {
696 // ell =2, mprime=1, mm = -1
697 ans = cos(b) / 2.0 - cos(2.0 * b) / 2.0;
698 }
699 if (mm == 0)
700 {
701 // ell =2, mprime=1, mm = 0
702 ans = -sqrt(6.0) * sin(2.0 * b) / 4.0;
703 }
704 if (mm == 1)
705 {
706 // ell =2, mprime=1, mm = 1
707 ans = cos(b) / 2.0 + cos(2.0 * b) / 2.0;
708 }
709 if (mm == 2)
710 {
711 // ell =2, mprime=1, mm = 2
712 ans = (cos(b) + 1.0) * sin(b) / 2.0;
713 }
714 }
715 }
716 else if (ell == 3)
717 {
718 if (abs(mprime) == 3)
719 {
720 if (mm == -3)
721 {
722 // ell =3, mprime=3, mm = -3
723 ans = -15.0 * cos(b) / 32.0 + 3.0 * cos(2.0 * b) / 16.0 - cos(3.0 * b) / 32.0 + 5.0 / 16.0;
724 }
725 if (mm == -2)
726 {
727 // ell =3, mprime=3, mm = -2
728 ans = sqrt(6.0) * (-5.0 * sin(b) + 4.0 * sin(2.0 * b) - sin(3.0 * b)) / 32.0;
729 }
730 if (mm == -1)
731 {
732 // ell =3, mprime=3, mm = -1
733 ans = sqrt(15.0) * (4.0 * pow(sin(b), 2.0) - cos(b) + cos(3.0 * b)) / 32.0;
734 }
735 if (mm == 0)
736 {
737 // ell =3, mprime=3, mm = 0
738 ans = sqrt(5.0) * (-3.0 * sin(b) + sin(3.0 * b)) / 16.0;
739 }
740 if (mm == 1)
741 {
742 // ell =3, mprime=3, mm = 1
743 ans = sqrt(15.0) * (4.0 * pow(sin(b), 2.0) + cos(b) - cos(3.0 * b)) / 32.0;
744 }
745 if (mm == 2)
746 {
747 // ell =3, mprime=3, mm = 2
748 ans = -sqrt(6.0) * (5.0 * sin(b) + 4.0 * sin(2.0 * b) + sin(3.0 * b)) / 32.0;
749 }
750 if (mm == 3)
751 {
752 // ell =3, mprime=3, mm = 3
753 ans = 15.0 * cos(b) / 32.0 + 3.0 * cos(2.0 * b) / 16.0 + cos(3.0 * b) / 32.0 + 5.0 / 16.0;
754 }
755 }
756 if (abs(mprime) == 2)
757 {
758 if (mm == -3)
759 {
760 // ell =3, mprime=2, mm = -3
761 ans = sqrt(6.0) * (-5.0 * sin(b) + 4.0 * sin(2.0 * b) - sin(3.0 * b)) / 32.0;
762 }
763 if (mm == -2)
764 {
765 // ell =3, mprime=2, mm = -2
766 ans = 5.0 * cos(b) / 16.0 - cos(2.0 * b) / 2.0 + 3.0 * cos(3.0 * b) / 16.0;
767 }
768 if (mm == -1)
769 {
770 // ell =3, mprime=2, mm = -1
771 ans = sqrt(10.0) * (-sin(b) - 4.0 * sin(2.0 * b) + 3.0 * sin(3.0 * b)) / 32.0;
772 }
773 if (mm == 0)
774 {
775 // ell =3, mprime=2, mm = 0
776 ans = sqrt(30.0) * (cos(b) - cos(3.0 * b)) / 16.0;
777 }
778 if (mm == 1)
779 {
780 // ell =3, mprime=2, mm = 1
781 ans = sqrt(10.0) * (sin(b) - 4.0 * sin(2.0 * b) - 3.0 * sin(3.0 * b)) / 32.0;
782 }
783 if (mm == 2)
784 {
785 // ell =3, mprime=2, mm = 2
786 ans = 5.0 * cos(b) / 16.0 + cos(2.0 * b) / 2.0 + 3.0 * cos(3.0 * b) / 16.0;
787 }
788 if (mm == 3)
789 {
790 // ell =3, mprime=2, mm = 3
791 ans = sqrt(6.0) * (5.0 * sin(b) + 4.0 * sin(2.0 * b) + sin(3.0 * b)) / 32.0;
792 }
793 }
794 }
795 else if (ell == 4)
796 {
797 if (abs(mprime) == 4)
798 {
799 if (mm == -4)
800 {
801 // ell =4, mprime=4, mm = -4
802 ans = -7.0 * cos(b) / 16.0 + 7.0 * cos(2.0 * b) / 32.0 - cos(3.0 * b) / 16.0 + cos(4.0 * b) / 128.0 + 35.0 / 128.0;
803 }
804 if (mm == -3)
805 {
806 // ell =4, mprime=4, mm = -3
807 ans = sqrt(2.0) * (-14.0 * sin(b) + 14.0 * sin(2.0 * b) - 6.0 * sin(3.0 * b) + sin(4 * b)) / 64.0;
808 }
809 if (mm == -2)
810 {
811 // ell =4, mprime=4, mm = -2
812 ans = sqrt(7.0) * (-2.0 * pow(sin(b), 4.0) + 4.0 * pow(sin(b), 2.0) - cos(b) + cos(3.0 * b)) / 16.0;
813 }
814 if (mm == -1)
815 {
816 // ell =4, mprime=4, mm = -1
817 ans = sqrt(14.0) * (4.0 * pow(sin(b), 3.0) * cos(b) - 3.0 * sin(b) + sin(3.0 * b)) / 32.0;
818 }
819 if (mm == 0)
820 {
821 // ell =4, mprime=4, mm = 0
822 ans = sqrt(70.0) * pow(sin(b), 4.0) / 16.0;
823 }
824 if (mm == 1)
825 {
826 // ell =4, mprime=4, mm = 1
827 ans = sqrt(14.0) * (-4.0 * pow(sin(b), 3.0) * cos(b) - 3.0 * sin(b) + sin(3.0 * b)) / 32.0;
828 }
829 if (mm == 2)
830 {
831 // ell =4, mprime=4, mm = 2
832 ans = sqrt(7.0) * (-2.0 * pow(sin(b), 4.0) + 4.0 * pow(sin(b), 2.0) + cos(b) - cos(3.0 * b)) / 16.0;
833 }
834 if (mm == 3)
835 {
836 // ell =4, mprime=4, mm = 3
837 ans = -sqrt(2.0) * (14.0 * sin(b) + 14.0 * sin(2.0 * b) + 6.0 * sin(3.0 * b) + sin(4.0 * b)) / 64.0;
838 }
839 if (mm == 4)
840 {
841 // ell =4, mprime=4, mm = 4
842 ans = pow(sin(b), 4.0) / 16.0 - pow(sin(b), 2.0) / 2.0 + 7.0 * cos(b) / 16.0 + cos(3.0 * b) / 16.0 + 1.0 / 2.0;
843 }
844 }
845 if (abs(mprime) == 3)
846 {
847 if (mm == -4)
848 {
849 // ell =4, mprime=3, mm = -4
850 ans = sqrt(2.0) * (-14.0 * sin(b) + 14.0 * sin(2.0 * b) - 6.0 * sin(3.0 * b) + sin(4.0 * b)) / 64.0;
851 }
852 if (mm == -3)
853 {
854 // ell =4, mprime=3, mm = -3
855 ans = 7.0 * cos(b) / 32.0 - 7.0 * cos(2.0 * b) / 16.0 + 9.0 * cos(3.0 * b) / 32.0 - cos(4.0 * b) / 16.0;
856 }
857 if (mm == -2)
858 {
859 // ell =4, mprime=3, mm = -2
860 ans = sqrt(14.0) * (-sin(b) - 2.0 * sin(2.0 * b) + 3.0 * sin(3.0 * b) - sin(4.0 * b)) / 32.0;
861 }
862 if (mm == -1)
863 {
864 // ell =4, mprime=3, mm = -1
865 ans = sqrt(7.0) * (3.0 * cos(b) - 2.0 * cos(2.0 * b) - 3.0 * cos(3.0 * b) + 2.0 * cos(4.0 * b)) / 32.0;
866 }
867 if (mm == 0)
868 {
869 // ell =4, mprime=3, mm = 0
870 ans = -sqrt(35.0) * pow(sin(b), 3.0) * cos(b) / 4.0;
871 }
872 if (mm == 1)
873 {
874 // ell =4, mprime=3, mm = 1
875 ans = sqrt(7.0) * (3.0 * cos(b) + 2.0 * cos(2.0 * b) - 3.0 * cos(3.0 * b) - 2.0 * cos(4.0 * b)) / 32.0;
876 }
877 if (mm == 2)
878 {
879 // ell =4, mprime=3, mm = 2
880 ans = sqrt(14.0) * (sin(b) - 2.0 * sin(2.0 * b) - 3.0 * sin(3.0 * b) - sin(4.0 * b)) / 32.0;
881 }
882 if (mm == 3)
883 {
884 // ell =4, mprime=3, mm = 3
885 ans = 7.0 * cos(b) / 32.0 + 7.0 * cos(2.0 * b) / 16.0 + 9.0 * cos(3.0 * b) / 32.0 + cos(4.0 * b) / 16.0;
886 }
887 if (mm == 4)
888 {
889 // ell =4, mprime=3, mm = 4
890 ans = sqrt(2.0) * (14.0 * sin(b) + 14.0 * sin(2.0 * b) + 6.0 * sin(3.0 * b) + sin(4.0 * b)) / 64.0;
891 }
892 }
893 }
894
895 *wig_d = ans * fac;
896
897 return XLAL_SUCCESS;
898}
double XLALSimIMRPhenomDFinalSpin(const REAL8 m1_in, const REAL8 m2_in, const REAL8 chi1_in, const REAL8 chi2_in)
Function to return the final spin (spin of the remnant black hole) as predicted by the IMRPhenomD mod...
const double b2
double PhenomInternal_EradRational0815(double eta, double chi1, double chi2)
Wrapper function for EradRational0815_s.
int PhenomInternal_AlignedSpinEnforcePrimaryIsm1(REAL8 *m1, REAL8 *m2, REAL8 *chi1z, REAL8 *chi2z)
Given m1 with aligned-spin chi1z and m2 with aligned-spin chi2z.
double XLALSimPhenomUtilsFDamp0(REAL8 Mtot_Msun, REAL8 distance)
compute the frequency domain amplitude pre-factor
double XLALSimPhenomUtilsIMRPhenomDFinalMass(REAL8 m1, REAL8 m2, REAL8 chi1z, REAL8 chi2z)
Helper function used in PhenomHM and PhenomPv3HM Returns the final mass from the fit used in PhenomD.
REAL8 XLALSimPhenomUtilsPhenomPv2FinalSpin(const REAL8 m1, const REAL8 m2, const REAL8 chi1_l, const REAL8 chi2_l, const REAL8 chip)
Wrapper for final-spin formula based on:
REAL8 XLALSimPhenomUtilsChiP(const REAL8 m1, const REAL8 m2, const REAL8 s1x, const REAL8 s1y, const REAL8 s2x, const REAL8 s2y)
Function to compute the effective precession parameter chi_p (1408.1810)
int XLALSimIMRPhenomPv3HMComputeAlphaElements(IMRPhenomPv3HMAlphaStruct **p, UINT4 ell, REAL8 alpha)
int XLALSimIMRPhenomPv3HMComputeWignerdElements(IMRPhenomPv3HMWignderStruct **p, UNUSED UINT4 ell, UNUSED INT4 mprime, UNUSED REAL8 b)
computes the wigner-d elements for -beta in batches.
double XLALSimPhenomUtilsMftoHz(REAL8 Mf, REAL8 Mtot_Msun)
Convert from geometric frequency to frequency in Hz.
double XLALSimPhenomUtilsHztoMf(REAL8 fHz, REAL8 Mtot_Msun)
Convert from frequency in Hz to geometric frequency.
REAL8 XLALSimPhenomUtilsPhenomPv3HMFinalSpin(const REAL8 m1, const REAL8 m2, const REAL8 chi1x, const REAL8 chi1y, const REAL8 chi1z, const REAL8 chi2x, const REAL8 chi2y, const REAL8 chi2z)
Wrapper for final-spin formula based on:
IMRPhenomPv3HMYlmStruct * XLALSimIMRPhenomPv3HMComputeYlmElements(REAL8 theta, REAL8 phi, INT4 ell)
int XLALSimPhenomUtilsPhenomPv3HMWignerdElement(REAL8 *wig_d, UINT4 ell, INT4 mprime, INT4 mm, REAL8 b)
Hard coded expressions for relevant Wignerd matrix elements.
#define SQRT_15_OVER_32
#define SQRT_14_OVER_32
#define SQRT_35_OVER_4
#define THREE_OVER_EIGHT
#define mSQRT_6_OVER_32
#define THREE_OVER_16
#define mSQRT_2_OVER_64
#define ONE_OVER_32
#define SEVEN_OVER_32
#define THIRTYFIVE_OVER_128
#define ONE_OVER_EIGHT
#define SQRT_2_OVER_64
#define mSQRT_15_OVER_32
#define SQRT_7_OVER_16
#define mSQRT_10_OVER_32
#define SEVEN_OVER_16
#define FIVE_OVER_16
#define SQRT_30_OVER_16
#define ONE_OVER_TWO
#define ONE_OVER_FOUR
#define SQRT_7_OVER_32
#define SQRT_10_OVER_32
#define ONE_OVER_128
#define ONE_OVER_16
#define SQRT_6
#define SQRT_5_OVER_16
#define FIFTEEN_OVER_32
#define NINE_OVER_32
#define SQRT_70_16
#define SQRT_6_OVER_32
REAL8 M
Definition: bh_qnmode.c:133
double theta
Definition: bh_sphwf.c:118
#define LAL_MTSUN_SI
#define LAL_MRSUN_SI
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
void XLALFree(void *p)
static const INT4 m
COMPLEX16 XLALSpinWeightedSphericalHarmonic(REAL8 theta, REAL8 phi, int s, int l, int m)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_ERROR(...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
p
double alpha
Definition: sgwb.c:106
a strcut to keep the complex exponential terms of the alpha precession angle
a strcut to keep the wigner-d matrix elements
a strcut to keep the spherical harmonic terms