/** * Destroy a waveform cache. */ void XLALDestroySimInspiralWaveformCache(LALSimInspiralWaveformCache *cache) { if (cache != NULL) { XLALDestroyREAL8TimeSeries(cache->hplus); XLALDestroyREAL8TimeSeries(cache->hcross); XLALDestroyCOMPLEX16FrequencySeries(cache->hptilde); XLALDestroyCOMPLEX16FrequencySeries(cache->hctilde); XLALFree(cache); } }
static void __del__(PyObject *self) { pylal_COMPLEX16FrequencySeries *obj = (pylal_COMPLEX16FrequencySeries *) self; if(obj->owner) Py_DECREF(obj->owner); else /* we are the owner */ XLALDestroyCOMPLEX16FrequencySeries(obj->series); self->ob_type->tp_free(self); }
REAL8 calculate_ligo_snr_from_strain_real8( REAL8TimeSeries *strain, const CHAR ifo[3]) { REAL8 ret = -1, snrSq, freq, psdValue; REAL8 deltaF; REAL8FFTPlan *pfwd; COMPLEX16FrequencySeries *fftData; UINT4 k; /* create the time series */ deltaF = strain->deltaT * strain->data->length; fftData = XLALCreateCOMPLEX16FrequencySeries( strain->name, &(strain->epoch), 0, deltaF, &lalDimensionlessUnit, strain->data->length/2 + 1 ); /* perform the fft */ pfwd = XLALCreateForwardREAL8FFTPlan( strain->data->length, 0 ); XLALREAL8TimeFreqFFT( fftData, strain, pfwd ); /* compute the SNR for initial LIGO at design */ for ( snrSq = 0, k = 0; k < fftData->data->length; k++ ) { freq = fftData->deltaF * k; if ( ifo[0] == 'V' ) { if (freq < 35) continue; LALVIRGOPsd( NULL, &psdValue, freq ); psdValue /= 9e-46; } else { if (freq < 40) continue; LALLIGOIPsd( NULL, &psdValue, freq ); } fftData->data->data[k] /= 3e-23; snrSq += creal(fftData->data->data[k]) * creal(fftData->data->data[k]) / psdValue; snrSq += cimag(fftData->data->data[k]) * cimag(fftData->data->data[k]) / psdValue; } snrSq *= 4*fftData->deltaF; XLALDestroyREAL8FFTPlan( pfwd ); XLALDestroyCOMPLEX16FrequencySeries( fftData ); ret = sqrt(snrSq); return ret; }
/** * Private function to generate time-domain waveforms given coefficients */ static int IMRPhenomCGenerateTD( REAL8TimeSeries **h, const REAL8 phi0, size_t *ind_t0, const REAL8 deltaT, const REAL8 m1, const REAL8 m2, //const REAL8 chi, const REAL8 f_min, const REAL8 f_max, const REAL8 distance, const BBHPhenomCParams *params ) { REAL8 deltaF; COMPLEX16FrequencySeries *htilde=NULL; /* We will generate the waveform from a frequency which is lower than the * f_min chosen. Also the cutoff frequency is higher than the f_max. We * will later apply a window function, and truncate the time-domain waveform * below an instantaneous frequency f_min. */ REAL8 f_min_wide = EstimateSafeFMinForTD(m1, m2, f_min, deltaT); const REAL8 f_max_wide = params->fCut; //0.5 / deltaT; if (EstimateSafeFMaxForTD(f_max, deltaT) > f_max_wide) XLAL_PRINT_WARNING("Warning: sampling rate (%" LAL_REAL8_FORMAT " Hz) too low for expected spectral content (%" LAL_REAL8_FORMAT " Hz) \n", deltaT, EstimateSafeFMaxForTD(f_max, deltaT)); const size_t nt = NextPow2(EstimateIMRLength(m1, m2, f_min_wide, deltaT)); const size_t ne = EstimateIMRLength(m1, m2, params->fRingDown, deltaT); *ind_t0 = ((nt - EstimateIMRLength(m1, m2, f_min_wide, deltaT)) > (4 * ne)) ? (nt -(2* ne)) : (nt - (1 * ne)); deltaF = 1. / (deltaT * (REAL8) nt); /* Get the length in time for the entire IMR waveform, so the coalesence * can be positioned (in time) accordingly, to avoid wrap-around */ REAL8 t0 = deltaT * ((REAL8) *ind_t0); /* generate in frequency domain */ if (IMRPhenomCGenerateFDForTD(&htilde, t0, phi0, deltaF, m1, m2, //chi, f_min_wide, f_max_wide, distance, params, nt/2 + 1)) XLAL_ERROR(XLAL_EFUNC); /* convert to time domain */ FDToTD(h, htilde, m1 + m2, deltaT, f_min, f_max, f_min_wide, f_max_wide); XLALDestroyCOMPLEX16FrequencySeries(htilde); if (!*h) XLAL_ERROR(XLAL_EFUNC); return XLAL_SUCCESS; }
void LALInferenceTemplateXLALSimInspiralChooseWaveform(LALInferenceModel *model) /*************************************************************************************************************************/ /* Wrapper for LALSimulation waveforms: */ /* XLALSimInspiralChooseFDWaveform() and XLALSimInspiralChooseTDWaveform(). */ /* */ /* model->params parameters are: */ /* - "name" description; type OPTIONAL (default value) */ /* */ /* MODEL PARAMETERS */ /* - "LAL_APPROXIMANT Approximant; Approximant */ /* - "LAL_PNORDER" Phase PN order; INT4 */ /* - "LAL_AMPORDER" Amplitude PN order; INT4 OPTIONAL (-1) */ /* - "spinO" Spin order; LALSimInspiralSpinOrder OPTIONAL (LAL_SIM_INSPIRAL_SPIN_ORDER_DEFAULT) */ /* - "tideO" Tidal order; LALSimInspiralTidalOrder OPTIONAL (LAL_SIM_INSPIRAL_TIDAL_ORDER_DEFAULT) */ /* - "f_ref" frequency at which the (frequency dependent) parameters are defined; REAL8 OPTIONAL (0.0) */ /* - "fLow" lower frequency bound; REAL8 OPTIONAL (model->fLow) */ /* */ /* MASS PARAMETERS; either: */ /* - "mass1" mass of object 1 in solar mass; REAL8 */ /* - "mass2" mass of object 1 in solar mass; REAL8 */ /* OR */ /* - "chirpmass" chirpmass in solar mass; REAL8 */ /* - "q" asymmetric mass ratio m2/m1, 0<q<1; REAL8 */ /* OR */ /* - "chirpmass" chirpmass in solar mass; REAL8 */ /* - "eta" symmetric mass ratio (m1*m2)/(m1+m2)^2; REAL8 */ /* */ /* ORIENTATION AND SPIN PARAMETERS */ /* - "phi0" reference phase as per LALSimulation convention; REAL8 */ /* - "distance" distance in Mpc */ /* - "costheta_jn"); cos of zenith angle between J and N in radians; REAL8 */ /* - "phi_jl"); azimuthal angle of L_N on its cone about J radians; REAL8 */ /* - "tilt_spin1"); zenith angle between S1 and LNhat in radians; REAL8 */ /* - "tilt_spin2"); zenith angle between S2 and LNhat in radians; REAL8 */ /* - "phi12"); difference in azimuthal angle between S1, S2 in radians; REAL8 */ /* - "a_spin1" magnitude of spin 1 in general configuration, -1<a_spin1<1; REAL8 OPTIONAL (0.0) */ /* - "a_spin2" magnitude of spin 2 in general configuration, -1<a_spin1<1; REAL8 OPTIONAL (0.0) */ /* */ /* OTHER PARAMETERS */ /* - "lambda1" tidal parameter of object 1; REAL8 OPTIONAL (0.0) */ /* - "lambda2" tidal parameter of object 1; REAL8 OPTIONAL (0.0) */ /* */ /* - "time" used as an OUTPUT only; REAL8 */ /* */ /* */ /* model needs to also contain: */ /* - model->fLow Unless - "fLow" OPTIONAL */ /* - model->deltaT */ /* - if model->domain == LAL_SIM_DOMAIN_FREQUENCY */ /* - model->deltaF */ /* - model->freqhCross */ /* - model->freqhPlus */ /* - else */ /* - model->timehPlus */ /* - model->timehCross */ /*************************************************************************************************************************/ { Approximant approximant = (Approximant) 0; INT4 order=-1; INT4 amporder; static int sizeWarning = 0; int ret=0; INT4 errnum=0; REAL8TimeSeries *hplus=NULL; /**< +-polarization waveform [returned] */ REAL8TimeSeries *hcross=NULL; /**< x-polarization waveform [returned] */ COMPLEX16FrequencySeries *hptilde=NULL, *hctilde=NULL; REAL8 mc; REAL8 phi0, deltaT, m1, m2, f_low, f_start, distance, inclination; REAL8 *m1_p,*m2_p; REAL8 deltaF, f_max; /* Sampling rate for time domain models */ deltaT = model->deltaT; if (LALInferenceCheckVariable(model->params, "LAL_APPROXIMANT")) approximant = *(Approximant*) LALInferenceGetVariable(model->params, "LAL_APPROXIMANT"); else { XLALPrintError(" ERROR in templateLALGenerateInspiral(): (INT4) \"LAL_APPROXIMANT\" parameter not provided!\n"); XLAL_ERROR_VOID(XLAL_EDATA); } if (LALInferenceCheckVariable(model->params, "LAL_PNORDER")) order = *(INT4*) LALInferenceGetVariable(model->params, "LAL_PNORDER"); else { XLALPrintError(" ERROR in templateLALGenerateInspiral(): (INT4) \"LAL_PNORDER\" parameter not provided!\n"); XLAL_ERROR_VOID(XLAL_EDATA); } /* Explicitly set the default amplitude order if one is not specified. * This serves two purposes: * 1) The default behavior of the code won't change unexpectedly due to changes in LALSimulation. * 2) We need to know the amplitude order in order to set the starting frequency of the waveform properly. */ if (LALInferenceCheckVariable(model->params, "LAL_AMPORDER")) amporder = *(INT4*) LALInferenceGetVariable(model->params, "LAL_AMPORDER"); else amporder = -1; REAL8 f_ref = 100.0; if (LALInferenceCheckVariable(model->params, "f_ref")) f_ref = *(REAL8 *)LALInferenceGetVariable(model->params, "f_ref"); REAL8 fTemp = f_ref; if(LALInferenceCheckVariable(model->params,"chirpmass")) { mc = *(REAL8*) LALInferenceGetVariable(model->params, "chirpmass"); if (LALInferenceCheckVariable(model->params,"q")) { REAL8 q = *(REAL8 *)LALInferenceGetVariable(model->params,"q"); q2masses(mc, q, &m1, &m2); } else { REAL8 eta = *(REAL8*) LALInferenceGetVariable(model->params, "eta"); mc2masses(mc, eta, &m1, &m2); } } else if((m1_p=(REAL8 *)LALInferenceGetVariable(model->params, "mass1")) && (m2_p=(REAL8 *)LALInferenceGetVariable(model->params, "mass2"))) { m1=*m1_p; m2=*m2_p; } else { fprintf(stderr,"No mass parameters found!"); exit(0); } distance = LALInferenceGetREAL8Variable(model->params,"distance")* LAL_PC_SI * 1.0e6; /* distance (1 Mpc) in units of metres */ phi0 = LALInferenceGetREAL8Variable(model->params, "phase"); /* START phase as per lalsimulation convention, radians*/ /* Zenith angle between J and N in radians. Also known as inclination angle when spins are aligned */ REAL8 thetaJN = acos(LALInferenceGetREAL8Variable(model->params, "costheta_jn")); /* zenith angle between J and N in radians */ /* Check if fLow is a model parameter, otherwise use data structure definition */ if(LALInferenceCheckVariable(model->params, "flow")) f_low = *(REAL8*) LALInferenceGetVariable(model->params, "flow"); else f_low = model->fLow; f_start = fLow2fStart(f_low, amporder, approximant); f_max = 0.0; /* for freq domain waveforms this will stop at ISCO. Previously found using model->fHigh causes NaNs in waveform (see redmine issue #750)*/ /* ==== SPINS ==== */ /* We will default to spinless signal and then add in the spin components if required */ /* If there are non-aligned spins, we must convert between the System Frame coordinates * and the cartestian coordinates */ /* The cartesian spin coordinates (default 0), as passed to LALSimulation */ REAL8 spin1x = 0.0; REAL8 spin1y = 0.0; REAL8 spin1z = 0.0; REAL8 spin2x = 0.0; REAL8 spin2y = 0.0; REAL8 spin2z = 0.0; /* System frame coordinates as used for jump proposals */ REAL8 a_spin1 = 0.0; /* Magnitude of spin1 */ REAL8 a_spin2 = 0.0; /* Magnitude of spin2 */ REAL8 phiJL = 0.0; /* azimuthal angle of L_N on its cone about J radians */ REAL8 tilt1 = 0.0; /* zenith angle between S1 and LNhat in radians */ REAL8 tilt2 = 0.0; /* zenith angle between S2 and LNhat in radians */ REAL8 phi12 = 0.0; /* difference in azimuthal angle btwn S1, S2 in radians */ /* Now check if we have spin amplitudes */ if(LALInferenceCheckVariable(model->params, "a_spin1")) a_spin1 = *(REAL8*) LALInferenceGetVariable(model->params, "a_spin1"); if(LALInferenceCheckVariable(model->params, "a_spin2")) a_spin2 = *(REAL8*) LALInferenceGetVariable(model->params, "a_spin2"); /* Check if we have spin angles too */ if(LALInferenceCheckVariable(model->params, "phi_jl")) phiJL = LALInferenceGetREAL8Variable(model->params, "phi_jl"); if(LALInferenceCheckVariable(model->params, "tilt_spin1")) tilt1 = LALInferenceGetREAL8Variable(model->params, "tilt_spin1"); if(LALInferenceCheckVariable(model->params, "tilt_spin2")) tilt2 = LALInferenceGetREAL8Variable(model->params, "tilt_spin2"); if(LALInferenceCheckVariable(model->params, "phi12")) phi12 = LALInferenceGetREAL8Variable(model->params, "phi12"); /* If we have tilt angles zero, then the spins are aligned and we just set the z component */ /* However, if the waveform supports precession then we still need to get the right coordinate components */ SpinSupport spin_support=XLALSimInspiralGetSpinSupportFromApproximant(approximant); if(tilt1==0.0 && tilt2==0.0 && (spin_support==LAL_SIM_INSPIRAL_SPINLESS || spin_support==LAL_SIM_INSPIRAL_ALIGNEDSPIN)) { spin1z=a_spin1; spin2z=a_spin2; inclination = thetaJN; /* Inclination angle is just thetaJN */ } else { /* Template is not aligned-spin only. */ /* Set all the other spin components according to the angles we received above */ /* The transformation function doesn't know fLow, so f_ref==0 isn't interpretted as a request to use the starting frequency for reference. */ if(fTemp==0.0) fTemp = f_start; XLAL_TRY(ret=XLALSimInspiralTransformPrecessingNewInitialConditions( &inclination, &spin1x, &spin1y, &spin1z, &spin2x, &spin2y, &spin2z, thetaJN, phiJL, tilt1, tilt2, phi12, a_spin1, a_spin2, m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, fTemp), errnum); if (ret == XLAL_FAILURE) { XLALPrintError(" ERROR in XLALSimInspiralTransformPrecessingNewInitialConditions(): error converting angles. errnum=%d\n",errnum ); return; } } /* ==== TIDAL PARAMETERS ==== */ REAL8 lambda1 = 0.; if(LALInferenceCheckVariable(model->params, "lambda1")) lambda1 = *(REAL8*) LALInferenceGetVariable(model->params, "lambda1"); REAL8 lambda2 = 0.; if(LALInferenceCheckVariable(model->params, "lambda2")) lambda2 = *(REAL8*) LALInferenceGetVariable(model->params, "lambda2"); REAL8 lambdaT = 0.; REAL8 dLambdaT = 0.; REAL8 sym_mass_ratio_eta = 0.; if(LALInferenceCheckVariable(model->params, "lambdaT")&&LALInferenceCheckVariable(model->params, "dLambdaT")){ lambdaT = *(REAL8*) LALInferenceGetVariable(model->params, "lambdaT"); dLambdaT = *(REAL8*) LALInferenceGetVariable(model->params, "dLambdaT"); sym_mass_ratio_eta = m1*m2/((m1+m2)*(m1+m2)); LALInferenceLambdaTsEta2Lambdas(lambdaT,dLambdaT,sym_mass_ratio_eta,&lambda1,&lambda2); } /* Only use GR templates */ LALSimInspiralTestGRParam *nonGRparams = NULL; /* ==== Call the waveform generator ==== */ if(model->domain == LAL_SIM_DOMAIN_FREQUENCY) { deltaF = model->deltaF; XLAL_TRY(ret=XLALSimInspiralChooseFDWaveformFromCache(&hptilde, &hctilde, phi0, deltaF, m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, spin1x, spin1y, spin1z, spin2x, spin2y, spin2z, f_start, f_max, f_ref, distance, inclination,lambda1, lambda2, model->waveFlags, nonGRparams, amporder, order, approximant,model->waveformCache, NULL), errnum); /* if the waveform failed to generate, fill the buffer with zeros * so that the previous waveform is not left there */ if (ret != XLAL_SUCCESS || hptilde == NULL || hctilde == NULL) { XLALPrintError(" ERROR in XLALSimInspiralChooseWaveformFromCache(): error generating waveform. errnum=%d\n",errnum ); memset(model->freqhPlus->data->data,0,sizeof(model->freqhPlus->data->data[0])*model->freqhPlus->data->length); memset(model->freqhCross->data->data,0,sizeof(model->freqhCross->data->data[0])*model->freqhCross->data->length); if ( hptilde ) XLALDestroyCOMPLEX16FrequencySeries(hptilde); if ( hctilde ) XLALDestroyCOMPLEX16FrequencySeries(hctilde); XLALSimInspiralDestroyTestGRParam(nonGRparams); XLAL_ERROR_VOID(XLAL_FAILURE); } if (hptilde==NULL || hptilde->data==NULL || hptilde->data->data==NULL ) { XLALPrintError(" ERROR in LALInferenceTemplateXLALSimInspiralChooseWaveform(): encountered unallocated 'hptilde'.\n"); XLAL_ERROR_VOID(XLAL_EFAULT); } if (hctilde==NULL || hctilde->data==NULL || hctilde->data->data==NULL ) { XLALPrintError(" ERROR in LALInferenceTemplateXLALSimInspiralChooseWaveform(): encountered unallocated 'hctilde'.\n"); XLAL_ERROR_VOID(XLAL_EFAULT); } INT4 rem=0; UINT4 size=hptilde->data->length; if(size>model->freqhPlus->data->length) size=model->freqhPlus->data->length; memcpy(model->freqhPlus->data->data,hptilde->data->data,sizeof(hptilde->data->data[0])*size); if( (rem=(model->freqhPlus->data->length - size)) > 0) memset(&(model->freqhPlus->data->data[size]),0, rem*sizeof(hptilde->data->data[0]) ); size=hctilde->data->length; if(size>model->freqhCross->data->length) size=model->freqhCross->data->length; memcpy(model->freqhCross->data->data,hctilde->data->data,sizeof(hctilde->data->data[0])*size); if( (rem=(model->freqhCross->data->length - size)) > 0) memset(&(model->freqhCross->data->data[size]),0, rem*sizeof(hctilde->data->data[0]) ); /* Destroy the nonGr params */ XLALSimInspiralDestroyTestGRParam(nonGRparams); REAL8 instant = model->freqhPlus->epoch.gpsSeconds + 1e-9*model->freqhPlus->epoch.gpsNanoSeconds; LALInferenceSetVariable(model->params, "time", &instant); } else { XLAL_TRY(ret=XLALSimInspiralChooseTDWaveformFromCache(&hplus, &hcross, phi0, deltaT, m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, spin1x, spin1y, spin1z, spin2x, spin2y, spin2z, f_start, f_ref, distance, inclination, lambda1, lambda2, model->waveFlags, nonGRparams, amporder, order, approximant,model->waveformCache), errnum); XLALSimInspiralDestroyTestGRParam(nonGRparams); if (ret == XLAL_FAILURE || hplus == NULL || hcross == NULL) { XLALPrintError(" ERROR in XLALSimInspiralChooseWaveformFromCache(): error generating waveform. errnum=%d\n",errnum ); memset(model->timehPlus->data->data,0,sizeof(model->timehPlus->data->data[0]) * model->timehPlus->data->length); memset(model->timehCross->data->data,0,sizeof(model->timehCross->data->data[0]) * model->timehCross->data->length); if ( hplus ) XLALDestroyREAL8TimeSeries(hplus); if ( hcross ) XLALDestroyREAL8TimeSeries(hcross); XLALSimInspiralDestroyTestGRParam(nonGRparams); XLAL_ERROR_VOID(XLAL_FAILURE); } /* The following complicated mess is a result of the following considerations: 1) The discrete time samples of the template and the timeModel buffers will not, in general line up. 2) The likelihood function will timeshift the template in the frequency domain to align it properly with the desired tc in each detector (these are different because the detectors receive the signal at different times). Because this timeshifting is done in the frequency domain, the effective time-domain template is periodic. We want to avoid the possibility of non-zero template samples wrapping around from the start/end of the buffer, since real templates are not periodic! 3) If the template apporaches the ends of the timeModel buffer, then it should be tapered in the same way as the timeData (currently 0.4 seconds, hard-coded! Tukey window; see LALInferenceReadData.c, near line 233) so that template and signal in the data match. However, as an optimization, we perform only one tapering and FFT-ing in the likelihood function; subsequent timeshifts for the different detectors will cause the tapered regions of the template and data to become mis-aligned. The algorthim we use is the following: 1) Inject the template to align with the nearest sample in the timeModel buffer to the desired geocent_end time. 2) Check whether either the start or the end of the template overlaps the tapered region, plus a safety buffer corresponding to a conservative estimate of the largest geocenter <--> detector timeshift. a) If there is no overlap at the start or end of the buffer, we're done. b) If there is an overlap, issue one warning per process (which can be disabled by setting the LAL debug level) about a too-short segment length, and return. */ size_t waveLength = hplus->data->length; size_t bufLength = model->timehPlus->data->length; /* 2*Rearth/(c*deltaT)---2 is safety factor---is the maximum time shift for any earth-based detector. */ size_t maxShift = (size_t)lround(4.255e-2/deltaT); /* Taper 0.4 seconds at start and end (hard-coded! in LALInferenceReadData.c, around line 233). */ size_t taperLength = (size_t)lround(0.4/deltaT); /* Within unsafeLength of ends of buffer, possible danger of wrapping and/or tapering interactions. */ size_t unsafeLength = taperLength + maxShift; REAL8 desiredTc = *(REAL8 *)LALInferenceGetVariable(model->params, "time"); REAL8 tStart = XLALGPSGetREAL8(&(model->timehPlus->epoch)); REAL8 tEnd = tStart + deltaT * model->timehPlus->data->length; if (desiredTc < tStart || desiredTc > tEnd) { XLALDestroyREAL8TimeSeries(hplus); XLALDestroyREAL8TimeSeries(hcross); XLAL_PRINT_ERROR("desired tc (%.4f) outside data buffer\n", desiredTc); XLAL_ERROR_VOID(XLAL_EDOM); } /* The nearest sample in model buffer to the desired tc. */ size_t tcSample = (size_t)lround((desiredTc - XLALGPSGetREAL8(&(model->timehPlus->epoch)))/deltaT); /* The acutal coalescence time that corresponds to the buffer sample on which the waveform's tC lands. */ REAL8 injTc = XLALGPSGetREAL8(&(model->timehPlus->epoch)) + tcSample*deltaT; /* The sample at which the waveform reaches tc. */ size_t waveTcSample = (size_t)lround(-XLALGPSGetREAL8(&(hplus->epoch))/deltaT); /* 1 + (number of samples post-tc in waveform) */ size_t wavePostTc = waveLength - waveTcSample; size_t bufStartIndex = (tcSample >= waveTcSample ? tcSample - waveTcSample : 0); size_t bufEndIndex = (wavePostTc + tcSample <= bufLength ? wavePostTc + tcSample : bufLength); size_t bufWaveLength = bufEndIndex - bufStartIndex; size_t waveStartIndex = (tcSample >= waveTcSample ? 0 : waveTcSample - tcSample); if (bufStartIndex < unsafeLength || (bufLength - bufEndIndex) <= unsafeLength) { /* The waveform could be timeshifted into a region where it will be tapered improperly, or even wrap around from the periodic timeshift. Issue warning. */ if (!sizeWarning) { fprintf(stderr, "WARNING: Generated template is too long to guarantee that it will not\n"); fprintf(stderr, "WARNING: (a) lie in a tapered region of the time-domain buffer\n"); fprintf(stderr, "WARNING: (b) wrap periodically when timeshifted in likelihood computation\n"); fprintf(stderr, "WARNING: Either of these may cause differences between the template and the\n"); fprintf(stderr, "WARNING: correct GW waveform in each detector.\n"); fprintf(stderr, "WARNING: Parameter estimation will continue, but you should consider\n"); fprintf(stderr, "WARNING: increasing the data segment length (using the --seglen) option.\n"); sizeWarning = 1; } } /* Clear model buffers */ memset(model->timehPlus->data->data, 0, sizeof(REAL8)*model->timehPlus->data->length); memset(model->timehCross->data->data, 0, sizeof(REAL8)*model->timehCross->data->length); /* Inject */ memcpy(model->timehPlus->data->data + bufStartIndex, hplus->data->data + waveStartIndex, bufWaveLength*sizeof(REAL8)); memcpy(model->timehCross->data->data + bufStartIndex, hcross->data->data + waveStartIndex, bufWaveLength*sizeof(REAL8)); LALInferenceSetVariable(model->params, "time", &injTc); } if ( hplus ) XLALDestroyREAL8TimeSeries(hplus); if ( hcross ) XLALDestroyREAL8TimeSeries(hcross); if ( hptilde ) XLALDestroyCOMPLEX16FrequencySeries(hptilde); if ( hctilde ) XLALDestroyCOMPLEX16FrequencySeries(hctilde); return; }
/* creates a waveform in the time domain; the waveform might be generated in * the frequency-domain and transformed */ int create_td_waveform(REAL8TimeSeries ** h_plus, REAL8TimeSeries ** h_cross, struct params p) { clock_t timer_start = 0; if (p.condition) { if (p.verbose) { fprintf(stderr, "generating waveform in time domain using XLALSimInspiralTD...\n"); timer_start = clock(); } XLALSimInspiralTD(h_plus, h_cross, p.m1, p.m2, p.s1x, p.s1y, p.s1z, p.s2x, p.s2y, p.s2z, p.distance, p.inclination, p.phiRef, p.longAscNodes, p.eccentricity, p.meanPerAno, 1.0 / p.srate, p.f_min, p.fRef, p.params, p.approx); if (p.verbose) fprintf(stderr, "generation took %g seconds\n", (double)(clock() - timer_start) / CLOCKS_PER_SEC); } else if (p.domain == LAL_SIM_DOMAIN_TIME) { /* generate time domain waveform */ if (p.verbose) { fprintf(stderr, "generating waveform in time domain using XLALSimInspiralChooseTDWaveform...\n"); timer_start = clock(); } XLALSimInspiralChooseTDWaveform(h_plus, h_cross, p.m1, p.m2, p.s1x, p.s1y, p.s1z, p.s2x, p.s2y, p.s2z, p.distance, p.inclination, p.phiRef, p.longAscNodes, p.eccentricity, p.meanPerAno, 1.0 / p.srate, p.f_min, p.fRef, p.params, p.approx); if (p.verbose) fprintf(stderr, "generation took %g seconds\n", (double)(clock() - timer_start) / CLOCKS_PER_SEC); } else { COMPLEX16FrequencySeries *htilde_plus = NULL; COMPLEX16FrequencySeries *htilde_cross = NULL; REAL8FFTPlan *plan; double chirplen, deltaF; int chirplen_exp; /* determine required frequency resolution */ /* length of the chirp in samples */ chirplen = imr_time_bound(p.f_min, p.m1, p.m2, p.s1z, p.s2z) * p.srate; /* make chirplen next power of two */ frexp(chirplen, &chirplen_exp); chirplen = ldexp(1.0, chirplen_exp); deltaF = p.srate / chirplen; if (p.verbose) fprintf(stderr, "using frequency resolution deltaF = %g Hz\n", deltaF); /* generate waveform in frequency domain */ if (p.verbose) { fprintf(stderr, "generating waveform in frequency domain using XLALSimInspiralChooseFDWaveform...\n"); timer_start = clock(); } XLALSimInspiralChooseFDWaveform(&htilde_plus, &htilde_cross, p.m1, p.m2, p.s1x, p.s1y, p.s1z, p.s2x, p.s2y, p.s2z, p.distance, p.inclination, p.phiRef, p.longAscNodes, p.eccentricity, p.meanPerAno, deltaF, p.f_min, 0.5 * p.srate, p.fRef, p.params, p.approx); if (p.verbose) fprintf(stderr, "generation took %g seconds\n", (double)(clock() - timer_start) / CLOCKS_PER_SEC); /* put the waveform in the time domain */ if (p.verbose) { fprintf(stderr, "transforming waveform to time domain...\n"); timer_start = clock(); } *h_plus = XLALCreateREAL8TimeSeries("h_plus", &htilde_plus->epoch, 0.0, 1.0 / p.srate, &lalStrainUnit, (size_t) chirplen); *h_cross = XLALCreateREAL8TimeSeries("h_cross", &htilde_cross->epoch, 0.0, 1.0 / p.srate, &lalStrainUnit, (size_t) chirplen); plan = XLALCreateReverseREAL8FFTPlan((size_t) chirplen, 0); XLALREAL8FreqTimeFFT(*h_cross, htilde_cross, plan); XLALREAL8FreqTimeFFT(*h_plus, htilde_plus, plan); if (p.verbose) fprintf(stderr, "transformation took %g seconds\n", (double)(clock() - timer_start) / CLOCKS_PER_SEC); /* clean up */ XLALDestroyREAL8FFTPlan(plan); XLALDestroyCOMPLEX16FrequencySeries(htilde_cross); XLALDestroyCOMPLEX16FrequencySeries(htilde_plus); } return 0; }
int main(int argc, char *argv[]) { struct params p; int istd, isfd; XLALSetErrorHandler(XLALBacktraceErrorHandler); p = parseargs(argc, argv); print_params(p); /* sanity check on domain; set to natural value if unspecified */ istd = XLALSimInspiralImplementedTDApproximants(p.approx); isfd = XLALSimInspiralImplementedFDApproximants(p.approx); if (!istd && !isfd) { fprintf(stderr, "error: approximant not supported\n"); exit(1); } switch (p.domain) { case LAL_SIM_DOMAIN_TIME: if (!istd) { fprintf(stderr, "error: approximant not supported in time domain\n"); exit(1); } break; case LAL_SIM_DOMAIN_FREQUENCY: if (!isfd) { fprintf(stderr, "error: approximant not supported in frequency domain\n"); exit(1); } break; default: switch (p.freq_dom) { case 0: p.domain = istd ? LAL_SIM_DOMAIN_TIME : LAL_SIM_DOMAIN_FREQUENCY; break; case 1: p.domain = isfd ? LAL_SIM_DOMAIN_FREQUENCY : LAL_SIM_DOMAIN_TIME; break; } break; } /* generate and output the waveform in appropriate domain */ if (p.freq_dom) { COMPLEX16FrequencySeries *htilde_plus = NULL; COMPLEX16FrequencySeries *htilde_cross = NULL; create_fd_waveform(&htilde_plus, &htilde_cross, p); output_fd_waveform(htilde_plus, htilde_cross, p); XLALDestroyCOMPLEX16FrequencySeries(htilde_cross); XLALDestroyCOMPLEX16FrequencySeries(htilde_plus); } else { REAL8TimeSeries *h_plus = NULL; REAL8TimeSeries *h_cross = NULL; create_td_waveform(&h_plus, &h_cross, p); output_td_waveform(h_plus, h_cross, p); XLALDestroyREAL8TimeSeries(h_cross); XLALDestroyREAL8TimeSeries(h_plus); } /* cleanup */ XLALDestroyDict(p.params); LALCheckMemoryLeaks(); return 0; }
REAL8 calculate_snr_from_strain_and_psd_real8( REAL8TimeSeries *strain, REAL8FrequencySeries *psd, REAL8 startFreq, const CHAR ifo[3]) { REAL8 ret = -1, snrSq, freq, psdValue; REAL8 deltaF; REAL8FFTPlan *pfwd; COMPLEX16FrequencySeries *fftData; UINT4 k; /* create the time series */ deltaF = strain->deltaT * strain->data->length; fftData = XLALCreateCOMPLEX16FrequencySeries( strain->name, &(strain->epoch), 0, deltaF, &lalDimensionlessUnit, strain->data->length/2 + 1 ); /* perform the fft */ pfwd = XLALCreateForwardREAL8FFTPlan( strain->data->length, 0 ); XLALREAL8TimeFreqFFT( fftData, strain, pfwd ); /* The PSD, if provided, comes in as it was in the original file */ /* since we don't know deltaF until we get here. Interpolate now */ if ( psd ) { psd = XLALInterpolatePSD(psd, 1.0 / deltaF); } /* compute the SNR for initial LIGO at design */ for ( snrSq = 0, k = 0; k < fftData->data->length; k++ ) { freq = fftData->deltaF * k; if ( psd ) { if ( freq < startFreq || k > psd->data->length ) continue; psdValue = psd->data->data[k]; psdValue /= 9e-46; } else if ( ifo[0] == 'V' ) { if (freq < 35) continue; LALVIRGOPsd( NULL, &psdValue, freq ); psdValue /= 9e-46; } else { if (freq < 40) continue; LALLIGOIPsd( NULL, &psdValue, freq ); } fftData->data->data[k] /= 3e-23; snrSq += creal(fftData->data->data[k]) * creal(fftData->data->data[k]) / psdValue; snrSq += cimag(fftData->data->data[k]) * cimag(fftData->data->data[k]) / psdValue; } snrSq *= 4*fftData->deltaF; XLALDestroyREAL8FFTPlan( pfwd ); XLALDestroyCOMPLEX16FrequencySeries( fftData ); if ( psd ) XLALDestroyREAL8FrequencySeries( psd ); ret = sqrt(snrSq); printf("Obtained snr=%f\n", ret); return ret; }
REAL8 calculate_lalsim_snr(SimInspiralTable *inj, char *IFOname, REAL8FrequencySeries *psd, REAL8 start_freq) { /* Calculate and return the single IFO SNR * * Required options: * * inj: SimInspiralTable entry for which the SNR has to be calculated * IFOname: The canonical name (e.g. H1, L1, V1) name of the IFO for which the SNR must be calculated * PSD: PSD curve to be used for the overlap integrap * start_freq: lower cutoff of the overlap integral * * */ int ret=0; INT4 errnum=0; UINT4 j=0; /* Fill detector site info */ LALDetector* detector=NULL; detector=calloc(1,sizeof(LALDetector)); if(!strcmp(IFOname,"H1")) memcpy(detector,&lalCachedDetectors[LALDetectorIndexLHODIFF],sizeof(LALDetector)); if(!strcmp(IFOname,"H2")) memcpy(detector,&lalCachedDetectors[LALDetectorIndexLHODIFF],sizeof(LALDetector)); if(!strcmp(IFOname,"LLO")||!strcmp(IFOname,"L1")) memcpy(detector,&lalCachedDetectors[LALDetectorIndexLLODIFF],sizeof(LALDetector)); if(!strcmp(IFOname,"V1")||!strcmp(IFOname,"VIRGO")) memcpy(detector,&lalCachedDetectors[LALDetectorIndexVIRGODIFF],sizeof(LALDetector)); Approximant approx=TaylorF2; approx=XLALGetApproximantFromString(inj->waveform); LALSimulationDomain modelDomain; if(XLALSimInspiralImplementedFDApproximants(approx)) modelDomain = LAL_SIM_DOMAIN_FREQUENCY; else if(XLALSimInspiralImplementedTDApproximants(approx)) modelDomain = LAL_SIM_DOMAIN_TIME; else { fprintf(stderr,"ERROR. Unknown approximant number %i. Unable to choose time or frequency domain model.",approx); exit(1); } REAL8 m1,m2, s1x,s1y,s1z,s2x,s2y,s2z,phi0,f_min,f_max,iota,polarization; /* No tidal PN terms until injtable is able to get them */ LALDict *LALpars= XLALCreateDict(); /* Spin and tidal interactions at the highest level (default) until injtable stores them. * When spinO and tideO are added to injtable we can un-comment those lines and should be ok * int spinO = inj->spinO; int tideO = inj->tideO; XLALSimInspiralSetSpinOrder(waveFlags, *(LALSimInspiralSpinOrder*) spinO); XLALSimInspiralSetTidalOrder(waveFlags, *(LALSimInspiralTidalOrder*) tideO); */ XLALSimInspiralWaveformParamsInsertPNPhaseOrder(LALpars,XLALGetOrderFromString(inj->waveform)); XLALSimInspiralWaveformParamsInsertPNAmplitudeOrder(LALpars,inj->amp_order); /* Read parameters */ m1=inj->mass1*LAL_MSUN_SI; m2=inj->mass2*LAL_MSUN_SI; s1x=inj->spin1x; s1y=inj->spin1y; s1z=inj->spin1z; s2x=inj->spin2x; s2y=inj->spin2y; s2z=inj->spin2z; iota=inj->inclination; f_min=XLALSimInspiralfLow2fStart(inj->f_lower,XLALSimInspiralWaveformParamsLookupPNAmplitudeOrder(LALpars),XLALGetApproximantFromString(inj->waveform)); phi0=inj->coa_phase; polarization=inj->polarization; REAL8 latitude=inj->latitude; REAL8 longitude=inj->longitude; LIGOTimeGPS epoch; memcpy(&epoch,&(inj->geocent_end_time),sizeof(LIGOTimeGPS)); /* Hardcoded values of srate and segment length. If changed here they must also be changed in inspinj.c */ REAL8 srate=4096.0; const CHAR *WF=inj->waveform; /* Increase srate for EOB WFs */ if (strstr(WF,"EOB")) srate=8192.0; REAL8 segment=64.0; f_max=(srate/2.0-(1.0/segment)); size_t seglen=(size_t) segment*srate; REAL8 deltaF=1.0/segment; REAL8 deltaT=1.0/srate; /* Frequency domain h+ and hx. They are going to be filled either by a FD WF or by the FFT of a TD WF*/ COMPLEX16FrequencySeries *freqHplus; COMPLEX16FrequencySeries *freqHcross; freqHplus= XLALCreateCOMPLEX16FrequencySeries("fhplus", &epoch, 0.0, deltaF, &lalDimensionlessUnit, seglen/2+1 ); freqHcross=XLALCreateCOMPLEX16FrequencySeries("fhcross", &epoch, 0.0, deltaF, &lalDimensionlessUnit, seglen/2+1 ); /* If the approximant is on the FD call XLALSimInspiralChooseFDWaveform */ if (modelDomain == LAL_SIM_DOMAIN_FREQUENCY) { COMPLEX16FrequencySeries *hptilde=NULL; COMPLEX16FrequencySeries *hctilde=NULL; //We do not pass the polarization here, we assume it is taken into account when projecting h+,x onto the detector. XLAL_TRY(ret=XLALSimInspiralChooseFDWaveform(&hptilde,&hctilde, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, LAL_PC_SI * 1.0e6, iota, phi0, 0., 0., 0., deltaF, f_min, 0.0, 0.0, LALpars,approx),errnum); XLALDestroyDict(LALpars); if(!hptilde|| hptilde->data==NULL || hptilde->data->data==NULL ||!hctilde|| hctilde->data==NULL || hctilde->data->data==NULL) { XLALPrintError(" ERROR in XLALSimInspiralChooseFDWaveform(): error generating waveform. errnum=%d. Exiting...\n",errnum ); exit(1); } COMPLEX16 *dataPtr = hptilde->data->data; for (j=0; j<(UINT4) freqHplus->data->length; ++j) { if(j < hptilde->data->length) { freqHplus->data->data[j] = dataPtr[j]; } else { freqHplus->data->data[j]=0.0 + I*0.0; } } dataPtr = hctilde->data->data; for (j=0; j<(UINT4) freqHplus->data->length; ++j) { if(j < hctilde->data->length) { freqHcross->data->data[j] = dataPtr[j]; } else { freqHcross->data->data[j]=0.0+0.0*I; } } /* Clean */ if(hptilde) XLALDestroyCOMPLEX16FrequencySeries(hptilde); if(hctilde) XLALDestroyCOMPLEX16FrequencySeries(hctilde); } else { /* Otherwise use XLALSimInspiralChooseTDWaveform */ REAL8FFTPlan *timeToFreqFFTPlan = XLALCreateForwardREAL8FFTPlan((UINT4) seglen, 0 ); REAL8TimeSeries *hplus=NULL; REAL8TimeSeries *hcross=NULL; REAL8TimeSeries *timeHplus=NULL; REAL8TimeSeries *timeHcross=NULL; REAL8 padding =0.4;//seconds REAL8Window *window=XLALCreateTukeyREAL8Window(seglen,(REAL8)2.0*padding*srate/(REAL8)seglen); REAL4 WinNorm = sqrt(window->sumofsquares/window->data->length); timeHcross=XLALCreateREAL8TimeSeries("timeModelhCross", &epoch, 0.0, deltaT, &lalStrainUnit, seglen ); timeHplus=XLALCreateREAL8TimeSeries("timeModelhplus", &epoch, 0.0, deltaT, &lalStrainUnit, seglen ); for (j=0;j<(UINT4) timeHcross->data->length;++j) timeHcross->data->data[j]=0.0; for (j=0;j<(UINT4) timeHplus->data->length;++j) timeHplus->data->data[j]=0.0; XLAL_TRY(ret=XLALSimInspiralChooseTDWaveform(&hplus, &hcross, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, LAL_PC_SI*1.0e6, iota, phi0, 0., 0., 0., deltaT, f_min, 0., LALpars, approx), errnum); if (ret == XLAL_FAILURE || hplus == NULL || hcross == NULL) { XLALPrintError(" ERROR in XLALSimInspiralChooseTDWaveform(): error generating waveform. errnum=%d. Exiting...\n",errnum ); exit(1); } hplus->epoch = timeHplus->epoch; hcross->epoch = timeHcross->epoch; XLALSimAddInjectionREAL8TimeSeries(timeHplus, hplus, NULL); XLALSimAddInjectionREAL8TimeSeries(timeHcross, hcross, NULL); for (j=0; j<(UINT4) timeHplus->data->length; ++j) timeHplus->data->data[j]*=window->data->data[j]; for (j=0; j<(UINT4) timeHcross->data->length; ++j) timeHcross->data->data[j]*=window->data->data[j]; for (j=0; j<(UINT4) freqHplus->data->length; ++j) { freqHplus->data->data[j]=0.0+I*0.0; freqHcross->data->data[j]=0.0+I*0.0; } /* FFT into freqHplus and freqHcross */ XLALREAL8TimeFreqFFT(freqHplus,timeHplus,timeToFreqFFTPlan); XLALREAL8TimeFreqFFT(freqHcross,timeHcross,timeToFreqFFTPlan); for (j=0; j<(UINT4) freqHplus->data->length; ++j) { freqHplus->data->data[j]/=WinNorm; freqHcross->data->data[j]/=WinNorm; } /* Clean... */ if ( hplus ) XLALDestroyREAL8TimeSeries(hplus); if ( hcross ) XLALDestroyREAL8TimeSeries(hcross); if ( timeHplus ) XLALDestroyREAL8TimeSeries(timeHplus); if ( timeHcross ) XLALDestroyREAL8TimeSeries(timeHcross); if (timeToFreqFFTPlan) LALFree(timeToFreqFFTPlan); if (window) XLALDestroyREAL8Window(window); } /* The WF has been generated and is in freqHplus/cross. Now project into the IFO frame */ double Fplus, Fcross; double FplusScaled, FcrossScaled; double HSquared; double GPSdouble=(REAL8) inj->geocent_end_time.gpsSeconds+ (REAL8) inj->geocent_end_time.gpsNanoSeconds*1.0e-9; double gmst; LIGOTimeGPS GPSlal; XLALGPSSetREAL8(&GPSlal, GPSdouble); gmst=XLALGreenwichMeanSiderealTime(&GPSlal); /* Fill Fplus and Fcross*/ XLALComputeDetAMResponse(&Fplus, &Fcross, (const REAL4 (*)[3])detector->response,longitude, latitude, polarization, gmst); /* And take the distance into account */ FplusScaled = Fplus / (inj->distance); FcrossScaled = Fcross / (inj->distance); REAL8 timedelay = XLALTimeDelayFromEarthCenter(detector->location,longitude, latitude, &GPSlal); REAL8 timeshift = timedelay; REAL8 twopit = LAL_TWOPI * timeshift; UINT4 lower = (UINT4)ceil(start_freq / deltaF); UINT4 upper = (UINT4)floor(f_max / deltaF); REAL8 re = cos(twopit*deltaF*lower); REAL8 im = -sin(twopit*deltaF*lower); /* Incremental values, using cos(theta) - 1 = -2*sin(theta/2)^2 */ REAL8 dim = -sin(twopit*deltaF); REAL8 dre = -2.0*sin(0.5*twopit*deltaF)*sin(0.5*twopit*deltaF); REAL8 TwoDeltaToverN = 2.0 *deltaT / ((double) seglen); REAL8 plainTemplateReal, plainTemplateImag,templateReal,templateImag; REAL8 newRe, newIm,temp; REAL8 this_snr=0.0; if ( psd ) { psd = XLALInterpolatePSD(psd, deltaF); } for (j=lower; j<=(UINT4) upper; ++j) { /* derive template (involving location/orientation parameters) from given plus/cross waveforms: */ plainTemplateReal = FplusScaled * creal(freqHplus->data->data[j]) + FcrossScaled *creal(freqHcross->data->data[j]); plainTemplateImag = FplusScaled * cimag(freqHplus->data->data[j]) + FcrossScaled * cimag(freqHcross->data->data[j]); /* do time-shifting... */ /* (also un-do 1/deltaT scaling): */ templateReal = (plainTemplateReal*re - plainTemplateImag*im) / deltaT; templateImag = (plainTemplateReal*im + plainTemplateImag*re) / deltaT; HSquared = templateReal*templateReal + templateImag*templateImag ; temp = ((TwoDeltaToverN * HSquared) / psd->data->data[j]); this_snr += temp; /* Now update re and im for the next iteration. */ newRe = re + re*dre - im*dim; newIm = im + re*dim + im*dre; re = newRe; im = newIm; } /* Clean */ if (freqHcross) XLALDestroyCOMPLEX16FrequencySeries(freqHcross); if (freqHplus) XLALDestroyCOMPLEX16FrequencySeries(freqHplus); if (detector) free(detector); return sqrt(this_snr*2.0); }
INT4 main (INT4 argc, char* argv[]) { UINT4 startAtZero = 1; // RNG seed UINT8 seed; REAL8 desiredDeltaF; // if passed parameters, assume first parameter is the seed if(argc > 1) { seed = atoi(argv[1]); if(seed == 0) { seed = time(0); } if(argc > 2) { desiredDeltaF = atof(argv[2]); } else { desiredDeltaF = 0.1; } } else { seed = time(0); } // seed the RNG srand(seed); printf("Starting TestTaylorTFourier with seed %" LAL_UINT8_FORMAT "\n" , seed); // define different orders LALSimInspiralSpinOrder spinO = 7; LALSimInspiralTidalOrder tideO = 0; INT4 phaseO = 7; INT4 amplitudeO = 3; // define parameters REAL8 phiRef, v0, m1, m2, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2; v0 = 1.; // deformability parameters turned off lambda1 = 0.; lambda2 = 0.; quadparam1 = 0.; quadparam2 = 0.; // define instrument projection parameters REAL8 Fplus, Fcross; // define range for the parameters REAL8 m1Min, m1Max, m2Min, m2Max, chi1Min, chi1Max, chi2Min, chi2Max, rMin, rMax; m1Min = 1.; // in solar masses m1Max = 2.5; // in solar masses m2Min = 1.; // in solar masses m2Max = 2.5; // in solar masses chi1Min = 0.; chi1Max = 1.; chi2Min = 0.; chi2Max = 1.; rMin = 3.e24; rMax = 3.e24; // randomize parameters randomize(&phiRef, &m1, &m2, &r, &s1x, &s1y, &s1z, &s2x, &s2y, &s2z, &lnhatx, &lnhaty, &lnhatz, &e1x, &e1y, &e1z, &Fplus, &Fcross, m1Min, m1Max, m2Min, m2Max, chi1Min, chi1Max, chi2Min, chi2Max, rMin, rMax); // misc parameters REAL8 tTot; REAL8 deltaF; INT4 nSamples; REAL8 fMin; REAL8 fMax; REAL8 tInit; REAL8 desiredFMin; UINT4 i; fMax = 2000.; desiredFMin = 10.; REAL8 M = m1 + m2; REAL8 eta = (m1*m2)/(M*M); // define time series for time domain waveform REAL8TimeSeries* hPlus = 0; REAL8TimeSeries* hCross = 0; // define extra parameters for TD WF REAL8 deltaT; REAL8 fStart = 9.; REAL8 fRef = 70.; INT4 phiRefAtEnd = 0; // more misc variables COMPLEX16* hPlusTildeTD; COMPLEX16* hCrossTildeTD; REAL8 factTukey, t1, t2, t3, t4; REAL8 sinfact, t; fftw_complex* ftilde_data; fftw_plan plan; INT4 iStart, jStart, nSkip; REAL8 rStop; INT4 nMax; // define frequency series for FD WFs COMPLEX16FrequencySeries* hPlusTildeFD = 0; COMPLEX16FrequencySeries* hCrossTildeFD = 0; INT4 kMax; REAL8 normalizationTD; REAL8 meanDeltaT; REAL8 match; printf("TaylorT4:\nStarting time domain...\n"); // compute TD WF with deltaT=1 to get signal time duration deltaT = 1.; XLALSimInspiralSpinTaylorT4(&hPlus, &hCross, phiRef, v0, deltaT, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO); // compute deltaT necessary for Nyquist frequency at fMax tTot = -(hPlus->epoch.gpsSeconds + 1.e-9*hPlus->epoch.gpsNanoSeconds); deltaF = 1./tTot; nSamples = 2.*fMax/deltaF; deltaT = tTot/nSamples; // compute TD WF with good deltaT XLALDestroyREAL8TimeSeries(hPlus); XLALDestroyREAL8TimeSeries(hCross); XLALSimInspiralSpinTaylorT4(&hPlus, &hCross, phiRef, v0, deltaT, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO); // define and allocate DFT of TD WF hPlusTildeTD = (COMPLEX16*)malloc(sizeof(COMPLEX16)*(hPlus->data->length)); hCrossTildeTD = (COMPLEX16*)malloc(sizeof(COMPLEX16)*(hCross->data->length)); tInit = hPlus->epoch.gpsSeconds + 1.e-9*hPlus->epoch.gpsNanoSeconds; deltaF = 1./(deltaT*(hPlus->data->length)); // define Tukey window parameters factTukey = (-5.*LAL_G_SI*M)/(((256.*eta*LAL_C_SI)*LAL_C_SI)*LAL_C_SI); t1 = tInit; t2 = factTukey*pow((LAL_PI*LAL_G_SI)*M*9.5/(((((REAL8)LAL_C_SI)*LAL_C_SI)*LAL_C_SI)), -8./3.); // 9.5 Hertz Newtonian t3 = factTukey*50625.; // 15M separation Newtonian t4 = 0.; // apply Tukey window i = 0; t = tInit; while(t < t2) { sinfact = sin(LAL_PI_2*(t - t1)/(t2 - t1)); hPlus->data->data[i] *= sinfact*sinfact; hCross->data->data[i] *= sinfact*sinfact; i++; t = tInit + i*deltaT; } i = hPlus->data->length-1; t = tInit + i*deltaT; while(t > t3) { sinfact = sin(LAL_PI_2*(t - t4)/(t3 - t4)); hPlus->data->data[i] *= sinfact*sinfact; hCross->data->data[i] *= sinfact*sinfact; i--; t = tInit + i*deltaT; } // compute the DFTs, applying the necessary time shift ftilde_data = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*(hPlus->data->length)); plan = fftw_plan_dft_r2c_1d(hPlus->data->length, hPlus->data->data, ftilde_data, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); for(i = 0; i <= hPlus->data->length >> 1; i++) { hPlusTildeTD[i] = deltaT*cexp(-I*LAL_TWOPI*i*deltaF*tInit)*ftilde_data[i]; } plan = fftw_plan_dft_r2c_1d(hCross->data->length, hCross->data->data, ftilde_data, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); for(i = 0; i <= hCross->data->length >> 1; i++) { hCrossTildeTD[i] = deltaT*cexp(-I*LAL_TWOPI*i*deltaF*tInit)*ftilde_data[i]; } fftw_free(ftilde_data); // compute fMin and deltaF for the frequency domain WFs, close to desiredFMin and desiredDeltaF but a multiple of deltaF for the TD WF iStart = (INT4)ceil(desiredFMin/deltaF); nSkip = (INT4)ceil(desiredDeltaF/deltaF); iStart -= iStart % nSkip; fMin = iStart*deltaF; deltaF *= nSkip; if(startAtZero) { jStart = iStart/nSkip; } else { jStart = 0; } // set maximum frequency for the comparison rStop = 20.; // frequency of r = 20M fMax = LAL_C_SI*(LAL_C_SI*(LAL_C_SI/(LAL_PI*LAL_G_SI*M*rStop*sqrt(rStop)))); nMax = (INT4)floor((fMax - fMin)/deltaF) + jStart; // normalize TD WF normalizationTD = normalizeTD(hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax); printf("Matches:\n"); for(kMax = 0; kMax <= 10; kMax++) // loop over kMax { //compute FD WF XLALSimInspiralSpinTaylorT4Fourier(&hPlusTildeFD, &hCrossTildeFD, fMin, fMax, deltaF, kMax, phiRef, v0, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO, phiRefAtEnd); // XLALSimInspiralSpinTaylorT4 and XLALSimInspiralSpinTaylorT4Fourier return with a slight time offset between the two. We get rid of that. if(startAtZero) { meanDeltaT = meanTimeOffset(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax, 0., deltaF); for(i = 0; i < hPlusTildeFD->data->length; i++) { hPlusTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(i*deltaF)*meanDeltaT); hCrossTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(i*deltaF)*meanDeltaT); } } else { meanDeltaT = meanTimeOffset(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax, fMin, deltaF); for(i = 0; i < hPlusTildeFD->data->length; i++) { hPlusTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(fMin + i*deltaF)*meanDeltaT); hCrossTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(fMin + i*deltaF)*meanDeltaT); } } // compute match match = normalizationTD*computeMatch(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax); printf("kMax = %2d: %.15f\n", kMax, match); XLALDestroyCOMPLEX16FrequencySeries(hPlusTildeFD); XLALDestroyCOMPLEX16FrequencySeries(hCrossTildeFD); } XLALDestroyREAL8TimeSeries(hPlus); XLALDestroyREAL8TimeSeries(hCross); free(hPlusTildeTD); free(hCrossTildeTD); printf("\nTaylorT2:\nStarting time domain...\n"); // compute TD WF with deltaT=1 to get signal time duration deltaT = 1.; XLALSimInspiralSpinTaylorT2(&hPlus, &hCross, phiRef, v0, deltaT, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO); // compute deltaT necessary for Nyquist frequency at fMax tTot = -(hPlus->epoch.gpsSeconds + 1.e-9*hPlus->epoch.gpsNanoSeconds); deltaF = 1./tTot; nSamples = 2.*fMax/deltaF; deltaT = tTot/nSamples; // compute TD WF with good deltaT XLALDestroyREAL8TimeSeries(hPlus); XLALDestroyREAL8TimeSeries(hCross); XLALSimInspiralSpinTaylorT2(&hPlus, &hCross, phiRef, v0, deltaT, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO); // define and allocate DFT of TD WF hPlusTildeTD = (COMPLEX16*)malloc(sizeof(COMPLEX16)*(hPlus->data->length)); hCrossTildeTD = (COMPLEX16*)malloc(sizeof(COMPLEX16)*(hCross->data->length)); tInit = hPlus->epoch.gpsSeconds + 1.e-9*hPlus->epoch.gpsNanoSeconds; deltaF = 1./(deltaT*(hPlus->data->length)); // define Tukey window parameters factTukey = (-5.*LAL_G_SI*M)/(((256.*eta*LAL_C_SI)*LAL_C_SI)*LAL_C_SI); t1 = tInit; t2 = factTukey*pow((LAL_PI*LAL_G_SI)*M*9.5/(((((REAL8)LAL_C_SI)*LAL_C_SI)*LAL_C_SI)), -8./3.); // 9.5 Hertz Newtonian t3 = factTukey*25.*25.*25.*25.; // 25M separation Newtonian. For TaylorT2 we need a huge half-Hann window at the end for some reason. t4 = 0.; // apply Tukey window i = 0; t = tInit; while(t < t2) { sinfact = sin(LAL_PI_2*(t - t1)/(t2 - t1)); hPlus->data->data[i] *= sinfact*sinfact; hCross->data->data[i] *= sinfact*sinfact; i++; t = tInit + i*deltaT; } i = hPlus->data->length-1; t = tInit + i*deltaT; while(t > t3) { sinfact = sin(LAL_PI_2*(t - t4)/(t3 - t4)); hPlus->data->data[i] *= sinfact*sinfact; hCross->data->data[i] *= sinfact*sinfact; i--; t = tInit + i*deltaT; } // compute the DFTs, applying the necessary time shift ftilde_data = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*(hPlus->data->length)); plan = fftw_plan_dft_r2c_1d(hPlus->data->length, hPlus->data->data, ftilde_data, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); for(i = 0; i <= hPlus->data->length >> 1; i++) { hPlusTildeTD[i] = deltaT*cexp(-I*LAL_TWOPI*i*deltaF*tInit)*ftilde_data[i]; } plan = fftw_plan_dft_r2c_1d(hCross->data->length, hCross->data->data, ftilde_data, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); for(i = 0; i <= hCross->data->length >> 1; i++) { hCrossTildeTD[i] = deltaT*cexp(-I*LAL_TWOPI*i*deltaF*tInit)*ftilde_data[i]; } fftw_free(ftilde_data); // compute fMin and deltaF for the frequency domain WFs, close to desiredFMin and desiredDeltaF but a multiple of deltaF for the TD WF iStart = (INT4)ceil(desiredFMin/deltaF); nSkip = (INT4)ceil(desiredDeltaF/deltaF); iStart -= iStart % nSkip; fMin = iStart*deltaF; deltaF *= nSkip; if(startAtZero) { jStart = iStart/nSkip; } else { jStart = 0; } // set maximum frequency for the comparison rStop = 25.; // frequency of r = 20M fMax = LAL_C_SI*(LAL_C_SI*(LAL_C_SI/(LAL_PI*LAL_G_SI*M*rStop*sqrt(rStop)))); nMax = (INT4)floor((fMax - fMin)/deltaF) + jStart; // define frequency series for FD WFs hPlusTildeFD = 0; hCrossTildeFD = 0; // normalize TD WF normalizationTD = normalizeTD(hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax); printf("Matches:\n"); for(kMax = 0; kMax <= 10; kMax++) // loop over kMax { //compute FD WF XLALSimInspiralSpinTaylorT2Fourier(&hPlusTildeFD, &hCrossTildeFD, fMin, fMax, deltaF, kMax, phiRef, v0, m1, m2, fStart, fRef, r, s1x, s1y, s1z, s2x, s2y, s2z, lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, quadparam1, quadparam2, spinO, tideO, phaseO, amplitudeO, phiRefAtEnd); // XLALSimInspiralSpinTaylorT2 and XLALSimInspiralSpinTaylorT2Fourier return with a slight time offset between the two. We get rid of that. if(startAtZero) { meanDeltaT = meanTimeOffset(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax, 0., deltaF); for(i = 0; i < hPlusTildeFD->data->length; i++) { hPlusTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(i*deltaF)*meanDeltaT); hCrossTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(i*deltaF)*meanDeltaT); } } else { meanDeltaT = meanTimeOffset(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax, fMin, deltaF); for(i = 0; i < hPlusTildeFD->data->length; i++) { hPlusTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(fMin + i*deltaF)*meanDeltaT); hCrossTildeFD->data->data[i] *= cexp(I*LAL_TWOPI*(fMin + i*deltaF)*meanDeltaT); } } // compute match match = normalizationTD*computeMatch(hPlusTildeFD, hCrossTildeFD, hPlusTildeTD, hCrossTildeTD, Fplus, Fcross, iStart, jStart, nSkip, nMax); printf("kMax = %2d: %.15f\n", kMax, match); XLALDestroyCOMPLEX16FrequencySeries(hPlusTildeFD); XLALDestroyCOMPLEX16FrequencySeries(hCrossTildeFD); } XLALDestroyREAL8TimeSeries(hPlus); XLALDestroyREAL8TimeSeries(hCross); free(hPlusTildeTD); free(hCrossTildeTD); fftw_cleanup(); return XLAL_SUCCESS; }
/* * main */ int main (int argc , char **argv) { FILE *f; int status; int start_time; COMPLEX16FrequencySeries *hptilde = NULL, *hctilde = NULL; REAL8TimeSeries *hplus = NULL; REAL8TimeSeries *hcross = NULL; GSParams *params; /* set us up to fail hard */ XLALSetErrorHandler(XLALAbortErrorHandler); /* parse commandline */ params = parse_args(argc, argv); /* generate waveform */ start_time = time(NULL); switch (params->domain) { case LAL_SIM_DOMAIN_FREQUENCY: XLALSimInspiralChooseFDWaveform(&hptilde, &hctilde, params->phiRef, params->deltaF, params->m1, params->m2, params->s1x, params->s1y, params->s1z, params->s2x, params->s2y, params->s2z, params->f_min, params->f_max, params->fRef, params->distance, params->inclination, params->lambda1, params->lambda2, params->waveFlags, params->nonGRparams, params->ampO, params->phaseO, params->approximant); break; case LAL_SIM_DOMAIN_TIME: XLALSimInspiralChooseTDWaveform(&hplus, &hcross, params->phiRef, params->deltaT, params->m1, params->m2, params->s1x, params->s1y, params->s1z, params->s2x, params->s2y, params->s2z, params->f_min, params->fRef, params->distance, params->inclination, params->lambda1, params->lambda2, params->waveFlags, params->nonGRparams, params->ampO, params->phaseO, params->approximant); break; default: XLALPrintError("Error: domain must be either TD or FD\n"); } if (params->verbose) XLALPrintInfo("Generation took %.0f seconds\n", difftime(time(NULL), start_time)); if (((params->domain == LAL_SIM_DOMAIN_FREQUENCY) && (!hptilde || !hctilde)) || ((params->domain == LAL_SIM_DOMAIN_TIME) && (!hplus || !hcross))) { XLALPrintError("Error: waveform generation failed\n"); goto fail; } /* dump file */ if ( strlen(params->outname) > 0 ) { f = fopen(params->outname, "w"); if (f==NULL) { printf("**ERROR** Impossible to write file %s\n",params->outname); exit(1); } else { if (params->domain == LAL_SIM_DOMAIN_FREQUENCY) if (params->ampPhase == 1) status = dump_FD2(f, hptilde, hctilde); else status = dump_FD(f, hptilde, hctilde); else if (params->ampPhase == 1) status = dump_TD2(f, hplus, hcross); else status = dump_TD(f, hplus, hcross); fclose(f); } if (status) goto fail; } /* clean up */ XLALSimInspiralDestroyWaveformFlags(params->waveFlags); XLALSimInspiralDestroyTestGRParam(params->nonGRparams); XLALFree(params); XLALDestroyCOMPLEX16FrequencySeries(hptilde); XLALDestroyCOMPLEX16FrequencySeries(hctilde); return 0; fail: XLALSimInspiralDestroyWaveformFlags(params->waveFlags); XLALSimInspiralDestroyTestGRParam(params->nonGRparams); XLALFree(params); XLALDestroyCOMPLEX16FrequencySeries(hptilde); XLALDestroyCOMPLEX16FrequencySeries(hctilde); return 1; }
int main(void) { clock_t s1, e1, s2, e2; double diff1, diff2; unsigned int i; REAL8 plusdiff, crossdiff, temp; REAL8TimeSeries *hplus = NULL; REAL8TimeSeries *hcross = NULL; REAL8TimeSeries *hplusC = NULL; REAL8TimeSeries *hcrossC = NULL; COMPLEX16FrequencySeries *hptilde = NULL; COMPLEX16FrequencySeries *hctilde = NULL; COMPLEX16FrequencySeries *hptildeC = NULL; COMPLEX16FrequencySeries *hctildeC = NULL; REAL8 m1 = 10. * LAL_MSUN_SI, m2 = 10 * LAL_MSUN_SI; REAL8 s1x = 0., s1y = 0., s1z = 0., s2x = 0., s2y = 0., s2z = 0.; REAL8 f_min = 40., f_ref = 0., lambda1 = 0., lambda2 = 0.i, f_max = 0.; REAL8 dt = 1./16384., df = 1./16.; int ret, phaseO = 7, ampO = 0; Approximant approx = SEOBNRv1; Approximant approxFD = TaylorF2; REAL8 phiref1 = 0., phiref2 = 0.3; REAL8 inc1 = 0.2, inc2 = 1.3; REAL8 dist1 = 1.e6 * LAL_PC_SI, dist2 = 2.e6 * LAL_PC_SI; LALSimInspiralWaveformCache *cache = XLALCreateSimInspiralWaveformCache(); // // Test TD path with SEOBNRv1 // // Generate waveform via usual ChooseTDWaveform path s1 = clock(); ret = XLALSimInspiralChooseTDWaveform(&hplus, &hcross, phiref1, dt, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_ref, dist1, inc1, lambda1, lambda2, NULL, NULL, ampO, phaseO, approx); e1 = clock(); diff1 = (double) (e1 - s1) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Generate waveform via FromCache - will call ChooseWaveform this 1st time s2 = clock(); ret = XLALSimInspiralChooseTDWaveformFromCache(&hplusC, &hcrossC, phiref1, dt, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_ref, dist1, inc1, lambda1, lambda2, NULL, NULL, ampO, phaseO, approx, cache); e2 = clock(); diff2 = (double) (e2 - s2) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Find level of agreement plusdiff = crossdiff = 0.; for(i=0; i < hplus->data->length; i++) { temp = abs(hplus->data->data[i] - hplusC->data->data[i]); if(temp > plusdiff) plusdiff = temp; temp = abs(hcross->data->data[i] - hcrossC->data->data[i]); if(temp > crossdiff) crossdiff = temp; } printf("Comparing waveforms from ChooseTDWaveform and ChooseTDWaveformFromCache\n"); printf("when both must be generated from scratch...\n"); printf("ChooseTDWaveform took %f seconds\n", diff1); printf("ChooseTDWaveformFromCache took %f seconds\n", diff2); printf("Largest difference in plus polarization is: %.16g\n", plusdiff); printf("Largest difference in cross polarization is: %.16g\n\n", crossdiff); // Generate another waveform via ChooseTDWaveform path s1 = clock(); ret = XLALSimInspiralChooseTDWaveform(&hplus, &hcross, phiref2, dt, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_ref, dist2, inc2, lambda1, lambda2, NULL, NULL, ampO, phaseO, approx); e1 = clock(); diff1 = (double) (e1 - s1) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Generate waveform via FromCache - will transform previous waveform s2 = clock(); ret = XLALSimInspiralChooseTDWaveformFromCache(&hplusC, &hcrossC, phiref2, dt, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_ref, dist2, inc2, lambda1, lambda2, NULL, NULL, ampO, phaseO, approx, cache); e2 = clock(); diff2 = (double) (e2 - s2) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Find level of agreement plusdiff = crossdiff = 0.; for(i=0; i < hplus->data->length; i++) { temp = abs(hplus->data->data[i] - hplusC->data->data[i]); if(temp > plusdiff) plusdiff = temp; temp = abs(hcross->data->data[i] - hcrossC->data->data[i]); if(temp > crossdiff) crossdiff = temp; } printf("Comparing waveforms from ChooseTDWaveform and ChooseTDWaveformFromCache\n"); printf("when the latter is cached and transformed...\n"); printf("ChooseTDWaveform took %f seconds\n", diff1); printf("ChooseTDWaveformFromCache took %f seconds\n", diff2); printf("Largest difference in plus polarization is: %.16g\n", plusdiff); printf("Largest difference in cross polarization is: %.16g\n\n", crossdiff); XLALDestroyREAL8TimeSeries(hplus); XLALDestroyREAL8TimeSeries(hcross); XLALDestroyREAL8TimeSeries(hplusC); XLALDestroyREAL8TimeSeries(hcrossC); // // Test FD path with TaylorF2 // // Generate waveform via usual ChooseFDWaveform path s1 = clock(); ret = XLALSimInspiralChooseFDWaveform(&hptilde, &hctilde, phiref1, df, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_max, dist1, inc1, lambda1, lambda2, NULL, NULL, ampO, phaseO, approxFD); e1 = clock(); diff1 = (double) (e1 - s1) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Generate waveform via FromCache - will call ChooseWaveform this 1st time s2 = clock(); ret = XLALSimInspiralChooseFDWaveformFromCache(&hptildeC, &hctildeC, phiref1, df, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_max, dist1, inc1, lambda1, lambda2, NULL, NULL, ampO, phaseO, approxFD, cache); e2 = clock(); diff2 = (double) (e2 - s2) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Find level of agreement plusdiff = crossdiff = 0.; for(i=0; i < hptilde->data->length; i++) { temp = abs(hptilde->data->data[i] - hptildeC->data->data[i]); if(temp > plusdiff) plusdiff = temp; temp = abs(hctilde->data->data[i] - hctildeC->data->data[i]); if(temp > crossdiff) crossdiff = temp; } printf("Comparing waveforms from ChooseFDWaveform and ChooseFDWaveformFromCache\n"); printf("when both must be generated from scratch...\n"); printf("ChooseFDWaveform took %f seconds\n", diff1); printf("ChooseFDWaveformFromCache took %f seconds\n", diff2); printf("Largest difference in plus polarization is: %.16g\n", plusdiff); printf("Largest difference in cross polarization is: %.16g\n\n", crossdiff); XLALDestroyCOMPLEX16FrequencySeries(hptilde); XLALDestroyCOMPLEX16FrequencySeries(hctilde); XLALDestroyCOMPLEX16FrequencySeries(hptildeC); XLALDestroyCOMPLEX16FrequencySeries(hctildeC); hptilde = hctilde = hptildeC = hctildeC = NULL; // Generate another waveform via ChooseFDWaveform path s1 = clock(); ret = XLALSimInspiralChooseFDWaveform(&hptilde, &hctilde, phiref2, df, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_max, dist2, inc2, lambda1, lambda2, NULL, NULL, ampO, phaseO, approxFD); e1 = clock(); diff1 = (double) (e1 - s1) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Generate waveform via FromCache - will transform previous waveform s2 = clock(); ret = XLALSimInspiralChooseFDWaveformFromCache(&hptildeC, &hctildeC, phiref2, df, m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, f_min, f_max, dist2, inc2, lambda1, lambda2, NULL, NULL, ampO, phaseO, approxFD, cache); e2 = clock(); diff2 = (double) (e2 - s2) / CLOCKS_PER_SEC; if( ret == XLAL_FAILURE ) XLAL_ERROR(XLAL_EFUNC); // Find level of agreement plusdiff = crossdiff = 0.; for(i=0; i < hptilde->data->length; i++) { temp = abs(hptilde->data->data[i] - hptildeC->data->data[i]); if(temp > plusdiff) plusdiff = temp; temp = abs(hctilde->data->data[i] - hctildeC->data->data[i]); if(temp > crossdiff) crossdiff = temp; } printf("Comparing waveforms from ChooseFDWaveform and ChooseFDWaveformFromCache\n"); printf("when the latter is cached and transformed...\n"); printf("ChooseFDWaveform took %f seconds\n", diff1); printf("ChooseFDWaveformFromCache took %f seconds\n", diff2); printf("Largest difference in plus polarization is: %.16g\n", plusdiff); printf("Largest difference in cross polarization is: %.16g\n\n", crossdiff); XLALDestroySimInspiralWaveformCache(cache); XLALDestroyCOMPLEX16FrequencySeries(hptilde); XLALDestroyCOMPLEX16FrequencySeries(hctilde); XLALDestroyCOMPLEX16FrequencySeries(hptildeC); XLALDestroyCOMPLEX16FrequencySeries(hctildeC); LALCheckMemoryLeaks(); return 0; }
/** Store the output FD hptilde and hctilde in cache. */ static int StoreFDHCache(LALSimInspiralWaveformCache *cache, COMPLEX16FrequencySeries *hptilde, COMPLEX16FrequencySeries *hctilde, REAL8 phiRef, REAL8 deltaT, REAL8 m1, REAL8 m2, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, REAL8 f_min, REAL8 f_ref, REAL8 f_max, REAL8 r, REAL8 i, LALDict *LALpars, Approximant approximant, REAL8Sequence *frequencies ) { /* Clear any time-domain data. */ if (cache->hplus != NULL) { XLALDestroyREAL8TimeSeries(cache->hplus); cache->hplus = NULL; } if (cache->hcross != NULL) { XLALDestroyREAL8TimeSeries(cache->hcross); cache->hcross = NULL; } /* Store params in cache */ cache->phiRef = phiRef; cache->deltaTF = deltaT; cache->m1 = m1; cache->m2 = m2; cache->S1x = S1x; cache->S1y = S1y; cache->S1z = S1z; cache->S2x = S2x; cache->S2y = S2y; cache->S2z = S2z; cache->f_min = f_min; cache->f_ref = f_ref; cache->f_max = f_max; cache->r = r; cache->i = i; cache->LALpars = LALpars; cache->approximant = approximant; XLALDestroyREAL8Sequence(cache->frequencies); cache->frequencies = NULL; if (frequencies != NULL){ cache->frequencies = XLALCopyREAL8Sequence(frequencies); } // Copy over the waveforms // NB: XLALCut... creates a new Series object and copies data and metadata XLALDestroyCOMPLEX16FrequencySeries(cache->hptilde); XLALDestroyCOMPLEX16FrequencySeries(cache->hctilde); cache->hptilde = XLALCutCOMPLEX16FrequencySeries(hptilde, 0, hptilde->data->length); if (cache->hptilde == NULL) return XLAL_ENOMEM; cache->hctilde = XLALCutCOMPLEX16FrequencySeries(hctilde, 0, hctilde->data->length); if (cache->hctilde == NULL) { XLALDestroyCOMPLEX16FrequencySeries(cache->hptilde); cache->hptilde = NULL; return XLAL_ENOMEM; } return XLAL_SUCCESS; }
/** Store the output TD hplus and hcross in the cache. */ static int StoreTDHCache(LALSimInspiralWaveformCache *cache, REAL8TimeSeries *hplus, REAL8TimeSeries *hcross, REAL8 phiRef, REAL8 deltaT, REAL8 m1, REAL8 m2, REAL8 S1x, REAL8 S1y, REAL8 S1z, REAL8 S2x, REAL8 S2y, REAL8 S2z, REAL8 f_min, REAL8 f_ref, REAL8 r, REAL8 i, LALDict *LALpars, Approximant approximant ) { /* Clear any frequency-domain data. */ if (cache->hptilde != NULL) { XLALDestroyCOMPLEX16FrequencySeries(cache->hptilde); cache->hptilde = NULL; } if (cache->hctilde != NULL) { XLALDestroyCOMPLEX16FrequencySeries(cache->hctilde); cache->hctilde = NULL; } /* Store params in cache */ cache->phiRef = phiRef; cache->deltaTF = deltaT; cache->m1 = m1; cache->m2 = m2; cache->S1x = S1x; cache->S1y = S1y; cache->S1z = S1z; cache->S2x = S2x; cache->S2y = S2y; cache->S2z = S2z; cache->f_min = f_min; cache->f_ref = f_ref; cache->r = r; cache->i = i; cache->LALpars = LALpars; cache->approximant = approximant; cache->frequencies = NULL; // Copy over the waveforms // NB: XLALCut... creates a new Series object and copies data and metadata XLALDestroyREAL8TimeSeries(cache->hplus); XLALDestroyREAL8TimeSeries(cache->hcross); if (hplus == NULL || hcross == NULL || hplus->data == NULL || hcross->data == NULL){ XLALPrintError("We have null pointers for h+, hx in StoreTDHCache \n"); XLALPrintError("Houston-S, we've got a problem SOS, SOS, SOS, the waveform generator returns NULL!!!... m1 = %.18e, m2 = %.18e, fMin = %.18e, spin1 = {%.18e, %.18e, %.18e}, spin2 = {%.18e, %.18e, %.18e} \n", m1, m2, (double)f_min, S1x, S1y, S1z, S2x, S2y, S2z); return XLAL_ENOMEM; } cache->hplus = XLALCutREAL8TimeSeries(hplus, 0, hplus->data->length); if (cache->hplus == NULL) return XLAL_ENOMEM; cache->hcross = XLALCutREAL8TimeSeries(hcross, 0, hcross->data->length); if (cache->hcross == NULL) { XLALDestroyREAL8TimeSeries(cache->hplus); cache->hplus = NULL; return XLAL_ENOMEM; } return XLAL_SUCCESS; }
/** * Chooses between different approximants when requesting a waveform to be generated * Returns the waveform in the frequency domain. * The parameters passed must be in SI units. * * This version allows caching of waveforms. The most recently generated * waveform and its parameters are stored. If the next call requests a waveform * that can be obtained by a simple transformation, then it is done. * This bypasses the waveform generation and speeds up the code. */ int XLALSimInspiralChooseFDWaveformFromCache( COMPLEX16FrequencySeries **hptilde, /**< +-polarization waveform */ COMPLEX16FrequencySeries **hctilde, /**< x-polarization waveform */ REAL8 phiRef, /**< reference orbital phase (rad) */ REAL8 deltaF, /**< sampling interval (Hz) */ REAL8 m1, /**< mass of companion 1 (kg) */ REAL8 m2, /**< mass of companion 2 (kg) */ REAL8 S1x, /**< x-component of the dimensionless spin of object 1 */ REAL8 S1y, /**< y-component of the dimensionless spin of object 1 */ REAL8 S1z, /**< z-component of the dimensionless spin of object 1 */ REAL8 S2x, /**< x-component of the dimensionless spin of object 2 */ REAL8 S2y, /**< y-component of the dimensionless spin of object 2 */ REAL8 S2z, /**< z-component of the dimensionless spin of object 2 */ REAL8 f_min, /**< starting GW frequency (Hz) */ REAL8 f_max, /**< ending GW frequency (Hz) */ REAL8 f_ref, /**< Reference GW frequency (Hz) */ REAL8 r, /**< distance of source (m) */ REAL8 i, /**< inclination of source (rad) */ LALDict *LALpars, /**< LALDictionary containing non-mandatory variables/flags */ Approximant approximant, /**< post-Newtonian approximant to use for waveform production */ LALSimInspiralWaveformCache *cache, /**< waveform cache structure */ REAL8Sequence *frequencies /**< sequence of frequencies for which the waveform will be computed. Pass in NULL (or None in python) for standard f_min to f_max sequence. */ ) { int status; size_t j; REAL8 dist_ratio, incl_ratio_plus, incl_ratio_cross, phase_diff; COMPLEX16 exp_dphi; CacheVariableDiffersBitmask changedParams; // If nonGRparams are not NULL, don't even try to cache. if ( !XLALSimInspiralWaveformParamsNonGRAreDefault(LALpars) || (!cache) ) { if (frequencies != NULL) return XLALSimInspiralChooseFDWaveformSequence(hptilde, hctilde, phiRef, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_ref, r, i, LALpars, approximant,frequencies); else return XLALSimInspiralChooseFDWaveform(hptilde, hctilde, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, r, i, phiRef, 0., 0., 0., deltaF, f_min, f_max, f_ref, LALpars, approximant); } // Check which parameters have changed changedParams = CacheArgsDifferenceBitmask(cache, phiRef, deltaF, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_min, f_ref, f_max, r, i, LALpars, approximant, frequencies); // No parameters have changed! Copy the cached polarizations if( changedParams == NO_DIFFERENCE ) { *hptilde = XLALCutCOMPLEX16FrequencySeries(cache->hptilde, 0, cache->hptilde->data->length); if (*hptilde == NULL) return XLAL_ENOMEM; *hctilde = XLALCutCOMPLEX16FrequencySeries(cache->hctilde, 0, cache->hctilde->data->length); if (*hctilde == NULL) { XLALDestroyCOMPLEX16FrequencySeries(*hptilde); *hptilde = NULL; return XLAL_ENOMEM; } return XLAL_SUCCESS; } // Intrinsic parameters have changed. We must generate a new waveform if( (changedParams & INTRINSIC) != 0 ) { if ( frequencies != NULL ){ status = XLALSimInspiralChooseFDWaveformSequence(hptilde, hctilde, phiRef, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_ref, r, i, LALpars, approximant, frequencies); } else { status = XLALSimInspiralChooseFDWaveform(hptilde, hctilde, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, r, i, phiRef, 0., 0., 0., deltaF, f_min, f_max, f_ref, LALpars, approximant); } if (status == XLAL_FAILURE) return status; return StoreFDHCache(cache, *hptilde, *hctilde, phiRef, deltaF, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_min, f_ref, f_max, r, i, LALpars, approximant, frequencies); } // case 1: Non-precessing, 2nd harmonic only if( approximant == TaylorF2 || approximant == TaylorF2RedSpin || approximant == TaylorF2RedSpinTidal || approximant == IMRPhenomA || approximant == IMRPhenomB || approximant == IMRPhenomC ) { // If polarizations are not cached we must generate a fresh waveform // FIXME: Will need to check hlms and/or dynamical variables as well if( cache->hptilde == NULL || cache->hctilde == NULL) { if ( frequencies != NULL ){ status = XLALSimInspiralChooseFDWaveformSequence(hptilde, hctilde, phiRef, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_ref, r, i, LALpars, approximant,frequencies); } else { status = XLALSimInspiralChooseFDWaveform(hptilde, hctilde, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, r, i, phiRef, 0., 0., 0., deltaF, f_min, f_max, f_ref, LALpars, approximant); } if (status == XLAL_FAILURE) return status; return StoreFDHCache(cache, *hptilde, *hctilde, phiRef, deltaF, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_min, f_ref, f_max, r, i, LALpars, approximant, frequencies); } // Set transformation coefficients for identity transformation. // We'll adjust them depending on which extrinsic parameters changed. dist_ratio = incl_ratio_plus = incl_ratio_cross = 1.; phase_diff = 0.; exp_dphi = 1.; if( changedParams & PHI_REF ) { // Only 2nd harmonic present, so {h+,hx} \propto e^(2 i phiRef) phase_diff = 2.*(phiRef - cache->phiRef); exp_dphi = cpolar(1., phase_diff); } if( changedParams & INCLINATION) { // Rescale h+, hx by ratio of new/old inclination dependence incl_ratio_plus = (1.0 + cos(i)*cos(i)) / (1.0 + cos(cache->i)*cos(cache->i)); incl_ratio_cross = cos(i) / cos(cache->i); } if( changedParams & DISTANCE ) { // Rescale h+, hx by ratio of (1/new_dist)/(1/old_dist) = old/new dist_ratio = cache->r / r; } // Create the output polarizations *hptilde = XLALCreateCOMPLEX16FrequencySeries(cache->hptilde->name, &(cache->hptilde->epoch), cache->hptilde->f0, cache->hptilde->deltaF, &(cache->hptilde->sampleUnits), cache->hptilde->data->length); if (*hptilde == NULL) return XLAL_ENOMEM; *hctilde = XLALCreateCOMPLEX16FrequencySeries(cache->hctilde->name, &(cache->hctilde->epoch), cache->hctilde->f0, cache->hctilde->deltaF, &(cache->hctilde->sampleUnits), cache->hctilde->data->length); if (*hctilde == NULL) { XLALDestroyCOMPLEX16FrequencySeries(*hptilde); *hptilde = NULL; return XLAL_ENOMEM; } // Get new polarizations by transforming the old incl_ratio_plus *= dist_ratio; incl_ratio_cross *= dist_ratio; for (j = 0; j < cache->hptilde->data->length; j++) { (*hptilde)->data->data[j] = exp_dphi * incl_ratio_plus * cache->hptilde->data->data[j]; (*hctilde)->data->data[j] = exp_dphi * incl_ratio_cross * cache->hctilde->data->data[j]; } return XLAL_SUCCESS; } // case 2: Precessing /*else if( approximant == SpinTaylorF2 ) { }*/ // Catch-all. Unsure what to do, don't try to cache. // Basically, you requested a waveform type which is not setup for caching // b/c of lack of interest or it's unclear what/how to cache for that model else { if ( frequencies != NULL ){ return XLALSimInspiralChooseFDWaveformSequence(hptilde, hctilde, phiRef, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, f_ref, r, i, LALpars, approximant,frequencies); } else { return XLALSimInspiralChooseFDWaveform(hptilde, hctilde, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, r, i, phiRef, 0., 0., 0., deltaF, f_min, f_max, f_ref, NULL, approximant); } } }
/* * Core function for computing the ROM waveform. * Evaluates projection coefficients and shifts in time and phase at desired q. * Construct 1D splines for amplitude and phase. * Compute strain waveform from amplitude and phase. */ static INT4 EOBNRv2HMROMCore( COMPLEX16FrequencySeries **hptilde, COMPLEX16FrequencySeries **hctilde, REAL8 phiRef, REAL8 deltaF, REAL8 fLow, REAL8 fHigh, REAL8 fRef, REAL8 distance, REAL8 inclination, REAL8 Mtot_sec, REAL8 q) { INT4 ret = XLAL_SUCCESS; INT4 i; INT4 j; double tpeak22estimate = 0.; /* 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\n",(*hptilde),(*hctilde)); XLAL_ERROR(XLAL_EFAULT); } /* Check if the data has been set up */ if(__lalsim_EOBNRv2HMROM_setup) { XLALPrintError("Error: the ROM data has not been set up\n"); XLAL_ERROR(XLAL_EFAULT); } /* Set the global pointers to data */ ListmodesEOBNRHMROMdata* listdata = *__lalsim_EOBNRv2HMROM_data; ListmodesEOBNRHMROMdata_interp* listdata_interp = *__lalsim_EOBNRv2HMROM_interp; /* Global amplitude prefactor - includes total mass scaling, Fourier scaling, distance scaling, and undoing an additional arbitrary scaling */ REAL8 Mtot_msol = Mtot_sec / LAL_MTSUN_SI; /* Mtot_msol and M_ROM in units of solar mass */ REAL8 amp0 = (Mtot_msol/M_ROM) * Mtot_sec * 1.E-16 * 1.E6 * LAL_PC_SI / distance; /* Highest allowed geometric frequency for the first mode of listmode in the ROM - used for fRef * by convention, we use the first mode of listmode (presumably the 22) for phiref */ ListmodesEOBNRHMROMdata* listdata_ref = ListmodesEOBNRHMROMdata_GetMode(listdata, listmode[0][0], listmode[0][1]); EOBNRHMROMdata* data_ref = listdata_ref->data; REAL8 Mf_ROM_max_ref = gsl_vector_get(data_ref->freq, nbfreq-1); /* Convert to geometric units for frequency */ REAL8 fLow_geom = fLow * Mtot_sec; REAL8 fHigh_geom = fHigh * Mtot_sec; REAL8 fRef_geom = fRef * Mtot_sec; REAL8 deltaF_geom = deltaF * Mtot_sec; /* Enforce allowed geometric frequency range */ if (fLow_geom < Mf_ROM_min) { /* Enforce minimal frequency */ XLALPrintWarning("Starting frequency Mflow=%g is smaller than lowest frequency in ROM Mf=%g. Starting at lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min); fLow_geom = Mf_ROM_min; } /* Default highest frequency */ if (fHigh == 0) fHigh_geom = Mf_ROM_max; /* In case the user asks for a frequency higher than covered by the ROM, we keep it that way as we will just 0-pad the waveform (and do it anyway for some modes) */ if (fRef_geom > Mf_ROM_max_ref || fRef_geom == 0) fRef_geom = Mf_ROM_max_ref; /* If fRef > fhigh or 0 we reset fRef to default value of cutoff frequency for the first mode of the list (presumably the 22 mode) */ if (0 < fRef_geom && fRef_geom < Mf_ROM_min) { XLALPrintWarning("Reference frequency Mf_ref=%g is smaller than lowest frequency in ROM Mf=%g. Setting it to the lowest frequency in ROM.\n", fLow_geom, Mf_ROM_min); fRef_geom = Mf_ROM_min; } /* Set up output array with size closest power of 2 - fHigh is the upper frequency specified by the user */ size_t nbpt = NextPow2(fHigh_geom / deltaF_geom) + 1; /* Internal storage for the projection coefficients and shifts in time and phase */ /* Initialized only once, and reused for the different modes */ EOBNRHMROMdata_coeff *data_coeff = NULL; EOBNRHMROMdata_coeff_Init(&data_coeff); /* Create spherical harmonic frequency series that will contain the hlm's */ SphHarmFrequencySeries** hlmsphharmfreqseries = XLALMalloc(sizeof(SphHarmFrequencySeries)); *hlmsphharmfreqseries = NULL; /* GPS time definition - common to all modes */ LIGOTimeGPS tC; XLALGPSAdd(&tC, -1. / deltaF); /* coalesce at t=0 */ /* The phase change imposed by phiref, from the phase of the first mode in the list - to be set in the first step of the loop on the modes */ REAL8 phase_change_ref = 0; /* Main loop over the modes */ for( i=0; i<nbmode; i++ ){ UINT4 l = listmode[i][0]; INT4 m = listmode[i][1]; /* Getting the relevant modes in the lists of data */ ListmodesEOBNRHMROMdata* listdata_mode = ListmodesEOBNRHMROMdata_GetMode(listdata, l, m); ListmodesEOBNRHMROMdata_interp* listdata_interp_mode = ListmodesEOBNRHMROMdata_interp_GetMode(listdata_interp, l, m); /* Evaluating the projection coefficients and shift in time and phase */ ret |= Evaluate_Spline_Data(q, listdata_interp_mode->data_interp, data_coeff); /* Evaluating the unnormalized amplitude and unshifted phase vectors for the mode */ /* Notice a change in convention: B matrices are transposed with respect to the B matrices in SEOBNRROM */ /* amp_pts = Bamp . Camp_coeff */ /* phi_pts = Bphi . Cphi_coeff */ gsl_vector* amp_f = gsl_vector_alloc(nbfreq); gsl_vector* phi_f = gsl_vector_alloc(nbfreq); gsl_blas_dgemv(CblasNoTrans, 1.0, listdata_mode->data->Bamp, data_coeff->Camp_coeff, 0.0, amp_f); gsl_blas_dgemv(CblasNoTrans, 1.0, listdata_mode->data->Bphi, data_coeff->Cphi_coeff, 0.0, phi_f); /* The downsampled frequencies for the mode - we undo the rescaling of the frequency for the 44 and 55 modes */ gsl_vector* freq_ds = gsl_vector_alloc(nbfreq); gsl_vector_memcpy(freq_ds, listdata_mode->data->freq); if ( l==4 && m==4) gsl_vector_scale( freq_ds, 1./Scaling44(q)); if ( l==5 && m==5) gsl_vector_scale( freq_ds, 1./Scaling55(q)); /* Evaluating the shifts in time and phase - conditional scaling for the 44 and 55 modes */ /* Note: the stored values of 'shifttime' correspond actually to 2pi*Deltat */ SplineList* shifttime_splinelist = listdata_interp_mode->data_interp->shifttime_interp; SplineList* shiftphase_splinelist = listdata_interp_mode->data_interp->shiftphase_interp; REAL8 twopishifttime; if( l==4 && m==4) { twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel) * Scaling44(q); } else if( l==5 && m==5) { twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel) * Scaling55(q); } else { twopishifttime = gsl_spline_eval(shifttime_splinelist->spline, q, shifttime_splinelist->accel); } REAL8 shiftphase = gsl_spline_eval(shiftphase_splinelist->spline, q, shiftphase_splinelist->accel); /* If first mode in the list, assumed to be the 22 mode, set totalshifttime and phase_change_ref */ if( i==0 ) { if(l==2 && m==2) { /* Setup 1d cubic spline for the phase of the 22 mode */ gsl_interp_accel* accel_phi22 = gsl_interp_accel_alloc(); gsl_spline* spline_phi22 = gsl_spline_alloc(gsl_interp_cspline, nbfreq); gsl_spline_init(spline_phi22, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(phi_f,0), nbfreq); /* Compute the shift in time needed to set the peak of the 22 mode roughly at t=0 */ /* We use the SPA formula tf = -(1/2pi)*dPsi/df to estimate the correspondence between frequency and time */ /* The frequency corresponding to the 22 peak is omega22peak/2pi, with omega22peak taken from the fit to NR in Pan&al 1106 EOBNRv2HM paper */ double f22peak = fmin(omega22peakOfq(q)/(2*LAL_PI), Mf_ROM_max_ref); /* We ensure we evaluate the spline within its range */ tpeak22estimate = -1./(2*LAL_PI) * gsl_spline_eval_deriv(spline_phi22, f22peak, accel_phi22); /* Determine the change in phase (to be propagated to all modes) required to have phi22(fRef) = 2*phiRef */ phase_change_ref = 2*phiRef + (gsl_spline_eval(spline_phi22, fRef_geom, accel_phi22) - (twopishifttime - 2*LAL_PI*tpeak22estimate) * fRef_geom - shiftphase); gsl_spline_free(spline_phi22); gsl_interp_accel_free(accel_phi22); } else { XLALPrintError("Error: the first mode in listmode must be the 22 mode to set the changes in phase and time \n"); XLAL_ERROR(XLAL_EFAILED); } } /* Total shift in time, and total change in phase for this mode */ double totaltwopishifttime = twopishifttime - 2*LAL_PI*tpeak22estimate; double constphaseshift = (double) m/listmode[0][1] * phase_change_ref + shiftphase; /* Initialize the complex series for the mode - notice that metadata used here is useless, only the one for the final output will matter */ COMPLEX16FrequencySeries* mode = XLALCreateCOMPLEX16FrequencySeries("mode hlm", &tC, 0.0, deltaF, &lalStrainUnit, nbpt); memset(mode->data->data, 0, nbpt * sizeof(COMPLEX16)); /* Setup 1d cubic spline for the phase and amplitude of the mode */ gsl_interp_accel* accel_phi = gsl_interp_accel_alloc(); gsl_interp_accel* accel_amp = gsl_interp_accel_alloc(); gsl_spline* spline_phi = gsl_spline_alloc(gsl_interp_cspline, nbfreq); gsl_spline* spline_amp = gsl_spline_alloc(gsl_interp_cspline, nbfreq); gsl_spline_init(spline_phi, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(phi_f,0), nbfreq); gsl_spline_init(spline_amp, gsl_vector_const_ptr(freq_ds,0), gsl_vector_const_ptr(amp_f,0), nbfreq); /* Interval in frequency covered by the ROM */ REAL8 fLow_geom_mode = gsl_vector_get(freq_ds, 0); REAL8 fHigh_geom_mode = fmin(gsl_vector_get(freq_ds, nbfreq-1), fHigh_geom); /* Initialize the loop - values outside this range in j are 0 by default */ INT4 jStart = (UINT4) ceil(fLow_geom_mode / deltaF_geom); INT4 jStop = (UINT4) ceil(fHigh_geom_mode / deltaF_geom); COMPLEX16 *modedata = mode->data->data; /* Mode-dependent complete amplitude prefactor */ REAL8 amp_pre = amp0 * ModeAmpFactor( l, m, q); /* Loop on the frequency samples chosen to evaluate the waveform */ /* We set apart the first and last step to avoid falling outside of the range of the splines by numerical errors */ REAL8 f, A, phase; f = fmax(fLow_geom_mode, jStart*deltaF_geom); A = gsl_spline_eval(spline_amp, f, accel_amp); phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */ modedata[jStart] = amp_pre * A * cexp(I*phase); for (j=jStart+1; j<jStop-1; j++) { f = j*deltaF_geom; A = gsl_spline_eval(spline_amp, f, accel_amp); phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */ modedata[j] = amp_pre * A * cexp(I*phase); } f = fmin(fHigh_geom_mode, (jStop-1)*deltaF_geom); A = gsl_spline_eval(spline_amp, f, accel_amp); phase = -gsl_spline_eval(spline_phi, f, accel_phi) + totaltwopishifttime * f + constphaseshift; /* Minus sign put here, in the internals of the ROM model \Psi = -phase */ modedata[jStop-1] = amp_pre * A * cexp(I*phase); /* Add the computed mode to the SphHarmFrequencySeries structure */ *hlmsphharmfreqseries = XLALSphHarmFrequencySeriesAddMode(*hlmsphharmfreqseries, mode, l, m); /* Cleanup for the mode */ gsl_spline_free(spline_amp); gsl_spline_free(spline_phi); gsl_interp_accel_free(accel_amp); gsl_interp_accel_free(accel_phi); gsl_vector_free(amp_f); gsl_vector_free(phi_f); gsl_vector_free(freq_ds); XLALDestroyCOMPLEX16FrequencySeries(mode); } /* Cleanup of the coefficients data structure */ EOBNRHMROMdata_coeff_Cleanup(data_coeff); /* Combining the modes for a hplus, hcross output */ /* Initialize the complex series hplus, hcross */ *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, nbpt); *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform", &tC, 0.0, deltaF, &lalStrainUnit, nbpt); if (!(hptilde) || !(*hctilde)) XLAL_ERROR(XLAL_EFUNC); memset((*hptilde)->data->data, 0, nbpt * sizeof(COMPLEX16)); memset((*hctilde)->data->data, 0, nbpt * sizeof(COMPLEX16)); XLALUnitDivide(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit); XLALUnitDivide(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit); /* Adding the modes to form hplus, hcross * - use of a function that copies XLALSimAddMode but for Fourier domain structures */ INT4 sym; /* sym will decide whether to add the -m mode (when equatorial symmetry is present) */ for( i=0; i<nbmode; i++){ INT4 l = listmode[i][0]; INT4 m = listmode[i][1]; COMPLEX16FrequencySeries* mode = XLALSphHarmFrequencySeriesGetMode(*hlmsphharmfreqseries, l, m); if ( m==0 ) sym = 0; /* We test for hypothetical m=0 modes */ else sym = 1; FDAddMode( *hptilde, *hctilde, mode, inclination, 0., l, m, sym); /* The phase \Phi is set to 0 - assumes phiRef is defined as half the phase of the 22 mode h22 (or the first mode in the list), not for h = hplus-I hcross */ } /* Destroying the list of frequency series for the modes, including the COMPLEX16FrequencySeries that it contains */ XLALDestroySphHarmFrequencySeries(*hlmsphharmfreqseries); XLALFree(hlmsphharmfreqseries); /* Additional complex conjugation of hptilde, hctilde - due to the difference in convention for the Fourier transform between LAL and the ROM internals */ COMPLEX16* datap = (*hptilde)->data->data; COMPLEX16* datac = (*hctilde)->data->data; for ( j = 0; j < (INT4) (*hptilde)->data->length; ++j ) { datap[j] = conj(datap[j]); } for ( j = 0; j < (INT4) (*hctilde)->data->length; ++j ) { datac[j] = conj(datac[j]); } return(XLAL_SUCCESS); }