/** * Driver routine to compute the spin-aligned, inspiral-merger-ringdown * phenomenological waveform IMRPhenomD in the frequency domain. * * Reference: * - Waveform: Eq. * - Coefficients: Eq. and Table xyz * * All input parameters should be in SI units. Angles should be in radians. */ int XLALSimIMRPhenomDGenerateFD( COMPLEX16FrequencySeries **htilde, /**< FD waveform */ const REAL8 phi0, /**< Orbital phase at peak (rad) */ const REAL8 deltaF, /**< Sampling frequency (Hz) */ const REAL8 m1_SI, /**< Mass of companion 1 (kg) */ const REAL8 m2_SI, /**< Mass of companion 2 (kg) */ const REAL8 chi1, /**< Aligned-spin of companion 1 */ const REAL8 chi2, /**< Aligned-spin of companion 2 */ const REAL8 f_min, /**< Starting GW frequency (Hz) */ const REAL8 f_max, /**< End frequency; 0 defaults to ringdown cutoff freq */ const REAL8 distance /**< Distance of source (m) */ ) { /* external: SI; internal: solar masses */ const REAL8 m1 = m1_SI / LAL_MSUN_SI; const REAL8 m2 = m2_SI / LAL_MSUN_SI; const REAL8 q = (m1 > m2) ? (m1 / m2) : (m2 / m1); /* check inputs for sanity */ if (*htilde) XLAL_ERROR(XLAL_EFAULT); if (deltaF <= 0) XLAL_ERROR(XLAL_EDOM); if (m1 <= 0) XLAL_ERROR(XLAL_EDOM); if (m2 <= 0) XLAL_ERROR(XLAL_EDOM); if (fabs(chi1) > 1 || fabs(chi2) > 1) XLAL_ERROR(XLAL_EDOM); if (f_min <= 0) XLAL_ERROR(XLAL_EDOM); if (f_max < 0) XLAL_ERROR(XLAL_EDOM); if (distance <= 0) XLAL_ERROR(XLAL_EDOM); if (chi1 > 0.99 || chi1 < -1.0 || chi2 > 0.99 || chi2 < -1.0) XLAL_ERROR(XLAL_EDOM, "Spins outside the range [-1,0.99] are not supported\n"); if (q > 18.0) XLAL_PRINT_WARNING("Warning: The model is calibrated up to m1/m2 <= 18.\n"); const REAL8 M_sec = (m1+m2) * LAL_MTSUN_SI; const REAL8 fCut = 0.3/M_sec; if (fCut <= f_min) XLAL_ERROR(XLAL_EDOM, "(fCut = %gM) <= f_min = %g\n", fCut, f_min); /* default f_max to params->fCut */ REAL8 f_max_prime = f_max; f_max_prime = f_max ? f_max : fCut; f_max_prime = (f_max_prime > fCut) ? fCut : f_max_prime; if (f_max_prime <= f_min) XLAL_ERROR(XLAL_EDOM, "f_max <= f_min\n"); REAL8 status = IMRPhenomDGenerateFD(htilde, phi0, deltaF, m1, m2, chi1, chi2, f_min, f_max_prime, distance); if (f_max_prime < f_max) { // The user has requested a higher f_max than Mf=params->fCut. // Resize the frequency series to fill with zeros to fill with zeros beyond the cutoff frequency. size_t n_full = NextPow2(f_max / deltaF) + 1; // we actually want to have the length be a power of 2 + 1 *htilde = XLALResizeCOMPLEX16FrequencySeries(*htilde, 0, n_full); } return status; }
/** * Driver routine to compute the spin-aligned, inspiral-merger-ringdown * phenomenological waveform IMRPhenomC in the frequency domain. * * Reference: http://arxiv.org/pdf/1005.3306v3.pdf * - Waveform: Eq.(5.3)-(5.13) * - Coefficients: Eq.(5.14) and Table II * * All input parameters should be in SI units. Angles should be in radians. */ int XLALSimIMRPhenomCGenerateFD( COMPLEX16FrequencySeries **htilde, /**< FD waveform */ const REAL8 phi0, /**< orbital phase at peak (rad) */ const REAL8 deltaF, /**< sampling interval (Hz) */ const REAL8 m1_SI, /**< mass of companion 1 (kg) */ const REAL8 m2_SI, /**< mass of companion 2 (kg) */ const REAL8 chi, /**< mass-weighted aligned-spin parameter */ const REAL8 f_min, /**< starting GW frequency (Hz) */ const REAL8 f_max, /**< end frequency; 0 defaults to ringdown cutoff freq */ const REAL8 distance /**< distance of source (m) */ ) { BBHPhenomCParams *params; int status; REAL8 f_max_prime; /* external: SI; internal: solar masses */ const REAL8 m1 = m1_SI / LAL_MSUN_SI; const REAL8 m2 = m2_SI / LAL_MSUN_SI; /* check inputs for sanity */ if (*htilde) XLAL_ERROR(XLAL_EFAULT); if (deltaF <= 0) XLAL_ERROR(XLAL_EDOM); if (m1 <= 0) XLAL_ERROR(XLAL_EDOM); if (m2 <= 0) XLAL_ERROR(XLAL_EDOM); if (fabs(chi) > 1) XLAL_ERROR(XLAL_EDOM); if (f_min <= 0) XLAL_ERROR(XLAL_EDOM); if (f_max < 0) XLAL_ERROR(XLAL_EDOM); if (distance <= 0) XLAL_ERROR(XLAL_EDOM); /* If spins are above 0.9 or below -0.9, throw an error */ if (chi > 0.9 || chi < -0.9) XLAL_ERROR(XLAL_EDOM, "Spins outside the range [-0.9,0.9] are not supported\n"); /* If mass ratio is above 4 and below 20, give a warning, and if it is above * 20, throw an error */ REAL8 q = (m1 > m2) ? (m1 / m2) : (m2 / m1); if (q > 20.0) XLAL_ERROR(XLAL_EDOM, "Mass ratio is way outside the calibration range. m1/m2 should be <= 20.\n"); else if (q > 4.0) XLAL_PRINT_WARNING("Warning: The model is only calibrated for m1/m2 <= 4.\n"); /* phenomenological parameters*/ params = ComputeIMRPhenomCParams(m1, m2, chi); if (!params) XLAL_ERROR(XLAL_EFUNC); if (params->fCut <= f_min) XLAL_ERROR(XLAL_EDOM, "(fCut = 0.15M) <= f_min\n"); /* default f_max to params->fCut */ f_max_prime = f_max ? f_max : params->fCut; f_max_prime = (f_max_prime > params->fCut) ? params->fCut : f_max_prime; if (f_max_prime <= f_min) XLAL_ERROR(XLAL_EDOM, "f_max <= f_min\n"); status = IMRPhenomCGenerateFD(htilde, phi0, deltaF, m1, m2, f_min, f_max_prime, distance, params); if (f_max_prime < f_max) { // The user has requested a higher f_max than Mf=params->fCut. // Resize the frequency series to fill with zeros to fill with zeros beyond the cutoff frequency. size_t n_full = NextPow2(f_max / deltaF) + 1; // we actually want to have the length be a power of 2 + 1 *htilde = XLALResizeCOMPLEX16FrequencySeries(*htilde, 0, n_full); } LALFree(params); return status; }
int SEOBNRv4ROM_NRTidal_Core( struct tagCOMPLEX16FrequencySeries **hptilde, /**< Output: Frequency-domain waveform h+ */ struct tagCOMPLEX16FrequencySeries **hctilde, /**< Output: Frequency-domain waveform hx */ REAL8 phiRef, /**< Phase at reference time */ REAL8 fRef, /**< Reference frequency (Hz); 0 defaults to fLow */ REAL8 distance, /**< Distance of source (m) */ REAL8 inclination, /**< Inclination of source (rad) */ REAL8 m1_SI, /**< Mass of neutron star 1 (kg) */ REAL8 m2_SI, /**< Mass of neutron star 2 (kg) */ REAL8 chi1, /**< Dimensionless aligned component spin of NS 1 */ REAL8 chi2, /**< Dimensionless aligned component spin of NS 2 */ REAL8 lambda1, /**< Dimensionless tidal deformability of NS 1 */ REAL8 lambda2, /**< Dimensionless tidal deformability of NS 2 */ const REAL8Sequence *freqs_in, /**< Frequency points at which to evaluate the waveform (Hz) */ REAL8 deltaF) /**< Sampling frequency (Hz) */ { /* Check output arrays */ if(!hptilde || !hctilde) XLAL_ERROR(XLAL_EFAULT); if(*hptilde || *hctilde) { XLALPrintError("(*hptilde) and (*hctilde) are supposed to be NULL, but got %p and %p",(*hptilde),(*hctilde)); XLAL_ERROR(XLAL_EFAULT); } if (!freqs_in) XLAL_ERROR(XLAL_EFAULT); double fLow = freqs_in->data[0]; double fHigh = freqs_in->data[freqs_in->length - 1]; if(fRef == 0.0) fRef = fLow; /* Internally we need m1 > m2, so change around if this is not the case */ if (m1_SI < m2_SI) { // Swap m1 and m2 double m1temp = m1_SI; double chi1temp = chi1; double lambda1temp = lambda1; m1_SI = m2_SI; chi1 = chi2; lambda1 = lambda2; m2_SI = m1temp; chi2 = chi1temp; lambda2 = lambda1temp; } // double Mtot_MSUN = (m1_SI + m2_SI) / LAL_MSUN_SI; // double q = m1_SI / m2_SI; // Call SEOBNRv4 ROM. We call either the FrequencySequence version // or the regular LAL version depending on how we've been called. // These functions enforce m1 >= m2: // XLALSimIMRSEOBNRv4ROM / XLALSimIMRSEOBNRv4ROMFrequencySequence // XLALSimNRTunedTidesFDTidalPhaseFrequencySeries int ret = XLAL_SUCCESS; if (deltaF > 0) { // if using a uniform frequency series then we only need to generate // SEOBNRv4_ROM upto a bit beyond the BNS merger frequency. // if asked for a frequency beyond NRTIDAL_FMAX then the // returned waveform contains frequencies up to the input fHigh but // only contains zeros beyond NRTIDAL_FMAX double f_max_nr_tidal = fHigh; /**< tidal coupling constant.*/ const double kappa2T = XLALSimNRTunedTidesComputeKappa2T(m1_SI, m2_SI, lambda1, lambda2); /* Prepare tapering of amplitude beyond merger frequency */ const double fHz_mrg = XLALSimNRTunedTidesMergerFrequency( (m1_SI+m2_SI)/LAL_MSUN_SI , kappa2T, m1_SI/m2_SI); const double NRTIDAL_FMAX = 1.3*fHz_mrg; if ( ( fHigh > NRTIDAL_FMAX ) || ( fHigh == 0.0 ) ) { // only generate upto NRTIDAL_FMAX f_max_nr_tidal = NRTIDAL_FMAX; } ret = XLALSimIMRSEOBNRv4ROM( hptilde, hctilde, phiRef, deltaF, fLow, f_max_nr_tidal, fRef, distance, inclination, m1_SI, m2_SI, chi1, chi2, -1); // if uniform sampling and fHigh > NRTIDAL_FMAX then resize htilde // so that it goes up to the user fHigh but is filled with zeros // beyond NRTIDAL_FMAX if (fHigh > NRTIDAL_FMAX) { // resize // n_full is the next power of 2 +1. size_t n_full = (size_t) pow(2,ceil(log2(fHigh / deltaF))) + 1; *hptilde = XLALResizeCOMPLEX16FrequencySeries(*hptilde, 0, n_full); XLAL_CHECK ( *hptilde, XLAL_ENOMEM, "Failed to resize hptilde COMPLEX16FrequencySeries"); *hctilde = XLALResizeCOMPLEX16FrequencySeries(*hctilde, 0, n_full); XLAL_CHECK ( *hctilde, XLAL_ENOMEM, "Failed to resize hctilde COMPLEX16FrequencySeries"); } } else { ret = XLALSimIMRSEOBNRv4ROMFrequencySequence( hptilde, hctilde, freqs_in, phiRef, fRef, distance, inclination, m1_SI, m2_SI, chi1, chi2, -1); } XLAL_CHECK(XLAL_SUCCESS == ret, ret, "XLALSimIMRSEOBNRv4ROM() failed."); UINT4 offset; REAL8Sequence *freqs = NULL; if (deltaF > 0) { // uniform frequencies // Recreate freqs using only the lower and upper bounds UINT4 iStart = (UINT4) ceil(fLow / deltaF); UINT4 iStop = (*hptilde)->data->length - 1; // use the length calculated in the ROM function freqs = XLALCreateREAL8Sequence(iStop - iStart); if (!freqs) XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); for (UINT4 i=iStart; i<iStop; i++) freqs->data[i-iStart] = i*deltaF; offset = iStart; } else { // unequally spaced frequency sequence freqs = XLALCreateREAL8Sequence(freqs_in->length); if (!freqs) XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); for (UINT4 i=0; i<freqs_in->length; i++) freqs->data[i] = freqs_in->data[i]; // just copy input offset = 0; } COMPLEX16 *pdata=(*hptilde)->data->data; COMPLEX16 *cdata=(*hctilde)->data->data; // Get FD tidal phase correction and amplitude factor from arXiv:1706.02969 REAL8Sequence *phi_tidal = XLALCreateREAL8Sequence(freqs->length); REAL8Sequence *amp_tidal = XLALCreateREAL8Sequence(freqs->length); ret = XLALSimNRTunedTidesFDTidalPhaseFrequencySeries( phi_tidal, amp_tidal, freqs, m1_SI, m2_SI, lambda1, lambda2 ); XLAL_CHECK(XLAL_SUCCESS == ret, ret, "XLALSimNRTunedTidesFDTidalPhaseFrequencySeries Failed."); // // Prepare tapering of amplitude beyond merger frequency // double kappa2T = XLALSimNRTunedTidesComputeKappa2T(m1_SI, m2_SI, lambda1, lambda2); // double fHz_mrg = XLALSimNRTunedTidesMergerFrequency(Mtot_MSUN, kappa2T, q); // Assemble waveform from amplitude and phase for (size_t i=0; i<freqs->length; i++) { // loop over frequency points in sequence int j = i + offset; // shift index for frequency series if needed // Apply tidal phase correction and amplitude taper // double taper = 1.0 - PlanckTaper(freqs->data[i], fHz_mrg, 1.2*fHz_mrg); COMPLEX16 Corr = amp_tidal->data[i] * cexp(-I*phi_tidal->data[i]); pdata[j] *= Corr; cdata[j] *= Corr; } XLALDestroyREAL8Sequence(freqs); XLALDestroyREAL8Sequence(phi_tidal); XLALDestroyREAL8Sequence(amp_tidal); return XLAL_SUCCESS; }