GenerateParabolicSpinOrbitCW.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Teviet Creighton
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /****************** <lalVerbatim file="GenerateParabolicSpinOrbitCWCV">
00021 Author: Creighton, T. D.
00022 $Id: GenerateParabolicSpinOrbitCW.c,v 1.6 2007/06/08 14:41:47 bema Exp $
00023 **************************************************** </lalVerbatim> */
00024 
00025 /********************************************************** <lalLaTeX>
00026 
00027 \subsection{Module \texttt{GenerateParabolicSpinOrbitCW.c}}
00028 \label{ss:GenerateParabolicSpinOrbitCW.c}
00029 
00030 Computes a continuous waveform with frequency drift and Doppler
00031 modulation from a parabolic orbital trajectory.
00032 
00033 \subsubsection*{Prototypes}
00034 \vspace{0.1in}
00035 \input{GenerateParabolicSpinOrbitCWCP}
00036 \idx{LALGenerateParabolicSpinOrbitCW()}
00037 
00038 \subsubsection*{Description}
00039 
00040 This function computes a quaiperiodic waveform using the spindown and
00041 orbital parameters in \verb@*params@, storing the result in
00042 \verb@*output@.
00043 
00044 In the \verb@*params@ structure, the routine uses all the ``input''
00045 fields specified in \verb@GenerateSpinOrbitCW.h@, and sets all of the
00046 ``output'' fields.  If \verb@params->f@=\verb@NULL@, no spindown
00047 modulation is performed.  If \verb@params->oneMinusEcc@$\neq0$, or if
00048 \verb@params->rPeriNorm@$\times$\verb@params->angularSpeed@$\geq1$
00049 (faster-than-light speed at periapsis), an error is returned.
00050 
00051 In the \verb@*output@ structure, the field \verb@output->h@ is
00052 ignored, but all other pointer fields must be set to \verb@NULL@.  The
00053 function will create and allocate space for \verb@output->a@,
00054 \verb@output->f@, and \verb@output->phi@ as necessary.  The
00055 \verb@output->shift@ field will remain set to \verb@NULL@.
00056 
00057 \subsubsection*{Algorithm}
00058 
00059 For parabolic orbits, we combine Eqs.~(\ref{eq:spinorbit-tr}),
00060 (\ref{eq:spinorbit-t}), and~(\ref{eq:spinorbit-upsilon}) to get $t_r$
00061 directly as a function of $E$:
00062 \begin{equation}
00063 \label{eq:cubic-e}
00064 t_r = t_p + \frac{r_p\sin i}{c} \left[ \cos\omega +
00065         \left(\frac{1}{v_p} + \cos\omega\right)E -
00066         \frac{\sin\omega}{4}E^2 + \frac{1}{12v_p}E^3\right] \;,
00067 \end{equation}
00068 where $v_p=r_p\dot{\upsilon}_p\sin i/c$ is a normalized velocity at
00069 periapsis.  Following the prescription for the general analytic
00070 solution to the real cubic equation, we substitute
00071 $E=x+3v_p\sin\omega$ to obtain:
00072 \begin{equation}
00073 \label{eq:cubic-x}
00074 x^3 + px = q \;,
00075 \end{equation}
00076 where:
00077 \begin{eqnarray}
00078 \label{eq:cubic-p}
00079 p & = & 12 + 12v_p\cos\omega - 3v_p^2\sin^2\omega \;, \\
00080 \label{eq:cubic-q}
00081 q & = & 12v_p^2\sin\omega\cos\omega - 24v_p\sin\omega +
00082         2v_p^3\sin^3\omega + 12\dot{\upsilon}_p(t_r-t_p) \;.
00083 \end{eqnarray}
00084 We note that $p>0$ is guaranteed as long as $v_p<1$, so the right-hand
00085 side of Eq.~(\ref{eq:cubic-x}) is monotonic in $x$ and has exactly one
00086 root.  However, $p\rightarrow0$ in the limit $v_p\rightarrow1$ and
00087 $\omega=\pi$.  This may cause some loss of precision in subsequent
00088 calculations.  But $v_p\sim1$ means that our solution will be
00089 inaccurate anyway because we ignore significant relativistic effects.
00090 
00091 Since $p>0$, we can substitute $x=y\sqrt{3/4p}$ to obtain:
00092 \begin{equation}
00093 4y^3 + 3y = \frac{q}{2}\left(\frac{3}{p}\right)^{3/2} \equiv C \;.
00094 \end{equation}
00095 Using the triple-angle hyperbolic identity
00096 $\sinh(3\theta)=4\sinh^3\theta+3\sinh\theta$, we have
00097 $y=\sinh\left(\frac{1}{3}\sinh^{-1}C\right)$.  The solution to the
00098 original cubic equation is then:
00099 \begin{equation}
00100 E = 3v_p\sin\omega + 2\sqrt{\frac{p}{3}}
00101         \sinh\left(\mbox{$\frac{1}{3}$}\sinh^{-1}C\right) \;.
00102 \end{equation}
00103 To ease the calculation of $E$, we precompute the constant part
00104 $E_0=3v_p\sin\omega$ and the coefficient $\Delta E=2\sqrt{p/3}$.
00105 Similarly for $C$, we precompute a constant piece $C_0$ evaluated at
00106 the epoch of the output time series, and a stepsize coefficient
00107 $\Delta C=6(p/3)^{3/2}\dot{\upsilon}_p\Delta t$, where $\Delta t$ is
00108 the step size in the (output) time series in $t_r$.  Thus at any
00109 timestep $i$, we obtain $C$ and hence $E$ via:
00110 \begin{eqnarray}
00111 C & = & C_0 + i\Delta C \;, \nonumber\\
00112 E & = & E_0 + \Delta E\times\left\{\begin{array}{l@{\qquad}c}
00113         \sinh\left[\frac{1}{3}\ln\left(
00114                 C + \sqrt{C^2+1} \right) \right]\;, & C\geq0 \;,\\
00115         \\
00116         \sinh\left[-\frac{1}{3}\ln\left(
00117                 -C + \sqrt{C^2+1} \right) \right]\;, & C\leq0 \;,\\
00118         \end{array}\right. \nonumber
00119 \end{eqnarray}
00120 where we have explicitly written $\sinh^{-1}$ in terms of functions in
00121 \verb@math.h@.  Once $E$ is found, we can compute
00122 $t=E(12+E^2)/(12\dot{\upsilon}_p)$ (where again $1/12\dot{\upsilon}_p$
00123 can be precomputed), and hence $f$ and $\phi$ via
00124 Eqs.~(\ref{eq:taylorcw-freq}) and~(\ref{eq:taylorcw-phi}).  The
00125 frequency $f$ must then be divided by the Doppler factor:
00126 $$
00127 1 + \frac{\dot{R}}{c} = 1 + \frac{v_p}{4+E^2}\left(
00128         4\cos\omega - 2E\sin\omega \right)
00129 $$
00130 (where once again $4\cos\omega$ and $2\sin\omega$ can be precomputed).
00131 
00132 This routine does not account for relativistic timing variations, and
00133 issues warnings or errors based on the criterea of
00134 Eq.~(\ref{eq:relativistic-orbit}) in
00135 \verb@GenerateEllipticSpinOrbitCW.c@.  The routine will also warn if
00136 it seems likely that \verb@REAL8@ precision may not be sufficient to
00137 track the orbit accurately.  We estimate that numerical errors could
00138 cause the number of computed wave cycles to vary by
00139 $$
00140 \Delta N \lessim f_0 T\epsilon\left[
00141         \sim6+\ln\left(|C|+\sqrt{|C|^2+1}\right)\right] \;,
00142 $$
00143 where $|C|$ is the maximum magnitude of the variable $C$ over the
00144 course of the computation, $f_0T$ is the approximate total number of
00145 wave cycles over the computation, and $\epsilon\approx2\times10^{-16}$
00146 is the fractional precision of \verb@REAL8@ arithmetic.  If this
00147 estimate exceeds 0.01 cycles, a warning is issued.
00148 
00149 \subsubsection*{Uses}
00150 \begin{verbatim}
00151 LALMalloc()                   LALFree()
00152 LALSCreateVectorSequence()    LALSDestroyVectorSequence()
00153 LALSCreateVector()            LALSDestroyVector()
00154 LALDCreateVector()            LALDDestroyVector()
00155 LALSnprintf()                 LALWarning()
00156 \end{verbatim}
00157 
00158 \subsubsection*{Notes}
00159 
00160 \vfill{\footnotesize\input{GenerateParabolicSpinOrbitCWCV}}
00161 
00162 ******************************************************* </lalLaTeX> */
00163 
00164 #include <lal/LALStdio.h>
00165 #include <lal/LALStdlib.h>
00166 #include <lal/LALConstants.h>
00167 #include <lal/Units.h>
00168 #include <lal/AVFactories.h>
00169 #include <lal/SeqFactories.h>
00170 #include <lal/SimulateCoherentGW.h>
00171 #include <lal/GenerateSpinOrbitCW.h>
00172 
00173 NRCSID( GENERATEPARABOLICSPINORBITCWC, "$Id: GenerateParabolicSpinOrbitCW.c,v 1.6 2007/06/08 14:41:47 bema Exp $" );
00174 
00175 /* <lalVerbatim file="GenerateParabolicSpinOrbitCWCP"> */
00176 void
00177 LALGenerateParabolicSpinOrbitCW( LALStatus             *stat,
00178                                  CoherentGW            *output,
00179                                  SpinOrbitCWParamStruc *params )
00180 { /* </lalVerbatim> */
00181   UINT4 n, i;              /* number of and index over samples */
00182   UINT4 nSpin = 0, j;      /* number of and index over spindown terms */
00183   REAL8 t, dt, tPow;       /* time, interval, and t raised to a power */
00184   REAL8 phi0, f0, twopif0; /* initial phase, frequency, and 2*pi*f0 */
00185   REAL8 f, fPrev;      /* current and previous values of frequency */
00186   REAL4 df = 0.0;      /* maximum difference between f and fPrev */
00187   REAL8 phi;           /* current value of phase */
00188   REAL8 vp;            /* projected speed at periapsis */
00189   REAL8 argument;      /* argument of periapsis */
00190   REAL8 fourCosOmega;  /* four times the cosine of argument */
00191   REAL8 twoSinOmega;   /* two times the sine of argument */
00192   REAL8 vpCosOmega;    /* vp times cosine of argument */
00193   REAL8 vpSinOmega;    /* vp times sine of argument */
00194   REAL8 vpSinOmega2;   /* vpSinOmega squared */
00195   REAL8 vDot6;         /* 6 times angular speed at periapsis */
00196   REAL8 oneBy12vDot;   /* one over (12 times angular speed) */
00197   REAL8 pBy3;          /* constant sqrt(p/3) in cubic equation */
00198   REAL8 p32;           /* constant (p/3)^1.5 in cubic equation */
00199   REAL8 c, c0, dc;     /* C variable, offset, and step increment */
00200   REAL8 e, e2, e0;     /* E variable, E^2, and constant piece of E */
00201   REAL8 de;            /* coefficient of sinh() piece of E */
00202   REAL8 tpOff;         /* orbit epoch - time series epoch (s) */
00203   REAL8 spinOff;       /* spin epoch - orbit epoch (s) */
00204   REAL8 *fSpin = NULL; /* pointer to Taylor coefficients */
00205   REAL4 *fData;        /* pointer to frequency data */
00206   REAL8 *phiData;      /* pointer to phase data */
00207 
00208   INITSTATUS( stat, "LALGenerateParabolicSpinOrbitCW",
00209               GENERATEPARABOLICSPINORBITCWC );
00210   ATTATCHSTATUSPTR( stat );
00211 
00212   /* Make sure parameter and output structures exist. */
00213   ASSERT( params, stat, GENERATESPINORBITCWH_ENUL,
00214           GENERATESPINORBITCWH_MSGENUL );
00215   ASSERT( output, stat, GENERATESPINORBITCWH_ENUL,
00216           GENERATESPINORBITCWH_MSGENUL );
00217 
00218   /* Make sure output fields don't exist. */
00219   ASSERT( !( output->a ), stat, GENERATESPINORBITCWH_EOUT,
00220           GENERATESPINORBITCWH_MSGEOUT );
00221   ASSERT( !( output->f ), stat, GENERATESPINORBITCWH_EOUT,
00222           GENERATESPINORBITCWH_MSGEOUT );
00223   ASSERT( !( output->phi ), stat, GENERATESPINORBITCWH_EOUT,
00224           GENERATESPINORBITCWH_MSGEOUT );
00225   ASSERT( !( output->shift ), stat, GENERATESPINORBITCWH_EOUT,
00226           GENERATESPINORBITCWH_MSGEOUT );
00227 
00228   /* If Taylor coeficients are specified, make sure they exist. */
00229   if ( params->f ) {
00230     ASSERT( params->f->data, stat, GENERATESPINORBITCWH_ENUL,
00231             GENERATESPINORBITCWH_MSGENUL );
00232     nSpin = params->f->length;
00233     fSpin = params->f->data;
00234   }
00235 
00236   /* Set up some constants (to avoid repeated calculation or
00237      dereferencing), and make sure they have acceptable values. */
00238   vp = params->rPeriNorm*params->angularSpeed;
00239   vDot6 = 6.0*params->angularSpeed;
00240   n = params->length;
00241   dt = params->deltaT;
00242   f0 = fPrev = params->f0;
00243   if ( params->oneMinusEcc != 0.0 ) {
00244     ABORT( stat, GENERATESPINORBITCWH_EECC,
00245            GENERATESPINORBITCWH_MSGEECC );
00246   }
00247   if ( vp >= 1.0 ) {
00248     ABORT( stat, GENERATESPINORBITCWH_EFTL,
00249            GENERATESPINORBITCWH_MSGEFTL );
00250   }
00251   if ( vp <= 0.0 || dt <= 0.0 || f0 <= 0.0 || vDot6 <= 0.0 ||
00252        n == 0 ) {
00253     ABORT( stat, GENERATESPINORBITCWH_ESGN,
00254            GENERATESPINORBITCWH_MSGESGN );
00255   }
00256 #ifndef NDEBUG
00257   if ( lalDebugLevel & LALWARNING ) {
00258     if ( f0*n*dt*vp*vp > 0.5 )
00259       LALWarning( stat, "Orbit may have significant relativistic"
00260                   " effects that are not included" );
00261   }
00262 #endif
00263 
00264   /* Compute offset between time series epoch and periapsis, and
00265      betweem periapsis and spindown reference epoch. */
00266   tpOff = (REAL8)( params->orbitEpoch.gpsSeconds -
00267                    params->epoch.gpsSeconds );
00268   tpOff += 1.0e-9 * (REAL8)( params->orbitEpoch.gpsNanoSeconds -
00269                              params->epoch.gpsNanoSeconds );
00270   spinOff = (REAL8)( params->orbitEpoch.gpsSeconds -
00271                      params->spinEpoch.gpsSeconds );
00272   spinOff += 1.0e-9 * (REAL8)( params->orbitEpoch.gpsNanoSeconds -
00273                                params->spinEpoch.gpsNanoSeconds );
00274 
00275   /* Set up some other constants. */
00276   twopif0 = f0*LAL_TWOPI;
00277   phi0 = params->phi0;
00278   argument = params->omega;
00279   oneBy12vDot = 0.5/vDot6;
00280   fourCosOmega = 4.0*cos( argument );
00281   twoSinOmega = 2.0*sin( argument );
00282   vpCosOmega = 0.25*vp*fourCosOmega;
00283   vpSinOmega = 0.5*vp*twoSinOmega;
00284   vpSinOmega2 = vpSinOmega*vpSinOmega;
00285   pBy3 = sqrt( 4.0*( 1.0 + vpCosOmega ) - vpSinOmega2 );
00286   p32 = 1.0/( pBy3*pBy3*pBy3 );
00287   c0 = p32*( vpSinOmega*( 6.0*vpCosOmega - 12.0 + vpSinOmega2 ) -
00288              tpOff*vDot6 );
00289   dc = p32*vDot6*dt;
00290   e0 = 3.0*vpSinOmega;
00291   de = 2.0*pBy3;
00292 
00293   /* Check whether REAL8 precision is good enough. */
00294 #ifndef NDEBUG
00295   if ( lalDebugLevel & LALWARNING ) {
00296     REAL8 x = fabs( c0 + n*dc ); /* a temporary computation variable */
00297     if ( x < fabs( c0 ) )
00298       x = fabs( c0 );
00299     x = 6.0 + log( x + sqrt( x*x + 1.0 ) );
00300     if ( LAL_REAL8_EPS*f0*dt*n*x > 0.01 )
00301       LALWarning( stat, "REAL8 arithmetic may not have sufficient"
00302                   " precision for this orbit" );
00303   }
00304 #endif
00305 
00306   /* Allocate output structures. */
00307   if ( ( output->a = (REAL4TimeVectorSeries *)
00308          LALMalloc( sizeof(REAL4TimeVectorSeries) ) ) == NULL ) {
00309     ABORT( stat, GENERATESPINORBITCWH_EMEM,
00310            GENERATESPINORBITCWH_MSGEMEM );
00311   }
00312   memset( output->a, 0, sizeof(REAL4TimeVectorSeries) );
00313   if ( ( output->f = (REAL4TimeSeries *)
00314          LALMalloc( sizeof(REAL4TimeSeries) ) ) == NULL ) {
00315     LALFree( output->a ); output->a = NULL;
00316     ABORT( stat, GENERATESPINORBITCWH_EMEM,
00317            GENERATESPINORBITCWH_MSGEMEM );
00318   }
00319   memset( output->f, 0, sizeof(REAL4TimeSeries) );
00320   if ( ( output->phi = (REAL8TimeSeries *)
00321          LALMalloc( sizeof(REAL8TimeSeries) ) ) == NULL ) {
00322     LALFree( output->a ); output->a = NULL;
00323     LALFree( output->f ); output->f = NULL;
00324     ABORT( stat, GENERATESPINORBITCWH_EMEM,
00325            GENERATESPINORBITCWH_MSGEMEM );
00326   }
00327   memset( output->phi, 0, sizeof(REAL8TimeSeries) );
00328 
00329   /* Set output structure metadata fields. */
00330   output->position = params->position;
00331   output->psi = params->psi;
00332   output->a->epoch = output->f->epoch = output->phi->epoch
00333     = params->epoch;
00334   output->a->deltaT = n*params->deltaT;
00335   output->f->deltaT = output->phi->deltaT = params->deltaT;
00336   output->a->sampleUnits = lalStrainUnit;
00337   output->f->sampleUnits = lalHertzUnit;
00338   output->phi->sampleUnits = lalDimensionlessUnit;
00339   LALSnprintf( output->a->name, LALNameLength, "CW amplitudes" );
00340   LALSnprintf( output->f->name, LALNameLength, "CW frequency" );
00341   LALSnprintf( output->phi->name, LALNameLength, "CW phase" );
00342 
00343   /* Allocate phase and frequency arrays. */
00344   LALSCreateVector( stat->statusPtr, &( output->f->data ), n );
00345   BEGINFAIL( stat ) {
00346     LALFree( output->a );   output->a = NULL;
00347     LALFree( output->f );   output->f = NULL;
00348     LALFree( output->phi ); output->phi = NULL;
00349   } ENDFAIL( stat );
00350   LALDCreateVector( stat->statusPtr, &( output->phi->data ), n );
00351   BEGINFAIL( stat ) {
00352     TRY( LALSDestroyVector( stat->statusPtr, &( output->f->data ) ),
00353          stat );
00354     LALFree( output->a );   output->a = NULL;
00355     LALFree( output->f );   output->f = NULL;
00356     LALFree( output->phi ); output->phi = NULL;
00357   } ENDFAIL( stat );
00358 
00359   /* Allocate and fill amplitude array. */
00360   {
00361     CreateVectorSequenceIn in; /* input to create output->a */
00362     in.length = 2;
00363     in.vectorLength = 2;
00364     LALSCreateVectorSequence( stat->statusPtr, &(output->a->data), &in );
00365     BEGINFAIL( stat ) {
00366       TRY( LALSDestroyVector( stat->statusPtr, &( output->f->data ) ),
00367            stat );
00368       TRY( LALDDestroyVector( stat->statusPtr, &( output->phi->data ) ),
00369            stat );
00370       LALFree( output->a );   output->a = NULL;
00371       LALFree( output->f );   output->f = NULL;
00372       LALFree( output->phi ); output->phi = NULL;
00373     } ENDFAIL( stat );
00374     output->a->data->data[0] = output->a->data->data[2] = params->aPlus;
00375     output->a->data->data[1] = output->a->data->data[3] = params->aCross;
00376   }
00377 
00378   /* Fill frequency and phase arrays. */
00379   fData = output->f->data->data;
00380   phiData = output->phi->data->data;
00381   for ( i = 0; i < n; i++ ) {
00382 
00383     /* Compute emission time. */
00384     c = c0 + dc*i;
00385     if ( c > 0 )
00386       e = e0 + de*sinh( log( c + sqrt( c*c + 1.0 ) )/3.0 );
00387     else
00388       e = e0 + de*sinh( -log( -c + sqrt( c*c + 1.0 ) )/3.0 );
00389     e2 = e*e;
00390     phi = t = tPow = oneBy12vDot*e*( 12.0 + e2 );
00391 
00392     /* Compute source emission phase and frequency. */
00393     f = 1.0;
00394     for ( j = 0; j < nSpin; j++ ) {
00395       f += fSpin[j]*tPow;
00396       phi += fSpin[j]*( tPow*=t )/( j + 2.0 );
00397     }
00398 
00399     /* Appy frequency Doppler shift. */
00400     f *= f0 / ( 1.0 + vp*( fourCosOmega - e*twoSinOmega )
00401                 /( 4.0 + e2 ) );
00402     phi *= twopif0;
00403     if ( fabs( f - fPrev ) > df )
00404       df = fabs( f - fPrev );
00405     *(fData++) = fPrev = f;
00406     *(phiData++) = phi + phi0;
00407   }
00408 
00409   /* Set output field and return. */
00410   params->dfdt = df*dt;
00411   DETATCHSTATUSPTR( stat );
00412   RETURN( stat );
00413 }

Generated on Tue Oct 7 02:39:47 2008 for LAL by  doxygen 1.5.2