SimulateCoherentGWNew.c

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