LALPulsar  6.1.0.1-c9a8ef6
GenerateParabolicSpinOrbitCW.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 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 
21 #include <lal/LALStdio.h>
22 #include <lal/LALStdlib.h>
23 #include <lal/LALConstants.h>
24 #include <lal/Units.h>
25 #include <lal/AVFactories.h>
26 #include <lal/SeqFactories.h>
27 #include <lal/PulsarSimulateCoherentGW.h>
28 #include <lal/GenerateSpinOrbitCW.h>
29 
30 /**
31  * \author Creighton, T. D.
32  *
33  * \brief Computes a continuous waveform with frequency drift and Doppler
34  * modulation from a parabolic orbital trajectory.
35  *
36  * This function computes a quaiperiodic waveform using the spindown and
37  * orbital parameters in <tt>*params</tt>, storing the result in
38  * <tt>*output</tt>.
39  *
40  * In the <tt>*params</tt> structure, the routine uses all the "input"
41  * fields specified in \ref GenerateSpinOrbitCW_h, and sets all of the
42  * "output" fields. If <tt>params->f</tt>=\c NULL, no spindown
43  * modulation is performed. If <tt>params->oneMinusEcc</tt> \f$ \neq0 \f$ , or if
44  * <tt>params->rPeriNorm</tt> \f$ \times \f$ <tt>params->angularSpeed</tt> \f$ \geq1 \f$
45  * (faster-than-light speed at periapsis), an error is returned.
46  *
47  * In the <tt>*output</tt> structure, the field <tt>output->h</tt> is
48  * ignored, but all other pointer fields must be set to \c NULL. The
49  * function will create and allocate space for <tt>output->a</tt>,
50  * <tt>output->f</tt>, and <tt>output->phi</tt> as necessary. The
51  * <tt>output->shift</tt> field will remain set to \c NULL.
52  *
53  * ### Algorithm ###
54  *
55  * For parabolic orbits, we combine \eqref{eq_spinorbit-tr},
56  * \eqref{eq_spinorbit-t}, and \eqref{eq_spinorbit-upsilon} to get \f$ t_r \f$
57  * directly as a function of \f$ E \f$ :
58  * \f{equation}{
59  * \label{eq_cubic-e}
60  * t_r = t_p + \frac{r_p\sin i}{c} \left[ \cos\omega +
61  * \left(\frac{1}{v_p} + \cos\omega\right)E -
62  * \frac{\sin\omega}{4}E^2 + \frac{1}{12v_p}E^3\right] \;,
63  * \f}
64  * where \f$ v_p=r_p\dot{\upsilon}_p\sin i/c \f$ is a normalized velocity at
65  * periapsis. Following the prescription for the general analytic
66  * solution to the real cubic equation, we substitute
67  * \f$ E=x+3v_p\sin\omega \f$ to obtain:
68  * \f{equation}{
69  * \label{eq_cubic-x}
70  * x^3 + px = q \;,
71  * \f}
72  * where:
73  * \f{eqnarray}{
74  * \label{eq_cubic-p}
75  * p & = & 12 + 12v_p\cos\omega - 3v_p^2\sin^2\omega \;, \\
76  * \label{eq_cubic-q}
77  * q & = & 12v_p^2\sin\omega\cos\omega - 24v_p\sin\omega +
78  * 2v_p^3\sin^3\omega + 12\dot{\upsilon}_p(t_r-t_p) \;.
79  * \f}
80  * We note that \f$ p>0 \f$ is guaranteed as long as \f$ v_p<1 \f$ , so the right-hand
81  * side of \eqref{eq_cubic-x} is monotonic in \f$ x \f$ and has exactly one
82  * root. However, \f$ p\rightarrow0 \f$ in the limit \f$ v_p\rightarrow1 \f$ and
83  * \f$ \omega=\pi \f$ . This may cause some loss of precision in subsequent
84  * calculations. But \f$ v_p\sim1 \f$ means that our solution will be
85  * inaccurate anyway because we ignore significant relativistic effects.
86  *
87  * Since \f$ p>0 \f$ , we can substitute \f$ x=y\sqrt{3/4p} \f$ to obtain:
88  * \f{equation}{
89  * 4y^3 + 3y = \frac{q}{2}\left(\frac{3}{p}\right)^{3/2} \equiv C \;.
90  * \f}
91  * Using the triple-angle hyperbolic identity
92  * \f$ \sinh(3\theta)=4\sinh^3\theta+3\sinh\theta \f$ , we have
93  * \f$ y=\sinh\left(\frac{1}{3}\sinh^{-1}C\right) \f$ . The solution to the
94  * original cubic equation is then:
95  * \f{equation}{
96  * E = 3v_p\sin\omega + 2\sqrt{\frac{p}{3}}
97  * \sinh\left(\frac{1}{3}\sinh^{-1}C\right) \;.
98  * \f}
99  * To ease the calculation of \f$ E \f$ , we precompute the constant part
100  * \f$ E_0=3v_p\sin\omega \f$ and the coefficient \f$ \Delta E=2\sqrt{p/3} \f$ .
101  * Similarly for \f$ C \f$ , we precompute a constant piece \f$ C_0 \f$ evaluated at
102  * the epoch of the output time series, and a stepsize coefficient
103  * \f$ \Delta C=6(p/3)^{3/2}\dot{\upsilon}_p\Delta t \f$ , where \f$ \Delta t \f$ is
104  * the step size in the (output) time series in \f$ t_r \f$ . Thus at any
105  * timestep \f$ i \f$ , we obtain \f$ C \f$ and hence \f$ E \f$ via:
106  * \f{eqnarray}{
107  * C & = & C_0 + i\Delta C \;,\\
108  * E & = & E_0 + \Delta E\times\left\{\begin{array}{l@{\qquad}c}
109  * \sinh\left[\frac{1}{3}\ln\left(
110  * C + \sqrt{C^2+1} \right) \right]\;, & C\geq0 \;,\\ \\
111  * \sinh\left[-\frac{1}{3}\ln\left(
112  * -C + \sqrt{C^2+1} \right) \right]\;, & C\leq0 \;,\\
113  * \end{array}\right.
114  * \f}
115  * where we have explicitly written \f$ \sinh^{-1} \f$ in terms of functions in
116  * \c math.h. Once \f$ E \f$ is found, we can compute
117  * \f$ t=E(12+E^2)/(12\dot{\upsilon}_p) \f$ (where again \f$ 1/12\dot{\upsilon}_p \f$
118  * can be precomputed), and hence \f$ f \f$ and \f$ \phi \f$ via
119  * \eqref{eq_taylorcw-freq} and \eqref{eq_taylorcw-phi}. The
120  * frequency \f$ f \f$ must then be divided by the Doppler factor:
121  * \f[
122  * 1 + \frac{\dot{R}}{c} = 1 + \frac{v_p}{4+E^2}\left(
123  * 4\cos\omega - 2E\sin\omega \right)
124  * \f]
125  * (where once again \f$ 4\cos\omega \f$ and \f$ 2\sin\omega \f$ can be precomputed).
126  *
127  * This routine does not account for relativistic timing variations, and
128  * issues warnings or errors based on the criterea of
129  * \eqref{eq_relativistic-orbit} in GenerateEllipticSpinOrbitCW().
130  * The routine will also warn if
131  * it seems likely that \c REAL8 precision may not be sufficient to
132  * track the orbit accurately. We estimate that numerical errors could
133  * cause the number of computed wave cycles to vary by
134  * \f[
135  * \Delta N \lesssim f_0 T\epsilon\left[
136  * \sim6+\ln\left(|C|+\sqrt{|C|^2+1}\right)\right] \;,
137  * \f]
138  * where \f$ |C| \f$ is the maximum magnitude of the variable \f$ C \f$ over the
139  * course of the computation, \f$ f_0T \f$ is the approximate total number of
140  * wave cycles over the computation, and \f$ \epsilon\approx2\times10^{-16} \f$
141  * is the fractional precision of \c REAL8 arithmetic. If this
142  * estimate exceeds 0.01 cycles, a warning is issued.
143  */
144 void
148 {
149  UINT4 n, i; /* number of and index over samples */
150  UINT4 nSpin = 0, j; /* number of and index over spindown terms */
151  REAL8 t, dt, tPow; /* time, interval, and t raised to a power */
152  REAL8 phi0, f0, twopif0; /* initial phase, frequency, and 2*pi*f0 */
153  REAL8 f, fPrev; /* current and previous values of frequency */
154  REAL4 df = 0.0; /* maximum difference between f and fPrev */
155  REAL8 phi; /* current value of phase */
156  REAL8 vp; /* projected speed at periapsis */
157  REAL8 argument; /* argument of periapsis */
158  REAL8 fourCosOmega; /* four times the cosine of argument */
159  REAL8 twoSinOmega; /* two times the sine of argument */
160  REAL8 vpCosOmega; /* vp times cosine of argument */
161  REAL8 vpSinOmega; /* vp times sine of argument */
162  REAL8 vpSinOmega2; /* vpSinOmega squared */
163  REAL8 vDot6; /* 6 times angular speed at periapsis */
164  REAL8 oneBy12vDot; /* one over (12 times angular speed) */
165  REAL8 pBy3; /* constant sqrt(p/3) in cubic equation */
166  REAL8 p32; /* constant (p/3)^1.5 in cubic equation */
167  REAL8 c, c0, dc; /* C variable, offset, and step increment */
168  REAL8 e, e2, e0; /* E variable, E^2, and constant piece of E */
169  REAL8 de; /* coefficient of sinh() piece of E */
170  REAL8 tpOff; /* orbit epoch - time series epoch (s) */
171  //REAL8 spinOff; /* spin epoch - orbit epoch (s) */
172  REAL8 *fSpin = NULL; /* pointer to Taylor coefficients */
173  REAL4 *fData; /* pointer to frequency data */
174  REAL8 *phiData; /* pointer to phase data */
175 
176  INITSTATUS( stat );
178 
179  /* Make sure parameter and output structures exist. */
181  GENERATESPINORBITCWH_MSGENUL );
183  GENERATESPINORBITCWH_MSGENUL );
184 
185  /* Make sure output fields don't exist. */
187  GENERATESPINORBITCWH_MSGEOUT );
189  GENERATESPINORBITCWH_MSGEOUT );
191  GENERATESPINORBITCWH_MSGEOUT );
193  GENERATESPINORBITCWH_MSGEOUT );
194 
195  /* If Taylor coeficients are specified, make sure they exist. */
196  if ( params->f ) {
198  GENERATESPINORBITCWH_MSGENUL );
199  nSpin = params->f->length;
200  fSpin = params->f->data;
201  }
202 
203  /* Set up some constants (to avoid repeated calculation or
204  dereferencing), and make sure they have acceptable values. */
205  vp = params->rPeriNorm * params->angularSpeed;
206  vDot6 = 6.0 * params->angularSpeed;
207  n = params->length;
208  dt = params->deltaT;
209  f0 = fPrev = params->f0;
210  if ( params->oneMinusEcc != 0.0 ) {
212  GENERATESPINORBITCWH_MSGEECC );
213  }
214  if ( vp >= 1.0 ) {
216  GENERATESPINORBITCWH_MSGEFTL );
217  }
218  if ( vp <= 0.0 || dt <= 0.0 || f0 <= 0.0 || vDot6 <= 0.0 ||
219  n == 0 ) {
221  GENERATESPINORBITCWH_MSGESGN );
222  }
223  if ( lalDebugLevel & LALWARNING ) {
224  if ( f0 * n * dt * vp * vp > 0.5 )
225  LALWarning( stat, "Orbit may have significant relativistic"
226  " effects that are not included" );
227  }
228 
229  /* Compute offset between time series epoch and periapsis, and
230  betweem periapsis and spindown reference epoch. */
231  tpOff = ( REAL8 )( params->orbitEpoch.gpsSeconds -
233  tpOff += 1.0e-9 * ( REAL8 )( params->orbitEpoch.gpsNanoSeconds -
235  //spinOff = (REAL8)( params->orbitEpoch.gpsSeconds -
236  // params->spinEpoch.gpsSeconds );
237  //spinOff += 1.0e-9 * (REAL8)( params->orbitEpoch.gpsNanoSeconds -
238  // params->spinEpoch.gpsNanoSeconds );
239 
240  /* Set up some other constants. */
241  twopif0 = f0 * LAL_TWOPI;
242  phi0 = params->phi0;
243  argument = params->omega;
244  oneBy12vDot = 0.5 / vDot6;
245  fourCosOmega = 4.0 * cos( argument );
246  twoSinOmega = 2.0 * sin( argument );
247  vpCosOmega = 0.25 * vp * fourCosOmega;
248  vpSinOmega = 0.5 * vp * twoSinOmega;
249  vpSinOmega2 = vpSinOmega * vpSinOmega;
250  pBy3 = sqrt( 4.0 * ( 1.0 + vpCosOmega ) - vpSinOmega2 );
251  p32 = 1.0 / ( pBy3 * pBy3 * pBy3 );
252  c0 = p32 * ( vpSinOmega * ( 6.0 * vpCosOmega - 12.0 + vpSinOmega2 ) -
253  tpOff * vDot6 );
254  dc = p32 * vDot6 * dt;
255  e0 = 3.0 * vpSinOmega;
256  de = 2.0 * pBy3;
257 
258  /* Check whether REAL8 precision is good enough. */
259  if ( lalDebugLevel & LALWARNING ) {
260  REAL8 x = fabs( c0 + n * dc ); /* a temporary computation variable */
261  if ( x < fabs( c0 ) ) {
262  x = fabs( c0 );
263  }
264  x = 6.0 + log( x + sqrt( x * x + 1.0 ) );
265  if ( LAL_REAL8_EPS * f0 * dt * n * x > 0.01 )
266  LALWarning( stat, "REAL8 arithmetic may not have sufficient"
267  " precision for this orbit" );
268  }
269 
270  /* Allocate output structures. */
271  if ( ( output->a = ( REAL4TimeVectorSeries * )
272  LALMalloc( sizeof( REAL4TimeVectorSeries ) ) ) == NULL ) {
274  GENERATESPINORBITCWH_MSGEMEM );
275  }
276  memset( output->a, 0, sizeof( REAL4TimeVectorSeries ) );
277  if ( ( output->f = ( REAL4TimeSeries * )
278  LALMalloc( sizeof( REAL4TimeSeries ) ) ) == NULL ) {
279  LALFree( output->a );
280  output->a = NULL;
282  GENERATESPINORBITCWH_MSGEMEM );
283  }
284  memset( output->f, 0, sizeof( REAL4TimeSeries ) );
285  if ( ( output->phi = ( REAL8TimeSeries * )
286  LALMalloc( sizeof( REAL8TimeSeries ) ) ) == NULL ) {
287  LALFree( output->a );
288  output->a = NULL;
289  LALFree( output->f );
290  output->f = NULL;
292  GENERATESPINORBITCWH_MSGEMEM );
293  }
294  memset( output->phi, 0, sizeof( REAL8TimeSeries ) );
295 
296  /* Set output structure metadata fields. */
297  output->position = params->position;
298  output->psi = params->psi;
299  output->a->epoch = output->f->epoch = output->phi->epoch
300  = params->epoch;
301  output->a->deltaT = n * params->deltaT;
302  output->f->deltaT = output->phi->deltaT = params->deltaT;
303  output->a->sampleUnits = lalStrainUnit;
304  output->f->sampleUnits = lalHertzUnit;
305  output->phi->sampleUnits = lalDimensionlessUnit;
306  snprintf( output->a->name, LALNameLength, "CW amplitudes" );
307  snprintf( output->f->name, LALNameLength, "CW frequency" );
308  snprintf( output->phi->name, LALNameLength, "CW phase" );
309 
310  /* Allocate phase and frequency arrays. */
311  LALSCreateVector( stat->statusPtr, &( output->f->data ), n );
312  BEGINFAIL( stat ) {
313  LALFree( output->a );
314  output->a = NULL;
315  LALFree( output->f );
316  output->f = NULL;
317  LALFree( output->phi );
318  output->phi = NULL;
319  }
320  ENDFAIL( stat );
321  LALDCreateVector( stat->statusPtr, &( output->phi->data ), n );
322  BEGINFAIL( stat ) {
323  TRY( LALSDestroyVector( stat->statusPtr, &( output->f->data ) ),
324  stat );
325  LALFree( output->a );
326  output->a = NULL;
327  LALFree( output->f );
328  output->f = NULL;
329  LALFree( output->phi );
330  output->phi = NULL;
331  }
332  ENDFAIL( stat );
333 
334  /* Allocate and fill amplitude array. */
335  {
336  CreateVectorSequenceIn in; /* input to create output->a */
337  in.length = 2;
338  in.vectorLength = 2;
339  LALSCreateVectorSequence( stat->statusPtr, &( output->a->data ), &in );
340  BEGINFAIL( stat ) {
341  TRY( LALSDestroyVector( stat->statusPtr, &( output->f->data ) ),
342  stat );
343  TRY( LALDDestroyVector( stat->statusPtr, &( output->phi->data ) ),
344  stat );
345  LALFree( output->a );
346  output->a = NULL;
347  LALFree( output->f );
348  output->f = NULL;
349  LALFree( output->phi );
350  output->phi = NULL;
351  }
352  ENDFAIL( stat );
353  output->a->data->data[0] = output->a->data->data[2] = params->aPlus;
354  output->a->data->data[1] = output->a->data->data[3] = params->aCross;
355  }
356 
357  /* Fill frequency and phase arrays. */
358  fData = output->f->data->data;
359  phiData = output->phi->data->data;
360  for ( i = 0; i < n; i++ ) {
361 
362  /* Compute emission time. */
363  c = c0 + dc * i;
364  if ( c > 0 ) {
365  e = e0 + de * sinh( log( c + sqrt( c * c + 1.0 ) ) / 3.0 );
366  } else {
367  e = e0 + de * sinh( -log( -c + sqrt( c * c + 1.0 ) ) / 3.0 );
368  }
369  e2 = e * e;
370  phi = t = tPow = oneBy12vDot * e * ( 12.0 + e2 );
371 
372  /* Compute source emission phase and frequency. */
373  f = 1.0;
374  for ( j = 0; j < nSpin; j++ ) {
375  f += fSpin[j] * tPow;
376  phi += fSpin[j] * ( tPow *= t ) / ( j + 2.0 );
377  }
378 
379  /* Appy frequency Doppler shift. */
380  f *= f0 / ( 1.0 + vp * ( fourCosOmega - e * twoSinOmega )
381  / ( 4.0 + e2 ) );
382  phi *= twopif0;
383  if ( fabs( f - fPrev ) > df ) {
384  df = fabs( f - fPrev );
385  }
386  *( fData++ ) = fPrev = f;
387  *( phiData++ ) = phi + phi0;
388  }
389 
390  /* Set output field and return. */
391  params->dfdt = df * dt;
393  RETURN( stat );
394 }
int j
#define LALMalloc(n)
#define LALFree(p)
const double c0
#define c
#define ABORT(statusptr, code, mesg)
#define ENDFAIL(statusptr)
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define BEGINFAIL(statusptr)
double e
void LALSCreateVectorSequence(LALStatus *status, REAL4VectorSequence **vectorSequence, CreateVectorSequenceIn *vSeqParams)
#define GENERATESPINORBITCWH_EECC
Eccentricity out of range.
#define GENERATESPINORBITCWH_ESGN
Sign error: positive parameter expected.
#define GENERATESPINORBITCWH_EMEM
Out of memory.
#define GENERATESPINORBITCWH_ENUL
Unexpected null pointer in arguments.
#define GENERATESPINORBITCWH_EOUT
Output field a, f, phi, or shift already exists.
void LALGenerateParabolicSpinOrbitCW(LALStatus *stat, PulsarCoherentGW *output, SpinOrbitCWParamStruc *params)
Computes a continuous waveform with frequency drift and Doppler modulation from a parabolic orbital t...
#define GENERATESPINORBITCWH_EFTL
Periapsis motion is faster than light.
#define LAL_REAL8_EPS
#define LAL_TWOPI
double REAL8
uint32_t UINT4
float REAL4
LALNameLength
#define lalDebugLevel
LALWARNING
int LALWarning(LALStatus *status, const char *warning)
const LALUnit lalStrainUnit
const LALUnit lalHertzUnit
const LALUnit lalDimensionlessUnit
void LALDCreateVector(LALStatus *, REAL8Vector **, UINT4)
void LALDDestroyVector(LALStatus *, REAL8Vector **)
void LALSDestroyVector(LALStatus *, REAL4Vector **)
void LALSCreateVector(LALStatus *, REAL4Vector **, UINT4)
n
INT4 gpsNanoSeconds
This structure stores a representation of a plane gravitational wave propagating from a particular po...
This structure stores the parameters for constructing a gravitational waveform with both a Taylor-pol...
LIGOTimeGPS epoch
double psi
double df