Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 */
144void
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