SimulateCoherentGW.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Jolien Creighton, Reinhard Prix, Stephen Fairhurst, Teviet Creighton
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /*************************** <lalVerbatim file="SimulateCoherentGWCV">
00021 Author: Creighton, T. D.
00022 $Id: SimulateCoherentGW.c,v 1.36 2007/06/08 14:41:47 bema Exp $
00023 **************************************************** </lalVerbatim> */
00024 
00025 /********************************************************** <lalLaTeX>
00026 
00027 \providecommand{\lessim}{\stackrel{<}{\scriptstyle\sim}}
00028 
00029 \subsection{Module \texttt{SimulateCoherentGW.c}}
00030 \label{ss:SimulateCoherentGW.c}
00031 
00032 Computes the response of a detector to a coherent gravitational wave.
00033 
00034 \subsubsection*{Prototypes}
00035 \vspace{0.1in}
00036 \input{SimulateCoherentGWCP}
00037 \idx{LALSimulateCoherentGW()}
00038 
00039 \subsubsection*{Description}
00040 
00041 This function takes a quasiperiodic gravitational waveform given in
00042 \verb@*signal@, and estimates the corresponding response of the
00043 detector whose position, orientation, and transfer function are
00044 specified in \verb@*detector@.  The result is stored in
00045 \verb@*output@.
00046 
00047 The fields \verb@output->epoch@, \verb@output->deltaT@, and
00048 \verb@output->data@ must already be set, in order to specify the time
00049 period and sampling rate for which the response is required.  If
00050 \verb@output->f0@ is nonzero, idealized heterodyning is performed (an
00051 amount $2\pi f_0(t-t_0)$ is subtracted from the phase before computing
00052 the sinusoid, where $t_0$ is the heterodyning epoch defined in
00053 \verb@detector@).  For the input signal, \verb@signal->h@ is ignored,
00054 and the signal is treated as zero at any time for which either
00055 \verb@signal->a@ or \verb@signal->phi@ is not defined.
00056 
00057 This routine will convert \verb@signal->position@ to equatorial
00058 coordinates, if necessary.
00059 
00060 \subsubsection*{Algorithm}
00061 
00062 The routine first accounts for the time delay between the detector and
00063 the solar system barycentre, based on the detector position
00064 information stored in \verb@*detector@ and the propagation direction
00065 specified in \verb@*signal@.  Values of the propagation delay are
00066 precomuted at fixed intervals and stored in a table, with the
00067 intervals $\Delta T_\mathrm{delay}$ chosen such that the value
00068 interpolated from adjacent table entries will never differ from the
00069 true value by more than some timing error $\sigma_T$.  This implies
00070 that:
00071 $$
00072 \Delta T_\mathrm{delay} \leq \sqrt{
00073         \frac{8\sigma_T}{\max\{a/c\}} } \; ,
00074 $$
00075 where $\max\{a/c\}=1.32\times10^{-10}\mathrm{s}^{-1}$ is the maximum
00076 acceleration of an Earth-based detector in the barycentric frame.  The
00077 total propagation delay also includes Einstein and Shapiro delay, but
00078 these are more slowly varying and thus do not constrain the table
00079 spacing.  At present, a 400s table spacing is hardwired into the code,
00080 implying $\sigma_T\approx3\mu$s, comparable to the stated accuracy of
00081 \verb@LALBarycenter()@.
00082 
00083 Next, the polarization response functions of the detector
00084 $F_{+,\times}(\alpha,\delta)$ are computed for every 10~minutes of the
00085 signal's duration, using the position of the source in \verb@*signal@,
00086 the detector information in \verb@*detector@, and the function
00087 \verb@LALComputeDetAMResponseSeries()@.  Subsequently, the
00088 polarization functions are estimated for each output sample by
00089 interpolating these precomputed values.  This guarantees that the
00090 interpolated value is accurate to $\sim0.1\%$.
00091 
00092 Next, the frequency response of the detector is estimated in the
00093 quasiperiodic limit as follows:
00094 \begin{itemize}
00095 \item At each sample point in \verb@*output@, the propagation delay is
00096 computed and added to the sample time, and the instantaneous
00097 amplitudes $A_1$, $A_2$, frequency $f$, phase $\phi$, and polarization
00098 shift $\Phi$ are found by interpolating the nearest values in
00099 \verb@signal->a@, \verb@signal->f@, \verb@signal->phi@, and
00100 \verb@signal->shift@, respectively.  If \verb@signal->f@ is not
00101 defined at that point in time, then $f$ is estimated by differencing
00102 the two nearest values of $\phi$, as $f\approx\Delta\phi/2\pi\Delta
00103 t$.  If \verb@signal->shift@ is not defined, then $\Phi$ is treated as
00104 zero.
00105 \item The complex transfer function of the detector the frequency $f$
00106 is found by interpolating \verb@detector->transfer@.  The amplitude of
00107 the transfer function is multiplied with $A_1$ and $A_2$, and the
00108 phase of the transfer function is added to $\phi$,
00109 \item The plus and cross contributions $o_+$, $o_\times$ to the
00110 detector output are computed as in Eqs.~\ref{eq:quasiperiodic-hplus}
00111 and~\ref{eq:quasiperiodic-hcross} of \verb@SimulateCoherentGW.h@, but
00112 using the response-adjusted amplitudes and phase.
00113 \item The final detector response $o$ is computed as
00114 $o=(o_+F_+)+(o_\times F_\times)$.
00115 \end{itemize}
00116 
00117 \paragraph{A note on interpolation:}
00118 Much of the computational work in this routine involves interpolating
00119 various time series to find their values at specific output times.
00120 The algorithm is summarized below.
00121 
00122 Let $A_j = A( t_A + j\Delta t_A )$ be a sampled time series, which we
00123 want to resample at new (output) time intervals $t_k = t_0 + k\Delta
00124 t$.  We first precompute the following quantities:
00125 \begin{eqnarray}
00126 t_\mathrm{off} & = & \frac{t_0-t_A}{\Delta t_A}  \; , \nonumber \\
00127             dt & = & \frac{\Delta t}{\Delta t_A} \; . \nonumber
00128 \end{eqnarray}
00129 Then, for each output sample time $t_k$, we compute:
00130 \begin{eqnarray}
00131 t & = & t_\mathrm{off} + k \times dt \; , \nonumber \\
00132 j & = & \lfloor t \rfloor            \; , \nonumber \\
00133 f & = & t - j                        \; , \nonumber
00134 \end{eqnarray}
00135 where $\lfloor x\rfloor$ is the ``floor'' function; i.e.\ the largest
00136 integer $\leq x$.  The time series sampled at the new time is then:
00137 $$
00138 A(t_k) = f \times A_{j+1} + (1-f) \times A_j \; .
00139 $$
00140 
00141 \subsubsection*{Uses}
00142 \begin{verbatim}
00143 LALWarning()                    LALInfo()
00144 LALSCreateVector()              LALSDestroyVector()
00145 LALDCreateVector()              LALDDestroyVector()
00146 LALConvertSkyCoordinates()      LALGeocentricToGeodetic()
00147 LALCVectorAbs()                 LALCVectorAngle()
00148 LALUnwrapREAL4Angle()
00149 \end{verbatim}
00150 
00151 \subsubsection*{Notes}
00152 
00153 The major computational hit in this routine comes from computing the
00154 sine and cosine of the phase angle in
00155 Eqs.~\ref{eq:quasiperiodic-hplus} and~\ref{eq:quasiperiodic-hcross} of
00156 \verb@SimulateCoherentGW.h@.  For better online performance, these can
00157 be replaced by other (approximate) trig functions.  Presently the code
00158 uses the native \verb@libm@ functions by default, or the function
00159 \verb@sincosp()@ in \verb@libsunmath@ \emph{if} this function is
00160 available \emph{and} the constant \verb@ONLINE@ is defined.
00161 Differences at the level of 0.01 begin to appear only for phase
00162 arguments greater than $10^{14}$ or so (corresponding to over 500
00163 years between phase epoch and observation time for frequencies of
00164 around 1kHz).
00165 
00166 To activate this feature, be sure that \verb@sunmath.h@ and
00167 \verb@libsunmath@ are on your system, and add \verb@-DONLINE@ to the
00168 \verb@--with-extra-cppflags@ configuration argument.  In future this
00169 flag may be used to turn on other efficient trig algorithms on other
00170 (non-Solaris) platforms.
00171 
00172 \vfill{\footnotesize\input{SimulateCoherentGWCV}}
00173 
00174 ******************************************************* </lalLaTeX> */
00175 
00176 /* Use more efficient trig routines for solaris, if available and
00177    requested. */
00178 #include <config.h>
00179 #ifdef HAVE_SUNMATH_H
00180 #include <sunmath.h>
00181 #if defined HAVE_LIBSUNMATH && defined ONLINE
00182 #define USE_SINCOSP 1
00183 #endif
00184 #endif     
00185 
00186 #include <math.h>
00187 #include <lal/LALStdio.h>
00188 #include <lal/LALStdlib.h>
00189 #include <lal/LALError.h>
00190 #include <lal/DetectorSite.h>
00191 #include <lal/DetResponse.h>
00192 #include <lal/AVFactories.h>
00193 #include <lal/Date.h>
00194 #include <lal/Units.h>
00195 #include <lal/TimeDelay.h>
00196 #include <lal/LALBarycenter.h>
00197 #include <lal/VectorOps.h>
00198 #include <lal/SimulateCoherentGW.h>
00199 #include <lal/SkyCoordinates.h>
00200 
00201 /* A macro that takes a detector time (in units of output->deltaT from
00202    output->epoch) and adds the propagation time interpolated from the
00203    delays tabulated in delayData.  The following parameters are
00204    required to be defined outside the macro, and are set by it:
00205 
00206    REAL4 realIndex;  the interpolation point in delayData
00207    INT4 intIndex;    the index immediately preceding realIndex
00208    REAL4 indexFrac;  the value realIndex - intIndex */
00209 #define TCENTRE( time )                                              \
00210 (                                                                    \
00211  realIndex = delayOff + (time)*delayDt,                              \
00212  intIndex = (INT4)floor( realIndex ),                                \
00213  indexFrac = realIndex - intIndex,                                   \
00214  time + indexFrac*delayData[intIndex+1]                              \
00215  + (1.0-indexFrac)*delayData[intIndex]                               \
00216 )
00217 
00218 
00219 NRCSID( SIMULATECOHERENTGWC, "$Id: SimulateCoherentGW.c,v 1.36 2007/06/08 14:41:47 bema Exp $" );
00220 
00221 /* <lalVerbatim file="SimulateCoherentGWCP"> */
00222 void
00223 LALSimulateCoherentGW( LALStatus        *stat,
00224                        REAL4TimeSeries  *output,
00225                        CoherentGW       *signal,
00226                        DetectorResponse *detector )
00227 { /* </lalVerbatim> */
00228   INT4 i, n;          /* index over output->data, and its final value */
00229   INT4 nMax;          /* used to store limits on index ranges */
00230   INT4 fInit, fFinal; /* index range for which signal->f is defined */
00231   INT4 shiftInit, shiftFinal; /* ditto for signal->shift */
00232   UINT4 dtDelayBy2 = 400;     /* delay table half-interval (s) */
00233   UINT4 dtPolBy2 = 300;       /* polarization table half-interval (s) */
00234   REAL4 *outData;             /* pointer to output data */
00235   REAL8 delayMin, delayMax;   /* min and max values of time delay */
00236   SkyPosition source;         /* source sky position */
00237   BOOLEAN transfer;  /* 1 if transfer function is specified */
00238   BOOLEAN fFlag = 0; /* 1 if frequency left detector->transfer range */
00239   BOOLEAN pFlag = 0; /* 1 if frequency was estimated from phase */
00240 
00241   /* The amplitude, frequency, phase, polarization shift, polarization
00242      response, and propagation delay are stored in arrays that must be
00243      interpolated.  For a quantity x, we define a pointer xData to the
00244      data array.  At some time t measured in units of output->deltaT,
00245      the interpolation point in xData is given by ( xOff + t*xDt ),
00246      where xOff is an offset and xDt is a relative sampling rate. */
00247   LALDetAMResponseSeries polResponse;
00248   REAL8Vector *delay = NULL;
00249   REAL4 *aData, *fData, *shiftData, *plusData, *crossData;
00250   REAL8 *phiData, *delayData;
00251   REAL8 aOff, fOff, phiOff, shiftOff, polOff, delayOff;
00252   REAL8 aDt, fDt, phiDt, shiftDt, polDt, delayDt;
00253 
00254   /* Frequencies in the detector transfer function are interpolated
00255      similarly, except everything is normalized with respect to
00256      detector->transfer->deltaF. */
00257   REAL4Vector *aTransfer = NULL;
00258   REAL4Vector *phiTransfer = NULL;
00259   REAL4Vector *phiTemp = NULL;
00260   REAL4 *aTransData = NULL, *phiTransData = NULL;
00261   REAL8 f0 = 1.0;
00262   REAL8 phiFac = 1.0, fFac = 1.0;
00263 
00264   /* Heterodyning phase factor LAL_TWOPI*output->f0*output->deltaT,
00265      and phase offset at the start of the series
00266      LAL_TWOPI*output->f0*(time offset). */
00267   REAL8 heteroFac, phi0;
00268 
00269   /* Variables required by the TCENTRE() macro, above. */
00270   REAL8 realIndex;
00271   INT4 intIndex;
00272   REAL8 indexFrac;
00273 
00274   INITSTATUS( stat, "LALSimulateCoherentGW", SIMULATECOHERENTGWC );
00275   ATTATCHSTATUSPTR( stat );
00276 
00277   /* Make sure parameter structures and their fields exist. */
00278   ASSERT( signal, stat, SIMULATECOHERENTGWH_ENUL,
00279           SIMULATECOHERENTGWH_MSGENUL );
00280   if ( !( signal->a ) ) {
00281     ABORT( stat, SIMULATECOHERENTGWH_ESIG,
00282            SIMULATECOHERENTGWH_MSGESIG );
00283   }
00284   ASSERT( signal->a->data, stat,
00285           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00286   ASSERT( signal->a->data->data, stat,
00287           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00288   if ( !( signal->phi ) ) {
00289     ABORT( stat, SIMULATECOHERENTGWH_ESIG,
00290            SIMULATECOHERENTGWH_MSGESIG );
00291   }
00292   ASSERT( signal->phi->data, stat,
00293           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00294   ASSERT( signal->phi->data->data, stat,
00295           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00296   if ( signal->f ) {
00297     ASSERT( signal->f->data, stat,
00298             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00299     ASSERT( signal->f->data->data, stat,
00300             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00301   }
00302   if ( signal->shift ) {
00303     ASSERT( signal->shift->data, stat,
00304             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00305     ASSERT( signal->shift->data->data, stat,
00306             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00307   }
00308   ASSERT( detector, stat,
00309           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00310   if ( ( transfer = ( detector->transfer != NULL ) ) ) {
00311     ASSERT( detector->transfer->data, stat,
00312             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00313     ASSERT( detector->transfer->data->data, stat,
00314             SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00315   }
00316   ASSERT( output, stat,
00317           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00318   ASSERT( output->data, stat,
00319           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00320   ASSERT( output->data->data, stat,
00321           SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
00322 
00323   /* Check dimensions of amplitude array. */
00324   ASSERT( signal->a->data->vectorLength == 2, stat,
00325           SIMULATECOHERENTGWH_EDIM, SIMULATECOHERENTGWH_MSGEDIM );
00326 
00327   /* Make sure we never divide by zero. */
00328   ASSERT( signal->a->deltaT != 0.0, stat,
00329           SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00330   ASSERT( signal->phi->deltaT != 0.0, stat,
00331           SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00332   aDt = output->deltaT / signal->a->deltaT;
00333   phiDt = output->deltaT / signal->phi->deltaT;
00334   ASSERT( aDt != 0.0, stat,
00335           SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00336   ASSERT( phiDt != 0.0, stat,
00337           SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00338   if ( signal->f ) {
00339     ASSERT( signal->f->deltaT != 0.0, stat,
00340             SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00341     fDt = output->deltaT / signal->f->deltaT;
00342     ASSERT( fDt != 0.0, stat,
00343             SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00344   } else
00345     fDt = 0.0;
00346   if ( signal->shift ) {
00347     ASSERT( signal->shift->deltaT != 0.0, stat,
00348             SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00349     shiftDt = output->deltaT / signal->shift->deltaT;
00350     ASSERT( shiftDt != 0.0, stat,
00351             SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00352   } else
00353     shiftDt = 0.0;
00354   if ( transfer ) {
00355     ASSERT( detector->transfer->deltaF != 0.0, stat,
00356             SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
00357     fFac = 1.0 / detector->transfer->deltaF;
00358     phiFac = fFac / ( LAL_TWOPI*signal->phi->deltaT );
00359     f0 = detector->transfer->f0/detector->transfer->deltaF;
00360   }
00361   heteroFac = LAL_TWOPI*output->f0*output->deltaT;
00362   phi0 = (REAL8)( output->epoch.gpsSeconds -
00363                   detector->heterodyneEpoch.gpsSeconds );
00364   phi0 += 0.000000001*(REAL8)( output->epoch.gpsNanoSeconds -
00365                                detector->heterodyneEpoch.gpsNanoSeconds );
00366   phi0 *= LAL_TWOPI*output->f0;
00367   if ( phi0 > 1.0/LAL_REAL8_EPS ) {
00368     LALWarning( stat, "REAL8 arithmetic is not sufficient to maintain"
00369                 " heterodyne phase to within a radian." );
00370   }
00371 
00372   /* Check units on input, and set units on output. */
00373   {
00374     BOOLEAN unitsOK;
00375     LALUnitPair pair;
00376 
00377     pair.unitOne = &(signal->f->sampleUnits);
00378     pair.unitTwo = &lalHertzUnit;
00379     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00380     ASSERT( unitsOK, stat, SIMULATECOHERENTGWH_EUNIT,
00381             SIMULATECOHERENTGWH_MSGEUNIT );
00382     pair.unitOne = &(signal->phi->sampleUnits);
00383     pair.unitTwo = &lalDimensionlessUnit;
00384     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00385     ASSERT( unitsOK, stat, SIMULATECOHERENTGWH_EUNIT,
00386             SIMULATECOHERENTGWH_MSGEUNIT );
00387     if( signal->shift ) {
00388       pair.unitOne = &(signal->shift->sampleUnits);
00389       TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00390       ASSERT( unitsOK, stat, SIMULATECOHERENTGWH_EUNIT,
00391               SIMULATECOHERENTGWH_MSGEUNIT );
00392     }
00393     if ( transfer ) {
00394       pair.unitOne = &(signal->a->sampleUnits);
00395       pair.unitTwo = &(detector->transfer->sampleUnits);
00396       TRY( LALUnitMultiply( stat->statusPtr, &(output->sampleUnits),
00397                             &pair ), stat );
00398     } else
00399       output->sampleUnits = signal->a->sampleUnits;
00400     LALSnprintf( output->name, LALNameLength, "response to %s",
00401                  signal->a->name );
00402   }
00403 
00404   /* Define temporary variables to access the data of signal->a,
00405      signal->f, and signal->phi. */
00406   aData = signal->a->data->data;
00407   phiData = signal->phi->data->data;
00408   outData = output->data->data;
00409   if ( signal->f )
00410     fData = signal->f->data->data;
00411   else
00412     fData = NULL;
00413   if ( signal->shift )
00414     shiftData = signal->shift->data->data;
00415   else
00416     shiftData = NULL;
00417 
00418   /* Convert source position to equatorial coordinates, if
00419      required. */
00420   if ( detector->site ) {
00421     source = signal->position;
00422     if ( source.system != COORDINATESYSTEM_EQUATORIAL ) {
00423       ConvertSkyParams params; /* parameters for conversion */
00424       EarthPosition location;  /* location of detector */
00425       params.gpsTime = &( output->epoch );
00426       params.system = COORDINATESYSTEM_EQUATORIAL;
00427       if ( source.system == COORDINATESYSTEM_HORIZON ) {
00428         params.zenith = &( location.geodetic );
00429         location.x = detector->site->location[0];
00430         location.y = detector->site->location[1];
00431         location.z = detector->site->location[2];
00432         TRY( LALGeocentricToGeodetic( stat->statusPtr, &location ),
00433              stat );
00434       }
00435       TRY( LALConvertSkyCoordinates( stat->statusPtr, &source,
00436                                      &source, &params ), stat );
00437     }
00438   } 
00439 
00440   /* Generate the table of propagation delays.
00441   dtDelayBy2 = (UINT4)( 38924.9/sqrt( output->f0 +
00442                                       1.0/output->deltaT ) ); */
00443   delayDt = output->deltaT/( 2.0*dtDelayBy2 );
00444   nMax = (UINT4)( output->data->length*delayDt ) + 3;
00445   TRY( LALDCreateVector( stat->statusPtr, &delay, nMax ), stat );
00446   delayData = delay->data;
00447 
00448   /* Compute delay from solar system barycentre. */
00449   if ( detector->site && detector->ephemerides ) {
00450     LIGOTimeGPS gpsTime;   /* detector time when we compute delay */
00451     EarthState state;      /* Earth position info at that time */
00452     BarycenterInput input; /* input structure to LALBarycenter() */
00453     EmissionTime emit;     /* output structure from LALBarycenter() */
00454 
00455     /* Arrange nested pointers, and set initial values. */
00456     gpsTime = input.tgps = output->epoch;
00457     gpsTime.gpsSeconds -= dtDelayBy2;
00458     input.tgps.gpsSeconds -= dtDelayBy2;
00459     input.site = *(detector->site);
00460     for ( i = 0; i < 3; i++ )
00461       input.site.location[i] /= LAL_C_SI;
00462     input.alpha = source.longitude;
00463     input.delta = source.latitude;
00464     input.dInv = 0.0;
00465     delayMin = delayMax = 1.1*LAL_AU_SI/( LAL_C_SI*output->deltaT );
00466     delayMax *= -1;
00467 
00468     /* Compute table. */
00469     for ( i = 0; i < nMax; i++ ) {
00470       REAL8 tDelay; /* propagation time */
00471       LALBarycenterEarth( stat->statusPtr, &state, &gpsTime,
00472                           detector->ephemerides );
00473       BEGINFAIL( stat )
00474         TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00475       ENDFAIL( stat );
00476       LALBarycenter( stat->statusPtr, &emit, &input, &state );
00477       BEGINFAIL( stat )
00478         TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00479       ENDFAIL( stat );
00480       delayData[i] = tDelay = emit.deltaT/output->deltaT;
00481       if ( tDelay < delayMin )
00482         delayMin = tDelay;
00483       if ( tDelay > delayMax )
00484         delayMax = tDelay;
00485       gpsTime.gpsSeconds += 2*dtDelayBy2;
00486       input.tgps.gpsSeconds += 2*dtDelayBy2;
00487     }
00488   }
00489 
00490   /* Compute delay from Earth centre. */
00491   else if ( detector->site ) {
00492     LIGOTimeGPS gpsTime;     /* detector time when we compute delay */
00493     LALPlaceAndGPS event;    /* spacetime point where we compute delay */
00494     DetTimeAndASource input; /* input to time delay function */
00495 
00496     LALInfo( stat, "Ephemeris field absent; computing propagation"
00497              " delays from Earth centre" );
00498 
00499     /* Arrange nested pointers, and set initial values. */
00500     event.p_detector = detector->site;
00501     event.p_gps = &gpsTime;
00502     input.p_det_and_time = &event;
00503     input.p_source = &source;
00504     gpsTime = output->epoch;
00505     gpsTime.gpsSeconds -= dtDelayBy2;
00506     delayMin = delayMax = LAL_REARTH_SI / ( LAL_C_SI*output->deltaT );
00507     delayMin *= -1;
00508 
00509     /* Compute table. */
00510     for ( i = 0; i < nMax; i++ ) {
00511       REAL8 tDelay; /* propagation time */
00512       LALTimeDelayFromEarthCenter( stat->statusPtr, &tDelay, &input );
00513       BEGINFAIL( stat )
00514         TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00515       ENDFAIL( stat );
00516       /* TimeDelayFromEarthCenter() measures propagation delay from
00517          geocentre to detector, which is the opposite of what we want.
00518          We also want it normalized. */
00519       tDelay /= -output->deltaT;
00520       delayData[i] = tDelay;
00521       if ( tDelay < delayMin )
00522         delayMin = tDelay;
00523       if ( tDelay > delayMax )
00524         delayMax = tDelay;
00525       gpsTime.gpsSeconds += 2*dtDelayBy2;
00526     }
00527   }
00528 
00529   /* No information from which to compute delays. */
00530   else {
00531     LALInfo( stat, "Detector site absent; simulating hplus with no"
00532              " propagation delays" );
00533     memset( delayData, 0, nMax*sizeof(REAL8) );
00534     delayMin = delayMax = 0.0;
00535   }
00536 
00537   /* Generate the table of polarization response functions. */
00538   polDt = output->deltaT/( 2.0*dtPolBy2 );
00539   nMax = (UINT4)( output->data->length*polDt ) + 3;
00540   memset( &polResponse, 0, sizeof( LALDetAMResponseSeries ) );
00541   polResponse.pPlus = (REAL4TimeSeries *)
00542     LALMalloc( sizeof(REAL4TimeSeries) );
00543   polResponse.pCross = (REAL4TimeSeries *)
00544     LALMalloc( sizeof(REAL4TimeSeries) );
00545   polResponse.pScalar = (REAL4TimeSeries *)
00546     LALMalloc( sizeof(REAL4TimeSeries) );
00547   if ( !polResponse.pPlus || !polResponse.pCross ||
00548        !polResponse.pScalar ) {
00549     if ( polResponse.pPlus )
00550       LALFree( polResponse.pPlus );
00551     if ( polResponse.pCross )
00552       LALFree( polResponse.pCross );
00553     if ( polResponse.pScalar )
00554       LALFree( polResponse.pScalar );
00555     TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00556     ABORT( stat, SIMULATECOHERENTGWH_EMEM,
00557            SIMULATECOHERENTGWH_MSGEMEM );
00558   }
00559   memset( polResponse.pPlus, 0, sizeof(REAL4TimeSeries) );
00560   memset( polResponse.pCross, 0, sizeof(REAL4TimeSeries) );
00561   memset( polResponse.pScalar, 0, sizeof(REAL4TimeSeries) );
00562   LALSCreateVector( stat->statusPtr, &( polResponse.pPlus->data ),
00563                     nMax );
00564   BEGINFAIL( stat ) {
00565     LALFree( polResponse.pPlus );
00566     LALFree( polResponse.pCross );
00567     LALFree( polResponse.pScalar );
00568     TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00569   } ENDFAIL( stat );
00570   LALSCreateVector( stat->statusPtr, &( polResponse.pCross->data ),
00571                     nMax );
00572   BEGINFAIL( stat ) {
00573     TRY( LALSDestroyVector( stat->statusPtr,
00574                             &( polResponse.pPlus->data ) ), stat );
00575     LALFree( polResponse.pPlus );
00576     LALFree( polResponse.pCross );
00577     LALFree( polResponse.pScalar );
00578     TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00579   } ENDFAIL( stat );
00580   LALSCreateVector( stat->statusPtr, &( polResponse.pScalar->data ),
00581                     nMax );
00582   BEGINFAIL( stat ) {
00583     TRY( LALSDestroyVector( stat->statusPtr,
00584                             &( polResponse.pPlus->data ) ), stat );
00585     TRY( LALSDestroyVector( stat->statusPtr,
00586                             &( polResponse.pCross->data ) ), stat );
00587     LALFree( polResponse.pPlus );
00588     LALFree( polResponse.pCross );
00589     LALFree( polResponse.pScalar );
00590     TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00591   } ENDFAIL( stat );
00592   plusData = polResponse.pPlus->data->data;
00593   crossData = polResponse.pCross->data->data;
00594   if ( detector->site ) {
00595     LALSource polSource;     /* position and polarization angle */
00596     LALDetAndSource input;            /* response input structure */
00597     LALTimeIntervalAndNSample params; /* response parameter structure */
00598 
00599     /* Arrange nested pointers, and set initial values. */
00600     polSource.equatorialCoords = source;
00601     polSource.orientation = (REAL8)( signal->psi );
00602     input.pSource = &polSource;
00603     input.pDetector = detector->site;
00604     params.epoch = output->epoch;
00605     params.epoch.gpsSeconds -= dtPolBy2;
00606     params.deltaT = 2.0*dtPolBy2;
00607     params.nSample = nMax;
00608     params.accuracy = LALLEAPSEC_STRICT;
00609 
00610     /* Compute table of responses. */
00611     LALComputeDetAMResponseSeries( stat->statusPtr, &polResponse,
00612                                    &input, &params );
00613     BEGINFAIL( stat ) {
00614       TRY( LALSDestroyVector( stat->statusPtr,
00615                               &( polResponse.pPlus->data ) ), stat );
00616       TRY( LALSDestroyVector( stat->statusPtr,
00617                               &( polResponse.pCross->data ) ), stat );
00618       TRY( LALSDestroyVector( stat->statusPtr,
00619                               &( polResponse.pScalar->data ) ), stat );
00620       LALFree( polResponse.pPlus );
00621       LALFree( polResponse.pCross );
00622       LALFree( polResponse.pScalar );
00623       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00624     } ENDFAIL( stat );
00625   } else {
00626     /* No detector site, so just simulate response to hplus. */
00627     for ( i = 0; i < nMax; i++ ) {
00628       plusData[i] = 1.0;
00629       crossData[i] = 0.0;
00630     }
00631   }
00632   /* Free memory for the unused scalar mode. */
00633   TRY( LALSDestroyVector( stat->statusPtr,
00634                           &( polResponse.pScalar->data ) ), stat );
00635   LALFree( polResponse.pScalar );
00636 
00637   /* Decompose the transfer function into an amplitude and phase
00638      response. */
00639   if ( transfer ) {
00640     nMax = detector->transfer->data->length;
00641     LALSCreateVector( stat->statusPtr, &phiTemp, nMax );
00642     BEGINFAIL( stat ) {
00643       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00644       TRY( LALSDestroyVector( stat->statusPtr,
00645                               &( polResponse.pPlus->data ) ), stat );
00646       TRY( LALSDestroyVector( stat->statusPtr,
00647                               &( polResponse.pCross->data ) ), stat );
00648       LALFree( polResponse.pPlus );
00649       LALFree( polResponse.pCross );
00650     } ENDFAIL( stat );
00651     LALCVectorAngle( stat->statusPtr, phiTemp,
00652                      detector->transfer->data );
00653     BEGINFAIL( stat ) {
00654       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00655       TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
00656       TRY( LALSDestroyVector( stat->statusPtr,
00657                               &( polResponse.pPlus->data ) ), stat );
00658       TRY( LALSDestroyVector( stat->statusPtr,
00659                               &( polResponse.pCross->data ) ), stat );
00660       LALFree( polResponse.pPlus );
00661       LALFree( polResponse.pCross );
00662     } ENDFAIL( stat );
00663     LALSCreateVector( stat->statusPtr, &phiTransfer, nMax );
00664     BEGINFAIL( stat ) {
00665       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00666       TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
00667       TRY( LALSDestroyVector( stat->statusPtr,
00668                               &( polResponse.pPlus->data ) ), stat );
00669       TRY( LALSDestroyVector( stat->statusPtr,
00670                               &( polResponse.pCross->data ) ), stat );
00671       LALFree( polResponse.pPlus );
00672       LALFree( polResponse.pCross );
00673     } ENDFAIL( stat );
00674     LALUnwrapREAL4Angle( stat->statusPtr, phiTransfer, phiTemp );
00675     BEGINFAIL( stat ) {
00676       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00677       TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
00678       TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
00679       TRY( LALSDestroyVector( stat->statusPtr,
00680                               &( polResponse.pPlus->data ) ), stat );
00681       TRY( LALSDestroyVector( stat->statusPtr,
00682                               &( polResponse.pCross->data ) ), stat );
00683       LALFree( polResponse.pPlus );
00684       LALFree( polResponse.pCross );
00685     } ENDFAIL( stat );
00686     TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
00687     LALSCreateVector( stat->statusPtr, &aTransfer, nMax );
00688     BEGINFAIL( stat ) {
00689       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00690       TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
00691       TRY( LALSDestroyVector( stat->statusPtr,
00692                               &( polResponse.pPlus->data ) ), stat );
00693       TRY( LALSDestroyVector( stat->statusPtr,
00694                               &( polResponse.pCross->data ) ), stat );
00695       LALFree( polResponse.pPlus );
00696       LALFree( polResponse.pCross );
00697     } ENDFAIL( stat );
00698     LALCVectorAbs( stat->statusPtr, aTransfer,
00699                    detector->transfer->data );
00700     BEGINFAIL( stat ) {
00701       TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
00702       TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
00703       TRY( LALSDestroyVector( stat->statusPtr, &aTransfer ), stat );
00704       TRY( LALSDestroyVector( stat->statusPtr,
00705                               &( polResponse.pPlus->data ) ), stat );
00706       TRY( LALSDestroyVector( stat->statusPtr,
00707                               &( polResponse.pCross->data ) ), stat );
00708       LALFree( polResponse.pPlus );
00709       LALFree( polResponse.pCross );
00710     } ENDFAIL( stat );
00711     phiTransData = phiTransfer->data;
00712     aTransData = aTransfer->data;
00713   }
00714 
00715   /* Compute offsets for interpolating the signal, delay, and
00716      response functions. */
00717   aOff = ( output->epoch.gpsSeconds -
00718            signal->a->