SimulatePulsarSignal.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005 Reinhard Prix
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 /**
00021  * \author Reinhard Prix
00022  * \date 2005
00023  * \file 
00024  * \brief Routines to simulate pulsar-signals "exactly".
00025 
00026 The motivation for this module is to provide functions to
00027 simulate pulsar signals <em>with the best possible accuracy</em>, 
00028 i.e. using no approximations, contrary to LALGeneratePulsarSignal(). 
00029 
00030 Obviously this is not meant as a fast code to be used in a Monte-Carlo
00031 simulation, but rather as a <em>reference</em> to compare other (faster)
00032 functions agains, in order to be able to gauge the quality of a given
00033 signal-generation routine.
00034 
00035 We want to calculate \f$h(t)\f$, given by
00036 \f[
00037 \label{eq:1}
00038         h(t) = F_+(t)\, h_+(t) + F_\times(t) \,h_\times(t)\,,
00039 \f]
00040 where \f$F_+\f$ and \f$F_x\f$ are called the <em>beam-pattern</em> functions, 
00041 which depend of the wave polarization \f$\psi\f$,
00042 the source position \f$\alpha\f$, \f$\delta\f$ and the detector position and
00043 orientation (\f$\gamma\f$, \f$\lambda\f$, \f$L\f$ and \f$\xi\f$). The expressions for 
00044 the beam-pattern functions are given in \ref JKS98 "[JKS98]", which we write as
00045 \f{eqnarray}
00046 F_+(t) = \sin \zeta \cos 2\psi \, a(t)  + \sin \zeta \sin 2\psi \, b(t)\,,\\
00047 F_\times(t) = \sin\zeta  \cos 2\psi \,b(t) - \sin\zeta \sin 2\psi \, a(t) \,,
00048 \f}
00049 where \f$\zeta\f$ is the angle between the interferometer arms, and 
00050 \f{eqnarray}
00051 a(t) &=& a_1 \cos[ 2 (\alpha - T)) ] + a_2 \sin[ 2(\alpha - T)]
00052 + a_3 \cos[ \alpha - T ] + a_4 \sin [ \alpha - T ] + a_5\,,\\
00053 b(t) &=& b_1 \cos[ 2(\alpha - T)] + b_2 \sin[ 2(\alpha - T) ]
00054 + b_3 \cos[ \alpha - T ] + b_4 \sin[ \alpha - T]\,,
00055 \f}
00056 where \f$T\f$ is the local (mean) sidereal time of the detector, and the 
00057 time-independent coefficients \f$a_i\f$ and \f$b_i\f$ are given by
00058 \f{eqnarray}
00059 a_1 &=& {1\over 16} \sin 2\gamma \,(3- \cos 2\lambda)\,(3 - \cos 2\delta)\,,\\
00060 a_2 &=& -{1\over 4}\cos 2\gamma \,\sin \lambda \,(3 - \cos 2\delta) \,,\\
00061 a_3 &=& {1\over 4} \sin 2\gamma \,\sin 2\lambda \,\sin 2\delta  \,\\
00062 a_4 &=& -{1\over2} \cos 2\gamma \,\cos \lambda \,\sin 2 \delta\,,\\
00063 a_5 &=& {3\over4} \sin 2\gamma \, \cos^2 \lambda \,\cos^2 \delta\,,
00064 \f}
00065 and 
00066 \f{eqnarray}
00067 b_1 &=& \cos 2\gamma \,\sin \lambda \,\sin \delta\,,\\
00068 b_2 &=& {1\over 4} \sin 2\gamma \,(3-\cos 2\lambda)\, \sin \delta\,,\\
00069 b_3 &=& \cos 2\gamma \,\cos \lambda \,\cos\delta \,, \\
00070 b_4 &=& {1\over 2} \sin2\gamma \,\sin 2\lambda \,\cos\delta\,,
00071 \f}
00072 
00073 The source model considered is a plane-wave
00074 \f{eqnarray}
00075 h_+(t) &=& A_+\, \cos \Psi(t)\,,\\
00076 h_\times(t) &=& A_\times \, \sin \Psi(t)\,,
00077 \f}
00078 where the wave-phase is \f$\Psi(t) = \Phi_0 + \Phi(t)\f$, and for an
00079 isolated pulsar we have
00080 \f{equation}
00081 \Phi(t) = 2\pi \left[\sum_{s=0} {f^{(s)}(\tau_\mathrm{ref}) \over
00082 (s+1)!} \left( \tau(t) - \tau_\mathrm{ref} \right)^{s+1} \right]\,,
00083 \f}
00084 where \f$\tau_\mathrm{ref}\f$ is the "reference time" for the definition
00085 of the pulsar-parameters \f$f^{(s)}\f$ in the solar-system barycenter
00086 (SSB), and \f$\tau(t)\f$ is the SSB-time of the phase arriving at the
00087 detector at UTC-time \f$t\f$, which depends on the source-position
00088 (\f$\alpha\f$, \f$\delta\f$) and the detector-position, namely
00089 \f{equation}
00090   \tau (t) = t + { \vec{r}(t)\cdot\vec{n} \over c}\,,
00091 \f}
00092 where \f$\vec{r}(t)\f$ is the vector from SSB to the detector, and \f$\vec{n}\f$ 
00093 is the unit-vector pointing \emph{to} the source.
00094 
00095 This is a standalone "clean-room" implementation using no other 
00096 outside-functions <em>except</em> for LALGPStoLMST1() to calculate 
00097 the local (mean) sidereal time at the detector for given GPS-time, 
00098 (which I double-checked with an independent Mathematica script),
00099 and and LALBarycenter() to calculate \f$\tau(t)\f$.
00100 
00101  * $Id: SimulatePulsarSignal.c,v 1.16 2008/04/30 18:53:06 kipp Exp $
00102  *
00103  */
00104 
00105 #include <lal/AVFactories.h>
00106 #include <lal/TimeSeries.h>
00107 #include <lal/GeneratePulsarSignal.h>
00108 #include <lal/ComputeFstat.h>
00109 #include <lal/ExtrapolatePulsarSpins.h>
00110 
00111 NRCSID( SIMULATEPULSARSIGNALC, "$Id: SimulatePulsarSignal.c,v 1.16 2008/04/30 18:53:06 kipp Exp $");
00112 
00113 extern INT4 lalDebugLevel;
00114 
00115 
00116 /*----- Macros ----- */
00117 
00118 #define SQ(x) ((x) * (x))
00119 
00120 /** convert GPS-time to REAL8 */
00121 #define GPS2REAL8(gps) (1.0 * (gps).gpsSeconds + 1.e-9 * (gps).gpsNanoSeconds )
00122 
00123 /** copy 3 components of Euklidean vector */
00124 #define COPY_VECT(dst,src) do { (dst)[0] = (src)[0]; (dst)[1] = (src)[1]; (dst)[2] = (src)[2]; } while(0)
00125 
00126 /** Simple Euklidean scalar product for two 3-dim vectors in cartesian coords */
00127 #define SCALAR(u,v) ((u)[0]*(v)[0] + (u)[1]*(v)[1] + (u)[2]*(v)[2])
00128 
00129 #define TRUE  (1==1)
00130 #define FALSE (1==0)
00131 
00132 #define oneBillion 1000000000L
00133 
00134 #define NUM_SPINDOWNS   3
00135 
00136 /* error-codes */
00137 #define SIMULATEPULSARSIGNAL_ENULL              1
00138 #define SIMULATEPULSARSIGNAL_ENONULL            2
00139 #define SIMULATEPULSARSIGNAL_EMEM               3
00140 #define SIMULATEPULSARSIGNAL_ESYS               4
00141 #define SIMULATEPULSARSIGNAL_EINPUT             5
00142 #define SIMULATEPULSARSIGNAL_EFUN               6
00143 
00144 
00145 #define SIMULATEPULSARSIGNAL_MSGENULL           "Arguments contained an unexpected null pointer"
00146 #define SIMULATEPULSARSIGNAL_MSGENONULL         "Output pointer is not NULL"
00147 #define SIMULATEPULSARSIGNAL_MSGEMEM            "Out of memory"
00148 #define SIMULATEPULSARSIGNAL_MSGESYS            "System error, probably while File I/O"
00149 #define SIMULATEPULSARSIGNAL_MSGEINPUT          "Invalid input-arguments to function"
00150 #define SIMULATEPULSARSIGNAL_MSGEFUN            "Subroutine failed"
00151 
00152 static LALUnit emptyUnit;
00153 
00154 
00155 
00156 /** Simulate a pulsar signal to best accuracy possible.
00157  *
00158  * NOTE: currently only isolated pulsars are supported
00159  *
00160  * NOTE2: we don't really use the highest possible accuracy right now,
00161  *   as we blatently neglect all relativistic timing effects (i.e. using dT=v.n/c)
00162  *
00163  * NOTE3: no heterodyning is performed here, the time-series is generated and sampled
00164  * at the given rate, that's all! ==> the caller needs to make sure about the 
00165  * right sampling rate to use (->aliasing) and do the proper post-treatment...
00166  *
00167  */
00168 void
00169 LALSimulateExactPulsarSignal (LALStatus *status, 
00170                               REAL4TimeSeries **timeSeries, 
00171                               const PulsarSignalParams *params)
00172 {
00173   LALFrDetector *site = &(params->site->frDetector);
00174   REAL8 Delta, Alpha;
00175   UINT4 numSteps, i;
00176 
00177   REAL8 refTime, startTimeSSB;
00178   DetectorStateSeries *detStates = NULL;
00179   LIGOTimeGPSVector *timestamps = NULL;
00180   REAL8 dt;
00181   REAL8 vn[3];
00182   REAL8 A1, A2, A3, A4;
00183   REAL8 phi0, f0, f1dot, f2dot, f3dot;
00184   AMCoeffs *amcoe;
00185   REAL8 xAzi, yAzi;
00186   REAL8 Zeta, sinZeta;
00187   UINT4 numSpins = PULSAR_MAX_SPINS;
00188 
00189   CHAR *channel;
00190 
00191   INITSTATUS( status, "LALSimulatePulsarSignal", SIMULATEPULSARSIGNALC );
00192   ATTATCHSTATUSPTR(status);
00193 
00194   ASSERT ( timeSeries, status, SIMULATEPULSARSIGNAL_ENULL, SIMULATEPULSARSIGNAL_MSGENULL);
00195   ASSERT ( (*timeSeries)==NULL, status, SIMULATEPULSARSIGNAL_ENONULL, SIMULATEPULSARSIGNAL_MSGENONULL);
00196   /* don't accept heterodyning frequency */
00197   ASSERT ( params->fHeterodyne==0, status, SIMULATEPULSARSIGNAL_EINPUT, SIMULATEPULSARSIGNAL_MSGEINPUT);
00198 
00199   /* get timestamps of timeseries plus detector-states */
00200   dt = 1.0 / params->samplingRate;
00201   TRY ( LALMakeTimestamps(status->statusPtr, &timestamps, params->startTimeGPS, params->duration, dt),  status);
00202 
00203   numSteps = timestamps->length;
00204 
00205   TRY(LALGetDetectorStates(status->statusPtr, &detStates,timestamps,params->site,params->ephemerides,0), status );
00206   
00207   TRY ( LALDestroyTimestampVector (status->statusPtr, &timestamps), status );
00208   timestamps = NULL;
00209 
00210   amcoe = LALCalloc ( 1,  sizeof( *(amcoe)));
00211   amcoe->a = XLALCreateREAL4Vector ( numSteps );
00212   amcoe->b = XLALCreateREAL4Vector ( numSteps );
00213   TRY ( LALGetAMCoeffs (status->statusPtr, amcoe, detStates, params->pulsar.position ), status );
00214 
00215   /* create output timeseries (FIXME: should really know *detector* here, not just site!!) */
00216   if ( (channel = XLALGetChannelPrefix ( site->name )) == NULL )
00217     {
00218       LALPrintError ("\nXLALGetChannelPrefix() Failed to extract channel-prefix from site '%s'\n\n", site->name );
00219       ABORT (status, GENERATEPULSARSIGNALH_EDETECTOR, GENERATEPULSARSIGNALH_MSGEDETECTOR );
00220     }
00221 
00222   if ( NULL == ((*timeSeries) = XLALCreateREAL4TimeSeries( channel, &(detStates->data[0].tGPS), 0, dt, &emptyUnit, numSteps) ) )  {
00223     ABORT ( status, SIMULATEPULSARSIGNAL_EMEM, SIMULATEPULSARSIGNAL_MSGEMEM );
00224   }
00225   LALFree ( channel );
00226 
00227   /* orientation of detector arms */
00228   xAzi = site->xArmAzimuthRadians;
00229   yAzi = site->yArmAzimuthRadians;
00230   Zeta =  xAzi - yAzi;
00231   if (Zeta < 0) Zeta = -Zeta;
00232   if(params->site->type == LALDETECTORTYPE_CYLBAR) Zeta = LAL_PI_2;
00233   sinZeta = sin(Zeta);
00234 
00235   /* get source skyposition */
00236   Alpha = params->pulsar.position.longitude;
00237   Delta = params->pulsar.position.latitude;
00238   
00239   vn[0] = cos(Delta) * cos(Alpha);
00240   vn[1] = cos(Delta) * sin(Alpha);
00241   vn[2] = sin(Delta);
00242 
00243   /* get spin-parameters (restricted to maximally 3 spindowns right now) */
00244   phi0 = params->pulsar.phi0;
00245   f0   = params->pulsar.f0;
00246 
00247   if ( params->pulsar.spindown && (params->pulsar.spindown->length > numSpins) )
00248     {
00249       LALPrintError ("Sorry, SimulatePulsarSignal() only supports up to %d spindowns!\n", numSpins );
00250       ABORT (status,  SIMULATEPULSARSIGNAL_EINPUT,  SIMULATEPULSARSIGNAL_MSGEINPUT);
00251     }
00252   if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 3 ) )
00253     f3dot = params->pulsar.spindown->data[2];
00254   else
00255     f3dot = 0.0;
00256   if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 2 ) )
00257     f2dot = params->pulsar.spindown->data[1];
00258   else
00259     f2dot = 0.0;
00260   if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 1 ) )
00261     f1dot = params->pulsar.spindown->data[0];
00262   else
00263     f1dot = 0.0;
00264 
00265   /* internally we always work with refTime = startTime->SSB, therefore
00266    * we need to translate the pulsar spin-params and initial phase to the
00267    * startTime
00268    */
00269   startTimeSSB = GPS2REAL8(detStates->data[0].tGPS) + SCALAR(vn, detStates->data[0].rDetector );
00270   if ( params->pulsar.refTime.gpsSeconds != 0 )
00271     {
00272       REAL8 refTime0 = GPS2REAL8(params->pulsar.refTime);
00273       REAL8 deltaRef = startTimeSSB - refTime0; 
00274       LIGOTimeGPS newEpoch;
00275       PulsarSpins fkdotOld, fkdotNew;
00276       
00277       XLALGPSSetREAL8( &newEpoch, startTimeSSB );
00278 
00279       fkdotOld[0] = f0;
00280       fkdotOld[1] = f1dot;
00281       fkdotOld[2] = f2dot;
00282       fkdotOld[3] = f3dot;
00283 
00284       TRY ( LALExtrapolatePulsarSpins ( status->statusPtr, fkdotNew, newEpoch, fkdotOld, params->pulsar.refTime ), status );
00285 
00286       /* Finally, need to propagate phase */
00287       phi0 += LAL_TWOPI * (               f0    * deltaRef 
00288                             + (1.0/2.0) * f1dot * deltaRef * deltaRef 
00289                             + (1.0/6.0) * f2dot * deltaRef * deltaRef * deltaRef
00290                             + (1.0/24.0)* f3dot * deltaRef * deltaRef * deltaRef * deltaRef 
00291                             );
00292 
00293       f0    = fkdotNew[0];
00294       f1dot = fkdotNew[1];
00295       f2dot = fkdotNew[2];
00296       f3dot = fkdotNew[3];
00297 
00298       refTime = startTimeSSB;
00299 
00300     } /* if refTime given */
00301   else /* if not given: use startTime -> SSB */
00302     refTime = startTimeSSB;
00303 
00304   /* get 4 amplitudes A_\mu */
00305   {
00306     REAL8 aPlus  = sinZeta * params->pulsar.aPlus;
00307     REAL8 aCross = sinZeta * params->pulsar.aCross;
00308     REAL8 twopsi = 2.0 * params->pulsar.psi;
00309   
00310     A1 =  aPlus * cos(phi0) * cos(twopsi) - aCross * sin(phi0) * sin(twopsi);
00311     A2 =  aPlus * cos(phi0) * sin(twopsi) + aCross * sin(phi0) * cos(twopsi);
00312     A3 = -aPlus * sin(phi0) * cos(twopsi) - aCross * cos(phi0) * sin(twopsi);
00313     A4 = -aPlus * sin(phi0) * sin(twopsi) + aCross * cos(phi0) * cos(twopsi);
00314   }
00315 
00316   /* main loop: generate time-series */
00317   for (i=0; i < detStates->length; i++)
00318     {
00319       REAL8 ai, bi;
00320       LIGOTimeGPS *tiGPS = &(detStates->data[i].tGPS);
00321       REAL8 ti, deltati, dT, taui;
00322       REAL8 phi_i, cosphi_i, sinphi_i;
00323       REAL8 hi;
00324 
00325       ti = GPS2REAL8 ( (*tiGPS) );
00326       deltati = ti - refTime;
00327       dT = SCALAR(vn, detStates->data[i].rDetector );
00328       taui = deltati + dT;
00329 
00330       phi_i = LAL_TWOPI * ( f0 * taui 
00331                             + (1.0/2.0) * f1dot * taui*taui
00332                             + (1.0/6.0) * f2dot * taui*taui*taui
00333                             + (1.0/24.0)* f3dot * taui*taui*taui*taui
00334                             );
00335 
00336       cosphi_i = cos(phi_i);
00337       sinphi_i = sin(phi_i);
00338 
00339       ai = amcoe->a->data[i];
00340       bi = amcoe->b->data[i];
00341       
00342       hi = A1 * ai * cosphi_i 
00343         +  A2 * bi * cosphi_i 
00344         +  A3 * ai * sinphi_i 
00345         +  A4 * bi * sinphi_i;
00346 
00347       (*timeSeries)->data->data[i] = (REAL4)hi;
00348 
00349     } /* for i < Nsteps */
00350 
00351   TRY ( LALDestroyDetectorStateSeries(status->statusPtr, &detStates ), status );
00352   XLALDestroyREAL4Vector(  amcoe->a );
00353   XLALDestroyREAL4Vector(  amcoe->b );
00354   LALFree ( amcoe );
00355 
00356   DETATCHSTATUSPTR(status);
00357   RETURN(status);
00358 
00359 } /* LALSimulateExactPulsarSignal() */
00360 
00361 

Generated on Tue Oct 14 02:32:20 2008 for LAL by  doxygen 1.5.2