PulsarCatTest.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="PulsarCatTestCV">
00021 Author: Creighton, T. D.
00022 $Id: PulsarCatTest.c,v 1.6 2007/06/08 14:41:52 bema Exp $
00023 **************************************************** </lalVerbatim> */
00024 
00025 /********************************************************** <lalLaTeX>
00026 
00027 \subsection{Program \texttt{PulsarCatTest.c}}
00028 \label{ss:PulsarCatTest.c}
00029 
00030 Tests routines to manipulate pulsar data.
00031 
00032 \subsubsection*{Usage}
00033 \begin{verbatim}
00034 PulsarCatTest [-p posepoch ra dec pmra pmdec] [-l site earthfile sunfile] [-h]
00035               [-t newepoch] [-i infile] [-o outfile] [-d debuglevel]
00036               [fepoch f0 [f1 ...]]
00037 \end{verbatim}
00038 
00039 \subsubsection*{Description}
00040 
00041 This program reads in or randomly generates pulsar parameters, stores
00042 them in a pulsar catalogue structure, and manipulates them based on
00043 command-line arguments.  The following option flags are accepted (in
00044 any order):
00045 \begin{itemize}
00046 \item[\texttt{-p}] The pulsar position at time \verb@posepoch@ is set
00047 to \verb@ra@ radians right ascension and \verb@dec@ radians
00048 declination, with proper motions of \verb@pmra@ and \verb@pmdec@
00049 radians per second, respectively.  See below for parsing formats for
00050 \verb@posepoch@.  If the \verb@-p@ option is not specified, a random
00051 source position is generated.
00052 \item[\texttt{-l}] Sets the detector location.  \verb@site@ must be
00053 one of the following character strings: \verb@LHO@, \verb@LLO@,
00054 \verb@VIRGO@, \verb@GEO600@, \verb@TAMA300@, or \verb@CIT40@.
00055 \verb@earthfile@ and \verb@sunfile@ are ephemeris files of the format
00056 expected by \verb@LALInitBarycenter()@.  If the \verb@-l@ option is
00057 not specified, the detector is placed at the solar system barycentre.
00058 \item[\texttt{-h}] Prints usage information and then exits.
00059 \item[\texttt{-t}] Sets the new epoch to which the pulsar data will be
00060 updated.  See below for parsing formats for \verb@newepoch@.  If the
00061 \verb@-t@ option is not given, \verb@-t J2000.0@ is assumed.
00062 \item[\texttt{-i}] Reads the pulsar data from the file \verb@infile@,
00063 whose format is described below.  This overrides the position and spin
00064 information read from the command line.  If the name \verb@stdin@ is
00065 given, it will read from standard input, \emph{not} from a file named
00066 \verb@stdin@.
00067 \item[\texttt{-o}] Writes the pulsar data to the file \verb@outfile@.
00068 If the name \verb@stdout@ or \verb@stderr@ is given, it will write to
00069 standard output or standard error (respectively), \emph{not} to a file
00070 named \verb@stdout@ or \verb@stderr@.  If the \verb@-o@ option is not
00071 given, the routines are exercised, but no output is written.
00072 \item[\texttt{-d}] Sets the debug level to \verb@debuglevel@.  If
00073 absent, level 0 is assumed.
00074 \end{itemize}
00075 
00076 Once all valid options are read, the remaining command-line arguments
00077 are taken to be the epoch \verb@fepoch@ at which the pulsar spin
00078 frequency \verb@f@ (in Hz) was measured, plus zero or more frequency
00079 derivatives \verb@f1@$\ldots$ (in Hz${}^{k+1}$ for the $k^\mathrm{th}$
00080 derivative).  If no additional arguments are given, spin timing
00081 information will be omitted.
00082 
00083 Meaurement epoch \verb@posepoch@, \verb@newepoch@, and \verb@fepoch@
00084 may be specified either as a \verb@REAL8@ Julian epoch preceded by a
00085 \verb@J@ character (e.g.\ \verb@JD2000.0@), a \verb@REAL8@ number of
00086 Julian days preceded by \verb@JD@ (e.g.\ \verb@JD2451545.0@), or as an
00087 \verb@INT8@ number of GPS nanoseconds with no prefix (e.g.\
00088 \verb@630763213000000000@).  Note that the preceding examples all
00089 refer to noon UTC, January 1, 2000.  Also, note that each Julian epoch
00090 is assumed to be exactly 365.25 Julian days, so J2001.0 corresponds to
00091 18:00 UTC, January 1, 2001.
00092 
00093 If an input file is specified, it should consist of a header line
00094 that, when tokenized, can be parsed by \verb@LALReadPulsarCatHead()@,
00095 followed by one or more lines of pulsar data parseable (when
00096 tokenized) by \verb@LALReadPulsarCatLine()@.  Blank lines (with no
00097 tokens) or divider lines (with only one token) will be skipped.
00098 
00099 \subsubsection*{Exit codes}
00100 ****************************************** </lalLaTeX><lalErrTable> */
00101 #define PULSARCATTESTC_ENORM 0
00102 #define PULSARCATTESTC_ESUB  1
00103 #define PULSARCATTESTC_EARG  2
00104 #define PULSARCATTESTC_EVAL  3
00105 #define PULSARCATTESTC_EMEM  4
00106 #define PULSARCATTESTC_EFILE 5
00107 
00108 #define PULSARCATTESTC_MSGENORM "Normal exit"
00109 #define PULSARCATTESTC_MSGESUB  "Subroutine failed"
00110 #define PULSARCATTESTC_MSGEARG  "Error parsing arguments"
00111 #define PULSARCATTESTC_MSGEVAL  "Input argument out of valid range"
00112 #define PULSARCATTESTC_MSGEMEM  "Out of memory"
00113 #define PULSARCATTESTC_MSGEFILE "Could not open file"
00114 /******************************************** </lalErrTable><lalLaTeX>
00115 
00116 \subsubsection*{Algorithm}
00117 
00118 This routine simply parses the input arguments, stuffs the data into a
00119 \verb@PulsarCatNode@ structure, and then calls
00120 \verb@LAUpdatePulsarCatNode()@ to update it to the new epoch.
00121 
00122 If the \verb@-i@ option is given, the corresponding file is opened and
00123 read by \verb@LALCHARReadVectorSequence()@, then each line is
00124 tokenized by \verb@LALCreateTokenList()@.  
00125 
00126 Output via the \verb@-o@ option is in a custom human-readable format,
00127 which should be easy to figure out.
00128 
00129 \subsubsection*{Uses}
00130 \begin{verbatim}
00131 lalDebugLevel
00132 LALPrintError()                 LALCheckMemoryLeaks()
00133 LALMalloc()                     LALFree()
00134 LALDCreateVector()              LALDDestroyVector()
00135 LALCreateRandomParams()         LALDestroyRandomParams()
00136 LALUniformDeviate()             LALInitBarycenter()
00137 LALGPStoINT8()                  LALINT8toGPS()
00138 LALCHARReadVectorSequence()     LALCHARDestroyVectorSequence()
00139 LALCreateTokenList()            LALDestroyTokenList()
00140 LALReadPulsarCatHead()          LALReadPulsarCatLine()
00141 LALStringToD()                  LALStringToI8()
00142 LALLeapSec()                    LALUpdatePulsarCat()
00143 LALSnprintf()
00144 \end{verbatim}
00145 
00146 \subsubsection*{Notes}
00147 
00148 At present the routine is kludged up to ignore pulsar position and
00149 frequency information from the command line, using hardwired
00150 parameters for \mbox{PSR J0034-0534} instead.  It can still override
00151 this with the \verb@-i@ option.
00152 
00153 \vfill{\footnotesize\input{PulsarCatTestCV}}
00154 
00155 ******************************************************* </lalLaTeX> */
00156 
00157 #include <stdlib.h>
00158 #include <lal/LALStdio.h>
00159 #include <lal/LALStdlib.h>
00160 #include <lal/LALConstants.h>
00161 #include <lal/StringInput.h>
00162 #include <lal/StreamInput.h>
00163 #include <lal/AVFactories.h>
00164 #include <lal/SeqFactories.h>
00165 #include <lal/Random.h>
00166 #include <lal/LALInitBarycenter.h>
00167 #include <lal/Date.h>
00168 #include <lal/StringInput.h>
00169 #include <lal/DetectorSite.h>
00170 #include <lal/PulsarCat.h>
00171 
00172 NRCSID( PULSARCATTESTC, "$Id: PulsarCatTest.c,v 1.6 2007/06/08 14:41:52 bema Exp $" );
00173 
00174 /* Default parameter settings. */
00175 int lalDebugLevel = 0;
00176 #define J2000GPS 630763213 /* J2000.0 epoch in GPS seconds */
00177 #define J2000JD    2451545 /* J2000.0 epoch in Julian days */
00178 
00179 /* Usage format string. */
00180 #define USAGE "Usage: %s [-p posepoch ra dec pmra pmdec]\n" \
00181 "\t[-l site earthfile sunfile] [-h]\n" \
00182 "\t[-t newepoch] [-i infile] [-o outfile] [-d debuglevel]\n" \
00183 "\t[fepoch f0 [f1 ...]]\n"
00184 
00185 /* List of whitespace characters used for tokenizing input. */
00186 #define WHITESPACES " \b\f\n\r\t\v"
00187 
00188 /* Maximum length of fprintderr() format or error/info message
00189    strings. */
00190 #define MAXLEN 1024
00191 
00192 /* Macros for printing errors and testing subroutines. */
00193 #define ERROR( code, msg, statement )                                \
00194 do                                                                   \
00195 if ( lalDebugLevel & LALERROR )                                      \
00196 {                                                                    \
00197   LALPrintError( "Error[0] %d: program %s, file %s, line %d, %s\n"   \
00198                  "        %s %s\n", (code), *argv, __FILE__,         \
00199                  __LINE__, PULSARCATTESTC,                           \
00200                  statement ? statement : "", (msg) );                \
00201 }                                                                    \
00202 while (0)
00203 
00204 #define INFO( statement )                                            \
00205 do                                                                   \
00206 if ( lalDebugLevel & LALINFO )                                       \
00207 {                                                                    \
00208   LALPrintError( "Info[0]: program %s, file %s, line %d, %s\n"       \
00209                  "        %s\n", *argv, __FILE__, __LINE__,          \
00210                  PULSARCATTESTC, (statement) );                      \
00211 }                                                                    \
00212 while (0)
00213 
00214 #define WARNING( statement )                                         \
00215 do                                                                   \
00216 if ( lalDebugLevel & LALWARNING )                                    \
00217 {                                                                    \
00218   LALPrintError( "Warning[0]: program %s, file %s, line %d, %s\n"    \
00219                  "        %s\n", *argv, __FILE__, __LINE__,          \
00220                  PULSARCATTESTC, (statement) );                      \
00221 }                                                                    \
00222 while (0)
00223 
00224 #define SUB( func, statusptr )                                       \
00225 do                                                                   \
00226 if ( (func), (statusptr)->statusCode )                               \
00227 {                                                                    \
00228   ERROR( PULSARCATTESTC_ESUB, PULSARCATTESTC_MSGESUB,                \
00229          "Function call \"" #func "\" failed:" );                    \
00230   return PULSARCATTESTC_ESUB;                                        \
00231 }                                                                    \
00232 while (0)
00233 
00234 #define CHECKVAL( val, lower, upper )                                \
00235 do                                                                   \
00236 if ( ( (val) < (lower) ) || ( (val) > (upper) ) )                    \
00237 {                                                                    \
00238   ERROR( PULSARCATTESTC_EVAL, PULSARCATTESTC_MSGEVAL,                \
00239          "Value of " #val " out of range:" );                        \
00240   if ( lalDebugLevel & LALERROR )                                    \
00241     LALPrintError( #val " = %f, range = [%f,%f]\n", (REAL8)(val),    \
00242                    (REAL8)(lower), (REAL8)(upper) );                 \
00243   return PULSARCATTESTC_EVAL;                                        \
00244 }                                                                    \
00245 while (0)
00246 
00247 /* A global pointer for debugging. */
00248 #ifndef NDEBUG
00249 char *lalWatch;
00250 #endif
00251 
00252 /* Prototype for a routine to parse epoch strings. */
00253 static void
00254 ParseEpoch( LALStatus *stat, LIGOTimeGPS *epoch, const CHAR *string );
00255 
00256 /* Prototype for a routine to print floating-point numbers with
00257    uncertainties. */
00258 int
00259 fprintderr( FILE *fp, REAL8 x, REAL8 dx );
00260 
00261 /* Prototype for a routine to print GPS epochs. */
00262 int
00263 fprintepoch( FILE *fp, LIGOTimeGPS epoch );
00264 
00265 
00266 int
00267 main(int argc, char **argv)
00268 {
00269   static LALStatus stat;       /* status structure */
00270   int arg;                     /* command-line argument counter */
00271   BOOLEAN posGiven = 0;        /* whether position was given */
00272   CHAR *infile = NULL;         /* name of infile */
00273   CHAR *outfile = NULL;        /* name of outfile */
00274   CHAR *earthfile = NULL;      /* name of earthfile */
00275   CHAR *sunfile = NULL;        /* name of sunfile */
00276   CHAR *site = NULL;           /* name of detector site */
00277   PulsarCatNode node;          /* pulsar data structure */
00278   LIGOTimeGPS epoch;           /* epoch of update */
00279   LALPlaceAndGPS detectorTime; /* epoch and detector site */
00280   EphemerisData *edat = NULL;  /* detector ephemerides */
00281 
00282   /* First set up some defaults. */
00283   memset( &node, 0, sizeof(PulsarCatNode) );
00284   epoch.gpsSeconds = J2000GPS;
00285   epoch.gpsNanoSeconds = 0;
00286   detectorTime.p_gps = &epoch;
00287   detectorTime.p_detector = NULL;
00288 
00289   /*******************************************************************
00290    * ARGUMENT PARSING (arg stores the current position)              *
00291    *******************************************************************/
00292 
00293   /* Start reading options. */
00294   arg = 1;
00295   while ( arg < argc ) {
00296     /* Parse position option. */
00297     if ( !strcmp( argv[arg], "-p" ) ) {
00298       if ( argc > arg + 5 ) {
00299         arg++;
00300         SUB( ParseEpoch( &stat, &(node.posepoch), argv[arg++] ),
00301              &stat );
00302         node.pos.system = COORDINATESYSTEM_EQUATORIAL;
00303         node.pos.longitude = atof( argv[arg++] );
00304         node.pos.latitude = atof( argv[arg++] );
00305         node.pm.system = COORDINATESYSTEM_EQUATORIAL;
00306         node.pm.longitude = atof( argv[arg++] );
00307         node.pm.latitude = atof( argv[arg++] );
00308         posGiven = 1;
00309       } else {
00310         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00311         LALPrintError( USAGE, *argv );
00312         return PULSARCATTESTC_EARG;
00313       }
00314     }
00315     /* Parse detector location option. */
00316     else if ( !strcmp( argv[arg], "-l" ) ) {
00317       if ( argc > arg + 3 ) {
00318         arg++;
00319         site = argv[arg++];
00320         earthfile = argv[arg++];
00321         sunfile = argv[arg++];
00322       } else {
00323         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00324         LALPrintError( USAGE, *argv );
00325         return PULSARCATTESTC_EARG;
00326       }
00327     }
00328     /* Parse output time option. */
00329     else if ( !strcmp( argv[arg], "-t" ) ) {
00330       if ( argc > arg + 1 ) {
00331         arg++;
00332         SUB( ParseEpoch( &stat, &epoch, argv[arg++] ), &stat );
00333       } else {
00334         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00335         LALPrintError( USAGE, *argv );
00336         return PULSARCATTESTC_EARG;
00337       }
00338     }
00339     /* Parse input file option. */
00340     else if ( !strcmp( argv[arg], "-i" ) ) {
00341       if ( argc > arg + 1 ) {
00342         arg++;
00343         infile = argv[arg++];
00344       } else {
00345         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00346         LALPrintError( USAGE, *argv );
00347         return PULSARCATTESTC_EARG;
00348       }
00349     }
00350     /* Parse output file option. */
00351     else if ( !strcmp( argv[arg], "-o" ) ) {
00352       if ( argc > arg + 1 ) {
00353         arg++;
00354         outfile = argv[arg++];
00355       } else {
00356         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00357         LALPrintError( USAGE, *argv );
00358         return PULSARCATTESTC_EARG;
00359       }
00360     }
00361     /* Parse debug level option. */
00362     else if ( !strcmp( argv[arg], "-d" ) ) {
00363       if ( argc > arg + 1 ) {
00364         arg++;
00365         lalDebugLevel = atoi( argv[arg++] );
00366       } else {
00367         ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00368         LALPrintError( USAGE, *argv );
00369         return PULSARCATTESTC_EARG;
00370       }
00371     }
00372     /* Parse help option. */
00373     else if ( !strcmp( argv[arg], "-h" ) ) {
00374       INFO( PULSARCATTESTC_MSGENORM );
00375       LALPrintError( USAGE, *argv );
00376       return PULSARCATTESTC_ENORM;
00377     }
00378     /* Any additional command-line options are timing parameters. */
00379     else if ( argc >= arg + 2 ) {
00380       REAL8 *f; /* pointer to timing data */
00381       SUB( ParseEpoch( &stat, &(node.fepoch), argv[arg++] ), &stat );
00382       SUB( LALDCreateVector( &stat, &(node.f), argc - arg ), &stat );
00383       for ( f = node.f->data; arg < argc; f++ )
00384         *f = atof( argv[arg++] );
00385     }
00386     /* Unknown option. */
00387     else {
00388       ERROR( PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG, 0 );
00389       LALPrintError( USAGE, *argv );
00390       return PULSARCATTESTC_EARG;
00391     }
00392   }
00393 
00394   /*******************************************************************
00395    * SETUP                                                           *
00396    *******************************************************************/
00397 
00398   /* If position was not given, generate one randomly. */
00399   if ( !posGiven ) {
00400     RandomParams *params = NULL; /* random number parameters */
00401     REAL4 x;                     /* random deviate */
00402     SUB( LALCreateRandomParams( &stat, &params, 0 ), &stat );
00403     node.pos.system = COORDINATESYSTEM_EQUATORIAL;
00404     SUB( LALUniformDeviate( &stat, &x, params ), &stat );
00405     node.pos.longitude = LAL_TWOPI*x;
00406     SUB( LALUniformDeviate( &stat, &x, params ), &stat );
00407     node.pos.latitude = LAL_PI*( x - 0.5 );
00408     SUB( LALDestroyRandomParams( &stat, &params ), &stat );
00409     node.posepoch.gpsSeconds = J2000GPS;
00410     node.posepoch.gpsNanoSeconds = 0;
00411 
00412     /* Instead, kludge it up for PSR J1939+2134, B1937+21.
00413     memcpy( node.jname, "J1939+2134", 11*sizeof(CHAR) );
00414     memcpy( node.bname, "B1937+21", 9*sizeof(CHAR) );
00415     node.pos.system  = COORDINATESYSTEM_EQUATORIAL;
00416     node.dpos.system = COORDINATESYSTEM_EQUATORIAL;
00417     node.pm.system   = COORDINATESYSTEM_EQUATORIAL;
00418     node.dpm.system  = COORDINATESYSTEM_EQUATORIAL;
00419     node.pos.latitude   = 0.3766960555;
00420     node.dpos.latitude  = 0.0000000034;
00421     node.pos.longitude  = 5.1471621406;
00422     node.dpos.longitude = 0.0000000015;
00423     node.pm.latitude   = -7.13E-17;
00424     node.dpm.latitude  =  0.14E-17;
00425     node.pm.longitude  = -2.00E-17;
00426     node.dpm.longitude =  0.12E-17;
00427     SUB( ParseEpoch( &stat, &(node.posepoch), "JD2447500.0" ), &stat );
00428     SUB( LALDCreateVector( &stat, &(node.f), 2 ), &stat );
00429     SUB( LALDCreateVector( &stat, &(node.df), 2 ), &stat );
00430     node.f->data[0]  = 641.92825287201;
00431     node.df->data[0] =   0.00000000017;
00432     node.f->data[1]  =  -4.3313E-14;
00433     node.df->data[1] =   0.0013E-14;
00434     SUB( ParseEpoch( &stat, &(node.fepoch), "JD2450100.0" ), &stat ); */
00435 
00436     /* Instead, kludge it up for PSR J0034-0534.
00437     memcpy( node.jname, "J0034-0534", 11*sizeof(CHAR) );
00438     node.pos.system  = COORDINATESYSTEM_EQUATORIAL;
00439     node.dpos.system = COORDINATESYSTEM_EQUATORIAL;
00440     node.pm.system   = COORDINATESYSTEM_EQUATORIAL;
00441     node.dpm.system  = COORDINATESYSTEM_EQUATORIAL;
00442     node.pos.latitude   = -0.097334152;
00443     node.dpos.latitude  =  0.000000097;
00444     node.pos.longitude  =  0.149940232;
00445     node.dpos.longitude =  0.000000036;
00446     node.pm.latitude   = -0.5E-15;
00447     node.dpm.latitude  =  3.5E-15;
00448     node.pm.longitude  =  2.3E-15;
00449     node.dpm.longitude =  1.7E-15;
00450     SUB( ParseEpoch( &stat, &(node.posepoch), "JD2449550.0" ), &stat );
00451     SUB( LALDCreateVector( &stat, &(node.f), 2 ), &stat );
00452     SUB( LALDCreateVector( &stat, &(node.df), 2 ), &stat );
00453     node.f->data[0]  = 532.71343832081;
00454     node.df->data[0] =   0.00000000015;
00455     node.f->data[1]  =  -1.436E-15;
00456     node.df->data[1] =   0.009E-15;
00457     SUB( ParseEpoch( &stat, &(node.fepoch), "JD2449550.0" ), &stat ); */
00458   }
00459 
00460   /* If the detector was specified, set up the detector position. */
00461   if ( site ) {
00462     UINT4 i; /* site index */
00463     if ( !strcmp( site, "LHO" ) )
00464       i = LALDetectorIndexLHODIFF;
00465     else if ( !strcmp( site, "LLO" ) )
00466       i = LALDetectorIndexLLODIFF;
00467     else if ( !strcmp( site, "VIRGO" ) )
00468       i = LALDetectorIndexVIRGODIFF;
00469     else if ( !strcmp( site, "GEO600" ) )
00470       i = LALDetectorIndexGEO600DIFF;
00471     else if ( !strcmp( site, "TAMA300" ) )
00472       i = LALDetectorIndexTAMA300DIFF;
00473     else if ( !strcmp( site, "CIT40" ) )
00474       i = LALDetectorIndexCIT40DIFF;
00475     else {
00476       ERROR( PULSARCATTESTC_EVAL, PULSARCATTESTC_MSGEVAL,
00477              "Unrecognized site:" );
00478       if ( lalDebugLevel & LALERROR )
00479         LALPrintError( "%s", site );
00480       return PULSARCATTESTC_EVAL;
00481     }
00482     detectorTime.p_detector =
00483       (LALDetector *)LALMalloc( sizeof(LALDetector) );
00484     if ( !(detectorTime.p_detector) ) {
00485       ERROR( PULSARCATTESTC_EMEM, PULSARCATTESTC_MSGEMEM, 0 );
00486       return PULSARCATTESTC_EMEM;
00487     }
00488     *(detectorTime.p_detector) = lalCachedDetectors[i];
00489 
00490     /* Read ephemerides. */
00491     edat = (EphemerisData *)LALMalloc( sizeof(EphemerisData) );
00492     if ( !(edat) ) {
00493       ERROR( PULSARCATTESTC_EMEM, PULSARCATTESTC_MSGEMEM, 0 );
00494       return PULSARCATTESTC_EMEM;
00495     }
00496     edat->ephiles.earthEphemeris = earthfile;
00497     edat->ephiles.sunEphemeris = sunfile;
00498     SUB( LALInitBarycenter( &stat, edat ), &stat );
00499   }
00500 
00501   /* If an input file was specified, it overrides the preceding
00502      position and frequency information. */
00503   if ( infile ) {
00504     UINT4 i = 0;                     /* line number */
00505     UINT4 n = 0;                     /* number of pulsars read */
00506     CHAR msg[MAXLEN];                /* error/info message string */
00507     CHARVectorSequence *file = NULL; /* input file */
00508     TokenList *list = NULL;          /* input line parsed into tokens */
00509     INT4 indx[PULSARCATINDEX_NUM];   /* ordering of tokens in line */
00510     PulsarCatNode *here = &node;     /* structure for current line */
00511     FILE *fp = NULL;                 /* input file pointer */
00512 
00513     /* Read in file. */
00514     if ( !strcmp( infile, "stdin" ) )
00515       fp = stdin;
00516     else
00517       fp = fopen( infile, "r" ); 
00518     if ( fp == NULL ) {
00519       ERROR( PULSARCATTESTC_EFILE, PULSARCATTESTC_MSGEFILE, infile );
00520       return PULSARCATTESTC_EFILE;
00521     }
00522     SUB( LALCHARReadVectorSequence( &stat, &file, fp ), &stat );
00523     fclose( fp );
00524 
00525     /* Read header, skipping blank or divider lines. */
00526     SUB( LALCreateTokenList( &stat, &list, file->data, WHITESPACES ),
00527          &stat );
00528     while ( list->nTokens < 3 && ++i < file->length ) {
00529       SUB( LALDestroyTokenList( &stat, &list ), &stat );
00530       SUB( LALCreateTokenList( &stat, &list, file->data +
00531                                i*file->vectorLength, WHITESPACES ),
00532            &stat );
00533     }
00534     if ( i >= file->length ) {
00535       WARNING( "No header found in input file" );
00536     } else {
00537       SUB( LALReadPulsarCatHead( &stat, indx, list ), &stat );
00538     }
00539     SUB( LALDestroyTokenList( &stat, &list ), &stat );
00540 
00541     /* Read body, skipping blank or divider lines. */
00542     while ( ++i < file->length ) {
00543       SUB( LALCreateTokenList( &stat, &list, file->data +
00544                                i*file->vectorLength, WHITESPACES ),
00545            &stat );
00546       while ( list->nTokens < 3 && ++i < file->length ) {
00547         SUB( LALDestroyTokenList( &stat, &list ), &stat );
00548         SUB( LALCreateTokenList( &stat, &list, file->data +
00549                                  i*file->vectorLength, WHITESPACES ),
00550              &stat );
00551       }
00552       if ( i < file->length ) {
00553         if ( !( here->next = (PulsarCatNode *)
00554                 LALMalloc( sizeof(PulsarCatNode) ) ) ) {
00555           ERROR( PULSARCATTESTC_EMEM, PULSARCATTESTC_MSGEMEM, 0 );
00556           return PULSARCATTESTC_EMEM;
00557         }
00558         memset( here->next, 0, sizeof(PulsarCatNode) );
00559 
00560         /* Ignore lines that don't parse, moving on to the next. */
00561         LALReadPulsarCatLine( &stat, here->next, list, indx );
00562         if ( stat.statusCode ) {
00563           LALSnprintf( msg, MAXLEN, "Error reading line %i of %s:"
00564                        " skipping", i, infile );
00565           ERROR( 0, msg, 0 );
00566           if ( stat.statusPtr ) {
00567             FREESTATUSPTR( &stat );
00568           }
00569           memset( &stat, 0, sizeof(LALStatus) );
00570           SUB( LALDestroyPulsarCat( &stat, &(here->next) ), &stat );
00571         } else {
00572           here = here->next;
00573           n++;
00574         }
00575       }
00576       SUB( LALDestroyTokenList( &stat, &list ), &stat );
00577     }
00578     LALSnprintf( msg, MAXLEN, "File %s had %i lines and %i parseable"
00579                  " pulsars", infile, i, n );
00580     INFO( msg );
00581     SUB( LALCHARDestroyVectorSequence( &stat, &file ), &stat );
00582   }
00583 
00584 
00585   /*******************************************************************
00586    * CONVERSION                                                      *
00587    *******************************************************************/
00588 
00589   /* Perform update. */
00590   SUB( LALUpdatePulsarCat( &stat, &node, &detectorTime, edat ),
00591        &stat );
00592 
00593   /* If output was requested, print output. */
00594   if ( outfile ) {
00595     PulsarCatNode *here = &node; /* current position in catalogue */
00596     FILE *fp = NULL;             /* output file pointer */
00597     if ( !strcmp( outfile, "stdout" ) )
00598       fp = stdout;
00599     else if ( !strcmp( outfile, "stderr" ) )
00600       fp = stderr;
00601     else
00602       fp = fopen( outfile, "w" );
00603     if ( fp == NULL ) {
00604       ERROR( PULSARCATTESTC_EFILE, PULSARCATTESTC_MSGEFILE, outfile );
00605       return PULSARCATTESTC_EFILE;
00606     }
00607     if ( infile )
00608       here = here->next;
00609 
00610     /* First print epoch information. */
00611     if ( site ) {
00612       fprintf( fp, "%s time = ", site );
00613       fprintepoch( fp, epoch );
00614       fprintf( fp, "\n" );
00615     }
00616 
00617     /* Now print pulsar information. */
00618     while ( here ) {
00619       CompanionNode *companion = here->companion; /* companion data */
00620       UINT4 compNo = 0; /* companion number */
00621       fprintf( fp, "\n" );
00622       if ( here->jname[0] != '\0' ) {
00623         fprintf( fp, "PULSAR %s", here->jname );
00624         if ( here->bname[0] != '\0' )
00625           fprintf( fp, " (%s)", here->bname );
00626         fprintf( fp, "\n" );
00627       } else if ( here->bname[0] != '\0' )
00628         fprintf( fp, "PULSAR %s\n", here->bname );
00629       else
00630         fprintf( fp, "PULSAR (Unknown)\n" );
00631       fprintf( fp, "epoch = " );
00632       fprintepoch( fp, here->posepoch );
00633       fprintf( fp, "\n" );
00634       fprintf( fp, "ra    = " );
00635       fprintderr( fp, here->pos.longitude, here->dpos.longitude );
00636       fprintf( fp, " rad\n" );
00637       fprintf( fp, "dec   = " );
00638       fprintderr( fp, here->pos.latitude, here->dpos.latitude );
00639       fprintf( fp, " rad\n" );
00640       fprintf( fp, "pmra  = " );
00641       fprintderr( fp, here->pm.longitude, here->dpm.longitude );
00642       fprintf( fp, " rad/s\n" );
00643       fprintf( fp, "pmdec = " );
00644       fprintderr( fp, here->pm.latitude, here->dpm.latitude );
00645       fprintf( fp, " rad/s\n" );
00646       /* SUB( LALGPStoINT8( &stat, &ep, &(here->posepoch) ), &stat );
00647          fprintf( fp, "posepoch = %lli ns\n", ep ); */
00648       if ( here->f ) {
00649         UINT4 i; /* an index */
00650         fprintf( fp, "f0    = " );
00651         fprintderr( fp, 2.0*here->f->data[0], 2.0*here->df->data[0] );
00652         fprintf( fp, " Hz\n" );
00653         for ( i = 1; i < here->f->length; i++ ) {
00654           fprintf( fp, "f%i    = ", i );
00655           fprintderr( fp, 2.0*here->f->data[i], 2.0*here->df->data[i] );
00656           fprintf( fp, " Hz^%i\n", i+1 );
00657         }
00658         /* SUB( LALGPStoINT8( &stat, &ep, &(here->fepoch) ), &stat );
00659            fprintf( fp, "fepoch = %lli ns\n", ep ); */
00660       }
00661       if ( here->dist > 0.0 )
00662         fprintf( fp, "dist = %15.8e m\n", here->dist );
00663       if ( here->dmin > 0.0 )
00664         fprintf( fp, "dmin = %15.8e m\n", here->dmin );
00665       if ( here->dmax > 0.0 )
00666         fprintf( fp, "dmax = %15.8e m\n", here->dmax );
00667       if ( here->lcode >= 'a' && here->lcode <= 'd' )
00668         fprintf( fp, "lcode = %c\n", here->lcode );
00669       if ( here->ucode >= 'a' && here->ucode <= 'd' )
00670         fprintf( fp, "ucode = %c\n", here->ucode );
00671       /* fprintf( fp, "typecode = %i\n", here->typecode ); */
00672       while ( companion ) {
00673         fprintf( fp, "Companion %i\n", ++compNo );
00674         /* SUB( LALGPStoINT8( &stat, &ep, &(companion->epoch) ), &stat );
00675            fprintf( fp, "  epoch = %lli ns\n", ep ); */
00676         fprintf( fp, "  epoch = " );
00677         fprintepoch( fp, companion->epoch );
00678         fprintf( fp, "\n" );
00679         fprintf( fp, "  x     = %23.16e s\n", companion->x );
00680         fprintf( fp, "  p     = %23.16e s\n", companion->p );
00681         fprintf( fp, "  pDot  = %23.16e\n", companion->pDot );
00682         fprintf( fp, "  w     = %23.16e rad\n", companion->w );
00683         fprintf( fp, "  wDot  = %23.16e rad/s\n", companion->wDot );
00684         fprintf( fp, "  ecc   = %23.16e\n", companion->ecc );
00685         fprintf( fp, "  gamma = %23.16e s\n", companion->gamma );
00686         fprintf( fp, "  sin   = %23.16e\n", companion->sin );
00687         fprintf( fp, "  r     = %23.16e\n", companion->r );
00688         companion = companion->next;
00689       }
00690       here = here->next;
00691     }
00692     fclose( fp );
00693   }
00694 
00695 
00696   /*******************************************************************
00697    * CLEANUP                                                         *
00698    *******************************************************************/
00699 
00700   /* Destroy any allocated memory. */
00701   if ( node.next ) {
00702     SUB( LALDestroyPulsarCat( &stat, &(node.next) ), &stat );
00703   }
00704   if ( node.f ) {
00705     SUB( LALDDestroyVector( &stat, &(node.f) ), &stat );
00706   }
00707   if ( node.df ) {
00708     SUB( LALDDestroyVector( &stat, &(node.df) ), &stat );
00709   }
00710   if ( edat ) {
00711     if ( edat->ephemE )
00712       LALFree( edat->ephemE );
00713     if ( edat->ephemS )
00714       LALFree( edat->ephemS );
00715     LALFree( edat );
00716   }
00717   if ( detectorTime.p_detector )
00718     LALFree( detectorTime.p_detector );
00719 
00720   /* Done! */
00721   LALCheckMemoryLeaks();
00722   INFO( PULSARCATTESTC_MSGENORM );
00723   return PULSARCATTESTC_ENORM;
00724 }
00725 
00726 
00727 /* A routine to parse epoch strings. */
00728 static void
00729 ParseEpoch( LALStatus *stat, LIGOTimeGPS *epoch, const CHAR *string )
00730 {
00731   INT8 gpsNan;  /* number of GPS nanoseconds */
00732   CHAR *endptr; /* pointer to end of parsed data */
00733 
00734   INITSTATUS( stat, "ParseEpoch", PULSARCATTESTC );
00735   ATTATCHSTATUSPTR( stat );
00736 
00737   /* Parse Julian days, or Julian epochs (converted to days). */
00738   if ( string[0] == 'J' ) {
00739     REAL8 julianDay;            /* Julian date */
00740     INT4 leap1, leap2;          /* number of leap seconds to date */
00741     LALLeapSecFormatAndAcc acc; /* accuracy of leap second computation */
00742     if ( string[1] == 'D' ) {
00743       TRY( LALStringToD( stat->statusPtr, &julianDay, string+2,
00744                          &endptr ), stat );
00745       if ( endptr == string+2 ) {
00746         ABORT( stat, PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG );
00747       }
00748     } else {
00749       TRY( LALStringToD( stat->statusPtr, &julianDay, string+1,
00750                          &endptr ), stat );
00751       if ( endptr == string+1 ) {
00752         ABORT( stat, PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG );
00753       }
00754       julianDay -= 2000.0;
00755       julianDay *= 365.25;
00756       julianDay += J2000JD;
00757     }
00758 
00759     /* Convert Julian days to GPS nanoseconds. */
00760     acc.accuracy = LALLEAPSEC_STRICT;
00761     acc.format = LALLEAPSEC_GPSUTC;
00762     gpsNan = (INT8)( ( julianDay - 2444244.5 )*(8.64e13L) );
00763     TRY( LALINT8toGPS( stat->statusPtr, epoch, &gpsNan ), stat );
00764     leap2 = 0;
00765     do {
00766       leap1 = leap2;
00767       TRY( LALLeapSecs( stat->statusPtr, &leap2, epoch, &acc ),
00768            stat );
00769       epoch->gpsSeconds += leap2 - leap1;
00770     } while ( leap2 != leap1 );
00771   }
00772 
00773   /* Parse GPS times directly. */
00774   else {
00775     TRY( LALStringToI8( stat->statusPtr, &gpsNan, string, &endptr ),
00776          stat );
00777     if ( endptr == string ) {
00778       ABORT( stat, PULSARCATTESTC_EARG, PULSARCATTESTC_MSGEARG );
00779     }
00780     TRY( LALINT8toGPS( stat->statusPtr, epoch, &gpsNan ), stat );
00781   }
00782 
00783   /* That's all. */
00784   DETATCHSTATUSPTR( stat );
00785   RETURN( stat );
00786 }
00787 
00788 
00789 int
00790 fprintderr( FILE *fp, REAL8 x, REAL8 dx ) {
00791   CHAR format[MAXLEN]; /* format string for fprintf() */
00792   INT4 gsd = 0;        /* place index of greatest significant digit */
00793   INT4 lsd = 0;        /* place index of least significant digit */
00794   REAL8 norm;          /* normalization factor */
00795 
00796   /* Compute gsd, lsd, y, and dy. */
00797   if ( dx < LAL_REAL8_EPS*fabs( x ) )
00798     dx = 0.0;
00799   if ( dx > 0.0 ) {
00800     REAL8 lsdd = log( 0.5*dx )/log( 10.0 );
00801     if ( lsdd >= 0.0 )
00802       lsd = (INT4)( lsdd );
00803     else
00804       lsd = (INT4)( lsdd ) - 1;
00805   }
00806   if ( x != 0.0 ) {
00807     REAL8 gsdd = log( fabs( x ) )/log( 10.0 );
00808     if ( gsdd >= 0.0 )
00809       gsd = (INT4)( gsdd );
00810     else
00811       gsd = (INT4)( gsdd ) - 1;
00812   }
00813 
00814   /* If x is zero, format is determined entirely by dx. */
00815   if ( x == 0.0 ) {
00816     if ( dx <= 0.0 )
00817       return fprintf( fp, "0" );
00818     if ( abs( lsd ) > 3 ) {
00819       norm = pow( 10.0, -lsd );
00820       return fprintf( fp, "( 0 +/- %.0f )e%+i", dx*norm, lsd );
00821     }
00822     if ( lsd <= 0 ) {
00823       LALSnprintf( format, MAXLEN, "%%.%if +/- %%.%if", -lsd, -lsd );
00824       return fprintf( fp, format, 0.0, dx );
00825     }
00826     norm = pow( 10.0, -lsd );
00827     LALSnprintf( format, MAXLEN, "0 +/- %%.0f%%0%ii", lsd );
00828     return fprintf( fp, format, dx*norm, 0 );
00829   }
00830 
00831   /* If number is exact to 8-byte precision, print it as such. */
00832   if ( dx <= 0.0 ) {
00833     if ( abs( gsd ) > 3 )
00834       return fprintf( fp, "%.16e", x );
00835     LALSnprintf( format, MAXLEN, "%%.%if", 16 - gsd );
00836     return fprintf( fp, format, x );
00837   }
00838 
00839   /* Otherwise, format depends on x and dx. */
00840   if ( gsd < lsd )
00841     gsd = lsd;
00842   if ( lsd > 3 || gsd < -3 ) {
00843     norm = pow( 10.0, -gsd );
00844     LALSnprintf( format, MAXLEN, "( %%.%if +/- %%.%if )e