/** * \author Creighton, T. D. * * \brief Computes the response of a detector to a coherent gravitational wave. * * This function takes a quasiperiodic gravitational waveform given in * <tt>*signal</tt>, and estimates the corresponding response of the * detector whose position, orientation, and transfer function are * specified in <tt>*detector</tt>. The result is stored in * <tt>*output</tt>. * * The fields <tt>output-\>epoch</tt>, <tt>output->deltaT</tt>, and * <tt>output-\>data</tt> must already be set, in order to specify the time * period and sampling rate for which the response is required. If * <tt>output-\>f0</tt> is nonzero, idealized heterodyning is performed (an * amount \f$2\pi f_0(t-t_0)\f$ is subtracted from the phase before computing * the sinusoid, where \f$t_0\f$ is the heterodyning epoch defined in * \c detector). For the input signal, <tt>signal-\>h</tt> is ignored, * and the signal is treated as zero at any time for which either * <tt>signal-\>a</tt> or <tt>signal-\>phi</tt> is not defined. * * This routine will convert <tt>signal-\>position</tt> to equatorial * coordinates, if necessary. * * ### Algorithm ### * * The routine first accounts for the time delay between the detector and * the solar system barycentre, based on the detector position * information stored in <tt>*detector</tt> and the propagation direction * specified in <tt>*signal</tt>. Values of the propagation delay are * precomuted at fixed intervals and stored in a table, with the * intervals \f$\Delta T_\mathrm{delay}\f$ chosen such that the value * interpolated from adjacent table entries will never differ from the * true value by more than some timing error \f$\sigma_T\f$. This implies * that: * \f[ * \Delta T_\mathrm{delay} \leq \sqrt{ * \frac{8\sigma_T}{\max\{a/c\}} } \; , * \f] * where \f$\max\{a/c\}=1.32\times10^{-10}\mathrm{s}^{-1}\f$ is the maximum * acceleration of an Earth-based detector in the barycentric frame. The * total propagation delay also includes Einstein and Shapiro delay, but * these are more slowly varying and thus do not constrain the table * spacing. At present, a 400s table spacing is hardwired into the code, * implying \f$\sigma_T\approx3\mu\f$s, comparable to the stated accuracy of * <tt>LALBarycenter()</tt>. * * Next, the polarization response functions of the detector * \f$F_{+,\times}(\alpha,\delta)\f$ are computed for every 10 minutes of the * signal's duration, using the position of the source in <tt>*signal</tt>, * the detector information in <tt>*detector</tt>, and the function * <tt>LALComputeDetAMResponseSeries()</tt>. Subsequently, the * polarization functions are estimated for each output sample by * interpolating these precomputed values. This guarantees that the * interpolated value is accurate to \f$\sim0.1\%\f$. * * Next, the frequency response of the detector is estimated in the * quasiperiodic limit as follows: * <ul> * <li> At each sample point in <tt>*output</tt>, the propagation delay is * computed and added to the sample time, and the instantaneous * amplitudes \f$A_1\f$, \f$A_2\f$, frequency \f$f\f$, phase \f$\phi\f$, and polarization * shift \f$\Phi\f$ are found by interpolating the nearest values in * <tt>signal-\>a</tt>, <tt>signal-\>f</tt>, <tt>signal-\>phi</tt>, and * <tt>signal-\>shift</tt>, respectively. If <tt>signal-\>f</tt> is not * defined at that point in time, then \f$f\f$ is estimated by differencing * the two nearest values of \f$\phi\f$, as \f$f\approx\Delta\phi/2\pi\Delta * t\f$. If <tt>signal-\>shift</tt> is not defined, then \f$\Phi\f$ is treated as * zero.</li> * <li> The complex transfer function of the detector the frequency \f$f\f$ * is found by interpolating <tt>detector-\>transfer</tt>. The amplitude of * the transfer function is multiplied with \f$A_1\f$ and \f$A_2\f$, and the * phase of the transfer function is added to \f$\phi\f$,</li> * <li> The plus and cross contributions \f$o_+\f$, \f$o_\times\f$ to the * detector output are computed as in \eqref{eq_quasiperiodic_hpluscross} * of \ref PulsarSimulateCoherentGW_h, but * using the response-adjusted amplitudes and phase.</li> * <li> The final detector response \f$o\f$ is computed as * \f$o=(o_+F_+)+(o_\times F_\times)\f$.</li> * </ul> * * ### A note on interpolation: ### * * Much of the computational work in this routine involves interpolating * various time series to find their values at specific output times. * The algorithm is summarized below. * * Let \f$A_j = A( t_A + j\Delta t_A )\f$ be a sampled time series, which we * want to resample at new (output) time intervals \f$t_k = t_0 + k\Delta * t\f$. We first precompute the following quantities: * \f{eqnarray}{ * t_\mathrm{off} & = & \frac{t_0-t_A}{\Delta t_A} \; , \\ * dt & = & \frac{\Delta t}{\Delta t_A} \; . * \f} * Then, for each output sample time \f$t_k\f$, we compute: * \f{eqnarray}{ * t & = & t_\mathrm{off} + k \times dt \; , \\ * j & = & \lfloor t \rfloor \; , \\ * f & = & t - j \; , * \f} * where \f$\lfloor x\rfloor\f$ is the "floor" function; i.e.\ the largest * integer \f$\leq x\f$. The time series sampled at the new time is then: * \f[ * A(t_k) = f \times A_{j+1} + (1-f) \times A_j \; . * \f] * * ### Notes ### * * The major computational hit in this routine comes from computing the * sine and cosine of the phase angle in * \eqref{eq_quasiperiodic_hpluscross} of * \ref PulsarSimulateCoherentGW_h. For better online performance, these can * be replaced by other (approximate) trig functions. Presently the code * uses the native \c libm functions by default, or the function * <tt>sincosp()</tt> in \c libsunmath \e if this function is * available \e and the constant \c ONLINE is defined. * Differences at the level of 0.01 begin to appear only for phase * arguments greater than \f$10^{14}\f$ or so (corresponding to over 500 * years between phase epoch and observation time for frequencies of * around 1kHz). * * To activate this feature, be sure that <tt>sunmath.h</tt> and * \c libsunmath are on your system, and add <tt>-DONLINE</tt> to the * <tt>--with-extra-cppflags</tt> configuration argument. In future this * flag may be used to turn on other efficient trig algorithms on other * (non-Solaris) platforms. * */ void LALPulsarSimulateCoherentGW( LALStatus *stat, REAL4TimeSeries *output, PulsarCoherentGW *CWsignal, PulsarDetectorResponse *detector ) { INT4 i, n; /* index over output->data, and its final value */ INT4 nMax; /* used to store limits on index ranges */ INT4 fInit, fFinal; /* index range for which CWsignal->f is defined */ INT4 shiftInit, shiftFinal; /* ditto for CWsignal->shift */ UINT4 dtDelayBy2; /* delay table half-interval (s) */ UINT4 dtPolBy2; /* polarization table half-interval (s) */ REAL4 *outData; /* pointer to output data */ REAL8 delayMin, delayMax; /* min and max values of time delay */ SkyPosition source; /* source sky position */ BOOLEAN transfer; /* 1 if transfer function is specified */ BOOLEAN fFlag = 0; /* 1 if frequency left detector->transfer range */ BOOLEAN pFlag = 0; /* 1 if frequency was estimated from phase */ /* get delay table and polaristion tables half intervals if defined (>0) in the PulsarCoherentGW structure otherwise default to 400s for dtDelatBy2 and 300s for dtPolBy2 */ dtDelayBy2 = CWsignal->dtDelayBy2 > 0 ? CWsignal->dtDelayBy2 : 400; dtPolBy2 = CWsignal->dtPolBy2 > 0 ? CWsignal->dtPolBy2 : 300; /* The amplitude, frequency, phase, polarization shift, polarization response, and propagation delay are stored in arrays that must be interpolated. For a quantity x, we define a pointer xData to the data array. At some time t measured in units of output->deltaT, the interpolation point in xData is given by ( xOff + t*xDt ), where xOff is an offset and xDt is a relative sampling rate. */ LALDetAMResponseSeries polResponse; REAL8Vector *delay = NULL; REAL4 *aData, *fData, *shiftData, *plusData, *crossData; REAL8 *phiData, *delayData; REAL8 aOff, fOff, phiOff, shiftOff, polOff, delayOff; REAL8 aDt, fDt, phiDt, shiftDt, polDt, delayDt; /* Frequencies in the detector transfer function are interpolated similarly, except everything is normalized with respect to detector->transfer->deltaF. */ REAL4Vector *aTransfer = NULL; REAL4Vector *phiTransfer = NULL; REAL4Vector *phiTemp = NULL; REAL4 *aTransData = NULL, *phiTransData = NULL; REAL8 f0 = 1.0; REAL8 phiFac = 1.0, fFac = 1.0; /* Heterodyning phase factor LAL_TWOPI*output->f0*output->deltaT, and phase offset at the start of the series LAL_TWOPI*output->f0*(time offset). */ REAL8 heteroFac, phi0; /* Variables required by the TCENTRE() macro, above. */ REAL8 realIndex; INT4 intIndex; REAL8 indexFrac; INITSTATUS(stat); ATTATCHSTATUSPTR( stat ); /* Make sure parameter structures and their fields exist. */ ASSERT( CWsignal, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); if ( !( CWsignal->a ) ) { ABORT( stat, SIMULATECOHERENTGWH_ESIG, SIMULATECOHERENTGWH_MSGESIG ); } ASSERT( CWsignal->a->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( CWsignal->a->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); if ( !( CWsignal->phi ) ) { ABORT( stat, SIMULATECOHERENTGWH_ESIG, SIMULATECOHERENTGWH_MSGESIG ); } ASSERT( CWsignal->phi->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( CWsignal->phi->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); if ( CWsignal->f ) { ASSERT( CWsignal->f->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( CWsignal->f->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); } if ( CWsignal->shift ) { ASSERT( CWsignal->shift->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( CWsignal->shift->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); } ASSERT( detector, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); if ( ( transfer = ( detector->transfer != NULL ) ) ) { ASSERT( detector->transfer->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( detector->transfer->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); } ASSERT( output, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( output->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); ASSERT( output->data->data, stat, SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL ); /* Check dimensions of amplitude array. */ ASSERT( CWsignal->a->data->vectorLength == 2, stat, SIMULATECOHERENTGWH_EDIM, SIMULATECOHERENTGWH_MSGEDIM ); /* Make sure we never divide by zero. */ ASSERT( CWsignal->a->deltaT != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); ASSERT( CWsignal->phi->deltaT != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); aDt = output->deltaT / CWsignal->a->deltaT; phiDt = output->deltaT / CWsignal->phi->deltaT; ASSERT( aDt != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); ASSERT( phiDt != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); if ( CWsignal->f ) { ASSERT( CWsignal->f->deltaT != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); fDt = output->deltaT / CWsignal->f->deltaT; ASSERT( fDt != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); } else fDt = 0.0; if ( CWsignal->shift ) { ASSERT( CWsignal->shift->deltaT != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); shiftDt = output->deltaT / CWsignal->shift->deltaT; ASSERT( shiftDt != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); } else shiftDt = 0.0; if ( transfer ) { ASSERT( detector->transfer->deltaF != 0.0, stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); fFac = 1.0 / detector->transfer->deltaF; phiFac = fFac / ( LAL_TWOPI*CWsignal->phi->deltaT ); f0 = detector->transfer->f0/detector->transfer->deltaF; } heteroFac = LAL_TWOPI*output->f0*output->deltaT; phi0 = (REAL8)( output->epoch.gpsSeconds - detector->heterodyneEpoch.gpsSeconds ); phi0 += 0.000000001*(REAL8)( output->epoch.gpsNanoSeconds - detector->heterodyneEpoch.gpsNanoSeconds ); phi0 *= LAL_TWOPI*output->f0; if ( phi0 > 1.0/LAL_REAL8_EPS ) { LALWarning( stat, "REAL8 arithmetic is not sufficient to maintain" " heterodyne phase to within a radian." ); } /* Check units on input, and set units on output. */ { ASSERT( XLALUnitCompare( &(CWsignal->f->sampleUnits), &lalHertzUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT ); ASSERT( XLALUnitCompare( &(CWsignal->phi->sampleUnits), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT ); if( CWsignal->shift ) { ASSERT( XLALUnitCompare( &(CWsignal->shift->sampleUnits), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT ); } if ( transfer ) { if ( XLALUnitMultiply( &(output->sampleUnits), &(CWsignal->a->sampleUnits), &(detector->transfer->sampleUnits) ) == NULL ) { ABORT( stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT ); } } else { output->sampleUnits = CWsignal->a->sampleUnits; } snprintf( output->name, LALNameLength, "response to %s", CWsignal->a->name ); } /* Define temporary variables to access the data of CWsignal->a, CWsignal->f, and CWsignal->phi. */ aData = CWsignal->a->data->data; INT4 aLen = CWsignal->a->data->length * CWsignal->a->data->vectorLength; phiData = CWsignal->phi->data->data; INT4 phiLen = CWsignal->phi->data->length; outData = output->data->data; INT4 fLen=0, shiftLen=0; if ( CWsignal->f ) { fData = CWsignal->f->data->data; fLen = CWsignal->f->data->length; } else { fData = NULL; } if ( CWsignal->shift ) { shiftData = CWsignal->shift->data->data; shiftLen = CWsignal->shift->data->length; } else { shiftData = NULL; } /* Convert source position to equatorial coordinates, if required. */ if ( detector->site ) { source = CWsignal->position; if ( source.system != COORDINATESYSTEM_EQUATORIAL ) { ConvertSkyParams params; /* parameters for conversion */ EarthPosition location; /* location of detector */ params.gpsTime = &( output->epoch ); params.system = COORDINATESYSTEM_EQUATORIAL; if ( source.system == COORDINATESYSTEM_HORIZON ) { params.zenith = &( location.geodetic ); location.x = detector->site->location[0]; location.y = detector->site->location[1]; location.z = detector->site->location[2]; TRY( LALGeocentricToGeodetic( stat->statusPtr, &location ), stat ); } TRY( LALConvertSkyCoordinates( stat->statusPtr, &source, &source, ¶ms ), stat ); } } /* Generate the table of propagation delays. dtDelayBy2 = (UINT4)( 38924.9/sqrt( output->f0 + 1.0/output->deltaT ) ); */ delayDt = output->deltaT/( 2.0*dtDelayBy2 ); nMax = (UINT4)( output->data->length*delayDt ) + 3; TRY( LALDCreateVector( stat->statusPtr, &delay, nMax ), stat ); delayData = delay->data; /* Compute delay from solar system barycentre. */ if ( detector->site && detector->ephemerides ) { LIGOTimeGPS gpsTime; /* detector time when we compute delay */ EarthState state; /* Earth position info at that time */ BarycenterInput input; /* input structure to LALBarycenter() */ EmissionTime emit; /* output structure from LALBarycenter() */ /* Arrange nested pointers, and set initial values. */ gpsTime = input.tgps = output->epoch; gpsTime.gpsSeconds -= dtDelayBy2; input.tgps.gpsSeconds -= dtDelayBy2; input.site = *(detector->site); for ( i = 0; i < 3; i++ ) input.site.location[i] /= LAL_C_SI; input.alpha = source.longitude; input.delta = source.latitude; input.dInv = 0.0; delayMin = delayMax = 1.1*LAL_AU_SI/( LAL_C_SI*output->deltaT ); delayMax *= -1; /* Compute table. */ for ( i = 0; i < nMax; i++ ) { REAL8 tDelay; /* propagation time */ LALBarycenterEarth( stat->statusPtr, &state, &gpsTime, detector->ephemerides ); BEGINFAIL( stat ) TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); ENDFAIL( stat ); LALBarycenter( stat->statusPtr, &emit, &input, &state ); BEGINFAIL( stat ) TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); ENDFAIL( stat ); delayData[i] = tDelay = emit.deltaT/output->deltaT; if ( tDelay < delayMin ) delayMin = tDelay; if ( tDelay > delayMax ) delayMax = tDelay; gpsTime.gpsSeconds += 2*dtDelayBy2; input.tgps.gpsSeconds += 2*dtDelayBy2; } } /* No information from which to compute delays. */ else { LALInfo( stat, "Detector site and ephemerides absent; simulating hplus with no" " propagation delays" ); memset( delayData, 0, nMax*sizeof(REAL8) ); delayMin = delayMax = 0.0; } /* Generate the table of polarization response functions. */ polDt = output->deltaT/( 2.0*dtPolBy2 ); nMax = (UINT4)( output->data->length*polDt ) + 3; memset( &polResponse, 0, sizeof( LALDetAMResponseSeries ) ); polResponse.pPlus = (REAL4TimeSeries *) LALMalloc( sizeof(REAL4TimeSeries) ); polResponse.pCross = (REAL4TimeSeries *) LALMalloc( sizeof(REAL4TimeSeries) ); polResponse.pScalar = (REAL4TimeSeries *) LALMalloc( sizeof(REAL4TimeSeries) ); if ( !polResponse.pPlus || !polResponse.pCross || !polResponse.pScalar ) { if ( polResponse.pPlus ) LALFree( polResponse.pPlus ); if ( polResponse.pCross ) LALFree( polResponse.pCross ); if ( polResponse.pScalar ) LALFree( polResponse.pScalar ); TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); ABORT( stat, SIMULATECOHERENTGWH_EMEM, SIMULATECOHERENTGWH_MSGEMEM ); } memset( polResponse.pPlus, 0, sizeof(REAL4TimeSeries) ); memset( polResponse.pCross, 0, sizeof(REAL4TimeSeries) ); memset( polResponse.pScalar, 0, sizeof(REAL4TimeSeries) ); LALSCreateVector( stat->statusPtr, &( polResponse.pPlus->data ), nMax ); BEGINFAIL( stat ) { LALFree( polResponse.pPlus ); LALFree( polResponse.pCross ); LALFree( polResponse.pScalar ); TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); } ENDFAIL( stat ); LALSCreateVector( stat->statusPtr, &( polResponse.pCross->data ), nMax ); BEGINFAIL( stat ) { TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pPlus->data ) ), stat ); LALFree( polResponse.pPlus ); LALFree( polResponse.pCross ); LALFree( polResponse.pScalar ); TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); } ENDFAIL( stat ); LALSCreateVector( stat->statusPtr, &( polResponse.pScalar->data ), nMax ); BEGINFAIL( stat ) { TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pPlus->data ) ), stat ); TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pCross->data ) ), stat ); LALFree( polResponse.pPlus ); LALFree( polResponse.pCross ); LALFree( polResponse.pScalar ); TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); } ENDFAIL( stat ); plusData = polResponse.pPlus->data->data; crossData = polResponse.pCross->data->data; INT4 plusLen = polResponse.pPlus->data->length; INT4 crossLen = polResponse.pCross->data->length; if ( plusLen != crossLen ) { XLALPrintError ("plusLen = %d != crossLen = %d\n", plusLen, crossLen ); ABORT ( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD ); } if ( detector->site ) { LALSource polSource; /* position and polarization angle */ LALDetAndSource input; /* response input structure */ LALTimeIntervalAndNSample params; /* response parameter structure */ /* Arrange nested pointers, and set initial values. */ polSource.equatorialCoords = source; polSource.orientation = (REAL8)( CWsignal->psi ); input.pSource = &polSource; input.pDetector = detector->site; params.epoch = output->epoch; params.epoch.gpsSeconds -= dtPolBy2; params.deltaT = 2.0*dtPolBy2; params.nSample = nMax; /* Compute table of responses. */ LALComputeDetAMResponseSeries( stat->statusPtr, &polResponse, &input, ¶ms ); BEGINFAIL( stat ) { TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pPlus->data ) ), stat ); TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pCross->data ) ), stat ); TRY( LALSDestroyVector( stat->statusPtr, &( polResponse.pScalar->data ) ), stat ); LALFree( polResponse.pPlus ); LALFree( polResponse.pCross ); LALFree( polResponse.pScalar ); TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat ); } ENDFAIL( stat ); } else {
int main(void) { static LALStatus status; LALDetector detector; LALSource pulsar; CoarseFitOutput output; CoarseFitInput input; CoarseFitParams params; LIGOTimeGPS tgps[FITTOPULSARTEST_LENGTH]; REAL4 cosIota; REAL4 phase; REAL4 psi; REAL4 h0; REAL4 cos2phase, sin2phase; static RandomParams *randomParams; static REAL4Vector *noise; INT4 seed = 0; LALDetAndSource detAndSource; LALDetAMResponseSeries pResponseSeries = {NULL,NULL,NULL}; REAL4TimeSeries Fp, Fc, Fs; LALTimeIntervalAndNSample time_info; UINT4 i; /* Allocate memory */ input.B = NULL; input.var = NULL; LALZCreateVector( &status, &input.B, FITTOPULSARTEST_LENGTH); LALZCreateVector( &status, &input.var, FITTOPULSARTEST_LENGTH); noise = NULL; LALCreateVector( &status, &noise, FITTOPULSARTEST_LENGTH); LALCreateRandomParams( &status, &randomParams, seed); Fp.data = NULL; Fc.data = NULL; Fs.data = NULL; pResponseSeries.pPlus = &(Fp); pResponseSeries.pCross = &(Fc); pResponseSeries.pScalar = &(Fs); LALSCreateVector(&status, &(pResponseSeries.pPlus->data), 1); LALSCreateVector(&status, &(pResponseSeries.pCross->data), 1); LALSCreateVector(&status, &(pResponseSeries.pScalar->data), 1); input.t = tgps; /******** GENERATE FAKE INPUT **********/ time_info.epoch.gpsSeconds = FITTOPULSARTEST_T0; time_info.epoch.gpsNanoSeconds = 0; time_info.deltaT = 60; time_info.nSample = FITTOPULSARTEST_LENGTH; cosIota = 0.5; psi = 0.1; phase = 0.4; h0 = 5.0; cos2phase = cos(2.0*phase); sin2phase = sin(2.0*phase); detector = lalCachedDetectors[LALDetectorIndexGEO600DIFF]; /* use GEO 600 detector for tests */ pulsar.equatorialCoords.longitude = 1.4653; /* right ascention of pulsar */ pulsar.equatorialCoords.latitude = -1.2095; /* declination of pulsar */ pulsar.equatorialCoords.system = COORDINATESYSTEM_EQUATORIAL; /* coordinate system */ pulsar.orientation = psi; /* polarization angle */ strcpy(pulsar.name, "fakepulsar"); /* name of pulsar */ detAndSource.pDetector = &detector; detAndSource.pSource = &pulsar; LALNormalDeviates( &status, noise, randomParams ); LALComputeDetAMResponseSeries(&status, &pResponseSeries, &detAndSource, &time_info); for (i = 0;i < FITTOPULSARTEST_LENGTH; i++) { input.t[i].gpsSeconds = FITTOPULSARTEST_T0 + 60*i; input.t[i].gpsNanoSeconds = 0; input.B->data[i] = crect( pResponseSeries.pPlus->data->data[i]*h0*(1.0 + cosIota*cosIota)*cos2phase + 2.0*pResponseSeries.pCross->data->data[i]*h0*cosIota*sin2phase, pResponseSeries.pPlus->data->data[i]*h0*(1.0 + cosIota*cosIota)*sin2phase - 2.0*pResponseSeries.pCross->data->data[i]*h0*cosIota*cos2phase ); input.var->data[i] = crect( noise->data[FITTOPULSARTEST_LENGTH-i-1]*noise->data[FITTOPULSARTEST_LENGTH-i-1], noise->data[i]*noise->data[i] ); } input.B->length = FITTOPULSARTEST_LENGTH; input.var->length = FITTOPULSARTEST_LENGTH; /******* TEST RESPONSE TO VALID DATA ************/ /* Test that valid data generate the correct answers */ params.detector = detector; params.pulsarSrc = pulsar; params.meshH0[0] = 4.0; params.meshH0[1] = 0.2; params.meshH0[2] = 10; params.meshCosIota[0] = 0.0; params.meshCosIota[1] = 0.1; params.meshCosIota[2] = 10; params.meshPhase[0] = 0.0; params.meshPhase[1] = 0.1; params.meshPhase[2] = 10; params.meshPsi[0] = 0.0; params.meshPsi[1] = 0.1; params.meshPsi[2] = 10; output.mChiSquare = NULL; LALDCreateVector( &status, &output.mChiSquare,params.meshH0[2]*params.meshCosIota[2]*params.meshPhase[2]*params.meshPsi[2]); LALCoarseFitToPulsar(&status,&output, &input, ¶ms); if(status.statusCode) { printf("Unexpectedly got error code %d and message %s\n", status.statusCode, status.statusDescription); return FITTOPULSARTESTC_EFLS; } if(output.phase > phase + params.meshPhase[2] || output.phase < phase - params.meshPhase[2]) { printf("Got incorrect phase %f when expecting %f \n", output.phase, phase); return FITTOPULSARTESTC_EFLS; } if(output.cosIota > cosIota + params.meshCosIota[2] || output.cosIota < cosIota - params.meshCosIota[2]) { printf("Got incorrect cosIota %f when expecting %f \n", output.cosIota, cosIota); return FITTOPULSARTESTC_EFLS; } if(output.psi > psi + params.meshPsi[2] || output.psi < psi - params.meshPsi[2]) { printf("Got incorrect psi %f when expecting %f \n", output.psi, psi); return FITTOPULSARTESTC_EFLS; } /******* TEST RESPONSE OF LALCoarseFitToPulsar TO INVALID DATA ************/ #ifndef LAL_NDEBUG if ( ! lalNoDebug ) { /* Test that all the error conditions are correctly detected by the function */ LALCoarseFitToPulsar(&status, NULL, &input, ¶ms); if (status.statusCode != FITTOPULSARH_ENULLOUTPUT || strcmp(status.statusDescription, FITTOPULSARH_MSGENULLOUTPUT)) { printf( "Got error code %d and message %s\n", status.statusCode, status.statusDescription); printf( "Expected error code %d and message %s\n", FITTOPULSARH_ENULLOUTPUT, FITTOPULSARH_MSGENULLOUTPUT); return FITTOPULSARTESTC_ECHK; } LALCoarseFitToPulsar(&status, &output, NULL, ¶ms); if (status.statusCode != FITTOPULSARH_ENULLINPUT || strcmp(status.statusDescription, FITTOPULSARH_MSGENULLINPUT)) { printf( "Got error code %d and message %s\n", status.statusCode, status.statusDescription); printf( "Expected error code %d and message %s\n", FITTOPULSARH_ENULLINPUT, FITTOPULSARH_MSGENULLINPUT); return FITTOPULSARTESTC_ECHK; } LALCoarseFitToPulsar(&status, &output, &input, NULL); if (status.statusCode != FITTOPULSARH_ENULLPARAMS || strcmp(status.statusDescription, FITTOPULSARH_MSGENULLPARAMS)) { printf( "Got error code %d and message %s\n", status.statusCode, status.statusDescription); printf( "Expected error code %d and message %s\n", FITTOPULSARH_ENULLPARAMS, FITTOPULSARH_MSGENULLPARAMS); return FITTOPULSARTESTC_ECHK; } /* try having two input vectors of different length */ input.var->length = 1; LALCoarseFitToPulsar(&status, &output, &input, ¶ms); if (status.statusCode != FITTOPULSARH_EVECSIZE || strcmp(status.statusDescription, FITTOPULSARH_MSGEVECSIZE)) { printf( "Got error code %d and message %s\n", status.statusCode, status.statusDescription); printf( "Expected error code %d and message %s\n", FITTOPULSARH_EVECSIZE, FITTOPULSARH_MSGEVECSIZE); return FITTOPULSARTESTC_ECHK; } input.var->length = FITTOPULSARTEST_LENGTH; } /* if ( ! lalNoDebug ) */ #endif /* LAL_NDEBUG */ /******* CLEAN UP ************/ LALZDestroyVector(&status, &input.B); LALZDestroyVector(&status, &input.var); LALDestroyVector(&status, &noise); LALDDestroyVector(&status, &output.mChiSquare); LALDestroyRandomParams(&status, &randomParams); LALSDestroyVector(&status, &(pResponseSeries.pPlus->data)); LALSDestroyVector(&status, &(pResponseSeries.pCross->data)); LALSDestroyVector(&status, &(pResponseSeries.pScalar->data)); LALCheckMemoryLeaks(); return FITTOPULSARTESTC_ENOM; }