int XLALSimInspiralTaylorF2Core( COMPLEX16FrequencySeries **htilde_out, /**< FD waveform */ const REAL8Sequence *freqs, /**< frequency points at which to evaluate the waveform (Hz) */ const REAL8 phi_ref, /**< reference orbital phase (rad) */ const REAL8 m1_SI, /**< mass of companion 1 (kg) */ const REAL8 m2_SI, /**< mass of companion 2 (kg) */ const REAL8 S1z, /**< z component of the spin of companion 1 */ const REAL8 S2z, /**< z component of the spin of companion 2 */ const REAL8 f_ref, /**< Reference GW frequency (Hz) - if 0 reference point is coalescence */ const REAL8 shft, /**< time shift to be applied to frequency-domain phase (sec)*/ const REAL8 r, /**< distance of source (m) */ LALDict *p /**< Linked list containing the extra testing GR parameters >**/ ) { if (!htilde_out) XLAL_ERROR(XLAL_EFAULT); if (!freqs) XLAL_ERROR(XLAL_EFAULT); /* external: SI; internal: solar masses */ const REAL8 m1 = m1_SI / LAL_MSUN_SI; const REAL8 m2 = m2_SI / LAL_MSUN_SI; const REAL8 m = m1 + m2; const REAL8 m_sec = m * LAL_MTSUN_SI; /* total mass in seconds */ const REAL8 eta = m1 * m2 / (m * m); const REAL8 piM = LAL_PI * m_sec; const REAL8 m1OverM = m1 / m; const REAL8 m2OverM = m2 / m; REAL8 amp0; size_t i; COMPLEX16 *data = NULL; LIGOTimeGPS tC = {0, 0}; INT4 iStart = 0; COMPLEX16FrequencySeries *htilde = NULL; if (*htilde_out) { //case when htilde_out has been allocated in XLALSimInspiralTaylorF2 htilde = *htilde_out; iStart = htilde->data->length - freqs->length; //index shift to fill pre-allocated data if(iStart < 0) XLAL_ERROR(XLAL_EFAULT); } else { //otherwise allocate memory here htilde = XLALCreateCOMPLEX16FrequencySeries("htilde: FD waveform", &tC, freqs->data[0], 0., &lalStrainUnit, freqs->length); if (!htilde) XLAL_ERROR(XLAL_EFUNC); XLALUnitMultiply(&htilde->sampleUnits, &htilde->sampleUnits, &lalSecondUnit); } /* phasing coefficients */ PNPhasingSeries pfa; XLALSimInspiralPNPhasing_F2(&pfa, m1, m2, S1z, S2z, S1z*S1z, S2z*S2z, S1z*S2z, p); REAL8 pfaN = 0.; REAL8 pfa1 = 0.; REAL8 pfa2 = 0.; REAL8 pfa3 = 0.; REAL8 pfa4 = 0.; REAL8 pfa5 = 0.; REAL8 pfl5 = 0.; REAL8 pfa6 = 0.; REAL8 pfl6 = 0.; REAL8 pfa7 = 0.; INT4 phaseO=XLALSimInspiralWaveformParamsLookupPNPhaseOrder(p); switch (phaseO) { case -1: case 7: pfa7 = pfa.v[7]; case 6: pfa6 = pfa.v[6]; pfl6 = pfa.vlogv[6]; case 5: pfa5 = pfa.v[5]; pfl5 = pfa.vlogv[5]; case 4: pfa4 = pfa.v[4]; case 3: pfa3 = pfa.v[3]; case 2: pfa2 = pfa.v[2]; case 1: pfa1 = pfa.v[1]; case 0: pfaN = pfa.v[0]; break; default: XLAL_ERROR(XLAL_ETYPE, "Invalid phase PN order %d", phaseO); } /* Validate expansion order arguments. * This must be done here instead of in the OpenMP parallel loop * because when OpenMP parallelization is turned on, early exits * from loops (via return or break statements) are not permitted. */ /* Validate amplitude PN order. */ INT4 amplitudeO=XLALSimInspiralWaveformParamsLookupPNAmplitudeOrder(p); switch (amplitudeO) { case -1: case 7: case 6: case 5: case 4: case 3: case 2: case 0: break; default: XLAL_ERROR(XLAL_ETYPE, "Invalid amplitude PN order %d", amplitudeO); } /* Generate tidal terms separately. * Enums specifying tidal order are in LALSimInspiralWaveformFlags.h */ REAL8 pft10 = 0.; REAL8 pft12 = 0.; REAL8 lambda1=XLALSimInspiralWaveformParamsLookupTidalLambda1(p); REAL8 lambda2=XLALSimInspiralWaveformParamsLookupTidalLambda2(p); switch( XLALSimInspiralWaveformParamsLookupPNTidalOrder(p) ) { case LAL_SIM_INSPIRAL_TIDAL_ORDER_ALL: case LAL_SIM_INSPIRAL_TIDAL_ORDER_6PN: pft12 = pfaN * (lambda1*XLALSimInspiralTaylorF2Phasing_12PNTidalCoeff(m1OverM) + lambda2*XLALSimInspiralTaylorF2Phasing_12PNTidalCoeff(m2OverM) ); case LAL_SIM_INSPIRAL_TIDAL_ORDER_5PN: pft10 = pfaN * ( lambda1*XLALSimInspiralTaylorF2Phasing_10PNTidalCoeff(m1OverM) + lambda2*XLALSimInspiralTaylorF2Phasing_10PNTidalCoeff(m2OverM) ); case LAL_SIM_INSPIRAL_TIDAL_ORDER_0PN: break; default: XLAL_ERROR(XLAL_EINVAL, "Invalid tidal PN order %d", XLALSimInspiralWaveformParamsLookupPNTidalOrder(p) ); } /* The flux and energy coefficients below are used to compute SPA amplitude corrections */ /* flux coefficients */ const REAL8 FTaN = XLALSimInspiralPNFlux_0PNCoeff(eta); const REAL8 FTa2 = XLALSimInspiralPNFlux_2PNCoeff(eta); const REAL8 FTa3 = XLALSimInspiralPNFlux_3PNCoeff(eta); const REAL8 FTa4 = XLALSimInspiralPNFlux_4PNCoeff(eta); const REAL8 FTa5 = XLALSimInspiralPNFlux_5PNCoeff(eta); const REAL8 FTl6 = XLALSimInspiralPNFlux_6PNLogCoeff(eta); const REAL8 FTa6 = XLALSimInspiralPNFlux_6PNCoeff(eta); const REAL8 FTa7 = XLALSimInspiralPNFlux_7PNCoeff(eta); /* energy coefficients */ const REAL8 dETaN = 2. * XLALSimInspiralPNEnergy_0PNCoeff(eta); const REAL8 dETa1 = 2. * XLALSimInspiralPNEnergy_2PNCoeff(eta); const REAL8 dETa2 = 3. * XLALSimInspiralPNEnergy_4PNCoeff(eta); const REAL8 dETa3 = 4. * XLALSimInspiralPNEnergy_6PNCoeff(eta); /* Perform some initial checks */ if (m1_SI <= 0) XLAL_ERROR(XLAL_EDOM); if (m2_SI <= 0) XLAL_ERROR(XLAL_EDOM); if (f_ref < 0) XLAL_ERROR(XLAL_EDOM); if (r <= 0) XLAL_ERROR(XLAL_EDOM); /* extrinsic parameters */ amp0 = -4. * m1 * m2 / r * LAL_MRSUN_SI * LAL_MTSUN_SI * sqrt(LAL_PI/12.L); data = htilde->data->data; /* Compute the SPA phase at the reference point * N.B. f_ref == 0 means we define the reference time/phase at "coalescence" * when the frequency approaches infinity. In that case, * the integrals Eq. 3.15 of arXiv:0907.0700 vanish when evaluated at * f_ref == infinity. If f_ref is finite, we must compute the SPA phase * evaluated at f_ref, store it as ref_phasing and subtract it off. */ REAL8 ref_phasing = 0.; if( f_ref != 0. ) { const REAL8 vref = cbrt(piM*f_ref); const REAL8 logvref = log(vref); const REAL8 v2ref = vref * vref; const REAL8 v3ref = vref * v2ref; const REAL8 v4ref = vref * v3ref; const REAL8 v5ref = vref * v4ref; const REAL8 v6ref = vref * v5ref; const REAL8 v7ref = vref * v6ref; const REAL8 v8ref = vref * v7ref; const REAL8 v9ref = vref * v8ref; const REAL8 v10ref = vref * v9ref; const REAL8 v12ref = v2ref * v10ref; ref_phasing += pfa7 * v7ref; ref_phasing += (pfa6 + pfl6 * logvref) * v6ref; ref_phasing += (pfa5 + pfl5 * logvref) * v5ref; ref_phasing += pfa4 * v4ref; ref_phasing += pfa3 * v3ref; ref_phasing += pfa2 * v2ref; ref_phasing += pfa1 * vref; ref_phasing += pfaN; /* Tidal terms in reference phasing */ ref_phasing += pft12 * v12ref; ref_phasing += pft10 * v10ref; ref_phasing /= v5ref; } /* End of if(f_ref != 0) block */ #pragma omp parallel for for (i = 0; i < freqs->length; i++) { const REAL8 f = freqs->data[i]; const REAL8 v = cbrt(piM*f); const REAL8 logv = log(v); const REAL8 v2 = v * v; const REAL8 v3 = v * v2; const REAL8 v4 = v * v3; const REAL8 v5 = v * v4; const REAL8 v6 = v * v5; const REAL8 v7 = v * v6; const REAL8 v8 = v * v7; const REAL8 v9 = v * v8; const REAL8 v10 = v * v9; const REAL8 v12 = v2 * v10; REAL8 phasing = 0.; REAL8 dEnergy = 0.; REAL8 flux = 0.; REAL8 amp; phasing += pfa7 * v7; phasing += (pfa6 + pfl6 * logv) * v6; phasing += (pfa5 + pfl5 * logv) * v5; phasing += pfa4 * v4; phasing += pfa3 * v3; phasing += pfa2 * v2; phasing += pfa1 * v; phasing += pfaN; /* Tidal terms in phasing */ phasing += pft12 * v12; phasing += pft10 * v10; /* WARNING! Amplitude orders beyond 0 have NOT been reviewed! * Use at your own risk. The default is to turn them off. * These do not currently include spin corrections. * Note that these are not higher PN corrections to the amplitude. * They are the corrections to the leading-order amplitude arising * from the stationary phase approximation. See for instance * Eq 6.9 of arXiv:0810.5336 */ switch (amplitudeO) { case 7: flux += FTa7 * v7; case 6: flux += (FTa6 + FTl6*logv) * v6; dEnergy += dETa3 * v6; case 5: flux += FTa5 * v5; case 4: flux += FTa4 * v4; dEnergy += dETa2 * v4; case 3: flux += FTa3 * v3; case 2: flux += FTa2 * v2; dEnergy += dETa1 * v2; case -1: /* Default to no SPA amplitude corrections */ case 0: flux += 1.; dEnergy += 1.; } phasing /= v5; flux *= FTaN * v10; dEnergy *= dETaN * v; // Note the factor of 2 b/c phi_ref is orbital phase phasing += shft * f - 2.*phi_ref - ref_phasing; amp = amp0 * sqrt(-dEnergy/flux) * v; data[i+iStart] = amp * cos(phasing - LAL_PI_4) - amp * sin(phasing - LAL_PI_4) * 1.0j; } *htilde_out = htilde; return XLAL_SUCCESS; }
static void T4wdot_from_energy_flux( PNPhasingSeries *wdot, const REAL8 m1M, const REAL8 chi1, const REAL8 chi2, const REAL8 qm_def1, const REAL8 qm_def2 ) { REAL8 m2M = 1.-m1M; REAL8 eta = m1M*m2M; /* Spins use the wacky lal convention */ REAL8 S1L = m1M*m1M*chi1; REAL8 S2L = m2M*m2M*chi2; REAL8 energy[9]; REAL8 flux[9]; energy[1] = 0.; energy[2] = XLALSimInspiralPNEnergy_2PNCoeff(eta); energy[3] = 0.; energy[4] = XLALSimInspiralPNEnergy_4PNCoeff(eta); energy[5] = 0.; energy[6] = XLALSimInspiralPNEnergy_6PNCoeff(eta); energy[7] = 0.; //We do not add the non-spin part of the 4PN energy as the 4PN flux is unknown, apart from the SL terms energy[8] = 0.; flux[1] = 0.; flux[2] = XLALSimInspiralPNFlux_2PNCoeff(eta); flux[3] = XLALSimInspiralPNFlux_3PNCoeff(eta); flux[4] = XLALSimInspiralPNFlux_4PNCoeff(eta); flux[5] = XLALSimInspiralPNFlux_5PNCoeff(eta); flux[6] = XLALSimInspiralPNFlux_6PNCoeff(eta); flux[7] = XLALSimInspiralPNFlux_7PNCoeff(eta); flux[8] = 0.; /* Add the spin-orbit contributions */ REAL8 energy_so3=XLALSimInspiralPNEnergy_3PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_3PNSOCoeff(m2M)*S2L; energy[3] += energy_so3; REAL8 energy_so5=XLALSimInspiralPNEnergy_5PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_5PNSOCoeff(m2M)*S2L; energy[5] += energy_so5; energy[7] +=XLALSimInspiralPNEnergy_7PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_7PNSOCoeff(m2M)*S2L; flux[3] += XLALSimInspiralPNFlux_3PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_3PNSOCoeff(m2M)*S2L; flux[5] += XLALSimInspiralPNFlux_5PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_5PNSOCoeff(m2M)*S2L; REAL8 flux_so6=XLALSimInspiralPNFlux_6PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_6PNSOCoeff(m2M)*S2L; flux[6] += flux_so6; flux[7] += XLALSimInspiralPNFlux_7PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_7PNSOCoeff(m2M)*S2L; flux[8] += XLALSimInspiralPNFlux_8PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_8PNSOCoeff(m2M)*S2L; memset(wdot, 0, sizeof(PNPhasingSeries)); wdot->v[0] = -XLALSimInspiralPNFlux_0PNCoeff(eta)/(2./3.*XLALSimInspiralPNEnergy_0PNCoeff(eta)); wdot->v[1] = 0.; /* there's no 0.5 PN term */ for (int i = 2; i <8; i++) { wdot->v[i] = flux[i] - (1.+0.5*i)*energy[i] - sumE(energy, wdot->v, i); } wdot->vlogv[6]= XLALSimInspiralPNFlux_6PNLogCoeff(eta); // The 8PN SO term is check by hand wdot->v[8]=flux[8]-5.*energy[8] - flux_so6*2.*XLALSimInspiralPNEnergy_2PNCoeff(eta) - XLALSimInspiralPNFlux_5PNCoeff(eta)*5./2.*energy_so3 + XLALSimInspiralPNFlux_3PNCoeff(eta)*(-7./2.*energy_so5 + 10.*XLALSimInspiralPNEnergy_2PNCoeff(eta)*energy_so3); /* Calculate the leading-order spin-spin terms separately */ REAL8 energy_ss4 = XLALSimInspiralPNEnergy_4PNS1S2OCoeff(eta)*S1L*S2L; energy_ss4 += XLALSimInspiralPNEnergy_4PNS1S2Coeff(eta)*S1L*S2L; energy_ss4 += qm_def1*XLALSimInspiralPNEnergy_4PNQM2SCoeff(m1M)*S1L*S1L; energy_ss4 += qm_def1*XLALSimInspiralPNEnergy_4PNQM2SOCoeff(m1M)*S1L*S1L; energy_ss4 += qm_def2*XLALSimInspiralPNEnergy_4PNQM2SCoeff(m2M)*S2L*S2L; energy_ss4 += qm_def2*XLALSimInspiralPNEnergy_4PNQM2SOCoeff(m2M)*S2L*S2L; REAL8 flux_ss4 = XLALSimInspiralPNFlux_4PNS1S2OCoeff(eta)*S1L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNS1S2Coeff(eta)*S1L*S2L; flux_ss4 += qm_def1*XLALSimInspiralPNFlux_4PNQM2SCoeff(m1M)*S1L*S1L; flux_ss4 += qm_def1*XLALSimInspiralPNFlux_4PNQM2SOCoeff(m1M)*S1L*S1L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SCoeff(m1M)*S1L*S1L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SOCoeff(m1M)*S1L*S1L; flux_ss4 += qm_def2*XLALSimInspiralPNFlux_4PNQM2SCoeff(m2M)*S2L*S2L; flux_ss4 += qm_def2*XLALSimInspiralPNFlux_4PNQM2SOCoeff(m2M)*S2L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SCoeff(m2M)*S2L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SOCoeff(m2M)*S2L*S2L; wdot->v[4] += flux_ss4 -3.*energy_ss4; REAL8 energy_ss6 = XLALSimInspiralPNEnergy_6PNS1S2OCoeff(eta)*S1L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNS1S2Coeff(eta)*S1L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SCoeff(m1M)*S1L*S1L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SOCoeff(m1M)*S1L*S1L; energy_ss6 += qm_def1*XLALSimInspiralPNEnergy_6PNQM2SCoeff(m1M)*S1L*S1L; energy_ss6 += qm_def1*XLALSimInspiralPNEnergy_6PNQM2SOCoeff(m1M)*S1L*S1L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SCoeff(m2M)*S2L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SOCoeff(m2M)*S2L*S2L; energy_ss6 += qm_def2*XLALSimInspiralPNEnergy_6PNQM2SCoeff(m2M)*S2L*S2L; energy_ss6 += qm_def2*XLALSimInspiralPNEnergy_6PNQM2SOCoeff(m2M)*S2L*S2L; REAL8 flux_ss6 = XLALSimInspiralPNFlux_6PNS1S2OCoeff(eta)*S1L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNS1S2Coeff(eta)*S1L*S2L; flux_ss6 += qm_def1*XLALSimInspiralPNFlux_6PNQM2SCoeff(m1M)*S1L*S1L; flux_ss6 += qm_def1*XLALSimInspiralPNFlux_6PNQM2SOCoeff(m1M)*S1L*S1L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SCoeff(m1M)*S1L*S1L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SOCoeff(m1M)*S1L*S1L; flux_ss6 += qm_def2*XLALSimInspiralPNFlux_6PNQM2SCoeff(m2M)*S2L*S2L; flux_ss6 += qm_def2*XLALSimInspiralPNFlux_6PNQM2SOCoeff(m2M)*S2L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SCoeff(m2M)*S2L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SOCoeff(m2M)*S2L*S2L; wdot->v[6] += flux_ss6 - 4.*energy_ss6 -3.*flux[2]*energy_ss4 - 2.*flux_ss4*energy[2] + 12.*energy[2]*energy_ss4; return; }
/** * Computes the stationary phase approximation to the Fourier transform of * a chirp waveform with phase given by \eqref{eq_InspiralFourierPhase_f2} * and amplitude given by expanding \f$1/\sqrt{\dot{F}}\f$. If the PN order is * set to -1, then the highest implemented order is used. * * See arXiv:0810.5336 and arXiv:astro-ph/0504538 for spin corrections * to the phasing. * See arXiv:1303.7412 for spin-orbit phasing corrections at 3 and 3.5PN order */ int XLALSimInspiralSpinTaylorF2( COMPLEX16FrequencySeries **hplus_out, /**< FD hplus waveform */ COMPLEX16FrequencySeries **hcross_out, /**< FD hcross waveform */ const REAL8 phi_ref, /**< reference orbital phase (rad) */ const REAL8 deltaF, /**< frequency resolution */ const REAL8 m1_SI, /**< mass of companion 1 (kg) */ const REAL8 m2_SI, /**< mass of companion 2 (kg) */ const REAL8 s1x, /**< initial value of S1x */ const REAL8 s1y, /**< initial value of S1y */ const REAL8 s1z, /**< initial value of S1z */ const REAL8 lnhatx, /**< initial value of LNhatx */ const REAL8 lnhaty, /**< initial value of LNhaty */ const REAL8 lnhatz, /**< initial value of LNhatz */ const REAL8 fStart, /**< start GW frequency (Hz) */ const REAL8 fEnd, /**< highest GW frequency (Hz) of waveform generation - if 0, end at Schwarzschild ISCO */ const REAL8 f_ref, /**< Reference GW frequency (Hz) - if 0 reference point is coalescence */ const REAL8 r, /**< distance of source (m) */ LALDict *moreParams, /**< Linked list of extra. Pass in NULL (or None in python) for standard waveform. Set "sideband",m to get a single sideband (m=-2..2) */ const INT4 phaseO, /**< twice PN phase order */ const INT4 amplitudeO /**< twice PN amplitude order */ ) { /* external: SI; internal: solar masses */ const REAL8 m1 = m1_SI / LAL_MSUN_SI; const REAL8 m2 = m2_SI / LAL_MSUN_SI; const REAL8 m = m1 + m2; const REAL8 m_sec = m * LAL_MTSUN_SI; /* total mass in seconds */ const REAL8 eta = m1 * m2 / (m * m); const REAL8 piM = LAL_PI * m_sec; const REAL8 vISCO = 1. / sqrt(6.); const REAL8 fISCO = vISCO * vISCO * vISCO / piM; REAL8 shft, amp0, f_max; size_t i, n, iStart; COMPLEX16 *data_plus = NULL; COMPLEX16 *data_cross = NULL; LIGOTimeGPS tC = {0, 0}; /* If f_ref = 0, use f_ref = f_low for everything except the phase offset */ const REAL8 v_ref = f_ref > 0. ? cbrt(piM*f_ref) : cbrt(piM*fStart); REAL8 alpha, alpha_ref; COMPLEX16 prec_plus, prec_cross, phasing_fac; bool enable_precession = true; /* Handle the non-spinning case separately */ int mm; LALSimInspiralSF2Orientation orientation; XLALSimInspiralSF2CalculateOrientation(&orientation, m1, m2, v_ref, lnhatx, lnhaty, lnhatz, s1x, s1y, s1z); LALSimInspiralSF2Coeffs coeffs; XLALSimInspiralSF2CalculateCoeffs(&coeffs, m1, m2, orientation.chi, orientation.kappa); enable_precession = orientation.chi != 0. && orientation.kappa != 1. && orientation.kappa != -1.; alpha_ref = enable_precession ? XLALSimInspiralSF2Alpha(v_ref, coeffs) - orientation.alpha0 : 0.; COMPLEX16 SBplus[5]; /* complex sideband factors for plus pol, mm=2 is first entry */ COMPLEX16 SBcross[5]; /* complex sideband factors for cross pol, mm=2 is first entry */ REAL8 emission[5]; /* emission factor for each sideband */ if ( !XLALSimInspiralWaveformParamsSidebandIsDefault(moreParams)) { for(mm = -2; mm <= 2; mm++) { SBplus[2-mm] = XLALSimInspiralSF2Polarization(orientation.thetaJ, orientation.psiJ, mm); SBcross[2-mm] = XLALSimInspiralSF2Polarization(orientation.thetaJ, orientation.psiJ+LAL_PI/4., mm); } } else { memset(SBplus, 0, 5 * sizeof(COMPLEX16)); memset(SBcross, 0, 5 * sizeof(COMPLEX16)); mm = (int) XLALSimInspiralWaveformParamsLookupSideband(moreParams); SBplus[2-mm] = XLALSimInspiralSF2Polarization(orientation.thetaJ, orientation.psiJ, mm); SBcross[2-mm] = XLALSimInspiralSF2Polarization(orientation.thetaJ, orientation.psiJ+LAL_PI/4., mm); } const REAL8 chi1L = orientation.chi*orientation.kappa; const REAL8 chi1sq = orientation.chi*orientation.chi; /* FIXME: Cannot yet set QM constant in ChooseFDWaveform interface */ /* phasing coefficients */ PNPhasingSeries pfa; XLALSimInspiralPNPhasing_F2(&pfa, m1, m2, chi1L, 0., chi1sq, 0., 0., moreParams); REAL8 pfaN = 0.; REAL8 pfa1 = 0.; REAL8 pfa2 = 0.; REAL8 pfa3 = 0.; REAL8 pfa4 = 0.; REAL8 pfa5 = 0.; REAL8 pfl5 = 0.; REAL8 pfa6 = 0.; REAL8 pfl6 = 0.; REAL8 pfa7 = 0.; REAL8 pfa8 = 0.; switch (phaseO) { case -1: case 7: pfa7 = pfa.v[7]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 6: pfa6 = pfa.v[6]; pfl6 = pfa.vlogv[6]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 5: pfa5 = pfa.v[5]; pfl5 = pfa.vlogv[5]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 4: pfa4 = pfa.v[4]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 3: pfa3 = pfa.v[3]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 2: pfa2 = pfa.v[2]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 1: pfa1 = pfa.v[1]; #if __GNUC__ >= 7 __attribute__ ((fallthrough)); #endif case 0: pfaN = pfa.v[0]; break; default: XLAL_ERROR(XLAL_ETYPE, "Invalid phase PN order %d", phaseO); } /* Add the zeta factor to the phasing, since it looks like a pN series. * This is the third Euler angle after alpha and beta. */ if (enable_precession) { pfa2 += 2.*coeffs.prec_fac*coeffs.zc[0]; pfa3 += 2.*coeffs.prec_fac*coeffs.zc[1]; pfa4 += 2.*coeffs.prec_fac*coeffs.zc[2]; pfl5 += 2.*coeffs.prec_fac*coeffs.zc[3]; pfa6 += 2.*coeffs.prec_fac*coeffs.zc[4]; pfa7 += 2.*coeffs.prec_fac*coeffs.zc[5]; pfa8 += 2.*coeffs.prec_fac*coeffs.zc[6]; } /* Validate expansion order arguments. * This must be done here instead of in the OpenMP parallel loop * because when OpenMP parallelization is turned on, early exits * from loops (via return or break statements) are not permitted. */ /* Validate amplitude PN order. */ if (amplitudeO != 0) { XLAL_ERROR(XLAL_ETYPE, "Invalid amplitude PN order %d", amplitudeO); } /* energy coefficients - not currently used, but could for MECO const REAL8 dETaN = 2. * XLALSimInspiralPNEnergy_0PNCoeff(eta); const REAL8 dETa1 = 2. * XLALSimInspiralPNEnergy_2PNCoeff(eta); const REAL8 dETa2 = 3. * XLALSimInspiralPNEnergy_4PNCoeff(eta); const REAL8 dETa3 = 4. * XLALSimInspiralPNEnergy_6PNCoeff(eta); */ COMPLEX16FrequencySeries *hplus; COMPLEX16FrequencySeries *hcross; /* Perform some initial checks */ if (!hplus_out) XLAL_ERROR(XLAL_EFAULT); if (!hcross_out) XLAL_ERROR(XLAL_EFAULT); if (*hplus_out) XLAL_ERROR(XLAL_EFAULT); if (*hcross_out) XLAL_ERROR(XLAL_EFAULT); if (m1_SI <= 0) XLAL_ERROR(XLAL_EDOM); if (m2_SI <= 0) XLAL_ERROR(XLAL_EDOM); if (fStart <= 0) XLAL_ERROR(XLAL_EDOM); if (f_ref < 0) XLAL_ERROR(XLAL_EDOM); if (r <= 0) XLAL_ERROR(XLAL_EDOM); /* allocate htilde */ if ( fEnd == 0. ) // End at ISCO f_max = fISCO; else // End at user-specified freq. f_max = fEnd; n = (size_t) (f_max / deltaF + 1); XLALGPSAdd(&tC, -1 / deltaF); /* coalesce at t=0 */ /* Allocate hplus and hcross */ hplus = XLALCreateCOMPLEX16FrequencySeries("hplus: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, n); if (!hplus) XLAL_ERROR(XLAL_EFUNC); memset(hplus->data->data, 0, n * sizeof(COMPLEX16)); XLALUnitMultiply(&hplus->sampleUnits, &hplus->sampleUnits, &lalSecondUnit); hcross = XLALCreateCOMPLEX16FrequencySeries("hcross: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, n); if (!hcross) XLAL_ERROR(XLAL_EFUNC); memset(hcross->data->data, 0, n * sizeof(COMPLEX16)); XLALUnitMultiply(&hcross->sampleUnits, &hcross->sampleUnits, &lalSecondUnit); /* extrinsic parameters */ amp0 = -4. * m1 * m2 / r * LAL_MRSUN_SI * LAL_MTSUN_SI * sqrt(LAL_PI/12.L); amp0 *= sqrt(-2. * XLALSimInspiralPNEnergy_0PNCoeff(eta)/XLALSimInspiralPNFlux_0PNCoeff(eta)); shft = LAL_TWOPI * (tC.gpsSeconds + 1e-9 * tC.gpsNanoSeconds); /* Fill with non-zero vals from fStart to f_max */ iStart = (size_t) ceil(fStart / deltaF); data_plus = hplus->data->data; data_cross = hcross->data->data; /* Compute the SPA phase at the reference point */ REAL8 ref_phasing = 0.; if (f_ref > 0.) { const REAL8 logvref = log(v_ref); const REAL8 v2ref = v_ref * v_ref; const REAL8 v3ref = v_ref * v2ref; const REAL8 v4ref = v_ref * v3ref; const REAL8 v5ref = v_ref * v4ref; ref_phasing = (pfaN + pfa1 * v_ref +pfa2 * v2ref + pfa3 * v3ref + pfa4 * v4ref) / v5ref + (pfa5 + pfl5 * logvref) + (pfa6 + pfl6 * logvref) * v_ref + pfa7 * v2ref + pfa8 * v3ref; } /* end of if (f_ref > 0.) */ #pragma omp parallel for for (i = iStart; i < n; i++) { const REAL8 f = i * deltaF; const REAL8 v = cbrt(piM*f); const REAL8 logv = log(v); const REAL8 v2 = v * v; const REAL8 v3 = v * v2; const REAL8 v4 = v * v3; const REAL8 v5 = v * v4; REAL8 phasing = (pfaN + pfa1*v + pfa2 * v2 + pfa3 * v3 + pfa4 * v4) / v5 + (pfa5 + pfl5 * logv) + (pfa6 + pfl6 * logv) * v + pfa7 * v2 + pfa8 * v3; COMPLEX16 amp = amp0 / (v3 * sqrt(v)); alpha = enable_precession ? XLALSimInspiralSF2Alpha(v, coeffs) - alpha_ref : 0.; COMPLEX16 u = cos(alpha) + 1.0j*sin(alpha); XLALSimInspiralSF2Emission(emission, v, coeffs); prec_plus = SBplus[0]*emission[0]*u*u + SBplus[1]*emission[1]*u + SBplus[2]*emission[2] + SBplus[3]*emission[3]/u + SBplus[4]*emission[4]/u/u; prec_cross= SBcross[0]*emission[0]*u*u + SBcross[1]*emission[1]*u + SBcross[2]*emission[2] + SBcross[3]*emission[3]/u + SBcross[4]*emission[4]/u/u; // Note the factor of 2 b/c phi_ref is orbital phase phasing += shft * f - 2.*phi_ref - ref_phasing - LAL_PI_4; phasing_fac = cos(phasing) - 1.0j*sin(phasing); data_plus[i] = amp * prec_plus * phasing_fac; data_cross[i] = amp * prec_cross * phasing_fac; } *hplus_out = hplus; *hcross_out = hcross; return XLAL_SUCCESS; }
static void dtdv_from_energy_flux( PNPhasingSeries *dtdv, const REAL8 m1M, const REAL8 chi1, const REAL8 chi2, const REAL8 qm_def1, const REAL8 qm_def2 ) { /* Check is performed for aligned spin only*/ REAL8 m2M = 1.-m1M; REAL8 eta = m1M*m2M; /* Spins use the wacky lal convention */ REAL8 S1L = m1M*m1M*chi1; REAL8 S2L = m2M*m2M*chi2; REAL8 energy[9]; REAL8 flux[9]; energy[1] = 0.; energy[2] = XLALSimInspiralPNEnergy_2PNCoeff(eta); energy[3] = XLALSimInspiralPNEnergy_3PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_3PNSOCoeff(m2M)*S2L; energy[4] = XLALSimInspiralPNEnergy_4PNCoeff(eta); energy[5] = XLALSimInspiralPNEnergy_5PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_5PNSOCoeff(m2M)*S2L; energy[6] = XLALSimInspiralPNEnergy_6PNCoeff(eta); energy[7] = XLALSimInspiralPNEnergy_7PNSOCoeff(m1M)*S1L + XLALSimInspiralPNEnergy_7PNSOCoeff(m2M)*S2L; flux[1] = 0.; flux[2] = XLALSimInspiralPNFlux_2PNCoeff(eta); flux[3] = XLALSimInspiralPNFlux_3PNCoeff(eta); flux[4] = XLALSimInspiralPNFlux_4PNCoeff(eta); flux[5] = XLALSimInspiralPNFlux_5PNCoeff(eta); flux[6] = XLALSimInspiralPNFlux_6PNCoeff(eta); flux[7] = XLALSimInspiralPNFlux_7PNCoeff(eta); /* Add the spin-orbit fluxes */ flux[3] += XLALSimInspiralPNFlux_3PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_3PNSOCoeff(m2M)*S2L; flux[5] += XLALSimInspiralPNFlux_5PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_5PNSOCoeff(m2M)*S2L; flux[6] += XLALSimInspiralPNFlux_6PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_6PNSOCoeff(m2M)*S2L; flux[7] += XLALSimInspiralPNFlux_7PNSOCoeff(m1M)*S1L + XLALSimInspiralPNFlux_7PNSOCoeff(m2M)*S2L; REAL8 flux6l = XLALSimInspiralPNFlux_6PNLogCoeff(eta); memset(dtdv, 0, sizeof(PNPhasingSeries)); dtdv->v[0] = -2.*XLALSimInspiralPNEnergy_0PNCoeff(eta) / XLALSimInspiralPNFlux_0PNCoeff(eta); dtdv->v[1] = 0.; /* there's no 0.5 PN term */ for (int i = 2; i < 8; i++) { dtdv->v[i] = (1.+0.5*((double)i))*energy[i] - flux[i] - sum(flux, dtdv->v, i); } dtdv->vlogv[6] = -flux6l; /* Calculate the leading-order spin-spin terms separately * FIXME: For now, only do aligned spins */ REAL8 energy_ss4 = XLALSimInspiralPNEnergy_4PNS1S2OCoeff(eta)*S1L*S2L; energy_ss4 += XLALSimInspiralPNEnergy_4PNS1S2Coeff(eta)*S1L*S2L; energy_ss4 += qm_def1*XLALSimInspiralPNEnergy_4PNQM2SCoeff(m1M)*S1L*S1L; energy_ss4 += qm_def1*XLALSimInspiralPNEnergy_4PNQM2SOCoeff(m1M)*S1L*S1L; energy_ss4 += qm_def2*XLALSimInspiralPNEnergy_4PNQM2SCoeff(m2M)*S2L*S2L; energy_ss4 += qm_def2*XLALSimInspiralPNEnergy_4PNQM2SOCoeff(m2M)*S2L*S2L; REAL8 flux_ss4 = XLALSimInspiralPNFlux_4PNS1S2OCoeff(eta)*S1L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNS1S2Coeff(eta)*S1L*S2L; flux_ss4 += qm_def1*XLALSimInspiralPNFlux_4PNQM2SCoeff(m1M)*S1L*S1L; flux_ss4 += qm_def1*XLALSimInspiralPNFlux_4PNQM2SOCoeff(m1M)*S1L*S1L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SCoeff(m1M)*S1L*S1L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SOCoeff(m1M)*S1L*S1L; flux_ss4 += qm_def2*XLALSimInspiralPNFlux_4PNQM2SCoeff(m2M)*S2L*S2L; flux_ss4 += qm_def2*XLALSimInspiralPNFlux_4PNQM2SOCoeff(m2M)*S2L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SCoeff(m2M)*S2L*S2L; flux_ss4 += XLALSimInspiralPNFlux_4PNSelf2SOCoeff(m2M)*S2L*S2L; dtdv->v[4] += 3.*energy_ss4 - flux_ss4; REAL8 energy_ss6 = XLALSimInspiralPNEnergy_6PNS1S2OCoeff(eta)*S1L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNS1S2Coeff(eta)*S1L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SCoeff(m1M)*S1L*S1L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SOCoeff(m1M)*S1L*S1L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SCoeff(m2M)*S2L*S2L; energy_ss6 += XLALSimInspiralPNEnergy_6PNSelf2SOCoeff(m2M)*S2L*S2L; energy_ss6 += qm_def1*XLALSimInspiralPNEnergy_6PNQM2SCoeff(m1M)*S1L*S1L; energy_ss6 += qm_def1*XLALSimInspiralPNEnergy_6PNQM2SOCoeff(m1M)*S1L*S1L; energy_ss6 += qm_def2*XLALSimInspiralPNEnergy_6PNQM2SCoeff(m2M)*S2L*S2L; energy_ss6 += qm_def2*XLALSimInspiralPNEnergy_6PNQM2SOCoeff(m2M)*S2L*S2L; REAL8 flux_ss6 = XLALSimInspiralPNFlux_6PNS1S2OCoeff(eta)*S1L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNS1S2Coeff(eta)*S1L*S2L; flux_ss6 += qm_def1*XLALSimInspiralPNFlux_6PNQM2SCoeff(m1M)*S1L*S1L; flux_ss6 += qm_def1*XLALSimInspiralPNFlux_6PNQM2SOCoeff(m1M)*S1L*S1L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SCoeff(m1M)*S1L*S1L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SOCoeff(m1M)*S1L*S1L; flux_ss6 += qm_def2*XLALSimInspiralPNFlux_6PNQM2SCoeff(m2M)*S2L*S2L; flux_ss6 += qm_def2*XLALSimInspiralPNFlux_6PNQM2SOCoeff(m2M)*S2L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SCoeff(m2M)*S2L*S2L; flux_ss6 += XLALSimInspiralPNFlux_6PNSelf2SOCoeff(m2M)*S2L*S2L; dtdv->v[6] += 4.*energy_ss6 - flux_ss6 -3.*flux[2]*energy_ss4 - 2.*flux_ss4*energy[2] + 2.*flux[2]*flux_ss4; return; }