LALSimulation  5.4.0.1-fe68b98
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);
134  XLAL_CHECK(
135  XLAL_SUCCESS == retcode,
136  XLAL_EFUNC,
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
list 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