int XLALCOMPLEX16FreqTimeFFT( COMPLEX16TimeSeries *time, const COMPLEX16FrequencySeries *freq, const COMPLEX16FFTPlan *plan ) { COMPLEX16Vector *tmp; UINT4 k; if ( ! freq || ! time || ! plan ) XLAL_ERROR( XLAL_EFAULT ); if ( freq->deltaF <= 0.0 ) XLAL_ERROR( XLAL_EINVAL ); if ( plan->sign != 1 ) XLAL_ERROR( XLAL_EINVAL ); /* create temporary workspace */ tmp = XLALCreateCOMPLEX16Vector( freq->data->length ); if ( ! tmp ) XLAL_ERROR( XLAL_EFUNC ); /* pack the frequency series and multiply by deltaF */ for ( k = 0; k < freq->data->length / 2; ++k ) tmp->data[k+(freq->data->length+1)/2] = freq->deltaF * freq->data->data[k]; for ( k = freq->data->length / 2; k < freq->data->length; ++k ) tmp->data[k-freq->data->length/2] = freq->deltaF * freq->data->data[k]; /* perform transform */ if ( XLALCOMPLEX16VectorFFT( time->data, tmp, plan ) == XLAL_FAILURE ) { int saveErrno = xlalErrno; xlalErrno = 0; XLALDestroyCOMPLEX16Vector( tmp ); xlalErrno = saveErrno; XLAL_ERROR( XLAL_EFUNC ); } /* destroy temporary workspace */ XLALDestroyCOMPLEX16Vector( tmp ); if ( xlalErrno ) XLAL_ERROR( XLAL_EFUNC ); /* adjust the units */ if ( ! XLALUnitMultiply( &time->sampleUnits, &freq->sampleUnits, &lalHertzUnit ) ) XLAL_ERROR( XLAL_EFUNC ); /* remaining fields */ time->f0 = freq->f0 + freq->deltaF * floor( freq->data->length / 2 ); time->epoch = freq->epoch; time->deltaT = 1.0 / ( freq->deltaF * freq->data->length ); return 0; }
/** * \brief Chops and remerges data into stationary segments * * This function finds segments of data that appear to be stationary (have the same standard deviation). * * The function first attempts to chop up the data into as many stationary segments as possible. The splitting may not * be optimal, so it then tries remerging consecutive segments to see if the merged segments show more evidence of * stationarity. <b>[NOTE: Remerging is currently turned off and will make very little difference to the algorithm]</b>. * It then, if necessary, chops the segments again to make sure there are none greater than the required \c chunkMax. * The default \c chunkMax is 0, so this rechopping will not normally happen. * * This is all performed on data that has had a running median subtracted, to try and removed any underlying trends in * the data (e.g. those caused by a strong signal), which might affect the calculations (which assume the data is * Gaussian with zero mean). * * If the \c outputchunks is non-zero then a list of the segments will be output to a file called \c data_segment_list.txt, * with a prefix of the detector name. * * \param data [in] A data structure * \param chunkMin [in] The minimum length of a segment * \param chunkMax [in] The maximum length of a segment * \param outputchunks [in] A flag to check whether to output the segments * * \return A vector of segment/chunk lengths * * \sa subtract_running_median * \sa chop_data * \sa merge_data * \sa rechop_data */ UINT4Vector *chop_n_merge( LALInferenceIFOData *data, UINT4 chunkMin, UINT4 chunkMax, UINT4 outputchunks ){ UINT4 j = 0; UINT4Vector *chunkLengths = NULL; UINT4Vector *chunkIndex = NULL; COMPLEX16Vector *meddata = NULL; /* subtract a running median value from the data to remove any underlying trends (e.g. caused by a string signal) that * might affect the chunk calculations (which can assume the data is Gaussian with zero mean). */ meddata = subtract_running_median( data->compTimeData->data ); /* pass chop data a gsl_vector_view, so that internally it can use vector views rather than having to create new vectors */ gsl_vector_complex_view meddatagsl = gsl_vector_complex_view_array((double*)meddata->data, meddata->length); chunkIndex = chop_data( &meddatagsl.vector, chunkMin ); /* DON'T BOTHER WITH THE MERGING AS IT WILL MAKE VERY LITTLE DIFFERENCE */ /* merge_data( meddata, &chunkIndex ); */ XLALDestroyCOMPLEX16Vector( meddata ); /* free memory */ /* if a maximum chunk length is defined then rechop up the data, to segment any chunks longer than this value */ if ( chunkMax > chunkMin ) { rechop_data( &chunkIndex, chunkMax, chunkMin ); } chunkLengths = XLALCreateUINT4Vector( chunkIndex->length ); /* go through segments and turn into vector of chunk lengths */ for ( j = 0; j < chunkIndex->length; j++ ){ if ( j == 0 ) { chunkLengths->data[j] = chunkIndex->data[j]; } else { chunkLengths->data[j] = chunkIndex->data[j] - chunkIndex->data[j-1]; } } /* if required output the chunk end indices and lengths to a file */ if ( outputchunks ){ FILE *fpsegs = NULL; /* set detector name as prefix */ CHAR *outfile = NULL; outfile = XLALStringDuplicate( data->detector->frDetector.prefix ); outfile = XLALStringAppend( outfile, "data_segment_list.txt" ); /* check if file exists, i.e. given mutliple frequency harmonics, and if so open for appending */ FILE *fpcheck = NULL; if ( (fpcheck = fopen(outfile, "r")) != NULL ){ fclose(fpcheck); if ( (fpsegs = fopen(outfile, "a")) == NULL ){ fprintf(stderr, "Non-fatal error open file to output segment list.\n"); return chunkLengths; } } else{ if ( (fpsegs = fopen(outfile, "w")) == NULL ){ fprintf(stderr, "Non-fatal error open file to output segment list.\n"); return chunkLengths; } } XLALFree( outfile ); for ( j = 0; j < chunkIndex->length; j++ ) { fprintf(fpsegs, "%u\t%u\n", chunkIndex->data[j], chunkLengths->data[j]); } /* add space at the end so that you can separate lists from different detector data streams */ fprintf(fpsegs, "\n"); fclose( fpsegs ); } XLALDestroyUINT4Vector( chunkIndex ); return chunkLengths; }
/** \see See \ref BilinearTransform_c for documentation */ int XLALWToZCOMPLEX16ZPGFilter( COMPLEX16ZPGFilter *filter ) { INT4 i; /* A counter. */ INT4 j; /* Another counter. */ INT4 num; /* The total number of zeros or poles. */ INT4 numZeros; /* The number of finite zeros. */ INT4 numPoles; /* The number of finite poles. */ COMPLEX16 *a; /* A zero or pole in the w plane. */ COMPLEX16 *b; /* A zero or pole in the z plane. */ COMPLEX16 *g; /* A gain correction factor. */ COMPLEX16Vector *z=NULL; /* Vector of zeros or poles in z plane. */ COMPLEX16Vector *gain=NULL; /* Vector of gain correction factors. */ COMPLEX16Vector null; /* A vector of zero length. */ INT4Vector *idx=NULL; /* Index array for sorting absGain. */ /* Make sure the filter pointer is non-null. */ if ( ! filter ) XLAL_ERROR( XLAL_EFAULT ); /* If the filter->zeros or filter->poles pointers is null, this means that there are no zeros or no poles. For simplicity, we set the pointer to point to a vector of zero length. */ null.length=0; null.data=NULL; if(!filter->zeros) filter->zeros=&null; if(!filter->poles) filter->poles=&null; /* Check that the vector lengths are non-negative, and, if positive, that the vector data pointer is non-null. */ numZeros=filter->zeros->length; if (numZeros<0) XLAL_ERROR(XLAL_EINVAL); if(numZeros>0) if (!filter->zeros->data) XLAL_ERROR(XLAL_EFAULT); numPoles=filter->poles->length; if (numPoles<0) XLAL_ERROR(XLAL_EINVAL); if(numPoles>0) if (!filter->poles->data) XLAL_ERROR(XLAL_EFAULT); /* Compute the total number of zeros and poles in the w-plane, including those at w=infinity. */ num = (numZeros>numPoles) ? numZeros : numPoles; numZeros=numPoles=num; /* If there are neither zeros nor poles, then there is nothing to transform. (The <0 case should never occur if the ASSERT() macros have done their job, but is included for extra safety.) */ if(num<=0){ filter->zeros=NULL; filter->poles=NULL; return 0; } /* Compute the revised number of zeros and poles in the z-plane, excluding those at z=infinity (w=-i). */ for(i=0,a=filter->zeros->data;i<(INT4)filter->zeros->length;i++,a++) if((creal(*a)==0.0)&&(cimag(*a)==-1.0)) numZeros--; for(i=0,a=filter->poles->data;i<(INT4)filter->poles->length;i++,a++) if((creal(*a)==0.0)&&(cimag(*a)==-1.0)) numPoles--; /* Create the vector of gain correction factors. */ /* Create the new vector of zeros. */ gain=XLALCreateCOMPLEX16Vector(filter->zeros->length+filter->poles->length); z=XLALCreateCOMPLEX16Vector(numZeros); if (!gain||!z) { XLALDestroyCOMPLEX16Vector(gain); XLALDestroyCOMPLEX16Vector(z); XLAL_ERROR(XLAL_EFUNC); } g=gain->data; b=z->data; /* Transform existing zeros from w to z, except for those at w=-i, which are mapped to z=infinity. At the same time, compute the gain correction factors. */ for(i=0,j=0,a=filter->zeros->data;i<(INT4)filter->zeros->length; i++,a++,g++){ REAL8 ar=creal(*a); REAL8 ai=cimag(*a); if(ar==0.0){ if(ai==-1.0){ /* w=-i is mapped to z=infinity. */ *g=2.0*I; }else{ /* w=i*y is mapped to z=(1-y)/(1+y). */ *b=(1.0-ai)/(1.0+ai); *g=-(1.0+ai)*I; b++; j++; } }else if(fabs(1.0+ai)>fabs(ar)){ REAL8 ratio = -ar/(1.0+ai); REAL8 denom = 1.0+ai - ratio*ar; *b = (1.0-ai + ratio*ar)/denom; *b += I*(ar - ratio*(1.0-ai))/denom; *g = -ar; *g += -(1.0+ai)*I; b++; j++; }else{ REAL8 ratio = -(1.0+ai)/ar; REAL8 denom = -ar + ratio*(1.0+ai); *b = ((1.0-ai)*ratio + ar)/denom; *b += I*(ar*ratio - 1.0+ai)/denom; *g = -ar; *g += -(1.0+ai)*I; b++; j++; } } /* Transform any remaining zeros at w=infinity to z=-1. */ for(;j<numZeros;b++,j++){ *b = -1.0; } /* Replace the old filter zeros with the new ones. */ if(filter->zeros->length>0) XLALDestroyCOMPLEX16Vector(filter->zeros); filter->zeros=z; z=NULL; /* Create the new vector of poles. */ z=XLALCreateCOMPLEX16Vector(numPoles); if (!gain||!z) { XLALDestroyCOMPLEX16Vector(gain); XLAL_ERROR(XLAL_EFUNC); } b=z->data; /* Transform existing poles from w to z, except for those at w=-i, which are mapped to z=infinity. At the same time, compute the gain correction factors. */ for(i=0,j=0,a=filter->poles->data;i<(INT4)filter->poles->length; i++,a++,g++){ REAL8 ar=creal(*a); REAL8 ai=cimag(*a); if(ar==0.0){ if(ai==-1.0){ /* w=-i is mapped to z=infinity. */ *g=-0.5*I; }else{ /* w=i*y is mapped to z=(1-y)/(1+y). */ *b=(1.0-ai)/(1.0+ai); *g=I*1.0/(1.0+ai); b++; j++; } }else if(fabs(1.0+ai)>fabs(ar)){ REAL8 ratio = -ar/(1.0+ai); REAL8 denom = 1.0+ai - ratio*ar; *b = (1.0-ai + ratio*ar)/denom; *b += I*(ar - ratio*(1.0-ai))/denom; *g = ratio/denom; *g += I*1.0/denom; b++; j++; }else{ REAL8 ratio = -(1.0+ai)/ar; REAL8 denom = -ar + ratio*(1.0+ai); *b = ((1.0-ai)*ratio + ar)/denom; *b += I*(ar*ratio - 1.0+ai)/denom; *g = ratio/denom; *g += I*1.0/denom; b++; j++; } } /* Transform any remaining poles at w=infinity to z=-1. */ for(;j<numPoles;b++,j++){ *b = -1.0; } /* Replace the old filter poles with the new ones. */ if(filter->poles->length>0) XLALDestroyCOMPLEX16Vector(filter->poles); filter->poles=z; z=NULL; /* To avoid numerical overflow when applying the gain correction factors, we should multiply alternately by large and small factors. Create an idx vector that indexes the magnitudes from small to large. */ idx=XLALCreateINT4Vector(gain->length); if(!idx||XLALHeapIndex(idx->data,gain->data,gain->length,sizeof(*gain->data),NULL,CompareCOMPLEX16Abs)<0) { XLALDestroyCOMPLEX16Vector(gain); XLALDestroyINT4Vector(idx); XLAL_ERROR(XLAL_EFUNC); } /* Now multiply the gain alternately by small and large correction factors. */ for(i=0,j=gain->length-1;i<j;i++,j--){ /* Multiply the small and largest factors together. */ /* Multiply the gain by the combined factor. */ filter->gain *= gain->data[idx->data[i]] * gain->data[idx->data[j]]; } if(i==j){ /* Multiply by the remaining odd factor. */ filter->gain *= gain->data[idx->data[i]]; } /* Free remaining temporary vectors, and exit. */ XLALDestroyCOMPLEX16Vector(gain); XLALDestroyINT4Vector(idx); return 0; }
/** * The main workhorse function for performing the ringdown attachment for EOB * models EOBNRv2 and SEOBNRv1. This is the function which gets called by the * code generating the full IMR waveform once generation of the inspiral part * has been completed. * The ringdown is attached using the hybrid comb matching detailed in * The method is describe in Sec. II C of Pan et al. PRD 84, 124052 (2011), * specifically Eqs. 30 - 32.. Further details of the * implementation of the found in the DCC document T1100433. * In SEOBNRv1, the last physical overtone is replace by a pseudoQNM. See * Taracchini et al. PRD 86, 024011 (2012) for details. * STEP 1) Get mass and spin of the final black hole and the complex ringdown frequencies * STEP 2) Based on least-damped-mode decay time, allocate memory for rigndown waveform * STEP 3) Get values and derivatives of inspiral waveforms at matching comb points * STEP 4) Solve QNM coefficients and generate ringdown waveforms * STEP 5) Stitch inspiral and ringdown waveoforms */ static INT4 XLALSimIMREOBHybridAttachRingdown( REAL8Vector *signal1, /**<< OUTPUT, Real of inspiral waveform to which we attach ringdown */ REAL8Vector *signal2, /**<< OUTPUT, Imag of inspiral waveform to which we attach ringdown */ const INT4 l, /**<< Current mode l */ const INT4 m, /**<< Current mode m */ const REAL8 dt, /**<< Sample time step (in seconds) */ const REAL8 mass1, /**<< First component mass (in Solar masses) */ const REAL8 mass2, /**<< Second component mass (in Solar masses) */ const REAL8 spin1x, /**<<The spin of the first object; only needed for spin waveforms */ const REAL8 spin1y, /**<<The spin of the first object; only needed for spin waveforms */ const REAL8 spin1z, /**<<The spin of the first object; only needed for spin waveforms */ const REAL8 spin2x, /**<<The spin of the second object; only needed for spin waveforms */ const REAL8 spin2y, /**<<The spin of the second object; only needed for spin waveforms */ const REAL8 spin2z, /**<<The spin of the second object; only needed for spin waveforms */ REAL8Vector *timeVec, /**<< Vector containing the time values */ REAL8Vector *matchrange, /**<< Time values chosen as points for performing comb matching */ Approximant approximant /**<<The waveform approximant being used */ ) { COMPLEX16Vector *modefreqs; UINT4 Nrdwave; UINT4 j; UINT4 nmodes; REAL8Vector *rdwave1; REAL8Vector *rdwave2; REAL8Vector *rinspwave; REAL8Vector *dinspwave; REAL8Vector *ddinspwave; REAL8VectorSequence *inspwaves1; REAL8VectorSequence *inspwaves2; REAL8 eta, a, NRPeakOmega22; /* To generate pQNM frequency */ REAL8 mTot; /* In geometric units */ REAL8 spin1[3] = { spin1x, spin1y, spin1z }; REAL8 spin2[3] = { spin2x, spin2y, spin2z }; REAL8 finalMass, finalSpin; mTot = (mass1 + mass2) * LAL_MTSUN_SI; eta = mass1 * mass2 / ( (mass1 + mass2) * (mass1 + mass2) ); /* * STEP 1) Get mass and spin of the final black hole and the complex ringdown frequencies */ /* Create memory for the QNM frequencies */ nmodes = 8; modefreqs = XLALCreateCOMPLEX16Vector( nmodes ); if ( !modefreqs ) { XLAL_ERROR( XLAL_ENOMEM ); } if ( XLALSimIMREOBGenerateQNMFreqV2( modefreqs, mass1, mass2, spin1, spin2, l, m, nmodes, approximant ) == XLAL_FAILURE ) { XLALDestroyCOMPLEX16Vector( modefreqs ); XLAL_ERROR( XLAL_EFUNC ); } /* Call XLALSimIMREOBFinalMassSpin() to get mass and spin of the final black hole */ if ( XLALSimIMREOBFinalMassSpin(&finalMass, &finalSpin, mass1, mass2, spin1, spin2, approximant) == XLAL_FAILURE ) { XLAL_ERROR( XLAL_EFUNC ); } if ( approximant == SEOBNRv1 ) { /* Replace the last QNM with pQNM */ /* We assume aligned/antialigned spins here */ a = (spin1[2] + spin2[2]) / 2. * (1.0 - 2.0 * eta) + (spin1[2] - spin2[2]) / 2. * (mass1 - mass2) / (mass1 + mass2); NRPeakOmega22 = GetNRSpinPeakOmega( l, m, eta, a ) / mTot; /*printf("a and NRomega in QNM freq: %.16e %.16e %.16e %.16e %.16e\n",spin1[2],spin2[2], mTot/LAL_MTSUN_SI,a,NRPeakOmega22*mTot);*/ modefreqs->data[7] = (NRPeakOmega22/finalMass + creal(modefreqs->data[0])) / 2.; modefreqs->data[7] += I * 10./3. * cimag(modefreqs->data[0]); } /*for (j = 0; j < nmodes; j++) { printf("QNM frequencies: %d %d %d %e %e\n",l,m,j,modefreqs->data[j].re*mTot,1./modefreqs->data[j].im/mTot); }*/ /* Ringdown signal length: 10 times the decay time of the n=0 mode */ Nrdwave = (INT4) (EOB_RD_EFOLDS / cimag(modefreqs->data[0]) / dt); /* Check the value of attpos, to prevent memory access problems later */ if ( matchrange->data[0] * mTot / dt < 5 || matchrange->data[1]*mTot/dt > matchrange->data[2] *mTot/dt - 2 ) { XLALPrintError( "More inspiral points needed for ringdown matching.\n" ); //printf("%.16e,%.16e,%.16e\n",matchrange->data[0] * mTot / dt, matchrange->data[1]*mTot/dt, matchrange->data[2] *mTot/dt - 2); XLALDestroyCOMPLEX16Vector( modefreqs ); XLAL_ERROR( XLAL_EFAILED ); } /* * STEP 2) Based on least-damped-mode decay time, allocate memory for rigndown waveform */ /* Create memory for the ring-down and full waveforms, and derivatives of inspirals */ rdwave1 = XLALCreateREAL8Vector( Nrdwave ); rdwave2 = XLALCreateREAL8Vector( Nrdwave ); rinspwave = XLALCreateREAL8Vector( 6 ); dinspwave = XLALCreateREAL8Vector( 6 ); ddinspwave = XLALCreateREAL8Vector( 6 ); inspwaves1 = XLALCreateREAL8VectorSequence( 3, 6 ); inspwaves2 = XLALCreateREAL8VectorSequence( 3, 6 ); /* Check memory was allocated */ if ( !rdwave1 || !rdwave2 || !rinspwave || !dinspwave || !ddinspwave || !inspwaves1 || !inspwaves2 ) { XLALDestroyCOMPLEX16Vector( modefreqs ); if (rdwave1) XLALDestroyREAL8Vector( rdwave1 ); if (rdwave2) XLALDestroyREAL8Vector( rdwave2 ); if (rinspwave) XLALDestroyREAL8Vector( rinspwave ); if (dinspwave) XLALDestroyREAL8Vector( dinspwave ); if (ddinspwave) XLALDestroyREAL8Vector( ddinspwave ); if (inspwaves1) XLALDestroyREAL8VectorSequence( inspwaves1 ); if (inspwaves2) XLALDestroyREAL8VectorSequence( inspwaves2 ); XLAL_ERROR( XLAL_ENOMEM ); } memset( rdwave1->data, 0, rdwave1->length * sizeof( REAL8 ) ); memset( rdwave2->data, 0, rdwave2->length * sizeof( REAL8 ) ); /* * STEP 3) Get values and derivatives of inspiral waveforms at matching comb points */ /* Generate derivatives of the last part of inspiral waves */ /* Get derivatives of signal1 */ if ( XLALGenerateHybridWaveDerivatives( rinspwave, dinspwave, ddinspwave, timeVec, signal1, matchrange, dt, mass1, mass2 ) == XLAL_FAILURE ) { XLALDestroyCOMPLEX16Vector( modefreqs ); XLALDestroyREAL8Vector( rdwave1 ); XLALDestroyREAL8Vector( rdwave2 ); XLALDestroyREAL8Vector( rinspwave ); XLALDestroyREAL8Vector( dinspwave ); XLALDestroyREAL8Vector( ddinspwave ); XLALDestroyREAL8VectorSequence( inspwaves1 ); XLALDestroyREAL8VectorSequence( inspwaves2 ); XLAL_ERROR( XLAL_EFUNC ); } for (j = 0; j < 6; j++) { inspwaves1->data[j] = rinspwave->data[j]; inspwaves1->data[j + 6] = dinspwave->data[j]; inspwaves1->data[j + 12] = ddinspwave->data[j]; } /* Get derivatives of signal2 */ if ( XLALGenerateHybridWaveDerivatives( rinspwave, dinspwave, ddinspwave, timeVec, signal2, matchrange, dt, mass1, mass2 ) == XLAL_FAILURE ) { XLALDestroyCOMPLEX16Vector( modefreqs ); XLALDestroyREAL8Vector( rdwave1 ); XLALDestroyREAL8Vector( rdwave2 ); XLALDestroyREAL8Vector( rinspwave ); XLALDestroyREAL8Vector( dinspwave ); XLALDestroyREAL8Vector( ddinspwave ); XLALDestroyREAL8VectorSequence( inspwaves1 ); XLALDestroyREAL8VectorSequence( inspwaves2 ); XLAL_ERROR( XLAL_EFUNC ); } for (j = 0; j < 6; j++) { inspwaves2->data[j] = rinspwave->data[j]; inspwaves2->data[j + 6] = dinspwave->data[j]; inspwaves2->data[j + 12] = ddinspwave->data[j]; } /* * STEP 4) Solve QNM coefficients and generate ringdown waveforms */ /* Generate ring-down waveforms */ if ( XLALSimIMREOBHybridRingdownWave( rdwave1, rdwave2, dt, mass1, mass2, inspwaves1, inspwaves2, modefreqs, matchrange ) == XLAL_FAILURE ) { XLALDestroyCOMPLEX16Vector( modefreqs ); XLALDestroyREAL8Vector( rdwave1 ); XLALDestroyREAL8Vector( rdwave2 ); XLALDestroyREAL8Vector( rinspwave ); XLALDestroyREAL8Vector( dinspwave ); XLALDestroyREAL8Vector( ddinspwave ); XLALDestroyREAL8VectorSequence( inspwaves1 ); XLALDestroyREAL8VectorSequence( inspwaves2 ); XLAL_ERROR( XLAL_EFUNC ); } /* * STEP 5) Stitch inspiral and ringdown waveoforms */ /* Generate full waveforms, by stitching inspiral and ring-down waveforms */ UINT4 attachIdx = matchrange->data[1] * mTot / dt; for (j = 1; j < Nrdwave; ++j) { signal1->data[j + attachIdx] = rdwave1->data[j]; signal2->data[j + attachIdx] = rdwave2->data[j]; } memset( signal1->data+Nrdwave+attachIdx, 0, (signal1->length - Nrdwave - attachIdx)*sizeof(REAL8) ); memset( signal2->data+Nrdwave+attachIdx, 0, (signal2->length - Nrdwave - attachIdx)*sizeof(REAL8) ); /* Free memory */ XLALDestroyCOMPLEX16Vector( modefreqs ); XLALDestroyREAL8Vector( rdwave1 ); XLALDestroyREAL8Vector( rdwave2 ); XLALDestroyREAL8Vector( rinspwave ); XLALDestroyREAL8Vector( dinspwave ); XLALDestroyREAL8Vector( ddinspwave ); XLALDestroyREAL8VectorSequence( inspwaves1 ); XLALDestroyREAL8VectorSequence( inspwaves2 ); return XLAL_SUCCESS; }