LALPulsar  6.1.0.1-b72065a
PulsarSimulateCoherentGW.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Jolien Creighton, Reinhard Prix, Stephen Fairhurst, Teviet Creighton
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with with program; see the file COPYING. If not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  */
19 
20 #include <math.h>
21 #include <lal/LALStdio.h>
22 #include <lal/LALStdlib.h>
23 #include <lal/LALError.h>
24 #include <lal/DetectorSite.h>
25 #include <lal/DetResponse.h>
26 #include <lal/AVFactories.h>
27 #include <lal/Date.h>
28 #include <lal/Units.h>
29 #include <lal/TimeDelay.h>
30 #include <lal/LALBarycenter.h>
31 #include <lal/VectorOps.h>
32 #include <lal/PulsarSimulateCoherentGW.h>
33 #include <lal/SkyCoordinates.h>
34 #include <lal/SinCosLUT.h>
35 
36 /** \name Error Codes */
37 /** @{ */
38 #define SIMULATECOHERENTGWH_ENUL 1 /**< Unexpected null pointer in arguments */
39 #define SIMULATECOHERENTGWH_EBAD 2 /**< A sampling interval is (effectively) zero */
40 #define SIMULATECOHERENTGWH_ESIG 3 /**< Input signal must specify amplitude and phase functions */
41 #define SIMULATECOHERENTGWH_EDIM 4 /**< Amplitude must be a 2-dimensional vector */
42 #define SIMULATECOHERENTGWH_EMEM 5 /**< Memory allocation error */
43 #define SIMULATECOHERENTGWH_EUNIT 6 /**< Bad input units */
44 /** @} */
45 
46 /** \cond DONT_DOXYGEN */
47 #define SIMULATECOHERENTGWH_MSGENUL "Unexpected null pointer in arguments"
48 #define SIMULATECOHERENTGWH_MSGEBAD "A sampling interval is (effectively) zero"
49 #define SIMULATECOHERENTGWH_MSGESIG "Input signal must specify amplitude and phase functions"
50 #define SIMULATECOHERENTGWH_MSGEDIM "Amplitude must be a 2-dimensional vector"
51 #define SIMULATECOHERENTGWH_MSGEMEM "Memory allocation error"
52 #define SIMULATECOHERENTGWH_MSGEUNIT "Bad input units"
53 /** \endcond */
54 
55 /**
56  * FIXME: Temporary XLAL-wapper to LAL-function LALPulsarSimulateCoherentGW()
57  *
58  * NOTE: This violates the current version of the XLAL-spec, but is unavoidable at this time,
59  * as LALPulsarSimulateCoherentGW() hasn't been properly XLALified yet, and doing this would be beyond
60  * the scope of this patch.
61  * However, doing it here in this way is better than calling LALxxx() from various
62  * far-flung XLAL-functions, as in this way the "violation" is localized in one place, and serves
63  * as a reminder for future XLAL-ification at the same time.
64  */
65 int
66 XLALPulsarSimulateCoherentGW( REAL4TimeSeries *output, ///< [in/out] output timeseries
67  PulsarCoherentGW *CWsignal, ///< [in] internal signal representation
68  PulsarDetectorResponse *detector ///< [in] detector response
69  )
70 {
71  XLAL_CHECK( output != NULL, XLAL_EINVAL );
72  XLAL_CHECK( CWsignal != NULL, XLAL_EINVAL );
73  XLAL_CHECK( detector != NULL, XLAL_EINVAL );
74 
76 
78 
79  XLAL_CHECK( status.statusCode == 0, XLAL_EFAILED, "LALPulsarSimulateCoherentGW() failed with code=%d, msg='%s'\n", status.statusCode, status.statusDescription );
80 
81  return XLAL_SUCCESS;
82 
83 } // XLALPulsarSimulateCoherentGW()
84 
85 
86 
87 /* A macro that takes a detector time (in units of output->deltaT from
88  output->epoch) and adds the propagation time interpolated from the
89  delays tabulated in delayData. The following parameters are
90  required to be defined outside the macro, and are set by it:
91 
92  REAL4 realIndex; the interpolation point in delayData
93  INT4 intIndex; the index immediately preceding realIndex
94  REAL4 indexFrac; the value realIndex - intIndex */
95 #define TCENTRE( time ) \
96  ( \
97  realIndex = delayOff + (time)*delayDt, \
98  intIndex = (INT4)floor( realIndex ), \
99  indexFrac = realIndex - intIndex, \
100  time + indexFrac*delayData[intIndex+1] \
101  + (1.0-indexFrac)*delayData[intIndex] \
102  )
103 
104 /**
105  * \author Creighton, T. D.
106  *
107  * \brief Computes the response of a detector to a coherent gravitational wave.
108  *
109  * This function takes a quasiperiodic gravitational waveform given in
110  * <tt>*signal</tt>, and estimates the corresponding response of the
111  * detector whose position, orientation, and transfer function are
112  * specified in <tt>*detector</tt>. The result is stored in
113  * <tt>*output</tt>.
114  *
115  * The fields <tt>output->epoch</tt>, <tt>output->deltaT</tt>, and
116  * <tt>output->data</tt> must already be set, in order to specify the time
117  * period and sampling rate for which the response is required. If
118  * <tt>output->f0</tt> is nonzero, idealized heterodyning is performed (an
119  * amount \f$ 2\pi f_0(t-t_0) \f$ is subtracted from the phase before computing
120  * the sinusoid, where \f$ t_0 \f$ is the heterodyning epoch defined in
121  * \c detector). For the input signal, <tt>signal->h</tt> is ignored,
122  * and the signal is treated as zero at any time for which either
123  * <tt>signal->a</tt> or <tt>signal->phi</tt> is not defined.
124  *
125  * This routine will convert <tt>signal->position</tt> to equatorial
126  * coordinates, if necessary.
127  *
128  * ### Algorithm ###
129  *
130  * The routine first accounts for the time delay between the detector and
131  * the solar system barycentre, based on the detector position
132  * information stored in <tt>*detector</tt> and the propagation direction
133  * specified in <tt>*signal</tt>. Values of the propagation delay are
134  * precomuted at fixed intervals and stored in a table, with the
135  * intervals \f$ \Delta T_\mathrm{delay} \f$ chosen such that the value
136  * interpolated from adjacent table entries will never differ from the
137  * true value by more than some timing error \f$ \sigma_T \f$ . This implies
138  * that:
139  * \f[
140  * \Delta T_\mathrm{delay} \leq \sqrt{
141  * \frac{8\sigma_T}{\max\{a/c\}} } \; ,
142  * \f]
143  * where \f$ \max\{a/c\}=1.32\times10^{-10}\mathrm{s}^{-1} \f$ is the maximum
144  * acceleration of an Earth-based detector in the barycentric frame. The
145  * total propagation delay also includes Einstein and Shapiro delay, but
146  * these are more slowly varying and thus do not constrain the table
147  * spacing. At present, a 400s table spacing is hardwired into the code,
148  * implying \f$ \sigma_T\approx3\mu \f$ s, comparable to the stated accuracy of
149  * <tt>LALBarycenter()</tt>.
150  *
151  * Next, the polarization response functions of the detector
152  * \f$ F_{+,\times}(\alpha,\delta) \f$ are computed for every 10 minutes of the
153  * signal's duration, using the position of the source in <tt>*signal</tt>,
154  * the detector information in <tt>*detector</tt>, and the function
155  * <tt>LALComputeDetAMResponseSeries()</tt>. Subsequently, the
156  * polarization functions are estimated for each output sample by
157  * interpolating these precomputed values. This guarantees that the
158  * interpolated value is accurate to \f$ \sim0.1\% \f$ .
159  *
160  * Next, the frequency response of the detector is estimated in the
161  * quasiperiodic limit as follows:
162  * <ul>
163  * <li> At each sample point in <tt>*output</tt>, the propagation delay is
164  * computed and added to the sample time, and the instantaneous
165  * amplitudes \f$ A_1 \f$ , \f$ A_2 \f$ , frequency \f$ f \f$ , phase \f$ \phi \f$ , and polarization
166  * shift \f$ \Phi \f$ are found by interpolating the nearest values in
167  * <tt>signal->a</tt>, <tt>signal->f</tt>, <tt>signal->phi</tt>, and
168  * <tt>signal->shift</tt>, respectively. If <tt>signal->f</tt> is not
169  * defined at that point in time, then \f$ f \f$ is estimated by differencing
170  * the two nearest values of \f$ \phi \f$ , as \f$ f\approx\Delta\phi/2\pi\Delta
171  * t \f$ . If <tt>signal->shift</tt> is not defined, then \f$ \Phi \f$ is treated as
172  * zero.</li>
173  * <li> The complex transfer function of the detector the frequency \f$ f \f$
174  * is found by interpolating <tt>detector->transfer</tt>. The amplitude of
175  * the transfer function is multiplied with \f$ A_1 \f$ and \f$ A_2 \f$ , and the
176  * phase of the transfer function is added to \f$ \phi \f$ ,</li>
177  * <li> The plus and cross contributions \f$ o_+ \f$ , \f$ o_\times \f$ to the
178  * detector output are computed as in \eqref{eq_quasiperiodic_hpluscross}
179  * of \ref PulsarSimulateCoherentGW_h, but
180  * using the response-adjusted amplitudes and phase.</li>
181  * <li> The final detector response \f$ o \f$ is computed as
182  * \f$ o=(o_+F_+)+(o_\times F_\times) \f$ .</li>
183  * </ul>
184  *
185  * ### A note on interpolation: ###
186  *
187  * Much of the computational work in this routine involves interpolating
188  * various time series to find their values at specific output times.
189  * The algorithm is summarized below.
190  *
191  * Let \f$ A_j = A( t_A + j\Delta t_A ) \f$ be a sampled time series, which we
192  * want to resample at new (output) time intervals \f$ t_k = t_0 + k\Delta
193  * t \f$ . We first precompute the following quantities:
194  * \f{eqnarray}{
195  * t_\mathrm{off} & = & \frac{t_0-t_A}{\Delta t_A} \; , \\
196  * dt & = & \frac{\Delta t}{\Delta t_A} \; .
197  * \f}
198  * Then, for each output sample time \f$ t_k \f$ , we compute:
199  * \f{eqnarray}{
200  * t & = & t_\mathrm{off} + k \times dt \; , \\
201  * j & = & \lfloor t \rfloor \; , \\
202  * f & = & t - j \; ,
203  * \f}
204  * where \f$ \lfloor x\rfloor \f$ is the "floor" function; i.e.\ the largest
205  * integer \f$ \leq x \f$ . The time series sampled at the new time is then:
206  * \f[
207  * A(t_k) = f \times A_{j+1} + (1-f) \times A_j \; .
208  * \f]
209  *
210  * ### Notes ###
211  *
212  * The major computational hit in this routine comes from computing the
213  * sine and cosine of the phase angle in
214  * \eqref{eq_quasiperiodic_hpluscross} of
215  * \ref PulsarSimulateCoherentGW_h. For better online performance, these can
216  * be replaced by other (approximate) trig functions. Presently the code
217  * uses the native \c libm functions by default, or the function
218  * <tt>sincosp()</tt> in \c libsunmath \e if this function is
219  * available \e and the constant \c ONLINE is defined.
220  * Differences at the level of 0.01 begin to appear only for phase
221  * arguments greater than \f$ 10^{14} \f$ or so (corresponding to over 500
222  * years between phase epoch and observation time for frequencies of
223  * around 1kHz).
224  *
225  * To activate this feature, be sure that <tt>sunmath.h</tt> and
226  * \c libsunmath are on your system, and add <tt>-DONLINE</tt> to the
227  * <tt>--with-extra-cppflags</tt> configuration argument. In future this
228  * flag may be used to turn on other efficient trig algorithms on other
229  * (non-Solaris) platforms.
230  *
231  */
232 void
235  PulsarCoherentGW *CWsignal,
237 {
238  INT4 i, n; /* index over output->data, and its final value */
239  INT4 nMax; /* used to store limits on index ranges */
240  INT4 fInit, fFinal; /* index range for which CWsignal->f is defined */
241  INT4 shiftInit, shiftFinal; /* ditto for CWsignal->shift */
242  UINT4 dtDelayBy2; /* delay table half-interval (s) */
243  UINT4 dtPolBy2; /* polarization table half-interval (s) */
244  REAL4 *outData; /* pointer to output data */
245  REAL8 delayMin, delayMax; /* min and max values of time delay */
246  SkyPosition source; /* source sky position */
247  BOOLEAN transfer; /* 1 if transfer function is specified */
248  BOOLEAN fFlag = 0; /* 1 if frequency left detector->transfer range */
249  BOOLEAN pFlag = 0; /* 1 if frequency was estimated from phase */
250 
251  /* get delay table and polaristion tables half intervals if defined (>0) in
252  the PulsarCoherentGW structure otherwise default to 400s for dtDelatBy2 and 300s
253  for dtPolBy2 */
254  dtDelayBy2 = CWsignal->dtDelayBy2 > 0 ? CWsignal->dtDelayBy2 : 400;
255  dtPolBy2 = CWsignal->dtPolBy2 > 0 ? CWsignal->dtPolBy2 : 300;
256 
257  /* The amplitude, frequency, phase, polarization shift, polarization
258  response, and propagation delay are stored in arrays that must be
259  interpolated. For a quantity x, we define a pointer xData to the
260  data array. At some time t measured in units of output->deltaT,
261  the interpolation point in xData is given by ( xOff + t*xDt ),
262  where xOff is an offset and xDt is a relative sampling rate. */
263  LALDetAMResponseSeries polResponse;
264  REAL8Vector *delay = NULL;
265  REAL4 *aData, *fData, *shiftData, *plusData, *crossData;
266  REAL8 *phiData, *delayData;
267  REAL8 aOff, fOff, phiOff, shiftOff, polOff, delayOff;
268  REAL8 aDt, fDt, phiDt, shiftDt, polDt, delayDt;
269 
270  /* Frequencies in the detector transfer function are interpolated
271  similarly, except everything is normalized with respect to
272  detector->transfer->deltaF. */
273  REAL4Vector *aTransfer = NULL;
274  REAL4Vector *phiTransfer = NULL;
275  REAL4Vector *phiTemp = NULL;
276  REAL4 *aTransData = NULL, *phiTransData = NULL;
277  REAL8 f0 = 1.0;
278  REAL8 phiFac = 1.0, fFac = 1.0;
279 
280  /* Heterodyning phase factor LAL_TWOPI*output->f0*output->deltaT,
281  and phase offset at the start of the series
282  LAL_TWOPI*output->f0*(time offset). */
283  REAL8 heteroFac, phi0;
284 
285  /* Variables required by the TCENTRE() macro, above. */
286  REAL8 realIndex;
287  INT4 intIndex;
288  REAL8 indexFrac;
289 
290  INITSTATUS( stat );
292 
293  /* Make sure parameter structures and their fields exist. */
295  SIMULATECOHERENTGWH_MSGENUL );
296  if ( !( CWsignal->a ) ) {
298  SIMULATECOHERENTGWH_MSGESIG );
299  }
300  ASSERT( CWsignal->a->data, stat,
301  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
302  ASSERT( CWsignal->a->data->data, stat,
303  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
304  if ( !( CWsignal->phi ) ) {
306  SIMULATECOHERENTGWH_MSGESIG );
307  }
308  ASSERT( CWsignal->phi->data, stat,
309  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
310  ASSERT( CWsignal->phi->data->data, stat,
311  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
312  if ( CWsignal->f ) {
313  ASSERT( CWsignal->f->data, stat,
314  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
315  ASSERT( CWsignal->f->data->data, stat,
316  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
317  }
318  if ( CWsignal->shift ) {
319  ASSERT( CWsignal->shift->data, stat,
320  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
321  ASSERT( CWsignal->shift->data->data, stat,
322  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
323  }
324  ASSERT( detector, stat,
325  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
326  if ( ( transfer = ( detector->transfer != NULL ) ) ) {
327  ASSERT( detector->transfer->data, stat,
328  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
329  ASSERT( detector->transfer->data->data, stat,
330  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
331  }
332  ASSERT( output, stat,
333  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
334  ASSERT( output->data, stat,
335  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
336  ASSERT( output->data->data, stat,
337  SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
338 
339  /* Check dimensions of amplitude array. */
340  ASSERT( CWsignal->a->data->vectorLength == 2, stat,
341  SIMULATECOHERENTGWH_EDIM, SIMULATECOHERENTGWH_MSGEDIM );
342 
343  /* Make sure we never divide by zero. */
344  ASSERT( CWsignal->a->deltaT != 0.0, stat,
345  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
346  ASSERT( CWsignal->phi->deltaT != 0.0, stat,
347  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
348  aDt = output->deltaT / CWsignal->a->deltaT;
349  phiDt = output->deltaT / CWsignal->phi->deltaT;
350  ASSERT( aDt != 0.0, stat,
351  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
352  ASSERT( phiDt != 0.0, stat,
353  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
354  if ( CWsignal->f ) {
355  ASSERT( CWsignal->f->deltaT != 0.0, stat,
356  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
357  fDt = output->deltaT / CWsignal->f->deltaT;
358  ASSERT( fDt != 0.0, stat,
359  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
360  } else {
361  fDt = 0.0;
362  }
363  if ( CWsignal->shift ) {
364  ASSERT( CWsignal->shift->deltaT != 0.0, stat,
365  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
366  shiftDt = output->deltaT / CWsignal->shift->deltaT;
367  ASSERT( shiftDt != 0.0, stat,
368  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
369  } else {
370  shiftDt = 0.0;
371  }
372  if ( transfer ) {
373  ASSERT( detector->transfer->deltaF != 0.0, stat,
374  SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
375  fFac = 1.0 / detector->transfer->deltaF;
376  phiFac = fFac / ( LAL_TWOPI * CWsignal->phi->deltaT );
377  f0 = detector->transfer->f0 / detector->transfer->deltaF;
378  }
379  heteroFac = LAL_TWOPI * output->f0 * output->deltaT;
380  phi0 = ( REAL8 )( output->epoch.gpsSeconds -
381  detector->heterodyneEpoch.gpsSeconds );
382  phi0 += 0.000000001 * ( REAL8 )( output->epoch.gpsNanoSeconds -
383  detector->heterodyneEpoch.gpsNanoSeconds );
384  phi0 *= LAL_TWOPI * output->f0;
385  if ( phi0 > 1.0 / LAL_REAL8_EPS ) {
386  LALWarning( stat, "REAL8 arithmetic is not sufficient to maintain"
387  " heterodyne phase to within a radian." );
388  }
389 
390  /* Check units on input, and set units on output. */
391  {
392  if ( CWsignal->f ) {
393  ASSERT( XLALUnitCompare( &( CWsignal->f->sampleUnits ), &lalHertzUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
394  }
395  ASSERT( XLALUnitCompare( &( CWsignal->phi->sampleUnits ), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
396  if ( CWsignal->shift ) {
397  ASSERT( XLALUnitCompare( &( CWsignal->shift->sampleUnits ), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
398  }
399  if ( transfer ) {
400  if ( XLALUnitMultiply( &( output->sampleUnits ), &( CWsignal->a->sampleUnits ), &( detector->transfer->sampleUnits ) ) == NULL ) {
401  ABORT( stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
402  }
403  } else {
404  output->sampleUnits = CWsignal->a->sampleUnits;
405  }
406  strncpy( output->name, CWsignal->a->name, LALNameLength );
407  }
408 
409  /* Define temporary variables to access the data of CWsignal->a,
410  CWsignal->f, and CWsignal->phi. */
411  aData = CWsignal->a->data->data;
412  INT4 aLen = CWsignal->a->data->length * CWsignal->a->data->vectorLength;
413  phiData = CWsignal->phi->data->data;
414  INT4 phiLen = CWsignal->phi->data->length;
415  outData = output->data->data;
416  INT4 fLen = 0, shiftLen = 0;
417  if ( CWsignal->f ) {
418  fData = CWsignal->f->data->data;
419  fLen = CWsignal->f->data->length;
420  } else {
421  fData = NULL;
422  }
423 
424  if ( CWsignal->shift ) {
425  shiftData = CWsignal->shift->data->data;
426  shiftLen = CWsignal->shift->data->length;
427  } else {
428  shiftData = NULL;
429  }
430 
431  /* Convert source position to equatorial coordinates, if
432  required. */
433  if ( detector->site ) {
434  source = CWsignal->position;
435  if ( source.system != COORDINATESYSTEM_EQUATORIAL ) {
436  ConvertSkyParams params; /* parameters for conversion */
437  EarthPosition location; /* location of detector */
438  params.gpsTime = &( output->epoch );
440  if ( source.system == COORDINATESYSTEM_HORIZON ) {
441  params.zenith = &( location.geodetic );
442  location.x = detector->site->location[0];
443  location.y = detector->site->location[1];
444  location.z = detector->site->location[2];
445  TRY( LALGeocentricToGeodetic( stat->statusPtr, &location ),
446  stat );
447  }
448  TRY( LALConvertSkyCoordinates( stat->statusPtr, &source,
449  &source, &params ), stat );
450  }
451  }
452 
453  /* Generate the table of propagation delays.
454  dtDelayBy2 = (UINT4)( 38924.9/sqrt( output->f0 +
455  1.0/output->deltaT ) ); */
456  delayDt = output->deltaT / ( 2.0 * dtDelayBy2 );
457  nMax = ( UINT4 )( output->data->length * delayDt ) + 3;
458  TRY( LALDCreateVector( stat->statusPtr, &delay, nMax ), stat );
459  delayData = delay->data;
460 
461  /* Compute delay from solar system barycentre. */
462  if ( detector->site && detector->ephemerides ) {
463  LIGOTimeGPS gpsTime; /* detector time when we compute delay */
464  EarthState state; /* Earth position info at that time */
465  BarycenterInput input; /* input structure to XLALBarycenter() */
466  EmissionTime emit; /* output structure from XLALBarycenter() */
467 
468  /* Arrange nested pointers, and set initial values. */
469  gpsTime = input.tgps = output->epoch;
470  gpsTime.gpsSeconds -= dtDelayBy2;
471  input.tgps.gpsSeconds -= dtDelayBy2;
472  input.site = *( detector->site );
473  for ( i = 0; i < 3; i++ ) {
474  input.site.location[i] /= LAL_C_SI;
475  }
476  input.alpha = source.longitude;
477  input.delta = source.latitude;
478  input.dInv = 0.0;
479  delayMin = delayMax = 1.1 * LAL_AU_SI / ( LAL_C_SI * output->deltaT );
480  delayMax *= -1;
481 
482  /* Compute table. */
483  for ( i = 0; i < nMax; i++ ) {
484  REAL8 tDelay; /* propagation time */
485  if ( XLALBarycenterEarth( &state, &gpsTime,
486  detector->ephemerides ) != XLAL_SUCCESS ) {
487  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
488  ABORTXLAL( stat );
489  }
490  if ( XLALBarycenter( &emit, &input, &state ) != XLAL_SUCCESS ) {
491  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
492  ABORTXLAL( stat );
493  }
494  delayData[i] = tDelay = emit.deltaT / output->deltaT;
495  if ( tDelay < delayMin ) {
496  delayMin = tDelay;
497  }
498  if ( tDelay > delayMax ) {
499  delayMax = tDelay;
500  }
501  gpsTime.gpsSeconds += 2 * dtDelayBy2;
502  input.tgps.gpsSeconds += 2 * dtDelayBy2;
503  }
504  }
505 
506  /* No information from which to compute delays. */
507  else {
508  LALInfo( stat, "Detector site and ephemerides absent; simulating hplus with no"
509  " propagation delays" );
510  memset( delayData, 0, nMax * sizeof( REAL8 ) );
511  delayMin = delayMax = 0.0;
512  }
513 
514  /* Generate the table of polarization response functions. */
515  polDt = output->deltaT / ( 2.0 * dtPolBy2 );
516  nMax = ( UINT4 )( output->data->length * polDt ) + 3;
517  memset( &polResponse, 0, sizeof( LALDetAMResponseSeries ) );
518  polResponse.pPlus = ( REAL4TimeSeries * )
519  LALMalloc( sizeof( REAL4TimeSeries ) );
520  polResponse.pCross = ( REAL4TimeSeries * )
521  LALMalloc( sizeof( REAL4TimeSeries ) );
522  polResponse.pScalar = ( REAL4TimeSeries * )
523  LALMalloc( sizeof( REAL4TimeSeries ) );
524  if ( !polResponse.pPlus || !polResponse.pCross ||
525  !polResponse.pScalar ) {
526  if ( polResponse.pPlus ) {
527  LALFree( polResponse.pPlus );
528  }
529  if ( polResponse.pCross ) {
530  LALFree( polResponse.pCross );
531  }
532  if ( polResponse.pScalar ) {
533  LALFree( polResponse.pScalar );
534  }
535  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
537  SIMULATECOHERENTGWH_MSGEMEM );
538  }
539  memset( polResponse.pPlus, 0, sizeof( REAL4TimeSeries ) );
540  memset( polResponse.pCross, 0, sizeof( REAL4TimeSeries ) );
541  memset( polResponse.pScalar, 0, sizeof( REAL4TimeSeries ) );
542  LALSCreateVector( stat->statusPtr, &( polResponse.pPlus->data ),
543  nMax );
544  BEGINFAIL( stat ) {
545  LALFree( polResponse.pPlus );
546  LALFree( polResponse.pCross );
547  LALFree( polResponse.pScalar );
548  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
549  }
550  ENDFAIL( stat );
551  LALSCreateVector( stat->statusPtr, &( polResponse.pCross->data ),
552  nMax );
553  BEGINFAIL( stat ) {
554  TRY( LALSDestroyVector( stat->statusPtr,
555  &( polResponse.pPlus->data ) ), stat );
556  LALFree( polResponse.pPlus );
557  LALFree( polResponse.pCross );
558  LALFree( polResponse.pScalar );
559  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
560  }
561  ENDFAIL( stat );
562  LALSCreateVector( stat->statusPtr, &( polResponse.pScalar->data ),
563  nMax );
564  BEGINFAIL( stat ) {
565  TRY( LALSDestroyVector( stat->statusPtr,
566  &( polResponse.pPlus->data ) ), stat );
567  TRY( LALSDestroyVector( stat->statusPtr,
568  &( polResponse.pCross->data ) ), stat );
569  LALFree( polResponse.pPlus );
570  LALFree( polResponse.pCross );
571  LALFree( polResponse.pScalar );
572  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
573  }
574  ENDFAIL( stat );
575  plusData = polResponse.pPlus->data->data;
576  crossData = polResponse.pCross->data->data;
577  INT4 plusLen = polResponse.pPlus->data->length;
578  INT4 crossLen = polResponse.pCross->data->length;
579  if ( plusLen != crossLen ) {
580  XLALPrintError( "plusLen = %d != crossLen = %d\n", plusLen, crossLen );
581  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
582  }
583 
584  if ( detector->site ) {
585  LALSource polSource; /* position and polarization angle */
586  LALDetAndSource input; /* response input structure */
587  LALTimeIntervalAndNSample params; /* response parameter structure */
588 
589  /* Arrange nested pointers, and set initial values. */
590  polSource.equatorialCoords = source;
591  polSource.orientation = ( REAL8 )( CWsignal->psi );
592  input.pSource = &polSource;
593  input.pDetector = detector->site;
594  params.epoch = output->epoch;
595  params.epoch.gpsSeconds -= dtPolBy2;
596  params.deltaT = 2.0 * dtPolBy2;
597  params.nSample = nMax;
598 
599  /* Compute table of responses. */
600  LALComputeDetAMResponseSeries( stat->statusPtr, &polResponse,
601  &input, &params );
602  BEGINFAIL( stat ) {
603  TRY( LALSDestroyVector( stat->statusPtr,
604  &( polResponse.pPlus->data ) ), stat );
605  TRY( LALSDestroyVector( stat->statusPtr,
606  &( polResponse.pCross->data ) ), stat );
607  TRY( LALSDestroyVector( stat->statusPtr,
608  &( polResponse.pScalar->data ) ), stat );
609  LALFree( polResponse.pPlus );
610  LALFree( polResponse.pCross );
611  LALFree( polResponse.pScalar );
612  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
613  }
614  ENDFAIL( stat );
615  } else {
616  /* No detector site, so just simulate response to hplus. */
617  for ( i = 0; i < nMax; i++ ) {
618  plusData[i] = 1.0;
619  crossData[i] = 0.0;
620  }
621  }
622  /* Free memory for the unused scalar mode. */
623  TRY( LALSDestroyVector( stat->statusPtr,
624  &( polResponse.pScalar->data ) ), stat );
625  LALFree( polResponse.pScalar );
626 
627  /* Decompose the transfer function into an amplitude and phase
628  response. */
629  INT4 phiTransLen = 0, aTransLen = 0;
630  if ( transfer ) {
631  nMax = detector->transfer->data->length;
632  LALSCreateVector( stat->statusPtr, &phiTemp, nMax );
633  BEGINFAIL( stat ) {
634  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
635  TRY( LALSDestroyVector( stat->statusPtr,
636  &( polResponse.pPlus->data ) ), stat );
637  TRY( LALSDestroyVector( stat->statusPtr,
638  &( polResponse.pCross->data ) ), stat );
639  LALFree( polResponse.pPlus );
640  LALFree( polResponse.pCross );
641  }
642  ENDFAIL( stat );
643  LALCVectorAngle( stat->statusPtr, phiTemp,
644  detector->transfer->data );
645  BEGINFAIL( stat ) {
646  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
647  TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
648  TRY( LALSDestroyVector( stat->statusPtr,
649  &( polResponse.pPlus->data ) ), stat );
650  TRY( LALSDestroyVector( stat->statusPtr,
651  &( polResponse.pCross->data ) ), stat );
652  LALFree( polResponse.pPlus );
653  LALFree( polResponse.pCross );
654  }
655  ENDFAIL( stat );
656  LALSCreateVector( stat->statusPtr, &phiTransfer, nMax );
657  BEGINFAIL( stat ) {
658  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
659  TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
660  TRY( LALSDestroyVector( stat->statusPtr,
661  &( polResponse.pPlus->data ) ), stat );
662  TRY( LALSDestroyVector( stat->statusPtr,
663  &( polResponse.pCross->data ) ), stat );
664  LALFree( polResponse.pPlus );
665  LALFree( polResponse.pCross );
666  }
667  ENDFAIL( stat );
668  LALUnwrapREAL4Angle( stat->statusPtr, phiTransfer, phiTemp );
669  BEGINFAIL( stat ) {
670  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
671  TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
672  TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
673  TRY( LALSDestroyVector( stat->statusPtr,
674  &( polResponse.pPlus->data ) ), stat );
675  TRY( LALSDestroyVector( stat->statusPtr,
676  &( polResponse.pCross->data ) ), stat );
677  LALFree( polResponse.pPlus );
678  LALFree( polResponse.pCross );
679  }
680  ENDFAIL( stat );
681  TRY( LALSDestroyVector( stat->statusPtr, &phiTemp ), stat );
682  LALSCreateVector( stat->statusPtr, &aTransfer, nMax );
683  BEGINFAIL( stat ) {
684  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
685  TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
686  TRY( LALSDestroyVector( stat->statusPtr,
687  &( polResponse.pPlus->data ) ), stat );
688  TRY( LALSDestroyVector( stat->statusPtr,
689  &( polResponse.pCross->data ) ), stat );
690  LALFree( polResponse.pPlus );
691  LALFree( polResponse.pCross );
692  }
693  ENDFAIL( stat );
694  LALCVectorAbs( stat->statusPtr, aTransfer,
695  detector->transfer->data );
696  BEGINFAIL( stat ) {
697  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
698  TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
699  TRY( LALSDestroyVector( stat->statusPtr, &aTransfer ), stat );
700  TRY( LALSDestroyVector( stat->statusPtr,
701  &( polResponse.pPlus->data ) ), stat );
702  TRY( LALSDestroyVector( stat->statusPtr,
703  &( polResponse.pCross->data ) ), stat );
704  LALFree( polResponse.pPlus );
705  LALFree( polResponse.pCross );
706  }
707  ENDFAIL( stat );
708  phiTransData = phiTransfer->data;
709  phiTransLen = phiTransfer->length;
710  aTransData = aTransfer->data;
711  aTransLen = aTransfer->length;
712  }
713  if ( aTransLen != phiTransLen ) {
714  XLALPrintError( "aTransLen = %d != phiTransLen = %d\n", aTransLen, phiTransLen );
715  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
716  }
717 
718  /* Compute offsets for interpolating the signal, delay, and
719  response functions. */
720  aOff = ( output->epoch.gpsSeconds -
721  CWsignal->a->epoch.gpsSeconds ) /
722  CWsignal->a->deltaT;
723  aOff += ( output->epoch.gpsNanoSeconds -
724  CWsignal->a->epoch.gpsNanoSeconds ) * 1.0e-9 /
725  CWsignal->a->deltaT;
726  phiOff = ( output->epoch.gpsSeconds -
727  CWsignal->phi->epoch.gpsSeconds ) /
728  CWsignal->phi->deltaT;
729  phiOff += ( output->epoch.gpsNanoSeconds -
730  CWsignal->phi->epoch.gpsNanoSeconds ) * 1.0e-9 /
731  CWsignal->phi->deltaT;
732  if ( CWsignal->f ) {
733  fOff = ( output->epoch.gpsSeconds -
734  CWsignal->f->epoch.gpsSeconds ) /
735  CWsignal->f->deltaT;
736  fOff += ( output->epoch.gpsNanoSeconds -
737  CWsignal->f->epoch.gpsNanoSeconds ) * 1.0e-9 /
738  CWsignal->f->deltaT;
739  } else {
740  fOff = 0.0;
741  }
742  if ( CWsignal->shift ) {
743  shiftOff = ( output->epoch.gpsSeconds -
744  CWsignal->shift->epoch.gpsSeconds ) /
745  CWsignal->shift->deltaT;
746  shiftOff += ( output->epoch.gpsNanoSeconds -
747  CWsignal->shift->epoch.gpsNanoSeconds ) * 1.0e-9 /
748  CWsignal->shift->deltaT;
749  } else {
750  shiftOff = 0.0;
751  }
752  polOff = 0.5;
753  delayOff = 0.5;
754 
755  /* Compute initial value of i, ensuring that we will never index
756  CWsignal->a or CWsignal->phi below their range. */
757  i = 0;
758  if ( aOff + ( i + delayMin )*aDt < 0.0 ) {
759  INT4 j = ( INT4 )floor( -aOff / aDt - delayMax );
760  if ( i < j ) {
761  i = j;
762  }
763  while ( ( i < ( INT4 )( output->data->length ) ) &&
764  ( aOff + TCENTRE( i )*aDt < 0.0 ) ) {
765  i++;
766  }
767  }
768  if ( phiOff + ( i + delayMin )*phiDt < 0.0 ) {
769  INT4 j = ( INT4 )( -phiOff / phiDt - delayMax );
770  if ( i < j ) {
771  i = j;
772  }
773  while ( ( i < ( INT4 )( output->data->length ) ) &&
774  ( phiOff + TCENTRE( i )*phiDt < 0.0 ) ) {
775  i++;
776  }
777  }
778  if ( i >= ( INT4 )( output->data->length ) ) {
779  LALWarning( stat, "Signal starts after the end of the output"
780  " time series." );
781  i = ( INT4 )( output->data->length );
782  }
783 
784  /* Compute final value of i, ensuring that we will never index
785  CWsignal->a or CWsignal->phi above their range. */
786  n = output->data->length - 1;
787  INT4 nMax_a = CWsignal->a->data->length - 1;
788  if ( aOff + ( n + delayMax )*aDt > nMax_a ) {
789  INT4 j = ( INT4 )( ( nMax_a - aOff ) / aDt - delayMin + 1.0 );
790  if ( n > j ) {
791  n = j;
792  }
793  while ( ( n >= 0 ) &&
794  ( ( INT4 )floor( aOff + TCENTRE( n )*aDt ) > nMax ) ) {
795  n--;
796  }
797  }
798  nMax = CWsignal->phi->data->length - 1;
799  if ( phiOff + ( n + delayMax )*phiDt > nMax ) {
800  INT4 j = ( INT4 )( ( nMax - phiOff ) / phiDt - delayMin + 1.0 );
801  if ( n > j ) {
802  n = j;
803  }
804  while ( ( n >= 0 ) &&
805  ( ( INT4 )floor( phiOff + TCENTRE( n )*phiDt ) > nMax ) ) {
806  n--;
807  }
808  }
809  if ( n < 0 ) {
810  LALWarning( stat, "CWsignal ends before the start of the output"
811  " time series." );
812  n = -1;
813  }
814 
815  /* Compute the values of i for which CWsignal->f is given. */
816  if ( CWsignal->f ) {
817  fInit = i;
818  if ( fOff + ( fInit + delayMin )*fDt < 0.0 ) {
819  INT4 j = ( INT4 )floor( -fOff / fDt - delayMax );
820  if ( fInit < j ) {
821  fInit = j;
822  }
823  while ( ( fInit <= n ) &&
824  ( fOff + TCENTRE( fInit )*fDt < 0.0 ) ) {
825  fInit++;
826  }
827  }
828  fFinal = n;
829  nMax = CWsignal->f->data->length - 1;
830  if ( fOff + ( fFinal + delayMax )*fDt > nMax ) {
831  INT4 j = ( INT4 )( ( nMax - fOff ) / fDt - delayMin + 1.0 );
832  if ( fFinal > j ) {
833  fFinal = j;
834  }
835  while ( ( fFinal >= i ) &&
836  ( ( INT4 )floor( fOff + TCENTRE( fFinal )*fDt ) > nMax ) ) {
837  fFinal--;
838  }
839  }
840  } else {
841  fInit = n + 1;
842  fFinal = i - 1;
843  }
844 
845  /* Compute the values of i for which CWsignal->shift is given. */
846  if ( CWsignal->shift ) {
847  shiftInit = i;
848  if ( shiftOff + ( shiftInit + delayMin )*shiftDt < 0.0 ) {
849  INT4 j = ( INT4 )floor( -shiftOff / shiftDt - delayMax );
850  if ( shiftInit < j ) {
851  shiftInit = j;
852  }
853  while ( ( shiftInit <= n ) &&
854  ( shiftOff + TCENTRE( shiftInit )*shiftDt < 0.0 ) ) {
855  shiftInit++;
856  }
857  }
858  shiftFinal = n;
859  nMax = CWsignal->shift->data->length - 1;
860  if ( shiftOff + ( shiftFinal + delayMax )*shiftDt > nMax ) {
861  INT4 j = ( INT4 )( ( nMax - shiftOff ) / shiftDt - delayMin + 1.0 );
862  if ( shiftFinal > j ) {
863  shiftFinal = j;
864  }
865  while ( ( shiftFinal >= i ) &&
866  ( ( INT4 )floor( shiftOff + TCENTRE( shiftFinal )*shiftDt ) > nMax ) ) {
867  shiftFinal--;
868  }
869  }
870  } else {
871  shiftInit = n + 1;
872  shiftFinal = i - 1;
873  }
874 
875  /* Set output to zero where the CWsignal is not defined. */
876  if ( i > 0 ) {
877  memset( output->data->data, 0, i * sizeof( REAL4 ) );
878  }
879  if ( ( nMax = output->data->length - n - 1 ) > 0 ) {
880  memset( output->data->data + n + 1, 0, nMax * sizeof( REAL4 ) );
881  }
882 
883  /* Keep track of the frequency range of the transfer function, so
884  that we don't try to interpolate it out of its range. */
885  if ( transfer ) {
886  nMax = detector->transfer->data->length - 1;
887  }
888 
889  /* Start computing responses. */
890  for ( ; i <= n; i++ ) {
891  REAL8 iCentre = TCENTRE( i ); /* value of i + propagation delays */
892  REAL8 x; /* interpolation point in arrays */
893  INT4 j; /* array index preceding x */
894  REAL8 frac; /* value of x - j */
895  REAL4 a1, a2; /* current signal amplitudes */
896  REAL8 phi = 0.0; /* current signal phase */
897  REAL4 f = 0.0; /* current signal frequency */
898  REAL4 shift = 0.0; /* current signal polarization shift */
899  REAL4 aTrans, phiTrans; /* current values of the transfer function */
900  REAL4 oPlus, oCross; /* current output amplitudes */
901  REAL4 sp, cp, ss, cs; /* sine and cosine of shift and phase */
902 
903  /* Interpolate the signal amplitude. */
904  x = aOff + iCentre * aDt;
905  j = ( INT4 )floor( x );
906  frac = ( REAL8 )( x - j );
907  j *= 2;
908  if ( j + 3 >= aLen ) {
909  XLALPrintError( "Interpolation error: no point at or after last sample for {a1,a2}: i = %d, n = %d, j = %d, aLen = %d", i, n, j, aLen );
910  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
911  }
912  {
913  a1 = frac * aData[j + 2] + ( 1.0 - frac ) * aData[j];
914  a2 = frac * aData[j + 3] + ( 1.0 - frac ) * aData[j + 1];
915  }
916 
917  /* Interpolate the polarization shift. */
918  if ( ( i < shiftInit ) || ( i > shiftFinal ) ) {
919  shift = 0.0;
920  } else {
921  x = shiftOff + iCentre * shiftDt;
922  j = ( INT4 )floor( x );
923  frac = ( REAL8 )( x - j );
924 
925  if ( j + 1 >= shiftLen ) {
926  XLALPrintError( "Interpolation error: no point at or after last sample for 'shift'" );
927  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
928  }
929  shift = frac * shiftData[j + 1] + ( 1.0 - frac ) * shiftData[j];
930  }
931 
932  /* Interpolate the signal phase, and apply any heterodyning. */
933  x = phiOff + iCentre * phiDt;
934  j = ( INT4 )floor( x );
935  frac = ( REAL8 )( x - j );
936 
937  if ( j + 1 >= phiLen ) {
938  XLALPrintError( "Interpolation error: no point at or after last sample for 'phi'" );
939  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
940  }
941  phi = frac * phiData[j + 1] + ( 1.0 - frac ) * phiData[j];
942  phi -= heteroFac * i + phi0;
943 
944  /* Compute the frequency and apply the transfer function. */
945  if ( transfer ) {
946  if ( ( i < fInit ) || ( i > fFinal ) ) {
947  f = ( phiData[j + 1] - phiData[j] ) * phiFac;
948  pFlag = 1;
949  } else {
950  x = fOff + iCentre * fDt;
951  j = ( INT4 )floor( x );
952  frac = ( REAL8 )( x - j );
953  if ( j + 1 >= fLen ) {
954  XLALPrintError( "Interpolation error: no point at or after last sample for 'f'" );
955  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
956  }
957  f = frac * fData[j + 1] + ( 1.0 - frac ) * fData[j];
958  f *= fFac;
959  }
960  x = f - f0;
961  if ( ( x < 0.0 ) || ( x > nMax ) ) {
962  aTrans = 0.0;
963  phiTrans = 0.0;
964  fFlag = 1;
965  } else {
966  j = ( INT4 )floor( x );
967  frac = ( REAL8 )( x - j );
968  if ( j + 1 >= aTransLen ) {
969  XLALPrintError( "Interpolation error: no point at or after last sample for '{aTrans,phiTrans}'" );
970  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
971  }
972  {
973  aTrans = frac * aTransData[j + 1] + ( 1.0 - frac ) * aTransData[j];
974  phiTrans = frac * phiTransData[j + 1] + ( 1.0 - frac ) * phiTransData[j];
975  }
976  }
977  a1 *= aTrans;
978  a2 *= aTrans;
979  phi += phiTrans;
980  }
981 
982  /* Compute components of output. */
983  if ( XLALSinCosLUT( &ss, &cs, shift ) != XLAL_SUCCESS ) {
984  ABORT( stat, LAL_EXLAL, "XLALSinCosLUT(&ss, &cs, shift) failed" );
985  }
986  if ( XLALSinCosLUT( &sp, &cp, phi ) != XLAL_SUCCESS ) {
987  ABORT( stat, LAL_EXLAL, "XLALSinCosLUT(&sp, &cp, phi) failed" );
988  }
989  oPlus = a1 * cs * cp - a2 * ss * sp;
990  oCross = a1 * ss * cp + a2 * cs * sp;
991  /* oPlus = a1*cos( shift )*cos( phi ) - a2*sin( shift )*sin( phi ); */
992  /* oCross = a1*sin( shift )*cos( phi ) + a2*cos( shift )*sin( phi ); */
993 
994  /* Interpolate the polarization response, and compute output. */
995  x = polOff + i * polDt;
996  j = ( INT4 )floor( x );
997  frac = ( REAL8 )( x - j );
998  if ( j + 1 >= plusLen ) {
999  XLALPrintError( "Interpolation error: no point at or after last sample for '{oPlus,oCross}'" );
1000  ABORT( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
1001  }
1002  {
1003  oPlus *= frac * plusData[j + 1] + ( 1.0 - frac ) * plusData[j];
1004  oCross *= frac * crossData[j + 1] + ( 1.0 - frac ) * crossData[j];
1005  }
1006 
1007  outData[i] = oPlus + oCross;
1008  }
1009 
1010  /* Warn if we ever stepped outside of the frequency domain of the
1011  transfer function, or if we had to estimate f from phi. */
1012  if ( fFlag )
1013  LALWarning( stat, "Signal passed outside of the frequency domain"
1014  " of the transfer function (transfer function is"
1015  " treated as zero outside its specified domain)" );
1016  if ( pFlag )
1017  LALInfo( stat, "Signal frequency was estimated by differencing"
1018  " the signal phase" );
1019 
1020  /* Cleanup and exit. */
1021  TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
1022  if ( transfer ) {
1023  TRY( LALSDestroyVector( stat->statusPtr, &phiTransfer ), stat );
1024  TRY( LALSDestroyVector( stat->statusPtr, &aTransfer ), stat );
1025  }
1026  TRY( LALSDestroyVector( stat->statusPtr,
1027  &( polResponse.pPlus->data ) ), stat );
1028  TRY( LALSDestroyVector( stat->statusPtr,
1029  &( polResponse.pCross->data ) ), stat );
1030  LALFree( polResponse.pPlus );
1031  LALFree( polResponse.pCross );
1033  RETURN( stat );
1034 
1035 } /* LALPulsarSimulateCoherentGW() */
int j
#define LALMalloc(n)
#define LALFree(p)
#define ABORT(statusptr, code, mesg)
#define ENDFAIL(statusptr)
#define LAL_EXLAL
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define ABORTXLAL(sp)
#define BEGINFAIL(statusptr)
#define SIMULATECOHERENTGWH_EUNIT
Bad input units.
#define SIMULATECOHERENTGWH_ENUL
Unexpected null pointer in arguments.
#define SIMULATECOHERENTGWH_ESIG
Input signal must specify amplitude and phase functions.
#define SIMULATECOHERENTGWH_EMEM
Memory allocation error.
#define TCENTRE(time)
#define SIMULATECOHERENTGWH_EDIM
Amplitude must be a 2-dimensional vector.
#define SIMULATECOHERENTGWH_EBAD
A sampling interval is (effectively) zero.
const double a2
void LALComputeDetAMResponseSeries(LALStatus *status, LALDetAMResponseSeries *pResponseSeries, const LALDetAndSource *pDetAndSource, const LALTimeIntervalAndNSample *pTimeInfo)
int XLALBarycenterEarth(EarthState *earth, const LIGOTimeGPS *tGPS, const EphemerisData *edat)
Computes the position and orientation of the Earth, at some arrival time , specified LIGOTimeGPS inp...
Definition: LALBarycenter.c:78
int XLALBarycenter(EmissionTime *emit, const BarycenterInput *baryinput, const EarthState *earth)
Transforms from detector arrival time in GPS (as specified in the LIGOTimeGPS structure) to pulse em...
#define LAL_REAL8_EPS
#define LAL_TWOPI
unsigned char BOOLEAN
double REAL8
#define XLAL_INIT_DECL(var,...)
uint32_t UINT4
int32_t INT4
float REAL4
LALNameLength
int LALWarning(LALStatus *status, const char *warning)
int LALInfo(LALStatus *status, const char *info)
int XLALPulsarSimulateCoherentGW(REAL4TimeSeries *output, PulsarCoherentGW *CWsignal, PulsarDetectorResponse *detector)
FIXME: Temporary XLAL-wapper to LAL-function LALPulsarSimulateCoherentGW()
void LALPulsarSimulateCoherentGW(LALStatus *stat, REAL4TimeSeries *output, PulsarCoherentGW *CWsignal, PulsarDetectorResponse *detector)
Computes the response of a detector to a coherent gravitational wave.
int XLALSinCosLUT(REAL4 *sinx, REAL4 *cosx, REAL8 x)
Calculate sin(x) and cos(x) to roughly 1e-7 precision using a lookup-table and Taylor-expansion.
Definition: SinCosLUT.c:83
void LALConvertSkyCoordinates(LALStatus *stat, SkyPosition *output, SkyPosition *input, ConvertSkyParams *params)
COORDINATESYSTEM_HORIZON
COORDINATESYSTEM_EQUATORIAL
void LALGeocentricToGeodetic(LALStatus *stat, EarthPosition *location)
int XLALUnitCompare(const LALUnit *unit1, const LALUnit *unit2)
const LALUnit lalHertzUnit
const LALUnit lalDimensionlessUnit
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
void LALDCreateVector(LALStatus *, REAL8Vector **, UINT4)
void LALDDestroyVector(LALStatus *, REAL8Vector **)
void LALSDestroyVector(LALStatus *, REAL4Vector **)
void LALSCreateVector(LALStatus *, REAL4Vector **, UINT4)
void LALCVectorAngle(LALStatus *status, REAL4Vector *out, const COMPLEX8Vector *in)
void LALCVectorAbs(LALStatus *status, REAL4Vector *out, const COMPLEX8Vector *in)
void LALUnwrapREAL4Angle(LALStatus *status, REAL4Vector *out, const REAL4Vector *in)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_SUCCESS
XLAL_EINVAL
XLAL_EFAILED
ss
n
Basic input structure to LALBarycenter.c.
REAL8 alpha
Source right ascension in ICRS J2000 coords (radians).
REAL8 dInv
1/(distance to source), in 1/sec.
LIGOTimeGPS tgps
input GPS arrival time.
REAL8 delta
Source declination in ICRS J2000 coords (radians)
LALDetector site
detector site info.
SkyPosition geodetic
Basic output structure of LALBarycenterEarth.c.
Basic output structure produced by LALBarycenter.c.
REAL8 deltaT
(TDB) - (GPS)
REAL4TimeSeries * pCross
REAL4TimeSeries * pPlus
REAL4TimeSeries * pScalar
LALSource * pSource
const LALDetector * pDetector
REAL8 location[3]
SkyPosition equatorialCoords
REAL8 orientation
INT4 gpsNanoSeconds
This structure stores a representation of a plane gravitational wave propagating from a particular po...
REAL4TimeSeries * f
A time-sampled sequence storing the instantaneous frequency , in Hz.
REAL4 psi
The polarization angle , in radians, as defined in Appendix B of .
SkyPosition position
The location of the source in the sky; this should be in equatorial celestial coordinates,...
REAL4TimeVectorSeries * a
A time-sampled two-dimensional vector storing the amplitudes and , in dimensionless strain.
REAL4TimeSeries * shift
A time-sampled sequence storing the polarization shift , in radians.
UINT4 dtPolBy2
A user defined half-interval time step for the polarisation response look-up table (will default to 3...
UINT4 dtDelayBy2
A user specified half-interval time step for the Doppler delay look-up table (will default to 400s if...
REAL8TimeSeries * phi
A time-sampled sequence storing the phase function , in radians.
This structure contains information required to determine the response of a detector to a gravitation...
REAL4Sequence * data
LALUnit sampleUnits
LIGOTimeGPS epoch
CHAR name[LALNameLength]
REAL4VectorSequence * data
REAL4 * data
REAL8Sequence * data
LALUnit sampleUnits
LIGOTimeGPS epoch
REAL8 * data
REAL8 longitude
REAL8 latitude
CoordinateSystem system
LIGOTimeGPS epoch