void XLALDestroySBankWorkspaceCache(WS *workspace_cache) { size_t k = MAX_NUM_WS; for (;k--;) { if (workspace_cache[k].n) { XLALDestroyCOMPLEX8FFTPlan(workspace_cache[k].plan); XLALDestroyCOMPLEX8Vector(workspace_cache[k].zf); XLALDestroyCOMPLEX8Vector(workspace_cache[k].zt); } } free(workspace_cache); }
/** * Turn the given multi-IFO SFTvectors into one long Fourier transform (LFT) over the total observation time */ SFTtype * XLALSFTVectorToLFT ( SFTVector *sfts, /**< input SFT vector (gets modified!) */ REAL8 upsampling /**< upsampling factor >= 1 */ ) { XLAL_CHECK_NULL ( (sfts != NULL) && (sfts->length > 0), XLAL_EINVAL ); XLAL_CHECK_NULL ( upsampling >= 1, XLAL_EDOM, "Upsampling factor (%f) must be >= 1 \n", upsampling ); // ----- some useful SFT infos SFTtype *firstSFT = &(sfts->data[0]); UINT4 numBinsSFT = firstSFT->data->length; REAL8 dfSFT = firstSFT->deltaF; REAL8 Tsft = 1.0 / dfSFT; REAL8 f0SFT = firstSFT->f0; // ----- turn input SFTs into a complex (heterodyned) timeseries COMPLEX8TimeSeries *lTS; XLAL_CHECK_NULL ( (lTS = XLALSFTVectorToCOMPLEX8TimeSeries ( sfts )) != NULL, XLAL_EFUNC ); REAL8 dt = lTS->deltaT; UINT4 numSamples0 = lTS->data->length; REAL8 Tspan0 = numSamples0 * dt; // ---------- determine time-span of upsampled time-series /* NOTE: Tspan MUST be an integer multiple of Tsft, * in order for the frequency bins of the final FFT * to be commensurate with the SFT bins. * This is required so that fHet is an exact * frequency-bin in both cases */ UINT4 numSFTsFit = lround ( (Tspan0 * upsampling) / Tsft ); REAL8 Tspan = numSFTsFit * Tsft; UINT4 numSamples = lround ( Tspan / dt ); // ----- enlarge TimeSeries container for zero-padding if neccessary if ( numSamples > numSamples0 ) { XLAL_CHECK_NULL ( (lTS->data->data = XLALRealloc ( lTS->data->data, numSamples * sizeof(lTS->data->data[0]) )) != NULL, XLAL_ENOMEM ); lTS->data->length = numSamples; memset ( lTS->data->data + numSamples0, 0, (numSamples - numSamples0) * sizeof(lTS->data->data[0])); /* set all new time-samples to zero */ } /* translate this back into fmin for the LFT (counting down from DC==fHet) */ /* fHet = DC of our internal DFTs */ UINT4 NnegSFT = NhalfNeg ( numBinsSFT ); REAL8 fHet = f0SFT + 1.0 * NnegSFT * dfSFT; UINT4 NnegLFT = NhalfNeg ( numSamples ); REAL8 f0LFT = fHet - NnegLFT / Tspan; // ----- prepare output LFT ---------- SFTtype *outputLFT; XLAL_CHECK_NULL ( (outputLFT = XLALCreateSFT ( numSamples )) != NULL, XLAL_EFUNC ); // prepare LFT header strcpy ( outputLFT->name, firstSFT->name ); strncat ( outputLFT->name, ":long Fourier transform", sizeof(outputLFT->name) - 1 - strlen(outputLFT->name)); outputLFT->epoch = firstSFT->epoch; outputLFT->f0 = f0LFT; outputLFT->deltaF = 1.0 / Tspan; outputLFT->sampleUnits = firstSFT->sampleUnits; // ---------- FFT the long timeseries ---------- COMPLEX8FFTPlan *LFTplan; XLAL_CHECK_NULL ( (LFTplan = XLALCreateForwardCOMPLEX8FFTPlan( numSamples, 0 )) != NULL, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALCOMPLEX8VectorFFT( outputLFT->data, lTS->data, LFTplan ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALReorderFFTWtoSFT (outputLFT->data) == XLAL_SUCCESS, XLAL_EFUNC ); // apply proper normalization 'dt' for ( UINT4 k = 0; k < outputLFT->data->length; k ++ ) { outputLFT->data->data[k] *= dt; } /* cleanup memory */ XLALDestroyCOMPLEX8TimeSeries ( lTS ); XLALDestroyCOMPLEX8FFTPlan ( LFTplan ); return outputLFT; } // XLALSFTVectorToLFT()
/** * Turn the given SFTvector into one long time-series, properly dealing with gaps. */ COMPLEX8TimeSeries * XLALSFTVectorToCOMPLEX8TimeSeries ( const SFTVector *sftsIn /**< [in] SFT vector */ ) { // check input sanity XLAL_CHECK_NULL ( (sftsIn !=NULL) && (sftsIn->length > 0), XLAL_EINVAL ); // create a local copy of the input SFTs, as they will be locally modified! SFTVector *sfts; XLAL_CHECK_NULL ( (sfts = XLALDuplicateSFTVector ( sftsIn )) != NULL, XLAL_EFUNC ); /* define some useful shorthands */ UINT4 numSFTs = sfts->length; SFTtype *firstSFT = &(sfts->data[0]); SFTtype *lastSFT = &(sfts->data[numSFTs-1]); UINT4 numFreqBinsSFT = firstSFT->data->length; REAL8 dfSFT = firstSFT->deltaF; REAL8 Tsft = 1.0 / dfSFT; REAL8 deltaT = Tsft / numFreqBinsSFT; // complex FFT: numSamplesSFT = numFreqBinsSFT REAL8 f0SFT = firstSFT->f0; /* if the start and end input pointers are NOT NULL then determine start and time-span of the final long time-series */ LIGOTimeGPS start = firstSFT->epoch; LIGOTimeGPS end = lastSFT->epoch; XLALGPSAdd ( &end, Tsft ); /* determine output time span */ REAL8 Tspan; XLAL_CHECK_NULL ( (Tspan = XLALGPSDiff ( &end, &start ) ) > 0, XLAL_EINVAL ); UINT4 numSamples = lround ( Tspan / deltaT ); /* determine the heterodyning frequency */ /* fHet = DC of our internal DFTs */ UINT4 NnegSFT = NhalfNeg ( numFreqBinsSFT ); REAL8 fHet = f0SFT + 1.0 * NnegSFT * dfSFT; /* ----- Prepare invFFT of SFTs: compute plan for FFTW */ COMPLEX8FFTPlan *SFTplan; XLAL_CHECK_NULL ( (SFTplan = XLALCreateReverseCOMPLEX8FFTPlan( numFreqBinsSFT, 0 )) != NULL, XLAL_EFUNC ); /* ----- Prepare short time-series holding ONE invFFT of a single SFT */ LIGOTimeGPS XLAL_INIT_DECL(epoch); COMPLEX8TimeSeries *sTS; XLAL_CHECK_NULL ( (sTS = XLALCreateCOMPLEX8TimeSeries ( "short timeseries", &epoch, 0, deltaT, &emptyLALUnit, numFreqBinsSFT )) != NULL, XLAL_EFUNC ); /* ----- prepare long TimeSeries container ---------- */ COMPLEX8TimeSeries *lTS; XLAL_CHECK_NULL ( (lTS = XLALCreateCOMPLEX8TimeSeries ( firstSFT->name, &start, fHet, deltaT, &emptyLALUnit, numSamples )) != NULL, XLAL_EFUNC ); memset ( lTS->data->data, 0, numSamples * sizeof(*lTS->data->data)); /* set all time-samples to zero (in case there are gaps) */ /* ---------- loop over all SFTs and inverse-FFT them ---------- */ for ( UINT4 n = 0; n < numSFTs; n ++ ) { SFTtype *thisSFT = &(sfts->data[n]); /* find bin in long timeseries corresponding to starttime of *this* SFT */ REAL8 offset_n = XLALGPSDiff ( &(thisSFT->epoch), &start ); UINT4 bin0_n = lround ( offset_n / deltaT ); /* round to closest bin */ REAL8 nudge_n = bin0_n * deltaT - offset_n; /* rounding error */ nudge_n = 1e-9 * round ( nudge_n * 1e9 ); /* round to closest nanosecond */ /* nudge SFT into integer timestep bin if necessary */ XLAL_CHECK_NULL ( XLALTimeShiftSFT ( thisSFT, nudge_n ) == XLAL_SUCCESS, XLAL_EFUNC ); /* determine heterodyning phase-correction for this SFT */ REAL8 offset = XLALGPSDiff ( &thisSFT->epoch, &start ); // updated value after time-shift // fHet * Tsft is an integer by construction, because fHet was chosen as a frequency-bin of the input SFTs // therefore we only need the remainder (offset % Tsft) REAL8 offsetEff = fmod ( offset, Tsft ); REAL8 hetCycles = fmod ( fHet * offsetEff, 1); // heterodyning phase-correction for this SFT if ( nudge_n != 0 ){ XLALPrintInfo("n = %d, offset_n = %g, nudge_n = %g, offset = %g, offsetEff = %g, hetCycles = %g\n", n, offset_n, nudge_n, offset, offsetEff, hetCycles ); } REAL4 hetCorrection_re, hetCorrection_im; XLAL_CHECK_NULL ( XLALSinCos2PiLUT ( &hetCorrection_im, &hetCorrection_re, -hetCycles ) == XLAL_SUCCESS, XLAL_EFUNC ); COMPLEX8 hetCorrection = crectf( hetCorrection_re, hetCorrection_im ); /* Note: we also bundle the overall normalization of 'df' into the het-correction. * This ensures that the resulting timeseries will have the correct normalization, according to * x_l = invFT[sft]_l = df * sum_{k=0}^{N-1} xt_k * e^(i 2pi k l / N ) * where x_l is the l-th timestamp, and xt_k is the k-th frequency bin of the SFT. * See the LAL-conventions on FFTs: http://www.ligo.caltech.edu/docs/T/T010095-00.pdf * (the FFTw convention does not contain the factor of 'df', which is why we need to * apply it ourselves) * */ hetCorrection *= dfSFT; XLAL_CHECK_NULL ( XLALReorderSFTtoFFTW (thisSFT->data) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALCOMPLEX8VectorFFT( sTS->data, thisSFT->data, SFTplan ) == XLAL_SUCCESS, XLAL_EFUNC ); for ( UINT4 j=0; j < sTS->data->length; j++) { sTS->data->data[j] *= hetCorrection; } // for j < numFreqBinsSFT // copy the short (shifted) heterodyned timeseries into correct location within long timeseries UINT4 binsLeft = numSamples - bin0_n; UINT4 copyLen = MYMIN ( numFreqBinsSFT, binsLeft ); /* make sure not to write past the end of the long TS */ memcpy ( &lTS->data->data[bin0_n], sTS->data->data, copyLen * sizeof(lTS->data->data[0]) ); } /* for n < numSFTs */ // cleanup memory XLALDestroySFTVector ( sfts ); XLALDestroyCOMPLEX8TimeSeries ( sTS ); XLALDestroyCOMPLEX8FFTPlan ( SFTplan ); return lTS; } // XLALSFTVectorToCOMPLEX8TimeSeries()