LALPulsar  6.1.0.1-fe68b98
ReadPulsarParFile.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2013 Jolien Creighton, Matt Pitkin
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  * \author Matt Pitkin
22  * \date 2013
23  * \file
24  * \ingroup lalpulsar_general
25  * \brief Functions to read TEMPO pulsar parameter files
26  *
27  Functions for reading pulsar parameters from TEMPO .par files.
28 
29  # Prototypes
30 
31 
32 
33  # Description
34 
35  Radio astronomers fit pulsar parameters using TEMPO(2) which will output
36  the parameters in a <tt>.par</tt> file. The values allowed in this file can be
37  found in the TEMPO documentation. Two function are available to extract these
38  parameters from the <tt>.par</tt> files:
39  <ul>
40  <li>\c XLALReadTEMPOParFileOrig - this will read parameters into a \c BinaryPulsarParams structure and set
41  any unused parameters to zero or \c NULL. To use this you must know the correct parameter name within
42  the structure. This is deprecated in favour of \c XLALReadTEMPOParFile and is no longer maintained</li>
43  <li>\c XLALReadTEMPOParFile - this reads the parameters into a linked list \c PulsarParameters structure, from which the
44  parameters can be accessed using the appropriate access function. These use a hash table to quick look-up.
45  The parameters are assigned names, which are used as the hash table keys, which are fully uppercase
46  versions of the TEMPO parameter names.
47  </ul>
48  All parameters read in are converted into SI units.
49 
50  Functions are is also included which converts a string containing the right ascension or
51  declination in the format <tt>ddd/hh:mm:ss.s</tt> or <tt>ddd/hhmmss.s</tt>
52  (as is given in the <tt>.par</tt> file) into a \c REAL8 value in
53  radians.
54 
55  # Notes
56 
57 */
58 
59 #include <config.h>
60 #include <string.h>
61 #include <math.h>
62 #include <locale.h>
63 #include <ctype.h>
64 #ifdef HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
67 #include <lal/LALConstants.h>
68 #include <lal/LALStdlib.h>
69 #include <lal/LALString.h>
70 #include <lal/ComputeFstat.h>
71 #include <lal/TranslateAngles.h>
72 #include <lal/TranslateMJD.h>
73 #include <lal/LALHashFunc.h>
74 #include <lal/ReadPulsarParFile.h>
75 
76 #ifdef __GNUC__
77 #define UNUSED __attribute__ ((unused))
78 #else
79 #define UNUSED
80 #endif
81 
82 
83 #define DAYSTOSECS 86400.0 /* number of seconds in an SI day */
84 
85 size_t PulsarTypeSize[5] = {
86  sizeof( UINT4 ),
87  sizeof( REAL8 ),
88  sizeof( REAL8Vector * ),
89  sizeof( CHAR ) *PULSAR_PARNAME_MAX,
90  sizeof( void * )
91 };
92 
93 
94 /** Array for conversion from lowercase to uppercase */
95 static const CHAR a2A[256] = {
96  ['a'] = 'A', ['b'] = 'B', ['c'] = 'C', ['d'] = 'D', ['e'] = 'E', ['f'] = 'F', ['g'] = 'G', ['h'] = 'H',
97  ['i'] = 'I', ['j'] = 'J', ['k'] = 'K', ['l'] = 'L', ['m'] = 'M', ['n'] = 'N', ['o'] = 'O', ['p'] = 'P',
98  ['q'] = 'Q', ['r'] = 'R', ['s'] = 'S', ['t'] = 'T', ['u'] = 'U', ['v'] = 'V', ['w'] = 'W', ['x'] = 'X',
99  ['y'] = 'Y', ['z'] = 'Z'
100 };
101 
102 
103 /** \brief Convert string to uppercase */
104 static void strtoupper( CHAR *s )
105 {
106  /* convert everything to uppercase */
107  CHAR c;
108  for ( ; *s; ++s ) {
109  if ( ( c = a2A[( int )( *s )] ) ) {
110  *s = c;
111  }
112  }
113 }
114 
115 /* hash functions copied from LALInference.c */
116 typedef struct taghash_elem {
117  const char *name;
118  PulsarParam *itemPtr;
119 } hash_elem;
120 
121 static void *new_elem( const char *name, PulsarParam *itemPtr )
122 {
123  hash_elem e = { .name = name, .itemPtr = itemPtr };
124  return memcpy( XLALMalloc( sizeof( e ) ), &e, sizeof( e ) );
125 };
126 
127 static void del_elem( void *elem )
128 {
129  XLALFree( elem );
130 }
131 
132 
133 /* Compute a hash value based on element */
134 static UINT8 PulsarHash( const void *elem );
135 static UINT8 PulsarHash( const void *elem )
136 {
137  if ( !elem ) {
139  }
140  size_t len = strnlen( ( ( const hash_elem * )elem )->name, PULSAR_PARNAME_MAX );
141  return ( XLALCityHash64( ( ( const hash_elem * )elem )->name, len ) );
142 }
143 
144 
145 static int PulsarHashElemCmp( const void *elem1, const void *elem2 );
146 static int PulsarHashElemCmp( const void *elem1, const void *elem2 )
147 {
148  if ( !elem1 || !elem2 ) {
150  }
151  return ( strncmp( ( ( const hash_elem * )elem1 )->name, ( ( const hash_elem * )elem2 )->name, PULSAR_PARNAME_MAX ) );
152 }
153 
154 
155 /** \brief Get a pointer to a parameter of a given name from a \c PulsarParameters structure
156  *
157  * Note this function can only be used internally.
158  */
160 {
161  /* (this function is only to be used internally) */
162  /* Returns pointer to item for given item name. */
163  if ( pars == NULL ) {
164  return NULL;
165  }
166  if ( pars->nparams == 0 ) {
167  return NULL;
168  }
169 
170  PulsarParam *this = pars->head;
171 
172  /* loop through all values checking the name */
173  while ( this != NULL ) {
174  if ( !strcmp( this->name, name ) ) {
175  break;
176  } else {
177  this = this->next;
178  }
179  }
180 
181  return ( this );
182 }
183 
184 
185 /** \brief Get a pointer to a parameter of a given name from a \c PulsarParameters structure
186  *
187  * This function will return a pointer to the parameter. It will initially try and use the parameter's hash name,
188  * otherwise it will use \c PulsarGetParamItemSlow to loop through all parameters.
189  *
190  * Note this function can only be used internally.
191  */
193 {
194  /* (this function is only to be used internally) */
195  /* Returns pointer to item for given item name. */
196  hash_elem tmp;
197  const hash_elem *match = NULL;
198 
199  CHAR upperName[PULSAR_PARNAME_MAX];
200  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
201  strtoupper( upperName );
202 
203  if ( pars == NULL ) {
204  return NULL;
205  }
206  if ( pars->nparams == 0 ) {
207  return NULL;
208  }
209  if ( !pars->hash_table ) {
210  return PulsarGetParamItemSlow( pars, upperName );
211  }
212 
213  tmp.name = upperName;
214  XLALHashTblFind( pars->hash_table, &tmp, ( const void ** )&match );
215  if ( !match ) {
216  return NULL;
217  }
218 
219  return match->itemPtr;
220 }
221 
222 
223 void *PulsarGetParam( const PulsarParameters *pars, const CHAR *name )
224 {
225  /* Return the value of variable name from the pars structure */
226  PulsarParam *item = PulsarGetParamItem( pars, name );
227  if ( !item ) {
228  XLAL_ERROR_NULL( XLAL_EFAILED, "Entry \"%s\" not found.", name );
229  }
230 
231  return ( item->value );
232 }
233 
234 
236 {
237  return PulsarGetParamItem( pars, name )->type;
238 }
239 
240 
242 {
243  /* check type is a REAL8 */
244  if ( PulsarGetParamType( pars, name ) == PULSARTYPE_REAL8_t ) {
245  return *( REAL8 * )PulsarGetParam( pars, name );
246  } else {
247  XLAL_ERROR_REAL8( XLAL_EINVAL, "Used wrong type for required parameter" );
248  }
249 }
250 
251 
253 {
254  /* if parameter is there return it otherwise return zero */
255  return PulsarCheckParam( pars, name ) ? PulsarGetREAL8Param( pars, name ) : 0.;
256 }
257 
258 
260 {
261  /* check type is a UINT4 */
262  if ( PulsarGetParamType( pars, name ) == PULSARTYPE_UINT4_t ) {
263  return *( UINT4 * )PulsarGetParam( pars, name );
264  } else {
265  XLAL_ERROR( XLAL_EINVAL, "Used wrong type for required parameter" );
266  }
267 }
268 
269 
271 {
272  /* if parameter is there return it otherwise return zero */
273  return PulsarCheckParam( pars, name ) ? PulsarGetUINT4Param( pars, name ) : 0;
274 }
275 
276 
277 const CHAR *PulsarGetStringParam( const PulsarParameters *pars, const CHAR *name )
278 {
279  /* check type is a string */
280  if ( PulsarGetParamType( pars, name ) == PULSARTYPE_string_t ) {
281  CHAR *rvalue = *( CHAR ** )PulsarGetParam( pars, name );
282  return rvalue;
283  } else {
284  XLAL_ERROR_NULL( XLAL_EINVAL, "Used wrong type for required parameter" );
285  }
286 }
287 
288 
290 {
291  /* check type is a REAL8Vector */
293  return *( REAL8Vector ** )PulsarGetParam( pars, name );
294  } else {
295  XLAL_ERROR_NULL( XLAL_EINVAL, "Used wrong type for required parameter" );
296  }
297 }
298 
299 
301 {
302  /* split the input name into the parameter name and an index e.g. FB0 into FB and 0, or GLEP_1 */
303  CHAR *namecopy = NULL, *token;
304  namecopy = XLALStringDuplicate( name );
305  REAL8 val = 0.;
306 
307  if ( strchr( name, '_' ) ) { /* check for underscore delimiting numbers */
308  token = strtok( namecopy, "_" );
309  } else { /* name delimited by just numbers */
310  token = strtok( namecopy, "0123456789" );
311  }
312 
313  const REAL8Vector *vpars = PulsarGetREAL8VectorParam( pars, token );
314 
315  /* get the index value of the parameter name */
316  INT4 idx = -1;
317  INT4 loc = strlen( token );
318  if ( name[loc] == '_' ) {
319  loc++;
320  }
321  if ( sscanf( name + loc, "%d", &idx ) != 1 ) {
322  XLAL_ERROR_REAL8( XLAL_EINVAL, "Input parameter (%s) problem", name );
323  }
324 
325  /* for glitch parameters GL, or WAVE parameters the index starts at 1, so shift it */
326  if ( !strncmp( name, "GL", 2 ) || !strncmp( name, "WAVE", 4 ) ) {
327  idx--;
328  }
329  if ( idx < 0 || ( UINT4 )idx > vpars->length - 1 ) {
330  XLAL_ERROR_REAL8( XLAL_EINVAL, "Input parameter index %d is wrong", idx );
331  }
332 
333  val = vpars->data[idx];
334 
335  XLALFree( namecopy );
336 
337  return val;
338 }
339 
340 
341 void *PulsarGetParamErr( const PulsarParameters *pars, const CHAR *name )
342 {
343  /* Return the error value of variable name from the pars structure */
344  PulsarParam *item = PulsarGetParamItem( pars, name );
345  if ( !item ) {
346  XLAL_ERROR_NULL( XLAL_EFAILED, "Entry \"%s\" not found.", name );
347  }
348 
349  return ( item->err );
350 }
351 
352 
353 const UINT4 *PulsarGetParamFitFlag( const PulsarParameters *pars, const CHAR *name )
354 {
355  /* return the fit flag value */
356  PulsarParam *item = PulsarGetParamItem( pars, name );
357  if ( !item ) {
358  XLAL_ERROR_NULL( XLAL_EFAILED, "Entry \"%s\" not found.", name );
359  }
360 
361  if ( item->fitFlag == NULL ) {
362  return NULL;
363  } else {
364  if ( item->fitFlag->data == NULL ) {
365  return NULL;
366  } else {
367  return item->fitFlag->data;
368  }
369  }
370 }
371 
372 
374 {
375  /* return the fit flag value(s) */
376  PulsarParam *item = PulsarGetParamItem( pars, name );
377  if ( !item ) {
378  XLAL_ERROR_NULL( XLAL_EFAILED, "Entry \"%s\" not found.", name );
379  }
380 
381  if ( item->fitFlag == NULL ) {
382  return NULL;
383  } else {
384  return item->fitFlag;
385  }
386 }
387 
388 
390 {
391  /* Return the error value of variable name from the pars structure */
392  /* check type is a REAL8 */
393  if ( PulsarGetParamType( pars, name ) == PULSARTYPE_REAL8_t ) {
394  void *val = PulsarGetParamErr( pars, name );
395  if ( val == NULL ) {
396  return 0.; /* if no error is present return 0 */
397  } else {
398  return *( REAL8 * )val;
399  }
400  } else {
401  XLAL_ERROR_REAL8( XLAL_EINVAL, "Used wrong type for required parameter" );
402  }
403 }
404 
405 
407 {
408  /* Return the error value of variable name from the pars structure */
409  /* check type is a REAL8 */
411  void *val = PulsarGetParamErr( pars, name );
412  if ( val == NULL ) {
413  return NULL; /* if no error is present return NULL */
414  } else {
415  return *( REAL8Vector ** )val;
416  }
417  } else {
418  XLAL_ERROR_NULL( XLAL_EINVAL, "Used wrong type for required parameter" );
419  }
420 }
421 
422 
424 {
425  /* split the input name into the parameter name and an index e.g. FB0 into FB and 0*/
426  CHAR *namecopy = NULL, *token;
427  namecopy = XLALStringDuplicate( name );
428  REAL8 val = 0.;
429 
430  if ( strchr( name, '_' ) ) { /* check for underscore delimiting numbers */
431  token = strtok( namecopy, "_" );
432  } else { /* name delimited by just numbers */
433  token = strtok( namecopy, "0123456789" );
434  }
435 
436  const REAL8Vector *vpars = PulsarGetREAL8VectorParamErr( pars, token );
437 
438  /* get the index value of the parameter name */
439  INT4 idx = -1;
440  INT4 loc = strlen( token );
441  if ( name[loc] == '_' ) {
442  loc++;
443  }
444  if ( sscanf( name + loc, "%d", &idx ) != 1 ) {
445  XLAL_ERROR_REAL8( XLAL_EINVAL, "Input parameter (%s) problem", name );
446  }
447 
448  /* for glitch parameters GL, or WAVE parameters the index starts at 1, so shift it */
449  if ( !strncmp( name, "GL", 2 ) || !strncmp( name, "WAVE", 4 ) ) {
450  idx--;
451  }
452  if ( idx < 0 || ( UINT4 )idx > vpars->length - 1 ) {
453  XLAL_ERROR_REAL8( XLAL_EINVAL, "Input parameter index %d is wrong", idx );
454  }
455 
456  val = vpars->data[idx];
457 
458  XLALFree( namecopy );
459 
460  return val;
461 }
462 
463 
464 void PulsarAddParam( PulsarParameters *pars, const CHAR *name, void *value, PulsarParamType type )
465 {
466  /* Add the variable name with type type and value value to pars */
467  /* If variable already exists, it will over-write the current value if type compatible*/
468  PulsarParam *old = NULL;
469 
470  /* create the hash table if it does not exist */
471  if ( !pars->hash_table ) {
473  }
474 
475  /* Check input value is accessible */
476  if ( !value ) {
477  XLAL_ERROR_VOID( XLAL_EFAULT, "Unable to access value through null pointer; trying to add \"%s\".", name );
478  }
479 
480  /* Check the name doesn't already exist */
481  if ( PulsarCheckParam( pars, name ) ) {
482  old = PulsarGetParamItem( pars, name );
483 
484  /* If the type is incompatible, it should be removed */
485  if ( old->type != type || old->type == PULSARTYPE_REAL8Vector_t ) {
486  PulsarRemoveParam( pars, name );
487  } else {
488  PulsarSetParam( pars, name, value );
489  return;
490  }
491  }
492 
493  /* If we get this far it is safe to create a new node for this variable */
494  PulsarParam *new = XLALMalloc( sizeof( PulsarParam ) );
495  memset( new, 0, sizeof( PulsarParam ) );
496  if ( new ) {
497  new->value = ( void * )XLALMalloc( PulsarTypeSize[type] );
498  new->fitFlag = NULL;
499 
500  /* for REAL8 and REAL8Vector parameters initialise errors and fit flags to zero */
501  if ( type == PULSARTYPE_REAL8Vector_t ) {
502  REAL8Vector *tmpvector = *( REAL8Vector ** )value;
503  UINT4 dlength = tmpvector->length;
504 
505  new->fitFlag = XLALCreateUINT4Vector( dlength );
506  memset( new->fitFlag->data, 0, sizeof( UINT4 )*dlength ); // initialise to zero
507 
508  REAL8Vector *err = XLALCreateREAL8Vector( dlength );
509  memset( err->data, 0, sizeof( REAL8 )*dlength ); // initialise to zero
510 
511  new->err = ( void * )XLALMalloc( PulsarTypeSize[type] );
512  memcpy( new->err, ( void * )&err, PulsarTypeSize[type] );
513  } else if ( type == PULSARTYPE_REAL8_t ) {
514  new->fitFlag = XLALCreateUINT4Vector( 1 );
515  memset( new->fitFlag->data, 0, sizeof( UINT4 ) ); // initialise to zero
516 
517  new->err = ( void * )XLALMalloc( sizeof( UINT4Vector * ) );
518  REAL8 err = 0.;
519  memcpy( new->err, ( void * )&err, PulsarTypeSize[type] );
520  }
521  }
522 
523  if ( new == NULL || new->value == NULL ) {
524  XLAL_ERROR_VOID( XLAL_ENOMEM, "Unable to allocate memory for list item." );
525  }
526 
527  CHAR upperName[PULSAR_PARNAME_MAX];
528  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
529  strtoupper( upperName );
530 
531  XLALStringCopy( new->name, upperName, PULSAR_PARNAME_MAX );
532  new->type = type;
533  memcpy( new->value, value, PulsarTypeSize[type] );
534  new->next = pars->head;
535  pars->head = new;
536  hash_elem *elem = new_elem( new->name, new );
537  XLALHashTblAdd( pars->hash_table, ( void * )elem );
538  pars->nparams++;
539 }
540 
541 
542 void PulsarAddREAL8Param( PulsarParameters *pars, const CHAR *name, REAL8 value )
543 /* Typed version of PulsarAddParam for REAL8 values.*/
544 {
545  PulsarAddParam( pars, name, ( void * )&value, PULSARTYPE_REAL8_t );
546 }
547 
548 
549 void PulsarAddUINT4Param( PulsarParameters *pars, const CHAR *name, UINT4 value )
550 /* Typed version of PulsarAddParam for UINT4 values.*/
551 {
552  PulsarAddParam( pars, name, ( void * )&value, PULSARTYPE_UINT4_t );
553 }
554 
555 
557 /* Typed version of PulsarAddParam for REAL8Vector values.*/
558 {
559  REAL8Vector *fval = NULL;
560  fval = XLALCreateREAL8Vector( value->length );
561  memcpy( fval->data, value->data, sizeof( REAL8 )*value->length );
562  PulsarAddParam( pars, name, ( void * )&fval, PULSARTYPE_REAL8Vector_t );
563 }
564 
565 
566 void PulsarAddStringParam( PulsarParameters *pars, const CHAR *name, const CHAR *value )
567 /* Typed version of PulsarAddParam for string values.*/
568 {
569  CHAR *sval = NULL;
572  PulsarAddParam( pars, name, ( void * )&sval, PULSARTYPE_string_t );
573 }
574 
575 
576 /* Check for existence of name */
577 int PulsarCheckParam( const PulsarParameters *pars, const CHAR *name )
578 {
579  /* convert name to uppercase */
580  CHAR upperName[PULSAR_PARNAME_MAX];
581  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
582  strtoupper( upperName );
583 
584  if ( PulsarGetParamItem( pars, upperName ) ) {
585  return 1;
586  } else {
587  return 0;
588  }
589 }
590 
591 
593 {
594  /* Free all variables inside the linked list, leaving only the head struct */
595  PulsarParam *this, *next = NULL;
596 
597  if ( !pars ) {
598  return;
599  }
600 
601  this = pars->head;
602 
603  if ( this ) {
604  next = this->next;
605  }
606 
607  while ( this ) {
608  if ( this->type == PULSARTYPE_REAL8Vector_t ) {
609  if ( this->value ) {
610  XLALDestroyREAL8Vector( *( REAL8Vector ** )this->value );
611  }
612  if ( this->err ) {
613  XLALDestroyREAL8Vector( *( REAL8Vector ** )this->err );
614  }
615  } else if ( this->type == PULSARTYPE_string_t ) {
616  if ( this->value ) {
617  XLALFree( *( CHAR ** )this->value );
618  }
619  }
620  if ( this->fitFlag ) {
621  XLALDestroyUINT4Vector( this->fitFlag );
622  }
623  XLALFree( this->value );
624  XLALFree( this->err );
625  XLALFree( this );
626  this = next;
627  if ( this ) {
628  next = this->next;
629  }
630  }
631  pars->head = NULL;
632  pars->nparams = 0;
633 
634  if ( pars->hash_table ) {
636  }
637  pars->hash_table = NULL;
638 }
639 
640 
641 /* remove a given parameter */
643 {
644  PulsarParam *this;
645 
646  if ( !pars ) {
648  }
649 
650  CHAR upperName[PULSAR_PARNAME_MAX];
651  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
652  strtoupper( upperName );
653 
654  this = pars->head;
655  PulsarParam *parent = NULL;
656 
657  while ( this ) {
658  if ( !strcmp( this->name, upperName ) ) {
659  break;
660  } else {
661  parent = this;
662  this = this->next;
663  }
664  }
665  if ( !this ) {
666  XLAL_PRINT_WARNING( "Entry \"%s\" not found.", upperName );
667  return;
668  }
669 
670  if ( !parent ) {
671  pars->head = this->next;
672  } else {
673  parent->next = this->next;
674  }
675  /* Remove from hash table */
676  hash_elem elem;
677  elem.name = this->name;
678  XLALHashTblRemove( pars->hash_table, ( void * )&elem );
679  if ( this->type == PULSARTYPE_REAL8Vector_t ) {
680  if ( this->value ) {
681  XLALDestroyREAL8Vector( *( REAL8Vector ** )this->value );
682  }
683  if ( this->err ) {
684  XLALDestroyREAL8Vector( *( REAL8Vector ** )this->err );
685  }
686  } else if ( this->type == PULSARTYPE_string_t ) {
687  if ( this->value ) {
688  XLALFree( *( CHAR ** )this->value );
689  }
690  }
691  if ( this->fitFlag ) {
692  XLALDestroyUINT4Vector( this->fitFlag );
693  }
694  XLALFree( this->value );
695  XLALFree( this->err );
696  this->value = NULL;
697  this->err = NULL;
698  this->fitFlag = NULL;
699  XLALFree( this );
700 
701  this = NULL;
702  pars->nparams--;
703 }
704 
705 
706 /* Set the value of parameter name in the pars structure to value */
707 void PulsarSetParam( PulsarParameters *pars, const CHAR *name, const void *value )
708 {
709  PulsarParam *item;
710 
711  /* convert name to uppercase */
712  CHAR upperName[PULSAR_PARNAME_MAX];
713  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
714  strtoupper( upperName );
715 
716  item = PulsarGetParamItem( pars, upperName );
717  if ( !item ) {
718  XLAL_ERROR_VOID( XLAL_EINVAL, "Entry \"%s\" not found.", upperName );
719  }
720  memcpy( item->value, value, PulsarTypeSize[item->type] );
721 }
722 
723 
724 /* Set the value of parameter name error in the pars structure to value */
725 void PulsarSetParamErr( PulsarParameters *pars, const CHAR *name, void *value, const UINT4 *fitFlag, UINT4 len )
726 {
727  PulsarParam *item;
728 
729  /* convert name to uppercase */
730  CHAR upperName[PULSAR_PARNAME_MAX];
731  XLALStringCopy( upperName, name, PULSAR_PARNAME_MAX );
732  strtoupper( upperName );
733 
734  item = PulsarGetParamItem( pars, upperName );
735  if ( !item ) {
736  XLAL_ERROR_VOID( XLAL_EINVAL, "Entry \"%s\" not found.", name );
737  }
738 
739  if ( item->err != NULL ) {
740  // Remove previous error values if present
741  if ( item->type == PULSARTYPE_REAL8Vector_t ) {
742  XLALDestroyREAL8Vector( *( REAL8Vector ** )item->err );
743  }
744  XLALFree( item->err );
745  }
746 
747  if ( ( item->err = ( void * )XLALMalloc( PulsarTypeSize[PulsarGetParamType( pars, name )] ) ) == NULL ) {
748  XLAL_ERROR_VOID( XLAL_ENOMEM, "Unable to allocate memory for list item." );
749  }
750 
751  // Remove previous fit flag if present
752  if ( item->fitFlag != NULL ) {
754 
755  // set the fit flag values
756  item->fitFlag = NULL;
757  item->fitFlag = XLALCreateUINT4Vector( len );
758  memcpy( item->fitFlag->data, fitFlag, len * sizeof( UINT4 ) );
759  }
760 
761  // set error values
762  memcpy( item->err, value, PulsarTypeSize[item->type] );
763 }
764 
765 
766 /* Set the value of parameter name error in the pars structure to value */
767 void PulsarSetREAL8ParamErr( PulsarParameters *pars, const CHAR *name, REAL8 value, UINT4 fitFlag )
768 {
769  PulsarSetParamErr( pars, name, ( void * )&value, &fitFlag, 1 );
770 }
771 
772 
773 /* Set the value of parameter name error in the pars structure to value */
774 void PulsarSetREAL8VectorParamErr( PulsarParameters *pars, const CHAR *name, const REAL8Vector *value, const UINT4 *fitFlag )
775 {
776  REAL8Vector *evals = NULL;
777  evals = XLALCreateREAL8Vector( value->length );
778  memcpy( evals->data, value->data, sizeof( REAL8 )*value->length );
779 
780  PulsarSetParamErr( pars, name, ( void * )&evals, fitFlag, value->length );
781 }
782 
783 
784 /* free memory */
786 {
787  if ( !pars ) {
788  return;
789  }
790 
791  PulsarClearParams( pars );
792  if ( pars->hash_table ) {
794  }
795  XLALFree( pars );
796 }
797 
798 
799 /* create a copy of the parameters */
801 {
802  /* Check that the source and origin differ */
803  if ( origin == target ) {
804  return;
805  }
806 
807  if ( !origin ) {
808  XLAL_ERROR_VOID( XLAL_EFAULT, "Unable to access origin pointer." );
809  }
810 
811  /* Make sure the structure is initialised */
812  if ( !target ) {
813  XLAL_ERROR_VOID( XLAL_EFAULT, "Unable to copy to uninitialised PulsarParameters structure." );
814  }
815 
816  PulsarParam *this, *next = NULL;
817 
818  this = origin->head;
819 
820  if ( this ) {
821  next = this->next;
822  }
823 
824  /* first clear target variables */
825  PulsarClearParams( target );
826 
827  while ( this ) {
828  if ( this->type == PULSARTYPE_REAL8Vector_t ) {
829  const REAL8Vector *old = *( REAL8Vector ** )this->value;
831  if ( new ) {
832  memcpy( new->data, old->data, new->length * sizeof( REAL8 ) );
833  } else {
834  XLAL_ERROR_VOID( XLAL_ENOMEM, "Unable to copy vector!\n" );
835  }
836 
837  PulsarAddREAL8VectorParam( target, this->name, ( const REAL8Vector * )new );
838 
839  if ( this->err ) {
840  const REAL8Vector *olderr = *( REAL8Vector ** )this->err;
841  REAL8Vector *newerr = XLALCreateREAL8Vector( olderr->length );
842  if ( newerr ) {
843  memcpy( newerr->data, olderr->data, newerr->length * sizeof( REAL8 ) );
844  } else {
845  XLAL_ERROR_VOID( XLAL_ENOMEM, "Unable to copy vector!\n" );
846  }
847 
848  const UINT4 *oldfit = PulsarGetParamFitFlag( origin, this->name );
849  UINT4 *newfit = ( UINT4 * )XLALCalloc( newerr->length, sizeof( UINT4 ) );
850 
851  if ( newfit ) {
852  memcpy( newfit, oldfit, newerr->length * sizeof( UINT4 ) );
853  } else {
854  XLAL_ERROR_VOID( XLAL_ENOMEM, "Unable to copy vector!\n" );
855  }
856 
857  PulsarSetREAL8VectorParamErr( target, this->name, ( const REAL8Vector * )newerr, ( const UINT4 * )newfit );
858  }
859  } else if ( this->type == PULSARTYPE_string_t ) {
860  CHAR *parstr = XLALStringDuplicate( *( CHAR ** )this->value );
861  PulsarAddStringParam( target, this->name, ( const CHAR * )parstr );
862  } else {
863  PulsarAddParam( target, this->name, this->value, this->type );
864 
865  if ( ( this->type == PULSARTYPE_REAL8_t ) && this->err ) {
866  REAL8 err = *( REAL8 * )this->err;
867 
868  const UINT4 *oldfit = PulsarGetParamFitFlag( origin, this->name );
869  UINT4 newfit = oldfit[0];
870 
871  PulsarSetREAL8ParamErr( target, this->name, err, newfit );
872  }
873  }
874 
875  this = next;
876  if ( this ) {
877  next = this->next;
878  }
879  }
880 
881  return;
882 }
883 
884 
885 /* create functions for converting par file input e.g. from strings to floats, converting times, converting units */
886 enum {
894 };
895 
896 
897 #define DEFINE_CONV_FACTOR_FUNCTION( name, convfactor, type ) \
898  void ParConv ## name ( const CHAR *inval, void *out ){ \
899  CHAR *in = XLALStringDuplicate( inval ); \
900  if ( type != CONVSTRING && type != CONVINT ) { \
901  REAL8 x; \
902  if ( type == CONVFLOAT || type == CONVBINUNITS ){ \
903  /* check for exponents expressed as 'D/d' rather than 'E/e' and switch */ \
904  for ( INT4 i = 0; i < (INT4)strlen(in); i++ ) { \
905  if ( in[i] == 'D' || in[i] == 'd' ) { in[i] = 'e'; } \
906  } \
907  x = atof(in); \
908  if ( type == CONVBINUNITS ){ \
909  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */ \
910  if ( fabs( x ) > 1e-7 ) { x *= 1.e-12; } \
911  /* some of the parameter files in the ATNF catalogue have values of EDOT that are stupidly large e.g. O(1e33). \
912  * These can cause the time delay routines to fail, so if values of EDOT are greater than 10000 ignore them and \
913  * set it to zero */ \
914  if ( x > 10000. ) { x = 0.; } \
915  } \
916  else{ x *= convfactor; } \
917  } \
918  else if ( type == CONVHMS ) { /* convert to radians from hh:mm:ss.s format */ \
919  XLALTranslateHMStoRAD( &x, in ); \
920  } \
921  else if ( type == CONVDMS ) { /* convert to radians from hh:mm:ss.s format */ \
922  XLALTranslateDMStoRAD( &x, in ); \
923  } \
924  else if ( type == CONVMJD ) { /* convert an MJD to a GPS time */ \
925  x = XLALTTMJDtoGPS( atof(in) ); \
926  } \
927  memcpy(out, &x, sizeof(REAL8) ); \
928  } \
929  else if ( type == CONVSTRING ){ memcpy( out, in, strlen(in)+1 ); } \
930  else if ( type == CONVINT ) { /* convert to an integer */ \
931  UINT4 x; \
932  x = (UINT4)atoi(in); \
933  memcpy(out, &x, sizeof(UINT4) ); \
934  } \
935  XLALFree( in ); \
936  }
937 
938 
940 DEFINE_CONV_FACTOR_FUNCTION( ToFloat, 1., CONVFLOAT ) /* just convert string to float */
941 DEFINE_CONV_FACTOR_FUNCTION( ToInt, 0, CONVINT ) /* just convert string to float */
942 DEFINE_CONV_FACTOR_FUNCTION( DegsToRads, LAL_PI_180, CONVFLOAT ) /* convert degrees to radians */
943 DEFINE_CONV_FACTOR_FUNCTION( MasPerYrToRadPerSec, LAL_PI_180 / ( 3600.e3 * 365.25 * 86400. ), CONVFLOAT ) /* convert milliarcseconds/yr to radians/s */
944 DEFINE_CONV_FACTOR_FUNCTION( SecsToRads, LAL_TWOPI / ( 24.*3600. ), CONVFLOAT ) /* convert seconds to radians */
945 DEFINE_CONV_FACTOR_FUNCTION( ArcsecsToRads, LAL_PI_180 / 3600., CONVFLOAT ) /* convert arcseconds to radians */
946 DEFINE_CONV_FACTOR_FUNCTION( MasToRads, LAL_PI_180 / 3600.0e3, CONVFLOAT ) /* convert milliarcseconds to radians */
947 DEFINE_CONV_FACTOR_FUNCTION( InvArcsecsToInvRads, 3600. / LAL_PI_180, CONVFLOAT ) /* convert 1/arcsec to 1/rads */
948 DEFINE_CONV_FACTOR_FUNCTION( DaysToSecs, DAYSTOSECS, CONVFLOAT ) /* convert days to seconds */
949 DEFINE_CONV_FACTOR_FUNCTION( KpcToMetres, LAL_PC_SI * 1.e3, CONVFLOAT ) /* convert kiloparsecs to metres */
950 DEFINE_CONV_FACTOR_FUNCTION( BinaryUnits, 1.e-12, CONVBINUNITS ) /* convert certain binary units as defined in TEMPO2 with factor */
951 DEFINE_CONV_FACTOR_FUNCTION( MJDToGPS, 0, CONVMJD ) /* convert from MJD to GPS time */
952 DEFINE_CONV_FACTOR_FUNCTION( DegPerYrToRadPerSec, LAL_PI_180 / ( 365.25 * DAYSTOSECS ), CONVFLOAT ) /* convert degs/year to rads/s */
953 DEFINE_CONV_FACTOR_FUNCTION( SolarMassToKg, LALPULSAR_TEMPO2_MSUN_SI, CONVFLOAT ) /* convert solar masses to kg */
954 DEFINE_CONV_FACTOR_FUNCTION( RAToRads, 0, CONVHMS ) /* convert right ascension to radians */
955 DEFINE_CONV_FACTOR_FUNCTION( DecToRads, 0, CONVDMS ) /* convert declination to radians */
956 DEFINE_CONV_FACTOR_FUNCTION( MicrosecToSec, 1.e-6, CONVFLOAT ) /* convert microseconds to seconds */
957 
958 /** Function type definition for a conversion function */
959 typedef void ( *ParamConversionFunc )( const CHAR *in, void *out );
960 
961 /** A strcuture to contain all possible pulsar parameters that can be read in from a par file, and define
962  * the conversion function and type used for each */
963 typedef struct tagParConversion {
964  CHAR name[PULSAR_PARNAME_MAX]; /** Parameter name */
965  ParamConversionFunc convfunc; /** Conversion function from string to required value */
966  ParamConversionFunc converrfunc; /** Conversion function for error from string to value */
967  PulsarParamType ptype; /** Parameter type */
968 } ParConversion;
969 
970 
971 #define NUM_PARS 130 /* number of allowed parameters */
972 
973 /** Initialise conversion structure with most allowed TEMPO2 parameter names and conversion functions
974  * (convert all read in parameters to SI units where necessary). See http://arxiv.org/abs/astro-ph/0603381 and
975  * http://arxiv.org/abs/astro-ph/0603381 for parameter definitions.
976  *
977  * If requiring a new parameter to be read in in should be added to this structure and \c NUM_PARS should be
978  * incremented.
979  */
981  { .name = "F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* vector containing frequency and derivatives (Hz, Hz/s, Hz/s^2 ...) */
982  { .name = "P", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* vector containing period and derivatives (s, s/s, s/s^2 ...) */
983  { .name = "DIST", .convfunc = ParConvKpcToMetres, .converrfunc = ParConvKpcToMetres, .ptype = PULSARTYPE_REAL8_t }, /* distance to pulsar in metres */
984  { .name = "PX", .convfunc = ParConvMasToRads, .converrfunc = ParConvMasToRads, .ptype = PULSARTYPE_REAL8_t }, /* parallax (converted to radians) */
985  { .name = "DM", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* dispersion measure */
986  { .name = "DM1", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /*first derivative of the dispersion measure */
987 
988  /* position parameters */
989  { .name = "RA", .convfunc = ParConvRAToRads, .converrfunc = ParConvSecsToRads, .ptype = PULSARTYPE_REAL8_t }, /* right ascension (converted to radians) */
990  { .name = "RAJ", .convfunc = ParConvRAToRads, .converrfunc = ParConvSecsToRads, .ptype = PULSARTYPE_REAL8_t }, /* right ascension (converted to radians) */
991  { .name = "DEC", .convfunc = ParConvDecToRads, .converrfunc = ParConvArcsecsToRads, .ptype = PULSARTYPE_REAL8_t }, /* declination (converted to radians) */
992  { .name = "DECJ", .convfunc = ParConvDecToRads, .converrfunc = ParConvArcsecsToRads, .ptype = PULSARTYPE_REAL8_t }, /* declination (converted to radians) */
993  { .name = "PMRA", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in right ascension (converted to radians/s) */
994  { .name = "PMDEC", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in declination (converted to radians/s) */
995  { .name = "ELONG", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t }, /* ecliptic longitude (converted from degs to rads) */
996  { .name = "ELAT", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t }, /* ecliptic latitude (converted from degs to rads) */
997  { .name = "PMELONG", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in ecliptic longitude (converted to radians/s) */
998  { .name = "PMELAT", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in ecliptic latitude (converted to radians/s) */
999  { .name = "BETA", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t }, /* galactic latitude (converted from degs to rads) */
1000  { .name = "LAMBDA", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t }, /* galactic longitude (converted from degs to rads) */
1001  { .name = "PMBETA", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in galactic latitude (converted to radians/s) */
1002  { .name = "PMLAMBDA", .convfunc = ParConvMasPerYrToRadPerSec, .converrfunc = ParConvMasPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* proper motion in galactic longitude (converted to radians/s) */
1003 
1004  /* epoch parameters */
1005  { .name = "PEPOCH", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* period epoch (saved as GPS time) */
1006  { .name = "POSEPOCH", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* position epoch (saved as GPS time) */
1007  { .name = "DMEPOCH", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* dispersion measure epoch (saved as GPS time) */
1008 
1009  /* glitch parameters */
1010  { .name = "GLEP", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch epochs (saved as GPS times) */
1011  { .name = "GLPH", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch phase offsets (rotational phase) */
1012  { .name = "GLF0", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch frequency offsets (Hz) */
1013  { .name = "GLF1", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch frequency derivative offsets (Hz/s) */
1014  { .name = "GLF2", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch second frequency derivative offsets (Hz/s^2) */
1015  { .name = "GLF0D", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch decaying frequency component (Hz) */
1016  { .name = "GLTD", .convfunc = ParConvDaysToSecs, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8Vector_t }, /* glitch decay time (seconds) */
1017 
1018  /* string parameters */
1019  { .name = "NAME", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* pulsar name */
1020  { .name = "PSR", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* pulsar name */
1021  { .name = "PSRJ", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* pulsar J name */
1022  { .name = "PSRB", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* pulsar B name */
1023 
1024  /* binary parameters */
1025  { .name = "BINARY", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* binary model type */
1026  { .name = "A1", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* projected semi-major axis (light seconds) */
1027  { .name = "OM", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t }, /* angle of periastron (convert degrees to radians) */
1028  { .name = "ECC", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* eccentricity */
1029  { .name = "PB", .convfunc = ParConvDaysToSecs, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* orbital period (convert days to seconds) */
1030  { .name = "T0", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* time of perisatron (GPS) */
1031  { .name = "TASC", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t }, /* time ascending noise for ELL1 model (GPS) */
1032  { .name = "EPS1", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* e*sin(w0) for ELL1 model */
1033  { .name = "EPS2", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* e*cos(w0) for ELL1 model */
1034  { .name = "GAMMA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* relativistic parameter */
1035  { .name = "OMDOT", .convfunc = ParConvDegPerYrToRadPerSec, .converrfunc = ParConvDegPerYrToRadPerSec, .ptype = PULSARTYPE_REAL8_t }, /* angle of periastron time derivative (degs/year converted to rad/s) */
1036  { .name = "XDOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* project semi-major axis time derivative (light sec/sec) */
1037  { .name = "PBDOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* period time derivative */
1038  { .name = "EDOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* eccentricity time derivative (1/s) */
1039  { .name = "EPS1DOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1040  { .name = "EPS2DOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1041  { .name = "XPBDOT", .convfunc = ParConvBinaryUnits, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1042  { .name = "SINI", .convfunc = ParConvToString, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_string_t }, /* sin of inclination angle */
1043  { .name = "MTOT", .convfunc = ParConvSolarMassToKg, .converrfunc = ParConvSolarMassToKg, .ptype = PULSARTYPE_REAL8_t }, /* total system mass (convert solar masses to kg) */
1044  { .name = "M2", .convfunc = ParConvSolarMassToKg, .converrfunc = ParConvSolarMassToKg, .ptype = PULSARTYPE_REAL8_t }, /* binary companion mass (convert solar masses to kg) */
1045  { .name = "DR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1046  { .name = "DTHETA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1047  { .name = "SHAPMAX", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* used for DDS model */
1048 
1049  /* multiple system terms for BT1P and BT2P models */
1050  { .name = "A1_2", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1051  { .name = "A1_3", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1052  { .name = "OM_2", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t },
1053  { .name = "OM_3", .convfunc = ParConvDegsToRads, .converrfunc = ParConvDegsToRads, .ptype = PULSARTYPE_REAL8_t },
1054  { .name = "PB_2", .convfunc = ParConvDaysToSecs, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t },
1055  { .name = "PB_3", .convfunc = ParConvDaysToSecs, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t },
1056  { .name = "T0_2", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t },
1057  { .name = "T0_3", .convfunc = ParConvMJDToGPS, .converrfunc = ParConvDaysToSecs, .ptype = PULSARTYPE_REAL8_t },
1058  { .name = "ECC_2", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1059  { .name = "ECC_3", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1060  { .name = "FB", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* orbital frequency components for the BTX model */
1061 
1062  /* Aberration delay parameters */
1063  { .name = "A0", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1064  { .name = "B0", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1065 
1066  /* Kopeikin terms */
1067  { .name = "D_AOP", .convfunc = ParConvInvArcsecsToInvRads, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* inverse arsecs converted to inverse radians */
1068  { .name = "KIN", .convfunc = ParConvDegsToRads, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t },
1069  { .name = "KOM", .convfunc = ParConvDegsToRads, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t },
1070 
1071  /* FITWAVES parameters */
1072  { .name = "WAVE_OM", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* fundamental frequency (Hz) of sinusoids used for whitening */
1073  { .name = "WAVEEPOCH", .convfunc = ParConvMJDToGPS, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* frequency epoch (converted from MJD to GPS) */
1074  { .name = "WAVESIN", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* amplitudes of the sine terms for the kth sinusoids */
1075  { .name = "WAVECOS", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8Vector_t }, /* amplitudes of the cosine terms for the kth sinusoids */
1076 
1077  /* TEMPO parameters */
1078  { .name = "EPHEM", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* ephemeris type e.g. DE405 */
1079  { .name = "UNITS", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* TEMPO2 units e.g. TDB */
1080  { .name = "START", .convfunc = ParConvMJDToGPS, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* start of observations */
1081  { .name = "FINISH", .convfunc = ParConvMJDToGPS, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* end of observations */
1082  { .name = "NTOA", .convfunc = ParConvToInt, .converrfunc = NULL, .ptype = PULSARTYPE_UINT4_t }, /* number of TOAs in observation */
1083  { .name = "TRES", .convfunc = ParConvMicrosecToSec, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* timing residual (convert microseconds to seconds) */
1084  { .name = "CLK", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* The observatory clock */
1085 
1086  /* GW parameters */
1087  { .name = "H0", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* gravitational wave amplitude */
1088  { .name = "APLUS", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* plus polarisation component of GW amplitude */
1089  { .name = "ACROSS", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* cross polarisation component of GW amplitude */
1090  { .name = "PHI0", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* gravitational wave initial phase (radians) */
1091  { .name = "PSI", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* gravitational wave polarisation angle (radians) */
1092  { .name = "COSIOTA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* cosine of source inclination angle */
1093  { .name = "IOTA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* the source inclination angle in radians */
1094  { .name = "C22", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW amplitude of C22 component */
1095  { .name = "C21", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW amplitude of C21 component */
1096  { .name = "PHI22", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase of C22 component (radians) */
1097  { .name = "PHI21", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase of C21 component (radians) */
1098  { .name = "CGW", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* speed of gravitational waves as a fraction of the speed of light */
1099  { .name = "LAMBDAPIN", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* parameters from http://uk.arxiv.org/abs/0909.4035 */
1100  { .name = "COSTHETA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1101  { .name = "THETA", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1102  { .name = "I21", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1103  { .name = "I31", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t },
1104  { .name = "Q22", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* the l=m=2 mass quadrupole in kg m^2 */
1105 
1106  /* GW non-GR polarisation mode amplitude parameters (assuming emission at twice the rotation frequency) */
1107  { .name = "HPLUS", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor plus polarisation amplitude */
1108  { .name = "HCROSS", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor cross polarisation amplitude */
1109  { .name = "PSITENSOR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor angle polarisation */
1110  { .name = "PHI0TENSOR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase for tensor modes */
1111  { .name = "HSCALARB", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar breathing mode polarisation amplitude */
1112  { .name = "HSCALARL", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar longitudinal polarisation amplitude */
1113  { .name = "PSISCALAR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar angle polarisation */
1114  { .name = "PHI0SCALAR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase for scalar modes */
1115  { .name = "HVECTORX", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector x-mode amplitude */
1116  { .name = "HVECTORY", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector y-mode amplitude */
1117  { .name = "PSIVECTOR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector angle polarisation */
1118  { .name = "PHI0VECTOR", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector polarisation initial phase */
1119 
1120  /* GW non-GR polarisation mode amplitude parameters (assuming emission at the rotation frequency) */
1121  { .name = "H0_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GR 21 polarisation amplitude */
1122  { .name = "HPLUS_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor plus polarisation amplitude */
1123  { .name = "HCROSS_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor cross polarisation amplitude */
1124  { .name = "PSITENSOR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW tensor angle polarisation */
1125  { .name = "PHI0TENSOR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase for tensor modes */
1126  { .name = "HSCALARB_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar breathing mode polarisation amplitude */
1127  { .name = "HSCALARL_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar longitudinal polarisation amplitude */
1128  { .name = "PSISCALAR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW scalar angle polarisation */
1129  { .name = "PHI0SCALAR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* initial phase for scalar modes */
1130  { .name = "HVECTORX_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector x-mode amplitude */
1131  { .name = "HVECTORY_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector y-mode amplitude */
1132  { .name = "PSIVECTOR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector angle polarisation */
1133  { .name = "PHI0VECTOR_F", .convfunc = ParConvToFloat, .converrfunc = ParConvToFloat, .ptype = PULSARTYPE_REAL8_t }, /* GW vector polarisation initial phase */
1134 
1135  /* transient signal parameters */
1136  { .name = "TRANSIENTWINDOWTYPE", .convfunc = ParConvToString, .converrfunc = NULL, .ptype = PULSARTYPE_string_t }, /* window type, currently "RECT" (rectangular window) or "EXP" (exponentially decaying window) */
1137  { .name = "TRANSIENTSTARTTIME", .convfunc = ParConvMJDToGPS, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t }, /* transient start time in MJD */
1138  { .name = "TRANSIENTTAU", .convfunc = ParConvDaysToSecs, .converrfunc = NULL, .ptype = PULSARTYPE_REAL8_t } /* transient decay time scale (duration for "RECT" and decay constant for "EXP") */
1139 };
1140 
1141 /** \brief Parse a single line from a pulsar parameter file
1142  *
1143  * This will parse a line from the TEMPO-style pulsar parameter file containing the
1144  * parameter given by \c name. The parameter will be added to the \c par structure.
1145  *
1146  * This function can only be used internally.
1147  */
1148 static INT4 ParseParLine( PulsarParameters *par, const CHAR *name, FILE *fp )
1149 {
1150  INT4 nread = 0; /* number of values read from line */
1152  /* three potential values on the line */
1154  INT4 i = 0, tmpnum = 0;
1155  CHAR *nname = NULL; /* duplicate of name */
1156 
1157  if ( par == NULL ) {
1158  XLAL_ERROR( XLAL_EINVAL, "Error... PulsarParameter structure is not initialised!\n" );
1159  }
1160  if ( name == NULL ) {
1161  XLAL_ERROR( XLAL_EINVAL, "Error... parameter name is not set!\n" );
1162  }
1163  if ( fp == NULL ) {
1164  XLAL_ERROR( XLAL_EINVAL, "Error... parameter file pointer is NULL!\n" );
1165  }
1166 
1167  /* parse the line from the fp pointer */
1168  if ( fgets( str, PULSAR_PARNAME_MAX, fp ) == NULL ) {
1169  XLAL_PRINT_WARNING( "No value for parameter %s", name );
1170  return XLAL_SUCCESS;
1171  }
1172 
1173  /* scan the line for values */
1174  nread = sscanf( str, "%s %s %s", str1, str2, str3 );
1175 
1176  if ( !nread ) {
1177  XLAL_PRINT_WARNING( "No value for parameter %s", name );
1178  return XLAL_SUCCESS;
1179  }
1180 
1181  /* check for parameters with more than one possible name */
1182  if ( !strcmp( name, "E" ) ) {
1183  nname = XLALStringDuplicate( "ECC" );
1184  } else if ( !strcmp( name, "E_1" ) ) {
1185  nname = XLALStringDuplicate( "ECC_1" );
1186  } else if ( !strcmp( name, "E_2" ) ) {
1187  nname = XLALStringDuplicate( "ECC_2" );
1188  } else if ( !strcmp( name, "E_3" ) ) {
1189  nname = XLALStringDuplicate( "ECC_3" );
1190  } else {
1191  nname = XLALStringDuplicate( name );
1192  }
1193 
1194  /* perform parameter dependent inputs */
1195  for ( i = 0; i < NUM_PARS; i++ ) {
1196  /* this has to be hard-coded for the F, WAVE, FB and glitch (GL) vector parameters */
1197 
1198  /* check for parameters requiring placement in vectors */
1199  INT4 isfreq = ( !strncmp( nname, "F", 1 ) && !strcmp( "F", pc[i].name ) && sscanf( nname + strlen( "F" ), "%d", &tmpnum ) == 1 );
1200  INT4 isperiod = ( !strncmp( nname, "P", 1 ) && !strcmp( "P", pc[i].name ) && sscanf( nname + strlen( "P" ), "%d", &tmpnum ) == 1 );
1201  INT4 iswave = ( ( !strncmp( nname, "WAVE", 4 ) && ( !strcmp( "WAVESIN", pc[i].name ) || !strcmp( "WAVECOS", pc[i].name ) ) ) && strcmp( "WAVE_OM", nname ) && strcmp( "WAVEEPOCH", nname ) );
1202  INT4 isfb = ( !strncmp( nname, "FB", 2 ) && !strcmp( "FB", pc[i].name ) );
1203  INT4 isgl = ( !strncmp( nname, "GL", 2 ) && strstr( nname, pc[i].name ) && !strncmp( nname, pc[i].name, strlen( nname ) - 2 ) );
1204 
1205  if ( !strcmp( nname, pc[i].name ) || isfreq || isperiod || iswave || isfb || isgl ) {
1206  UINT4 num = 0, nsize = 0;
1207 
1208  if ( pc[i].convfunc == NULL ) {
1209  XLAL_PRINT_WARNING( "No conversion function for parameter %s. Skipping parameter.\n", pc[i].name );
1210  return XLAL_SUCCESS;
1211  }
1212 
1213  /* add parameter */
1214  if ( isfreq || isperiod || isfb ) { /* add frequency/period and frequency/period derivative values, or FB values */
1215  REAL8Vector *ptr = NULL, *eptr = NULL;
1216  UINT4 *fitFlag = NULL;
1217 
1218  if ( isfb ) {
1219  if ( strlen( nname ) > strlen( "FB" ) ) {
1220  if ( sscanf( nname + strlen( "FB" ), "%d", &num ) != 1 ) {
1221  XLAL_ERROR( XLAL_EINVAL, "Error...problem reading %s number from par file.\n", nname );
1222  }
1223  }
1224  } else if ( isfreq ) {
1225  if ( strlen( nname ) > strlen( "F" ) ) {
1226  if ( sscanf( nname + strlen( "F" ), "%d", &num ) != 1 ) {
1227  XLAL_ERROR( XLAL_EINVAL, "Error...problem reading %s number from par file.\n", nname );
1228  }
1229  }
1230  } else {
1231  if ( strlen( nname ) > strlen( "P" ) ) {
1232  if ( sscanf( nname + strlen( "P" ), "%d", &num ) != 1 ) {
1233  XLAL_ERROR( XLAL_EINVAL, "Error...problem reading %s number from par file.\n", nname );
1234  }
1235  }
1236  }
1237 
1238  void *val = ( void * )XLALMalloc( PulsarTypeSize[PULSARTYPE_REAL8_t] );
1239 
1240  pc[i].convfunc( str1, val );
1241 
1242  nsize = num + 1;
1243  if ( PulsarCheckParam( par, pc[i].name ) ) {
1244  // count any previous values
1245  const REAL8Vector *cptr = PulsarGetREAL8VectorParam( par, pc[i].name );
1246  nsize = ( cptr->length > num + 1 ) ? cptr->length : ( num + 1 );
1247  }
1248 
1249  // pointer for parameter values
1250  ptr = XLALCreateREAL8Vector( nsize );
1251  memset( ptr->data, 0, sizeof( REAL8 )*nsize );
1252 
1253  // pointers for error and fit flags
1254  eptr = XLALCreateREAL8Vector( nsize );
1255  memset( eptr->data, 0, sizeof( REAL8 )*nsize ); // initialise with zeros
1256  fitFlag = ( UINT4 * )XLALCalloc( nsize, sizeof( UINT4 ) ); // set fit values to zero (no-fit) by default
1257 
1258  if ( PulsarCheckParam( par, pc[i].name ) ) {
1259  // copy any previous values
1260  const REAL8Vector *cptr = PulsarGetREAL8VectorParam( par, pc[i].name );
1261  memcpy( ptr->data, cptr->data, cptr->length * sizeof( REAL8 ) );
1262 
1263  /* copy any error values, as updating REAL8Vector parameters destroys the original PulsarParam structure */
1264  const REAL8Vector *ceptr = PulsarGetREAL8VectorParamErr( par, pc[i].name );
1265  const UINT4 *ff = PulsarGetParamFitFlag( par, pc[i].name );
1266 
1267  // copy any previous error values
1268  memcpy( eptr->data, ceptr->data, sizeof( REAL8 )*cptr->length );
1269  memcpy( fitFlag, ff, sizeof( UINT4 )*cptr->length );
1270  }
1271 
1272  ptr->data[num] = *( REAL8 * )val;
1273 
1274  // NOTE: this will destroy the previous held PulsarParam structure for this parameter
1276 
1277  // (re-)add errors
1278  PulsarSetREAL8VectorParamErr( par, pc[i].name, ( const REAL8Vector * )eptr, ( const UINT4 * )fitFlag );
1279 
1280  XLALFree( val );
1282  XLALDestroyREAL8Vector( eptr );
1283  XLALFree( fitFlag );
1284  } else if ( iswave && nread == 2 ) { /* add WAVE values */
1285  REAL8Vector *ptr1 = NULL, *ptr2 = NULL;
1286 
1287  if ( strlen( nname ) > strlen( "WAVE" ) ) {
1288  if ( sscanf( nname + strlen( "WAVE" ), "%d", &num ) != 1 ) {
1289  XLAL_ERROR( XLAL_EINVAL, "Error...problem reading %s number from par file.\n", nname );
1290  }
1291  } else {
1292  break;
1293  }
1294 
1295  num--; /* WAVE values start from WAVE1, so subtract 1 from the num for the vector index */
1296 
1297  void *val1 = ( void * )XLALMalloc( PulsarTypeSize[PULSARTYPE_REAL8_t] );
1298  void *val2 = ( void * )XLALMalloc( PulsarTypeSize[PULSARTYPE_REAL8_t] );
1299 
1300  pc[i].convfunc( str1, val1 );
1301  pc[i].convfunc( str2, val2 );
1302 
1303  nsize = num + 1;
1304  if ( PulsarCheckParam( par, "WAVESIN" ) && PulsarCheckParam( par, "WAVECOS" ) ) {
1305  // count number of values
1306  const REAL8Vector *cptr = PulsarGetREAL8VectorParam( par, pc[i].name );
1307 
1308  nsize = ( cptr->length > num + 1 ) ? cptr->length : ( num + 1 );
1309  }
1310 
1311  // pointers for parameter values
1312  ptr1 = XLALCreateREAL8Vector( nsize );
1313  ptr2 = XLALCreateREAL8Vector( nsize );
1314  memset( ptr1->data, 0, sizeof( REAL8 )*nsize );
1315  memset( ptr2->data, 0, sizeof( REAL8 )*nsize );
1316 
1317  if ( PulsarCheckParam( par, "WAVESIN" ) && PulsarCheckParam( par, "WAVECOS" ) ) {
1318  const REAL8Vector *cptr1 = PulsarGetREAL8VectorParam( par, "WAVESIN" );
1319  const REAL8Vector *cptr2 = PulsarGetREAL8VectorParam( par, "WAVECOS" );
1320 
1321  // copy previous values
1322  memcpy( ptr1->data, cptr1->data, ptr1->length * sizeof( REAL8 ) );
1323  memcpy( ptr2->data, cptr2->data, ptr2->length * sizeof( REAL8 ) );
1324  }
1325 
1326  ptr1->data[num] = *( REAL8 * )val1;
1327  ptr2->data[num] = *( REAL8 * )val2;
1328 
1329  PulsarAddREAL8VectorParam( par, "WAVESIN", ( const REAL8Vector * )ptr1 );
1330  PulsarAddREAL8VectorParam( par, "WAVECOS", ( const REAL8Vector * )ptr2 );
1331 
1332  XLALFree( val1 );
1333  XLALFree( val2 );
1334  XLALDestroyREAL8Vector( ptr1 );
1335  XLALDestroyREAL8Vector( ptr2 );
1336 
1337  /* there are no errors on the wave parameters, so set defaults of zero and then break */
1338  UINT4 *fitFlag = ( UINT4 * )XLALCalloc( nsize, sizeof( UINT4 ) );
1339  REAL8Vector *eptr = XLALCreateREAL8Vector( nsize );
1340  memset( eptr->data, 0, sizeof( REAL8 )*nsize );
1341  PulsarSetREAL8VectorParamErr( par, "WAVESIN", ( const REAL8Vector * )eptr, ( const UINT4 * )fitFlag );
1342  PulsarSetREAL8VectorParamErr( par, "WAVECOS", ( const REAL8Vector * )eptr, ( const UINT4 * )fitFlag );
1343  XLALDestroyREAL8Vector( eptr );
1344  XLALFree( fitFlag );
1345 
1346  break;
1347  } else if ( isgl ) { /* get glitch parameters */
1348  REAL8Vector *ptr = NULL, *eptr = NULL;
1349  UINT4 *fitFlag = NULL;
1350 
1351  if ( sscanf( strstr( nname, "_" ) + 1, "%d", &num ) != 1 ) {
1352  XLAL_ERROR( XLAL_EINVAL, "Error...problem reading %s number from par file.\n", nname );
1353  }
1354 
1355  num--; /* GL values start from e.g. GLF0_1, so subtract 1 from the num for the vector index */
1356 
1357  void *val = ( void * )XLALMalloc( PulsarTypeSize[PULSARTYPE_REAL8_t] );
1358 
1359  pc[i].convfunc( str1, val );
1360 
1361  nsize = num + 1;
1362  if ( PulsarCheckParam( par, pc[i].name ) ) {
1363  // count previous values
1364  const REAL8Vector *cptr = PulsarGetREAL8VectorParam( par, pc[i].name );
1365  nsize = ( cptr->length > num + 1 ) ? cptr->length : ( num + 1 );
1366  }
1367 
1368  // pointer for parameter values
1369  ptr = XLALCreateREAL8Vector( nsize );
1370  memset( ptr->data, 0, sizeof( REAL8 )*nsize );
1371 
1372  // pointers for error and fit flags
1373  eptr = XLALCreateREAL8Vector( nsize );
1374  memset( eptr->data, 0, sizeof( REAL8 )*nsize ); // initialise with zeros
1375  fitFlag = ( UINT4 * )XLALCalloc( nsize, sizeof( UINT4 ) ); // set fit values to zero (no-fit) by default
1376 
1377  if ( PulsarCheckParam( par, pc[i].name ) ) {
1378  // copy any previous values
1379  const REAL8Vector *cptr = PulsarGetREAL8VectorParam( par, pc[i].name );
1380  memcpy( ptr->data, cptr->data, cptr->length * sizeof( REAL8 ) );
1381 
1382  /* copy any error values, as updating REAL8Vector parameters destroys the original PulsarParam structure */
1383  const REAL8Vector *ceptr = PulsarGetREAL8VectorParamErr( par, pc[i].name );
1384  const UINT4 *ff = PulsarGetParamFitFlag( par, pc[i].name );
1385 
1386  // copy any previous error values
1387  memcpy( eptr->data, ceptr->data, sizeof( REAL8 )*cptr->length );
1388  memcpy( fitFlag, ff, sizeof( UINT4 )*cptr->length );
1389  }
1390 
1391  ptr->data[num] = *( REAL8 * )val;
1392 
1394 
1395  // (re-)add errors
1396  PulsarSetREAL8VectorParamErr( par, pc[i].name, ( const REAL8Vector * )eptr, ( const UINT4 * )fitFlag );
1397 
1398  XLALFree( val );
1400  XLALDestroyREAL8Vector( eptr );
1401  XLALFree( fitFlag );
1402  } else {
1403  if ( pc[i].ptype != PULSARTYPE_string_t ) {
1404  void *val = ( void * )XLALMalloc( PulsarTypeSize[pc[i].ptype] );
1405  pc[i].convfunc( str1, val );
1406  PulsarAddParam( par, pc[i].name, val, pc[i].ptype );
1407  XLALFree( val );
1408  } else {
1409  CHAR *val = XLALStringDuplicate( str1 );
1410  PulsarAddStringParam( par, pc[i].name, ( const CHAR * )val );
1411  XLALFree( val );
1412  }
1413  }
1414 
1415  /* check for error values */
1416  if ( ( nread == 2 && strcmp( str2, "1" ) ) || ( nread == 3 && !strcmp( str2, "1" ) ) ) {
1417  if ( pc[i].converrfunc == NULL ) {
1418  XLAL_PRINT_WARNING( "No conversion function for parameter %s error. No error being set.\n", pc[i].name );
1419  return XLAL_SUCCESS;
1420  }
1421 
1422  void *val = ( void * )XLALMalloc( PulsarTypeSize[PULSARTYPE_REAL8_t] );
1423  UINT4 isFit = 0;
1424 
1425  /* get the fit flag */
1426  if ( isfreq || isperiod || isfb || isgl ) { /* do this for REAL8Vector parameters */
1428  const UINT4 *fitFlag = PulsarGetParamFitFlag( par, pc[i].name );
1429 
1430  XLAL_CHECK( ptr != NULL, XLAL_EFUNC, "No default errors set for parameter %s", pc[i].name );
1431 
1432  // copy of parameter errors and fit flags
1433  REAL8Vector *eptr = XLALCreateREAL8Vector( ptr->length );
1434  UINT4 *ff = ( UINT4 * )XLALMalloc( sizeof( UINT4 ) * ptr->length );
1435 
1436  memcpy( eptr->data, ptr->data, sizeof( REAL8 )*ptr->length );
1437  memcpy( ff, fitFlag, sizeof( UINT4 )*ptr->length );
1438 
1439  if ( nread == 2 ) {
1440  pc[i].converrfunc( str2, val );
1441  } else {
1442  if ( !strcmp( str2, "1" ) ) {
1443  isFit = 1; /* a fit flag is set to one */
1444  }
1445  pc[i].converrfunc( str3, val );
1446  }
1447 
1448  eptr->data[num] = *( REAL8 * )val;
1449  ff[num] = isFit;
1450 
1451  PulsarSetREAL8VectorParamErr( par, pc[i].name, ( const REAL8Vector * )eptr, ( const UINT4 * )ff );
1452 
1453  XLALDestroyREAL8Vector( eptr );
1454  XLALFree( ff );
1455  } else {
1456  if ( nread == 2 ) {
1457  pc[i].converrfunc( str2, val );
1458  } else {
1459  if ( !strcmp( str2, "1" ) ) {
1460  isFit = 1;
1461  }
1462  pc[i].converrfunc( str3, val );
1463  }
1464 
1465  PulsarSetREAL8ParamErr( par, pc[i].name, *( REAL8 * )val, isFit );
1466  }
1467 
1468  XLALFree( val );
1469  }
1470 
1471  break;
1472  }
1473  }
1474 
1475  XLALFree( nname );
1476 
1477  return XLAL_SUCCESS;
1478 }
1479 
1481 /* read in the pulsar parameter file */
1482 PulsarParameters *XLALReadTEMPOParFile( const CHAR *pulsarAndPath )
1483 {
1484  FILE *fp = NULL;
1485  CHAR str[PULSAR_PARNAME_MAX]; /* string to contain first value on line */
1486 
1487  PulsarParameters *par = XLALCalloc( sizeof( *par ), 1 );
1488 
1489  /* open file */
1490  if ( ( fp = fopen( pulsarAndPath, "r" ) ) == NULL ) {
1491  XLAL_PRINT_ERROR( "Error... Cannot open .par file %s\n", pulsarAndPath );
1492  XLALFree( par );
1494  }
1495 
1496  int nread = 0; /* number of parameters read from a line in the par file */
1497  int UNUSED c;
1498 
1499  /* read in the par file */
1500  while ( !feof( fp ) ) {
1501  /* Read in a line from the parameter file */
1502  nread = fscanf( fp, "%s", str );
1503  if ( nread == 1 ) {
1504  /* check for comment line and skip to end of line */
1505  if ( str[0] == '#' ) {
1506  c = fscanf( fp, "%*[^\n]" );
1507  continue;
1508  }
1509 
1510  CHAR upperName[PULSAR_PARNAME_MAX];
1511  XLALStringCopy( upperName, str, PULSAR_PARNAME_MAX );
1512  strtoupper( upperName );
1513 
1514  if ( XLAL_SUCCESS != ParseParLine( par, upperName, fp ) ) {
1515  XLAL_PRINT_WARNING( "Parameter \"%s\" could not be successfully parsed from par file", str );
1516  }
1517  }
1518  }
1519 
1520  /* check for linked parameters SINI and KIN */
1521  if ( PulsarCheckParam( par, "SINI" ) ) {
1522  CHAR *sini = XLALStringDuplicate( PulsarGetStringParam( par, "SINI" ) );
1523  strtoupper( sini );
1524 
1525  REAL8 sinid;
1526 
1527  PulsarRemoveParam( par, "SINI" );
1528 
1529  if ( !strcmp( sini, "KIN" ) ) {
1530  if ( PulsarCheckParam( par, "KIN" ) ) {
1531  sinid = sin( PulsarGetREAL8Param( par, "KIN" ) );
1532  PulsarAddParam( par, "SINI", &sinid, PULSARTYPE_REAL8_t );
1533  } else {
1534  XLAL_PRINT_ERROR( "Error... KIN not set in .par file %s\n", pulsarAndPath );
1536  XLALFree( par );
1538  }
1539  } else {
1540  sinid = atof( sini );
1541  PulsarAddParam( par, "SINI", &sinid, PULSARTYPE_REAL8_t );
1542  }
1543 
1544  XLALFree( sini );
1545  }
1546 
1547  fclose( fp );
1548 
1549  return par;
1550 }
1551 
1552 /* NOTE: Convert this function to be more like readParfile.C in TEMPO2 - read
1553  * in a line at a time using fgets and make each parameter a structure */
1554 void
1556  CHAR *pulsarAndPath )
1557 {
1558  XLAL_PRINT_DEPRECATION_WARNING( "XLALReadTEMPOParFile" );
1559 
1560  FILE *fp = NULL;
1561  CHAR val[500][40]; /* string array to hold all the read in values
1562  500 strings of max 40 characters is enough */
1563  INT4 i = 0, j = 1, k;
1564  int UNUSED c;
1565 
1566  if ( output == ( BinaryPulsarParams * )NULL ) {
1568  }
1569 
1570  output->name = NULL;
1571  output->jname = NULL;
1572  output->bname = NULL;
1573 
1574  output->model = NULL; /* set binary model to null - in case not a binary */
1575 
1576  /* set all output params to zero*/
1577  output->e = 0.0; /* orbital eccentricity */
1578  output->Pb = 0.0; /* orbital period (days) */
1579  output->w0 = 0.0; /* longitude of periastron (deg) */
1580  output->x = 0.0; /* projected semi-major axis/speed of light (light secs) */
1581  output->T0 = 0.0; /* time of orbital periastron as measured in TDB (MJD) */
1582 
1583  output->e2 = 0.0;
1584  output->Pb2 = 0.0;
1585  output->w02 = 0.0;
1586  output->x2 = 0.0;
1587  output->T02 = 0.0;
1588 
1589  output->e3 = 0.0;
1590  output->Pb3 = 0.0;
1591  output->w03 = 0.0;
1592  output->x3 = 0.0;
1593  output->T03 = 0.0;
1594 
1595  output->xpbdot = 0.0; /* (10^-12) */
1596 
1597  output->eps1 = 0.0; /* e*sin(w) */
1598  output->eps2 = 0.0; /* e*cos(w) */
1599  output->eps1dot = 0.0;
1600  output->eps2dot = 0.0;
1601  output->Tasc = 0.0; /* time of the ascending node (used rather than T0) */
1602 
1603  output->fb = NULL;
1604  output->fbErr = NULL;
1605  output->nfb = 0;
1606 
1607  output->wdot = 0.0; /* precesion of longitude of periastron w = w0 + wdot(tb-T0) (degs/year) */
1608  output->gamma = 0.0; /* gravitational redshift and time dilation parameter (s)*/
1609  output->Pbdot = 0.0; /* rate of change of Pb (dimensionless 10^-12) */
1610  output->xdot = 0.0; /* rate of change of x(=asini/c) - optional (10^-12)*/
1611  output->edot = 0.0; /* rate of change of e (10^-12)*/
1612 
1613  output->s = 0.0; /* Shapiro 'shape' parameter sin i */
1614  output->sstr = NULL;
1615 
1616  output->shapmax = 0.;
1617 
1618  /*output.r=0.0; Shapiro 'range' parameter */
1619  output->dr = 0.0;
1620  output->dth = 0.0; /* (10^-6) */
1621  output->a0 = 0.0;
1622  output->b0 = 0.0; /* abberation delay parameters */
1623 
1624  output->M = 0.0; /* M = m1 + m2 (m1 = pulsar mass, m2 = companion mass) */
1625  output->m2 = 0.0; /* companion mass */
1626 
1627  output->f0 = 0.0;
1628  output->f1 = 0.0;
1629  output->f2 = 0.0;
1630  output->f3 = 0.0;
1631  output->f4 = 0.0;
1632  output->f5 = 0.0;
1633  output->f6 = 0.0;
1634  output->f7 = 0.0;
1635  output->f8 = 0.0;
1636  output->f9 = 0.0;
1637  output->f10 = 0.0;
1638 
1639  output->waveSin = NULL;
1640  output->waveCos = NULL;
1641  output->wave_om = 0.0;
1642  output->waveepoch = 0.0;
1643  output->nwaves = 0;
1644 
1645  output->ra = 0.0;
1646  output->dec = 0.0;
1647  output->pmra = 0.0;
1648  output->pmdec = 0.0;
1649 
1650  output->px = 0.; /* parallax (mas) */
1651  output->dist = 0.; /* distance (kpc) */
1652 
1653  output->DM = 0.; /* dispersion measure */
1654  output->DM1 = 0.; /* first derivative of dispersion measure */
1655 
1656  output->daop = 0.;
1657  output->daopset = 0;
1658  output->kin = 0.;
1659  output->kinset = 0;
1660  output->kom = 0.;
1661  output->komset = 0;
1662 
1663  /* set all errors on params to zero */
1664  output->raErr = 0.0;
1665  output->decErr = 0.0;
1666  output->pmraErr = 0.0;
1667  output->pmdecErr = 0.0;
1668 
1669  output->posepoch = 0.0;
1670  output->pepoch = 0.0;
1671 
1672  output->posepochErr = 0.0;
1673  output->pepochErr = 0.0;
1674 
1675  output->startTime = 0.0;
1676  output->finishTime = INFINITY;
1677 
1678  output->xpbdotErr = 0.0; /* (10^-12) */
1679 
1680  output->eps1Err = 0.0; /* e*sin(w) */
1681  output->eps2Err = 0.0; /* e*cos(w) */
1682  output->eps1dotErr = 0.0;
1683  output->eps2dotErr = 0.0;
1684  output->TascErr = 0.0; /* time of the ascending node (used rather than T0) */
1685 
1686  output->wdotErr = 0.0; /* precesion of longitude of periastron w = w0 + wdot(tb-T0) (degs/year) */
1687  output->gammaErr = 0.0; /* gravitational redshift and time dilation parameter (s)*/
1688  output->PbdotErr = 0.0; /* rate of change of Pb (dimensionless 10^-12) */
1689  output->xdotErr = 0.0; /* rate of change of x(=asini/c) - optional (10^-12)*/
1690  output->edotErr = 0.0; /* rate of change of e (10^-12)*/
1691 
1692  output->sErr = 0.0; /* Shapiro 'shape' parameter sin i */
1693  output->shapmaxErr = 0.;
1694 
1695  /*output->rErr=0.0; Shapiro 'range' parameter */
1696  output->drErr = 0.0;
1697  output->dthErr = 0.0; /* (10^-6) */
1698  output->a0Err = 0.0;
1699  output->b0Err = 0.0; /* abberation delay parameters */
1700 
1701  output->MErr = 0.0; /* M = m1 + m2 (m1 = pulsar mass, m2 = companion mass) */
1702  output->m2Err = 0.0; /* companion mass */
1703 
1704  output->f0Err = 0.0;
1705  output->f1Err = 0.0;
1706  output->f2Err = 0.0;
1707  output->f3Err = 0.0;
1708  output->f4Err = 0.0;
1709  output->f5Err = 0.0;
1710  output->f6Err = 0.0;
1711  output->f7Err = 0.0;
1712  output->f8Err = 0.0;
1713  output->f9Err = 0.0;
1714  output->f10Err = 0.0;
1715 
1716  output->eErr = 0.0;
1717  output->w0Err = 0.0;
1718  output->PbErr = 0.0;
1719  output->xErr = 0.0;
1720  output->T0Err = 0.0;
1721 
1722  output->e2Err = 0.0;
1723  output->w02Err = 0.0;
1724  output->Pb2Err = 0.0;
1725  output->x2Err = 0.0;
1726  output->T02Err = 0.0;
1727 
1728  output->e3Err = 0.0;
1729  output->w03Err = 0.0;
1730  output->Pb3Err = 0.0;
1731  output->x3Err = 0.0;
1732  output->T03Err = 0.0;
1733 
1734  output->pxErr = 0.;
1735  output->distErr = 0.;
1736 
1737  output->DMErr = 0.;
1738  output->DM1Err = 0.;
1739 
1740  output->h0 = 0.;
1741  output->Q22 = 0.;
1742  output->cosiota = 0.;
1743  output->iota = 0.;
1744  output->psi = 0.;
1745  output->phi0 = 0.;
1746  output->Aplus = 0.;
1747  output->Across = 0.;
1748  output->I21 = 0.;
1749  output->I31 = 0.;
1750  output->lambdapin = 0.;
1751  output->costheta = 0.;
1752  output->theta = 0.;
1753  output->C22 = 0.;
1754  output->C21 = 0.;
1755  output->phi22 = 0.;
1756  output->phi21 = 0.;
1757 
1758  output->hPlus = 0.;
1759  output->hCross = 0.;
1760  output->psiTensor = 0.;
1761  output->phi0Tensor = 0.;
1762  output->hScalarB = 0.;
1763  output->hScalarL = 0.;
1764  output->psiScalar = 0.;
1765  output->phi0Scalar = 0.;
1766  output->hVectorX = 0.;
1767  output->hVectorY = 0.;
1768  output->psiVector = 0.;
1769  output->phi0Vector = 0.;
1770 
1771  output->h0Err = 0.;
1772  output->Q22Err = 0.;
1773  output->cosiotaErr = 0.;
1774  output->iotaErr = 0.;
1775  output->psiErr = 0.;
1776  output->phi0Err = 0.;
1777  output->AplusErr = 0.;
1778  output->AcrossErr = 0.;
1779  output->I21Err = 0.;
1780  output->I31Err = 0.;
1781  output->lambdapinErr = 0.;
1782  output->costhetaErr = 0.;
1783  output->thetaErr = 0.;
1784  output->C22Err = 0.;
1785  output->C21Err = 0.;
1786  output->phi22Err = 0.;
1787  output->phi21Err = 0.;
1788  output->hPlusErr = 0.;
1789  output->hCrossErr = 0.;
1790  output->psiTensorErr = 0.;
1791  output->phi0TensorErr = 0.;
1792  output->hScalarBErr = 0.;
1793  output->hScalarLErr = 0.;
1794  output->psiScalarErr = 0.;
1795  output->phi0ScalarErr = 0.;
1796  output->hVectorXErr = 0.;
1797  output->hVectorYErr = 0.;
1798  output->psiVectorErr = 0.;
1799  output->phi0VectorErr = 0.;
1800 
1801  output->wave_omErr = 0.0;
1802 
1803  output->cgw = 1.; /* initialise the GW speed to be the speed of light */
1804  output->cgwErr = 0.;
1805 
1806  output->units = NULL;
1807  output->ephem = NULL;
1808 
1809  if ( ( fp = fopen( pulsarAndPath, "r" ) ) == NULL ) {
1810  XLAL_PRINT_ERROR( "Error... Cannot open .par file %s\n", pulsarAndPath );
1812  }
1813 
1814  /* read all the pulsar data into the string array */
1815  while ( !feof( fp ) ) {
1816  /* make sure val[i] is clear first */
1817  sprintf( val[i], "%s", "" );
1818 
1819  c = fscanf( fp, "%s", val[i] );
1820 
1821  /* if line starts with a '#' then skip to end of line */
1822  if ( val[i][0] == '#' ) {
1823  /* skip to the end of the line */
1824  c = fscanf( fp, "%*[^\n]" );
1825  if ( feof( fp ) ) {
1826  break;
1827  }
1828  continue;
1829  }
1830 
1831  i++;
1832  }
1833 
1834  k = i; /* k is the end number */
1835  i = 0; /* reset i */
1836 
1837  /* set pulsar values for output */
1838  /* in .par files first column will param name, second will be param value,
1839  if third is defined it will be an integer to tell TEMPO whether to fit
1840  the param or not (don't need this), fourth will be the error on the
1841  param (in same units as the param) */
1842 
1843  /* convert all epochs given in MJD in .par files to secs in TDB */
1844  while ( 1 ) {
1845  j = i;
1846  if ( !strcmp( val[i], "NAME" ) || !strcmp( val[i], "name" ) ) {
1847  output->name = XLALStringDuplicate( val[i + 1] );
1848  j++;
1849  } else if ( !strcmp( val[i], "PSRJ" ) || !strcmp( val[i], "psrj" ) ) {
1850  output->jname = XLALStringDuplicate( val[i + 1] );
1851  j++;
1852  } else if ( !strcmp( val[i], "PSRB" ) || !strcmp( val[i], "psrb" ) ) {
1853  output->bname = XLALStringDuplicate( val[i + 1] );
1854  j++;
1855  } else if ( !strcmp( val[i], "ra" ) || !strcmp( val[i], "RA" ) || !strcmp( val[i], "RAJ" ) ) {
1856  /* this can be in form hh:mm:ss.ss or hhmmss.ss */
1857  XLALTranslateHMStoRAD( &output->ra, val[i + 1] );
1858  j++;
1859 
1860  /* only try to get error if one exists */
1861  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1862  /* assuming at the moment that error is in arcsec */
1863  output->raErr = LAL_TWOPI * atof( val[i + 3] ) / ( 24.0 * 60.0 * 60.0 );
1864  j += 2;
1865  }
1866  } else if ( !strcmp( val[i], "dec" ) || !strcmp( val[i], "DEC" ) || !strcmp( val[i], "DECJ" ) ) {
1867  XLALTranslateDMStoRAD( &output->dec, val[i + 1] );
1868  j++;
1869 
1870  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1871  /* assuming at the moment that error is in arcsec */
1872  output->decErr = LAL_TWOPI * atof( val[i + 3] ) / ( 360.0 * 60.0 * 60.0 );
1873  j += 2;
1874  }
1875  } else if ( !strcmp( val[i], "pmra" ) || !strcmp( val[i], "PMRA" ) ) {
1876  /* convert pmra from mas/year to rads/sec */
1877  output->pmra = LAL_PI_180 * atof( val[i + 1] ) / ( 60.0 * 60.0 * 1000.*365.25 * 86400. );
1878  j++;
1879  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1880  output->pmraErr =
1881  LAL_PI_180 * atof( val[i + 3] ) / ( 60.0 * 60.0 * 1000.*365.25 * 86400. );
1882  j += 2;
1883  }
1884  } else if ( !strcmp( val[i], "pmdec" ) || !strcmp( val[i], "PMDEC" ) ) {
1885  /* convert pmdec from mas/year to rads/sec */
1886  output->pmdec = LAL_PI_180 * atof( val[j + 1] ) / ( 60.0 * 60.0 * 1000.*365.25 * 86400. );
1887  j++;
1888 
1889  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1890  output->pmdecErr =
1891  LAL_PI_180 * atof( val[i + 3] ) / ( 60.0 * 60.0 * 1000.*365.25 * 86400. );
1892  j += 2;
1893  }
1894  } else if ( !strcmp( val[i], "pepoch" ) || !strcmp( val[i], "PEPOCH" ) ) {
1895  output->pepoch = XLALTTMJDtoGPS( atof( val[i + 1] ) ); /* convert all epochs to
1896  from MJD to GPS seconds in TDB */
1897  j++;
1898 
1899  } else if ( !strcmp( val[i], "posepoch" ) || !strcmp( val[i], "POSEPOCH" ) ) {
1900  output->posepoch = XLALTTMJDtoGPS( atof( val[i + 1] ) );
1901  j++;
1902  /* position epoch in GPS seconds TDB */
1903  } else if ( !strcmp( val[i], "start" ) || !strcmp( val[i], "START" ) ) {
1904  output->startTime = XLALTTMJDtoGPS( atof( val[i + 1] ) ); /* convert all epochs to
1905  from MJD to GPS seconds in TDB */
1906  j++;
1907 
1908  } else if ( !strcmp( val[i], "finish" ) || !strcmp( val[i], "FINISH" ) ) {
1909  output->finishTime = XLALTTMJDtoGPS( atof( val[i + 1] ) );
1910  j++;
1911  /* position epoch in GPS seconds TDB */
1912  } else if ( !strcmp( val[i], "f0" ) || !strcmp( val[i], "F0" ) ) {
1913  /* in .par files exponents sometimes shown as D/d rather than e/E
1914  need way to check this as atof will not convert D (but will
1915  work for e/E (if a d/D is present atof will convert the number
1916  before the d/D but not the exponent */
1917  CHAR *loc;
1918 
1919  output->f0 = atof( val[i + 1] );
1920  j++;
1921 
1922  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1923  /* check if exponent contains e/E or d/D or neither */
1924  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
1925  output->f0Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
1926  } else {
1927  output->f0Err = atof( val[i + 3] );
1928  }
1929  j += 2;
1930  }
1931  } else if ( !strcmp( val[i], "f1" ) || !strcmp( val[i], "F1" ) ) {
1932  CHAR *loc;
1933 
1934  /* check if exponent contains e/E or d/D or neither */
1935  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
1936  output->f1 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
1937  } else {
1938  output->f1 = atof( val[i + 1] );
1939  }
1940  j++;
1941 
1942  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1943  /* check if exponent contains e/E or d/D or neither */
1944  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
1945  output->f1Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
1946  } else {
1947  output->f1Err = atof( val[i + 3] );
1948  }
1949  j += 2;
1950  }
1951  } else if ( !strcmp( val[i], "f2" ) || !strcmp( val[i], "F2" ) ) {
1952  CHAR *loc;
1953 
1954  /* check if exponent contains e/E or d/D or neither */
1955  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
1956  output->f2 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
1957  } else {
1958  output->f2 = atof( val[i + 1] );
1959  }
1960  j++;
1961 
1962  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1963  /* check if exponent contains e/E or d/D or neither */
1964  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
1965  output->f2Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
1966  } else {
1967  output->f2Err = atof( val[i + 3] );
1968  }
1969  j += 2;
1970  }
1971  } else if ( !strcmp( val[i], "f3" ) || !strcmp( val[i], "F3" ) ) {
1972  CHAR *loc;
1973 
1974  /* check if exponent contains e/E or d/D or neither */
1975  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
1976  output->f3 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
1977  } else {
1978  output->f3 = atof( val[i + 1] );
1979  }
1980  j++;
1981 
1982  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
1983  /* check if exponent contains e/E or d/D or neither */
1984  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
1985  output->f3Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
1986  } else {
1987  output->f3Err = atof( val[i + 3] );
1988  }
1989  j += 2;
1990  }
1991  } else if ( !strcmp( val[i], "f4" ) || !strcmp( val[i], "F4" ) ) {
1992  CHAR *loc;
1993 
1994  /* check if exponent contains e/E or d/D or neither */
1995  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
1996  output->f4 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
1997  } else {
1998  output->f4 = atof( val[i + 1] );
1999  }
2000  j++;
2001 
2002  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2003  /* check if exponent contains e/E or d/D or neither */
2004  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2005  output->f4Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2006  } else {
2007  output->f4Err = atof( val[i + 3] );
2008  }
2009  j += 2;
2010  }
2011  } else if ( !strcmp( val[i], "f5" ) || !strcmp( val[i], "F5" ) ) {
2012  CHAR *loc;
2013 
2014  /* check if exponent contains e/E or d/D or neither */
2015  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2016  output->f5 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2017  } else {
2018  output->f5 = atof( val[i + 1] );
2019  }
2020  j++;
2021 
2022  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2023  /* check if exponent contains e/E or d/D or neither */
2024  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2025  output->f5Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2026  } else {
2027  output->f5Err = atof( val[i + 3] );
2028  }
2029  j += 2;
2030  }
2031  } else if ( !strcmp( val[i], "f6" ) || !strcmp( val[i], "F6" ) ) {
2032  CHAR *loc;
2033 
2034  /* check if exponent contains e/E or d/D or neither */
2035  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2036  output->f6 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2037  } else {
2038  output->f6 = atof( val[i + 1] );
2039  }
2040  j++;
2041 
2042  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2043  /* check if exponent contains e/E or d/D or neither */
2044  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2045  output->f6Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2046  } else {
2047  output->f6Err = atof( val[i + 3] );
2048  }
2049  j += 2;
2050  }
2051  } else if ( !strcmp( val[i], "f7" ) || !strcmp( val[i], "F7" ) ) {
2052  CHAR *loc;
2053 
2054  /* check if exponent contains e/E or d/D or neither */
2055  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2056  output->f7 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2057  } else {
2058  output->f7 = atof( val[i + 1] );
2059  }
2060  j++;
2061 
2062  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2063  /* check if exponent contains e/E or d/D or neither */
2064  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2065  output->f7Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2066  } else {
2067  output->f7Err = atof( val[i + 3] );
2068  }
2069  j += 2;
2070  }
2071  } else if ( !strcmp( val[i], "f8" ) || !strcmp( val[i], "F8" ) ) {
2072  CHAR *loc;
2073 
2074  /* check if exponent contains e/E or d/D or neither */
2075  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2076  output->f8 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2077  } else {
2078  output->f8 = atof( val[i + 1] );
2079  }
2080  j++;
2081 
2082  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2083  /* check if exponent contains e/E or d/D or neither */
2084  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2085  output->f8Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2086  } else {
2087  output->f8Err = atof( val[i + 3] );
2088  }
2089  j += 2;
2090  }
2091  } else if ( !strcmp( val[i], "f9" ) || !strcmp( val[i], "F9" ) ) {
2092  CHAR *loc;
2093 
2094  /* check if exponent contains e/E or d/D or neither */
2095  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2096  output->f9 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2097  } else {
2098  output->f9 = atof( val[i + 1] );
2099  }
2100  j++;
2101 
2102  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2103  /* check if exponent contains e/E or d/D or neither */
2104  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2105  output->f9Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2106  } else {
2107  output->f9Err = atof( val[i + 3] );
2108  }
2109  j += 2;
2110  }
2111  } else if ( !strcmp( val[i], "f10" ) || !strcmp( val[i], "F10" ) ) {
2112  CHAR *loc;
2113 
2114  /* check if exponent contains e/E or d/D or neither */
2115  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2116  output->f10 = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2117  } else {
2118  output->f10 = atof( val[i + 1] );
2119  }
2120  j++;
2121 
2122  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2123  /* check if exponent contains e/E or d/D or neither */
2124  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2125  output->f10Err = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2126  } else {
2127  output->f10Err = atof( val[i + 3] );
2128  }
2129  j += 2;
2130  }
2131  } else if ( !strcmp( val[i], "WAVE_OM" ) || !strcmp( val[i], "wave_om" ) ) {
2132  output->wave_om = atof( val[i + 1] );
2133  j++;
2134 
2135  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2136  output->wave_omErr = atof( val[i + 3] );
2137  j += 2;
2138  }
2139  } else if ( !strcmp( val[i], "WAVEEPOCH" ) || !strcmp( val[i], "waveepoch" ) ) {
2140  output->waveepoch = XLALTTMJDtoGPS( atof( val[i + 1] ) );
2141  j++;
2142  } else if ( strstr( val[i], "WAVE" ) != NULL || strstr( val[i], "wave" ) != NULL ) {
2143  INT4 wnum = 0;
2144 
2145  if ( sscanf( val[i] + 4, "%d", &wnum ) != 1 ) {
2146  fprintf( stderr, "Error reading WAVE number from par file\n" );
2147  exit( 1 );
2148  }
2149 
2150  if ( wnum > output->nwaves ) {
2151  output->nwaves = wnum;
2152  output->waveSin = XLALRealloc( output->waveSin, wnum * sizeof( REAL8 ) );
2153  output->waveCos = XLALRealloc( output->waveCos, wnum * sizeof( REAL8 ) );
2154  }
2155 
2156  output->waveSin[wnum - 1] = atof( val[i + 1] );
2157  output->waveCos[wnum - 1] = atof( val[i + 2] );
2158 
2159  j++;
2160  } else if ( !strcmp( val[i], "binary" ) || !strcmp( val[i], "BINARY" ) ) {
2161  output->model = XLALStringDuplicate( val[i + 1] );
2162  j++;
2163  } else if ( !strcmp( val[i], "ephem" ) || !strcmp( val[i], "EPHEM" ) ) {
2164  output->ephem = XLALStringDuplicate( val[i + 1] );
2165  j++;
2166  } else if ( !strcmp( val[i], "units" ) || !strcmp( val[i], "UNITS" ) ) {
2167  output->units = XLALStringDuplicate( val[i + 1] );
2168  j++;
2169  } else if ( !strcmp( val[i], "a1" ) || !strcmp( val[i], "A1" ) ) {
2170  output->x = atof( val[i + 1] );
2171  j++;
2172 
2173  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2174  output->xErr = atof( val[i + 3] );
2175  j += 2;
2176  }
2177  } else if ( !strcmp( val[i], "e" ) || !strcmp( val[i], "E" ) || !strcmp( val[i], "ECC" ) ||
2178  !strcmp( val[i], "ecc" ) ) {
2179  output->e = atof( val[i + 1] );
2180  j++;
2181 
2182  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2183  output->eErr = atof( val[i + 3] );
2184  j += 2;
2185  }
2186  } else if ( !strcmp( val[i], "pb" ) || !strcmp( val[i], "PB" ) ) {
2187  output->Pb = atof( val[i + 1] ) * DAYSTOSECS;
2188  j++;
2189 
2190  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2191  output->PbErr = atof( val[i + 3] ) * DAYSTOSECS;
2192  j += 2;
2193  }
2194  } else if ( !strcmp( val[i], "om" ) || !strcmp( val[i], "OM" ) ) {
2195  output->w0 = atof( val[i + 1] ) * LAL_PI_180; /* convert radians to seconds */
2196  j++;
2197 
2198  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2199  output->w0Err = atof( val[i + 3] ) * LAL_PI_180;
2200  j += 2;
2201  }
2202  } else if ( !strcmp( val[i], "T0" ) ) {
2203  output->T0 = XLALTTMJDtoGPS( atof( val[i + 1] ) );
2204  j++;
2205 
2206  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2207  output->T0Err = atof( val[i + 3] ) * DAYSTOSECS; /* convert to seconds */
2208  j += 2;
2209  }
2210  } else if ( !strcmp( val[i], "Tasc" ) || !strcmp( val[i], "TASC" ) ) {
2211  output->Tasc = XLALTTMJDtoGPS( atof( val[i + 1] ) );
2212  j++;
2213 
2214  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2215  output->TascErr = atof( val[i + 3] ) * DAYSTOSECS; /* convert to seconds; */
2216  j += 2;
2217  }
2218  } else if ( !strcmp( val[i], "eps1" ) || !strcmp( val[i], "EPS1" ) ) {
2219  output->eps1 = atof( val[i + 1] );
2220  j++;
2221 
2222  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2223  output->eps1Err = atof( val[i + 3] );
2224  j += 2;
2225  }
2226  } else if ( !strcmp( val[i], "eps2" ) || !strcmp( val[i], "EPS2" ) ) {
2227  output->eps2 = atof( val[i + 1] );
2228  j++;
2229 
2230  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2231  output->eps2Err = atof( val[i + 3] );
2232  j += 2;
2233  }
2234  } else if ( !strcmp( val[i], "eps1dot" ) || !strcmp( val[i], "EPS1DOT" ) ) {
2235  output->eps1dot = atof( val[i + 1] );
2236  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2237  if ( fabs( output->eps1dot ) > 1e-7 ) {
2238  output->eps1dot *= 1.e-12;
2239  }
2240  j++;
2241 
2242  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2243  output->eps1dotErr = atof( val[i + 3] );
2244  j += 2;
2245  }
2246  } else if ( !strcmp( val[i], "eps2dot" ) || !strcmp( val[i], "EPS2DOT" ) ) {
2247  output->eps2dot = atof( val[i + 1] );
2248  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2249  if ( fabs( output->eps2dot ) > 1e-7 ) {
2250  output->eps2dot *= 1.e-12;
2251  }
2252  j++;
2253 
2254  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2255  output->eps2dotErr = atof( val[i + 3] );
2256  j += 2;
2257  }
2258  } else if ( !strcmp( val[i], "xpbdot" ) || !strcmp( val[i], "XPBDOT" ) ) {
2259  output->xpbdot = atof( val[i + 1] );
2260  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2261  if ( fabs( output->xpbdot ) > 1e-7 ) {
2262  output->xpbdot *= 1.e-12;
2263  }
2264  j++;
2265 
2266  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2267  output->xpbdotErr = atof( val[i + 3] );
2268  j += 2;
2269  }
2270  } else if ( !strcmp( val[i], "omdot" ) || !strcmp( val[i], "OMDOT" ) ) {
2271  output->wdot = atof( val[i + 1] ) * LAL_PI_180 / ( 365.25 * DAYSTOSECS ); /* convert degs/years to rads/sec */
2272  j++;
2273 
2274  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2275  output->wdotErr = atof( val[i + 3] ) * LAL_PI_180 / ( 365.25 * DAYSTOSECS );
2276  j += 2;
2277  }
2278  } else if ( !strcmp( val[i], "pbdot" ) || !strcmp( val[i], "PBDOT" ) ) {
2279  output->Pbdot = atof( val[i + 1] );
2280  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2281  if ( fabs( output->Pbdot ) > 1e-7 ) {
2282  output->Pbdot *= 1.e-12;
2283  }
2284  j++;
2285 
2286  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2287  output->PbdotErr = atof( val[i + 3] );
2288  j += 2;
2289  }
2290  } else if ( !strcmp( val[i], "xdot" ) || !strcmp( val[i], "XDOT" ) ) {
2291  output->xdot = atof( val[i + 1] );
2292  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2293  if ( fabs( output->xdot ) > 1e-7 ) {
2294  output->xdot *= 1.e-12;
2295  }
2296  j++;
2297 
2298  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2299  output->xdotErr = atof( val[i + 3] );
2300  j += 2;
2301  }
2302  } else if ( !strcmp( val[i], "edot" ) || !strcmp( val[i], "EDOT" ) ) {
2303  output->edot = atof( val[i + 1] );
2304  /* TEMPO2 checks if this is > 1e-7 then it's in units of 1e-12, so needs converting */
2305  if ( fabs( output->edot ) > 1e-7 ) {
2306  output->edot *= 1.e-12;
2307  }
2308  j++;
2309 
2310  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2311  output->edotErr = atof( val[i + 3] );
2312  j += 2;
2313  }
2314 
2315  /* some of the parameter files in the ATNF catalogue have values
2316  of EDOT that are stupidly large e.g. O(1e33). These can cause
2317  the time delay routines to fail, so if values of EDOT are
2318  greater than 10000 ignore them and set it to zero */
2319  if ( output->edot > 10000 ) {
2320  output->edot = 0.;
2321  output->edotErr = 0.;
2322  }
2323  } else if ( !strcmp( val[i], "gamma" ) || !strcmp( val[i], "GAMMA" ) ) {
2324  output->gamma = atof( val[i + 1] );
2325  j++;
2326 
2327  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2328  output->gammaErr = atof( val[i + 3] );
2329  j += 2;
2330  }
2331  } else if ( !strcmp( val[i], "sini" ) || !strcmp( val[i], "SINI" ) ) {
2332  output->sstr = XLALStringDuplicate( val[i + 1] );
2333  j++;
2334 
2335  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2336  output->sErr = atof( val[i + 3] );
2337  j += 2;
2338  }
2339  } else if ( !strcmp( val[i], "mtot" ) || !strcmp( val[i], "MTOT" ) ) {
2340  output->M = atof( val[i + 1] ) * LALPULSAR_TEMPO2_MSUN_SI;
2341  j++;
2342 
2343  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2344  output->MErr = atof( val[i + 3] ) * LALPULSAR_TEMPO2_MSUN_SI;
2345  j += 2;
2346  }
2347  } else if ( !strcmp( val[i], "m2" ) || !strcmp( val[i], "M2" ) ) {
2348  output->m2 = atof( val[i + 1] ) * LALPULSAR_TEMPO2_MSUN_SI;
2349  j++;
2350 
2351  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2352  output->m2Err = atof( val[i + 3] ) * LALPULSAR_TEMPO2_MSUN_SI;
2353  j += 2;
2354  }
2355  } else if ( !strcmp( val[i], "a0" ) || !strcmp( val[i], "A0" ) ) {
2356  output->a0 = atof( val[i + 1] );
2357  j++;
2358 
2359  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2360  output->a0Err = atof( val[i + 3] );
2361  j += 2;
2362  }
2363  } else if ( !strcmp( val[i], "b0" ) || !strcmp( val[i], "B0" ) ) {
2364  output->b0 = atof( val[i + 1] );
2365  j++;
2366 
2367  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2368  output->b0Err = atof( val[i + 3] );
2369  j += 2;
2370  }
2371  } else if ( !strcmp( val[i], "dr" ) || !strcmp( val[i], "DR" ) ) {
2372  output->dr = atof( val[i + 1] );
2373  j++;
2374 
2375  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2376  output->drErr = atof( val[i + 3] );
2377  j += 2;
2378  }
2379  } else if ( !strcmp( val[i], "dtheta" ) || !strcmp( val[i], "DTHETA" ) ) {
2380  output->dth = atof( val[i + 1] );
2381  j++;
2382 
2383  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2384  output->dthErr = atof( val[i + 3] );
2385  j += 2;
2386  }
2387  } else if ( !strcmp( val[i], "shapmax" ) || !strcmp( val[i], "SHAPMAX" ) ) {
2388  output->shapmax = atof( val[i + 1] );
2389  j++;
2390 
2391  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2392  output->shapmaxErr = atof( val[i + 3] );
2393  j += 2;
2394  }
2395  }
2396 
2397  /* parameters for Kopeikin terms */
2398  else if ( !strcmp( val[i], "D_AOP" ) || !strcmp( val[i], "d_aop" ) ) {
2399  /* convert into 1/rads (factor from T2model.C in TEMPO2 */
2400  output->daop = atof( val[i + 1] ) * 3600.0 / LAL_PI_180;
2401  output->daopset = 1;
2402  j++;
2403  } else if ( !strcmp( val[i], "KIN" ) || !strcmp( val[i], "kin" ) ) {
2404  output->kin = atof( val[i + 1] ) * LAL_PI_180; /* convert degs to rads */
2405  output->kinset = 1;
2406  j++;
2407  } else if ( !strcmp( val[i], "KOM" ) || !strcmp( val[i], "kom" ) ) {
2408  output->kom = atof( val[i + 1] ) * LAL_PI_180; /* convert degs to rads */
2409  output->komset = 1;
2410  j++;
2411  }
2412 
2413  /* parameters for distance */
2414  else if ( !strcmp( val[i], "px" ) || !strcmp( val[i], "PX" ) ) { /* parallax */
2415  /* convert from mas to rads (factor from T2model.C in TEMPO2) */
2416  output->px = atof( val[i + 1] ) * LAL_PI_180 / 3600.0e3;
2417  j++;
2418 
2419  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2420  output->pxErr = atof( val[i + 3] );
2421  j += 2;
2422  }
2423  } else if ( !strcmp( val[i], "dist" ) || !strcmp( val[i], "DIST" ) ) { /* distance */
2424  output->dist = atof( val[i + 1] ); /* in kpc */
2425  j++;
2426 
2427  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2428  output->distErr = atof( val[i + 3] );
2429  j += 2;
2430  }
2431  }
2432 
2433  /* dispersion measure parameters */
2434  else if ( !strcmp( val[i], "dm" ) || !strcmp( val[i], "DM" ) ) {
2435  output->DM = atof( val[i + 1] );
2436  j++;
2437 
2438  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2439  output->DMErr = atof( val[i + 3] );
2440  j += 2;
2441  }
2442  } else if ( !strcmp( val[i], "dm1" ) || !strcmp( val[i], "DM1" ) ) {
2443  output->DM1 = atof( val[i + 1] );
2444  j++;
2445 
2446  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2447  output->DM1Err = atof( val[i + 3] );
2448  j += 2;
2449  }
2450  }
2451 
2452  /* add parameters extra orbital parameters for the BT1P and BT2P models */
2453  else if ( !strcmp( val[i], "a1_2" ) || !strcmp( val[i], "A1_2" ) ) {
2454  output->x2 = atof( val[i + 1] );
2455  j++;
2456 
2457  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2458  output->x2Err = atof( val[i + 3] );
2459  j += 2;
2460  }
2461  } else if ( !strcmp( val[i], "e_2" ) || !strcmp( val[i], "E_2" ) ||
2462  !strcmp( val[i], "ECC_2" ) || !strcmp( val[i], "ecc_2" ) ) {
2463  output->e2 = atof( val[i + 1] );
2464  j++;
2465 
2466  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2467  output->e2Err = atof( val[i + 3] );
2468  j += 2;
2469  }
2470  } else if ( !strcmp( val[i], "pb_2" ) || !strcmp( val[i], "PB_2" ) ) {
2471  output->Pb2 = atof( val[i + 1] ) * DAYSTOSECS;
2472  j++;
2473 
2474  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2475  output->Pb2Err = atof( val[i + 3] ) * DAYSTOSECS;
2476  j += 2;
2477  }
2478  } else if ( !strcmp( val[i], "om_2" ) || !strcmp( val[i], "OM_2" ) ) {
2479  output->w02 = atof( val[i + 1] ) * LAL_PI_180;
2480  j++;
2481 
2482  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2483  output->w02Err = atof( val[i + 3] ) * LAL_PI_180;
2484  j += 2;
2485  }
2486  } else if ( !strcmp( val[i], "T0_2" ) ) {
2487  output->T02 = XLALTTMJDtoGPS( atof( val[i + 1] ) );
2488  j++;
2489 
2490  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2491  output->T02Err = atof( val[i + 3] ) * DAYSTOSECS; /* convert to seconds */
2492  j += 2;
2493  }
2494  } else if ( !strcmp( val[i], "a1_3" ) || !strcmp( val[i], "A1_3" ) ) {
2495  output->x3 = atof( val[i + 1] );
2496  j++;
2497 
2498  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2499  output->x3Err = atof( val[i + 3] );
2500  j += 2;
2501  }
2502  } else if ( !strcmp( val[i], "e_3" ) || !strcmp( val[i], "E_3" ) ||
2503  !strcmp( val[i], "ECC_3" ) || !strcmp( val[i], "ecc_3" ) ) {
2504  output->e3 = atof( val[i + 1] );
2505  j++;
2506 
2507  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2508  output->e3Err = atof( val[i + 3] );
2509  j += 2;
2510  }
2511  } else if ( !strcmp( val[i], "pb_3" ) || !strcmp( val[i], "PB_3" ) ) {
2512  output->Pb3 = atof( val[i + 1] ) * DAYSTOSECS;
2513  j++;
2514 
2515  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2516  output->Pb3Err = atof( val[i + 3] ) * DAYSTOSECS;
2517  j += 2;
2518  }
2519  } else if ( !strcmp( val[i], "om_3" ) || !strcmp( val[i], "OM_3" ) ) {
2520  output->w03 = atof( val[i + 1] ) * LAL_PI_180;
2521  j++;
2522 
2523  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2524  output->w03Err = atof( val[i + 3] ) * LAL_PI_180;
2525  j += 2;
2526  }
2527  } else if ( !strcmp( val[i], "T0_3" ) ) {
2528  output->T03 = XLALTTMJDtoGPS( atof( val[i + 1] ) );
2529  j++;
2530 
2531  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2532  output->T03Err = atof( val[i + 3] ) * DAYSTOSECS; /* convert to seconds */
2533  j += 2;
2534  }
2535  }
2536  /* orbital frequency coefficients for BTX model (up to 12 FB coefficients), but
2537  only one orbit at the moment i.e. only a two body system */
2538  else if ( val[i][0] == 'F' && val[i][1] == 'B' ) {
2539  INT4 fbnum = 0;
2540  CHAR *loc;
2541 
2542  if ( strlen( val[i] ) == 2 ) {
2543  fbnum = 0; /* only one coefficient */
2544  } else {
2545  if ( sscanf( val[i] + 2, "%d", &fbnum ) != 1 ) {
2546  fprintf( stderr, "Error reading FB value from par file\n" );
2547  exit( 1 );
2548  }
2549  }
2550 
2551  /* add to number of coefficients */
2552  if ( output->nfb < fbnum + 1 ) {
2553  output->fb = XLALRealloc( output->fb, ( fbnum + 1 ) * sizeof( REAL8 ) );
2554  output->fbErr = XLALRealloc( output->fbErr, ( fbnum + 1 ) * sizeof( REAL8 ) );
2555  output->nfb = fbnum + 1;
2556  }
2557 
2558  /* check if exponent contains e/E or d/D or neither */
2559  if ( ( loc = strstr( val[i + 1], "D" ) ) != NULL || ( loc = strstr( val[i + 1], "d" ) ) != NULL ) {
2560  output->fb[fbnum] = atof( val[i + 1] ) * pow( 10, atof( loc + 1 ) );
2561  } else {
2562  output->fb[fbnum] = atof( val[i + 1] );
2563  }
2564  j++;
2565 
2566  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2567  /* check if exponent contains e/E or d/D or neither */
2568  if ( ( loc = strstr( val[i + 3], "D" ) ) != NULL || ( loc = strstr( val[i + 3], "d" ) ) != NULL ) {
2569  output->fbErr[fbnum] = atof( val[i + 3] ) * pow( 10, atof( loc + 1 ) );
2570  } else {
2571  output->fbErr[fbnum] = atof( val[i + 3] );
2572  }
2573  j += 2;
2574  }
2575  }
2576  /* read in pulsar gravitational wave parameters */
2577  else if ( !strcmp( val[i], "h0" ) || !strcmp( val[i], "H0" ) ) {
2578  output->h0 = atof( val[i + 1] );
2579  j++;
2580 
2581  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2582  output->h0Err = atof( val[i + 3] );
2583  j += 2;
2584  }
2585  } else if ( !strcmp( val[i], "q22" ) || !strcmp( val[i], "Q22" ) ) {
2586  output->Q22 = atof( val[i + 1] );
2587  j++;
2588 
2589  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2590  output->Q22Err = atof( val[i + 3] );
2591  j += 2;
2592  }
2593  } else if ( !strcmp( val[i], "cosiota" ) || !strcmp( val[i], "COSIOTA" ) ||
2594  !strcmp( val[i], "ciota" ) || !strcmp( val[i], "CIOTA" ) ) {
2595  output->cosiota = atof( val[i + 1] );
2596  j++;
2597 
2598  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2599  output->cosiotaErr = atof( val[i + 3] );
2600  j += 2;
2601  }
2602  } else if ( !strcmp( val[i], "iota" ) || !strcmp( val[i], "IOTA" ) ) {
2603  output->iota = atof( val[i + 1] );
2604  j++;
2605 
2606  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2607  output->iotaErr = atof( val[i + 3] );
2608  j += 2;
2609  }
2610  } else if ( !strcmp( val[i], "psi" ) || !strcmp( val[i], "PSI" ) ) {
2611  output->psi = atof( val[i + 1] );
2612  j++;
2613 
2614  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2615  output->psiErr = atof( val[i + 3] );
2616  j += 2;
2617  }
2618  } else if ( !strcmp( val[i], "phi0" ) || !strcmp( val[i], "PHI0" ) ) {
2619  output->phi0 = atof( val[i + 1] );
2620  j++;
2621 
2622  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2623  output->phi0Err = atof( val[i + 3] );
2624  j += 2;
2625  }
2626  } else if ( !strcmp( val[i], "aplus" ) || !strcmp( val[i], "APLUS" ) ) {
2627  output->Aplus = atof( val[i + 1] );
2628  j++;
2629 
2630  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2631  output->AplusErr = atof( val[i + 3] );
2632  j += 2;
2633  }
2634  } else if ( !strcmp( val[i], "across" ) || !strcmp( val[i], "ACROSS" ) ) {
2635  output->Across = atof( val[i + 1] );
2636  j++;
2637 
2638  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2639  output->AcrossErr = atof( val[i + 3] );
2640  j += 2;
2641  }
2642  } else if ( !strcmp( val[i], "i21" ) || !strcmp( val[i], "I21" ) ) {
2643  output->I21 = atof( val[i + 1] );
2644  j++;
2645 
2646  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2647  output->I21Err = atof( val[i + 3] );
2648  j += 2;
2649  }
2650  } else if ( !strcmp( val[i], "i31" ) || !strcmp( val[i], "I31" ) ) {
2651  output->I31 = atof( val[i + 1] );
2652  j++;
2653 
2654  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2655  output->I31Err = atof( val[i + 3] );
2656  j += 2;
2657  }
2658  } else if ( !strcmp( val[i], "lambdapin" ) || !strcmp( val[i], "LAMBDAPIN" ) ) {
2659  output->lambdapin = atof( val[i + 1] );
2660  j++;
2661 
2662  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2663  output->lambdapinErr = atof( val[i + 3] );
2664  j += 2;
2665  }
2666  } else if ( !strcmp( val[i], "costheta" ) || !strcmp( val[i], "COSTHETA" ) ) {
2667  output->costheta = atof( val[i + 1] );
2668  j++;
2669 
2670  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2671  output->costhetaErr = atof( val[i + 3] );
2672  j += 2;
2673  }
2674  } else if ( !strcmp( val[i], "theta" ) || !strcmp( val[i], "THETA" ) ) {
2675  output->theta = atof( val[i + 1] );
2676  j++;
2677 
2678  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2679  output->thetaErr = atof( val[i + 3] );
2680  j += 2;
2681  }
2682  } else if ( !strcmp( val[i], "c22" ) || !strcmp( val[i], "C22" ) ) {
2683  output->C22 = atof( val[i + 1] );
2684  j++;
2685 
2686  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2687  output->C22Err = atof( val[i + 3] );
2688  j += 2;
2689  }
2690  } else if ( !strcmp( val[i], "c21" ) || !strcmp( val[i], "C21" ) ) {
2691  output->C21 = atof( val[i + 1] );
2692  j++;
2693 
2694  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2695  output->C21Err = atof( val[i + 3] );
2696  j += 2;
2697  }
2698  } else if ( !strcmp( val[i], "phi22" ) || !strcmp( val[i], "PHI22" ) ) {
2699  output->phi22 = atof( val[i + 1] );
2700  j++;
2701 
2702  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2703  output->phi22Err = atof( val[i + 3] );
2704  j += 2;
2705  }
2706  } else if ( !strcmp( val[i], "phi21" ) || !strcmp( val[i], "phi21" ) ) {
2707  output->phi21 = atof( val[i + 1] );
2708  j++;
2709 
2710  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2711  output->phi21Err = atof( val[i + 3] );
2712  j += 2;
2713  }
2714  } else if ( !strcmp( val[i], "hplus" ) || !strcmp( val[i], "HPLUS" ) ) {
2715  output->hPlus = atof( val[i + 1] );
2716  j++;
2717 
2718  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2719  output->hPlus = atof( val[i + 3] );
2720  j += 2;
2721  }
2722  } else if ( !strcmp( val[i], "hcross" ) || !strcmp( val[i], "HCROSS" ) ) {
2723  output->hCross = atof( val[i + 1] );
2724  j++;
2725 
2726  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2727  output->hCrossErr = atof( val[i + 3] );
2728  j += 2;
2729  }
2730  } else if ( !strcmp( val[i], "psitensor" ) || !strcmp( val[i], "PSITENSOR" ) ) {
2731  output->psiTensor = atof( val[i + 1] );
2732  j++;
2733 
2734  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2735  output->psiTensorErr = atof( val[i + 3] );
2736  j += 2;
2737  }
2738  } else if ( !strcmp( val[i], "phi0tensor" ) || !strcmp( val[i], "PHI0TENSOR" ) ) {
2739  output->phi0Tensor = atof( val[i + 1] );
2740  j++;
2741 
2742  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2743  output->phi0TensorErr = atof( val[i + 3] );
2744  j += 2;
2745  }
2746  } else if ( !strcmp( val[i], "hscalarb" ) || !strcmp( val[i], "HSCALARB" ) ) {
2747  output->hScalarB = atof( val[i + 1] );
2748  j++;
2749 
2750  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2751  output->hScalarBErr = atof( val[i + 3] );
2752  j += 2;
2753  }
2754  } else if ( !strcmp( val[i], "hscalarl" ) || !strcmp( val[i], "HSCALARL" ) ) {
2755  output->hScalarL = atof( val[i + 1] );
2756  j++;
2757 
2758  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2759  output->hScalarLErr = atof( val[i + 3] );
2760  j += 2;
2761  }
2762  } else if ( !strcmp( val[i], "psiscalar" ) || !strcmp( val[i], "PSISCALAR" ) ) {
2763  output->psiScalar = atof( val[i + 1] );
2764  j++;
2765 
2766  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2767  output->psiScalarErr = atof( val[i + 3] );
2768  j += 2;
2769  }
2770  } else if ( !strcmp( val[i], "phi0scalar" ) || !strcmp( val[i], "PHI0SCALAR" ) ) {
2771  output->phi0Scalar = atof( val[i + 1] );
2772  j++;
2773 
2774  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2775  output->phi0ScalarErr = atof( val[i + 3] );
2776  j += 2;
2777  }
2778  } else if ( !strcmp( val[i], "hvectorx" ) || !strcmp( val[i], "HVECTORX" ) ) {
2779  output->hVectorX = atof( val[i + 1] );
2780  j++;
2781 
2782  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2783  output->hVectorXErr = atof( val[i + 3] );
2784  j += 2;
2785  }
2786  } else if ( !strcmp( val[i], "hvectory" ) || !strcmp( val[i], "HVECTORY" ) ) {
2787  output->hVectorY = atof( val[i + 1] );
2788  j++;
2789 
2790  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2791  output->hVectorYErr = atof( val[i + 3] );
2792  j += 2;
2793  }
2794  } else if ( !strcmp( val[i], "psivector" ) || !strcmp( val[i], "PSIVECTOR" ) ) {
2795  output->psiVector = atof( val[i + 1] );
2796  j++;
2797 
2798  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2799  output->psiVectorErr = atof( val[i + 3] );
2800  j += 2;
2801  }
2802  } else if ( !strcmp( val[i], "phi0vector" ) || !strcmp( val[i], "PHI0VECTOR" ) ) {
2803  output->phi0Vector = atof( val[i + 1] );
2804  j++;
2805 
2806  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2807  output->phi0VectorErr = atof( val[i + 3] );
2808  j += 2;
2809  }
2810  } else if ( !strcmp( val[i], "cgw" ) || !strcmp( val[i], "CGW" ) ) {
2811  output->cgw = atof( val[i + 1] );
2812  j++;
2813 
2814  if ( atoi( val[i + 2] ) == 1 && i + 2 < k ) {
2815  output->cgwErr = atof( val[i + 3] );
2816  j += 2;
2817  }
2818  }
2819 
2820  if ( j == i ) {
2821  i++;
2822  } else {
2823  i += ( j - i );
2824  }
2825 
2826  if ( i >= k ) {
2827  break;
2828  }
2829  }
2830 
2831  /*fprintf(stderr, "Have I got to the end of LALReadPARFile.\n");*/
2832  fclose( fp );
2833 
2834  /* check linked parameters */
2835  if ( output->sstr != NULL ) {
2836  if ( !strcmp( output->sstr, "KIN" ) || !strcmp( output->sstr, "kin" ) ) {
2837  if ( output->kinset ) {
2838  output->s = sin( output->kin );
2839  } else {
2840  XLAL_PRINT_ERROR( "Error... KIN not set in .par file %s\n", pulsarAndPath );
2842  }
2843  } else {
2844  output->s = atof( output->sstr );
2845  }
2846  }
2847 }
2848 
2850 /* function to print out to screen all the pulsar parameters and there associated errors */
2852 {
2853  fprintf( stderr, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" );
2854  fprintf( stderr, "PULSAR %s :\n", params.name );
2855  fprintf( stderr, "sky position:\tra %.7lf +/- %.3le rads, dec %.7lf +/- %.3le rads\n", params.ra,
2856  params.raErr, params.dec, params.decErr );
2857  if ( params.pmra != 0. || params.pmdec != 0. )
2858  fprintf( stderr, "proper motion:\tra %.4le +/- %.1le rads/s, dec %.4le +/- %.1le rads/s\n",
2859  params.pmra, params.pmraErr, params.pmdec, params.pmdecErr );
2860  if ( params.pepoch != 0. || params.posepoch != 0. )
2861  fprintf( stderr, "epochs:\tperiod %lf (GPS), position %lf (GPS)\n", params.pepoch,
2862  params.posepoch );
2863  fprintf( stderr, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n" );
2864 
2865  fprintf( stderr, "Frequency parameters\n" );
2866  if ( params.f0 != 0. ) {
2867  fprintf( stderr, "\tf0 = %.10lf +/- %.3le (Hz)\n", params.f0, params.f0Err );
2868  }
2869  if ( params.f1 != 0. ) {
2870  fprintf( stderr, "\tf1 = %.5le +/- %.3le (Hz/s)\n", params.f1, params.f1Err );
2871  }
2872  if ( params.f2 != 0. ) {
2873  fprintf( stderr, "\tf1 = %.5le +/- %.3le (Hz/s^2)\n", params.f2, params.f2Err );
2874  }
2875  /* print binary parameters */
2876  if ( params.model != NULL ) {
2877  fprintf( stderr, "\nBinary parameters:\tmodel %s\n", params.model );
2878 
2879  fprintf( stderr, "Keplarian parameters:-\n" );
2880  if ( params.Pb != 0. ) {
2881  fprintf( stderr, "\tperiod = %lf +/- %.3le (days)\n", params.Pb, params.PbErr );
2882  }
2883  if ( params.x != 0. )
2884  fprintf( stderr, "\tprojected semi-major axis = %lf +/- %.3le (light sec)\n", params.x,
2885  params.xErr );
2886  if ( params.e != 0. ) {
2887  fprintf( stderr, "\teccentricity = %lf +/- %.3le\n", params.e, params.eErr );
2888  }
2889  if ( params.w0 != 0. )
2890  fprintf( stderr, "\tlongitude of periastron = %lf +/- %.3lf (degs)\n", params.w0,
2891  params.w0Err );
2892  if ( params.T0 != 0. ) {
2893  fprintf( stderr, "\ttime of periastron = %lf +/- %.3lf (GPS)\n", params.T0, params.T0Err );
2894  }
2895  if ( params.Tasc != 0. )
2896  fprintf( stderr, "\ttime of ascending node = %lf +/- %.3lf (GPS)\n", params.Tasc,
2897  params.TascErr );
2898  if ( params.eps1 != 0. )
2899  fprintf( stderr, "\tfirst Laplace-Lagrange parameter (eps1) = %le +/- %.3le\n", params.eps1,
2900  params.eps1Err );
2901  if ( params.eps2 != 0. )
2902  fprintf( stderr, "\tsecond Laplace-Lagrange parameter (eps1) = %le +/- %.3le\n", params.eps2,
2903  params.eps2Err );
2904  if ( params.eps2 != 0. )
2905  fprintf( stderr, "\tsecond Laplace-Lagrange parameter (eps1) = %le +/- %.3le\n", params.eps2,
2906  params.eps2Err );
2907 
2908  /*fprintf(stderr, "Post-Newtonian parameters:-\n");
2909  if(params.gamma != 0.)
2910  fprintf(stderr, "\tGravitational redshift parameter = %le +/- %.3le\n", params.gamma,
2911  params.gammaErr);*/
2912 
2913  }
2914 }
2916 
2918 {
2919  FILE *fp = NULL;
2920  CHAR *firstline = XLALStringDuplicate( "" );
2921  CHAR onechar[2];
2922  INT4 i = 0, numPars = 0, c = 1, sl = 0;
2923  LALStringVector *tmpparams = NULL; /* temporary parameter names */
2924  LALStringVector *params = NULL;
2925  UINT4Vector *dims = NULL;
2926 
2927  /* check the file exists */
2928  if ( access( corfile, F_OK ) != 0 ) {
2929  XLAL_PRINT_ERROR( "Error... correlation matrix file does not exist!\n" );
2931  }
2932 
2933  /* open file */
2934  if ( ( fp = fopen( corfile, "r" ) ) == NULL ) {
2935  XLAL_PRINT_ERROR( "Error... cannot open correlation matrix file!\n" );
2937  }
2938 
2939  /* read in first line of the file */
2940  while ( !strchr( fgets( onechar, 2, fp ), '\n' ) ) {
2941  firstline = XLALStringAppend( firstline, onechar );
2942  }
2943 
2944  sl = strlen( firstline );
2945 
2946  /* count the number of parameters */
2947  for ( i = 0; i < sl; i++ ) {
2948  /* use isspace as delimiters could be unknown generic whitespace */
2949  if ( !isspace( firstline[i] ) ) {
2950  if ( c ) {
2951  numPars++;
2952  c = 0;
2953  }
2954  } else {
2955  c = 1;
2956  }
2957  }
2958 
2959  /* parse the line and put into the params vector */
2960  rewind( fp ); /* rewind to start of the file */
2961  for ( i = 0; i < numPars; i++ ) {
2962  CHAR tmpStr[128];
2963 
2964  if ( fscanf( fp, "%s", tmpStr ) == EOF ) {
2965  XLAL_PRINT_ERROR( "Error... Problem reading first line of correlation\
2966  matrix!\n" );
2968  }
2969 
2970  tmpparams = XLALAppendString2Vector( tmpparams, tmpStr );
2971 
2972  /* convert some parameter names to a more common convention */
2973  if ( !XLALStringCaseCompare( tmpStr, "RAJ" ) ) { /* convert RAJ to ra */
2975  } else if ( !XLALStringCaseCompare( tmpStr, "DECJ" ) ) { /* convert DECJ to dec */
2977  } else {
2978  params = XLALAppendString2Vector( params, tmpStr );
2979  }
2980  }
2981 
2982  dims = XLALCreateUINT4Vector( 2 );
2983  dims->data[0] = numPars;
2984  dims->data[1] = numPars;
2985 
2986  /* set the correlation matrix to the correct size */
2987  cormat = XLALResizeREAL8Array( cormat, dims );
2988 
2989  /* read through covariance values */
2990  for ( i = 0; i < numPars; i++ ) {
2991  CHAR tmpStr[128];
2992  INT4 j = 0;
2993 
2994  if ( fscanf( fp, "%s", tmpStr ) == EOF ) {
2995  XLAL_PRINT_ERROR( "Error... problem reading in correlation matrix!\n" );
2997  }
2998 
2999  if ( strcmp( tmpStr, tmpparams->data[i] ) ) {
3000  XLAL_PRINT_ERROR( "Error... problem reading in correlation matrix. \
3001 Parameters not in consistent order!\n" );
3003  }
3004 
3005  for ( j = 0; j < i + 1; j++ ) {
3006  REAL8 tmpval = 0.;
3007 
3008  if ( fscanf( fp, "%lf", &tmpval ) == EOF ) {
3009  XLAL_PRINT_ERROR( "Error... problem reading in correlation matrix!\n" );
3011  }
3012 
3013  /* if off diagonal values are +/-1 set to +/- 0.99999 */
3014  if ( j != i && fabs( tmpval ) == 1. ) {
3015  tmpval *= 0.99999;
3016  }
3017 
3018  cormat->data[i * numPars + j] = tmpval;
3019 
3020  /* set opposite elements */
3021  if ( j != i ) {
3022  cormat->data[j * numPars + i] = tmpval;
3023  }
3024  }
3025  }
3026 
3027  XLALDestroyStringVector( tmpparams );
3028 
3029  return params;
3030 }
3031 
3032 
3033 /* functions for converting times given in Terrestrial time TT or TDB in MJD to
3034 times in GPS - this is important for epochs given in .par files which are in
3035 TDB. TT and GPS are different by a factor of 51.184 secs, this is just the
3036 historical factor of 32.184 secs between TT and TAI (International Atomic Time)
3037 and the other 19 seconds come from the leap seonds added between the TAI and
3038 UTC up to the point of definition of GPS time at UTC 01/01/1980 (see
3039 http://www.stjarnhimlen.se/comp/time.html for details) */
3040 
3041 /* a very good paper describing the tranforms between different time systems
3042 and why they are necessary can be found in Seidelmann and Fukushima, A&A 265
3043 (1992) http://ukads.nottingham.ac.uk/abs/1992A%26A...265..833S */
3044 
3045 /** This function converts a MJD format time corrected to Terrestrial Time (TT)
3046  * into an equivalent GPS time */
3047 REAL8 XLALTTMJDtoGPS( REAL8 MJD )
3048 {
3049 
3050  LIGOTimeGPS GPS;
3051  REAL8 mjdInt, mjdFrac;
3052  mjdFrac = modf( MJD, &mjdInt );
3053  XLAL_CHECK_REAL8( XLALTranslateMJDTTtoGPS( &GPS, ( INT4 )mjdInt, mjdFrac ) != NULL, XLAL_EFUNC );
3054 
3055  return XLALGPSGetREAL8( &GPS );
3056 }
3057 
3058 /** If you have an MJD arrival time on the Earth then this will convert it to
3059  * the equivalent GPS time in TDB (see Table 1 of Seidelmann and Fukushima,
3060  * Astronomy & Astrophysics, 265, 833-838 (1992).
3061  *
3062  * Note that XLALBarycenter performs these TDBtoTT corrections (i.e. the
3063  * Einstein delay) when correcting a GPS time on the Earth to TDB. Also, for
3064  * TEMPO produced pulsar epochs given in MJD these are already in the TDB
3065  * system and an equivalent GPS time in the TDB can be calculated just using
3066  * \c XLALTTMJDtoGPS.
3067  */
3069 {
3070  REAL8 GPS;
3071  REAL8 T, TDBtoTT;
3072 
3073  /* Check not before the start of GPS time */
3074  XLAL_CHECK_REAL8( MJD >= GPS0MJD, XLAL_EDOM, "Input MJD time %.1f is not in range, must be > %.1f.\n", MJD, GPS0MJD );
3075 
3076  /* use factors from Table 1 of Seidelmann and Fukushima, Astronomy &
3077  * Astrophysics, 265, 833-838 (1992) where TDB = TDT + P
3078  * and:
3079  * P = 0.0016568 sin(35999.37 degs x T + 357.5 degs) +
3080  0.0000224 sin(32964.5 degs x T + 246.0 degs) +
3081  0.0000138 sin(71998.7 degs x T + 355.0 degs) +
3082  0.0000048 sin(3034.9 degs x T + 25.0 degs) +
3083  0.0000047 sin(34777.3 degs x T + 230.0 degs)
3084  * and T is the elapsed time from J2000 (which has a Julian day date of
3085  * JD 2451545.0) in Julian centuries.*/
3086  T = MJD + ( XLAL_MJD_REF - XLAL_EPOCH_J2000_0_JD );
3087  T /= 36525.; /* covert days to Julian centuries */
3088 
3089  /* time diff in seconds (the Einstein delay) */
3090  TDBtoTT = 0.0016568 * sin( ( 35999.37 * T + 357.5 ) * LAL_PI_180 ) +
3091  0.0000224 * sin( ( 32964.5 * T + 246.0 ) * LAL_PI_180 ) +
3092  0.0000138 * sin( ( 71998.7 * T + 355.0 ) * LAL_PI_180 ) +
3093  0.0000048 * sin( ( 3034.9 * T + 25.0 ) * LAL_PI_180 ) +
3094  0.0000047 * sin( ( 34777.3 * T + 230.0 ) * LAL_PI_180 );
3095 
3096  /* convert TDB to TT (TDB-TDBtoTT) and then convert TT to GPS */
3097  /* there is the magical number factor of 32.184 + 19 leap seconds to the
3098  * start of GPS time */
3099  GPS = ( MJD - GPS0MJD ) * 86400. - GPS_TDT - TDBtoTT;
3100 
3101  return GPS;
3102 }
3103 
3104 
3105 /** If you have an MJD arrival time on the Earth then this will convert it to
3106  * the equivalent GPS time in TCB (see Table 1 of Seidelmann and Fukushima,
3107  * Astronomy & Astrophysics, 265, 833-838, 1992).
3108  *
3109  * Note that for default TEMPO2 produced pulsar epochs given in MJD these are
3110  * already in the TCB system and an equivalent GPS time in the TCB can be
3111  * calculated just using \c XLALTTMJDtoGPS. */
3113 {
3114  REAL8 GPS;
3115  REAL8 Tdiff;
3116  REAL8 TCBtoTDB;
3117 
3118  /* Check not before the start of GPS time (MJD 44244) */
3119  XLAL_CHECK_REAL8( MJD >= GPS0MJD, XLAL_EDOM, "Input MJD time %.1f is not in\
3120  range, must be > %.1f.\n", MJD, GPS0MJD );
3121 
3122  /* from Seidelmann and Fukushima we have a linear drift term:
3123  * TCB - TDB = 1.550506e-8 x (JD - 2443144.5) x 86400
3124  */
3125  Tdiff = ( MJD + XLAL_MJD_REF - 2443144.5 ) * 86400.;
3126  TCBtoTDB = 1.550506e-8 * Tdiff;
3127 
3128  /* convert from TDB to GPS */
3129  GPS = XLALTDBMJDtoGPS( MJD );
3130 
3131  /* add extra factor as the MJD was really in TCB not TDB) */
3132  GPS -= TCBtoTDB;
3133 
3134  return GPS;
3135 }
int j
ProcessParamsTable * ptr
int k
#define c
void PulsarSetParam(PulsarParameters *pars, const CHAR *name, const void *value)
Set the value of a parameter in the PulsarParameters structure.
void * PulsarGetParamErr(const PulsarParameters *pars, const CHAR *name)
Get the required parameter error value from the PulsarParameters structure.
PulsarParameters * XLALReadTEMPOParFile(const CHAR *pulsarAndPath)
Read in the parameters from a TEMPO(2) parameter file into a PulsarParameters structure.
static int PulsarHashElemCmp(const void *elem1, const void *elem2)
static void del_elem(void *elem)
LALStringVector * XLALReadTEMPOCorFile(REAL8Array *cormat, CHAR *corfile)
This function will read in a TEMPO-style parameter correlation matrix.
#define DAYSTOSECS
void PulsarSetREAL8ParamErr(PulsarParameters *pars, const CHAR *name, REAL8 value, UINT4 fitFlag)
Set the error value for a REAL8 parameter.
void PulsarAddREAL8Param(PulsarParameters *pars, const CHAR *name, REAL8 value)
Add a REAL8 parameter to the PulsarParameters structure.
void PulsarCopyParams(PulsarParameters *origin, PulsarParameters *target)
Function to copy a PulsarParameters structure.
const UINT4 * PulsarGetParamFitFlag(const PulsarParameters *pars, const CHAR *name)
Get the fit flag array for a given parameter from the PulsarParameters structure.
REAL8 PulsarGetREAL8VectorParamErrIndividual(const PulsarParameters *pars, const CHAR *name)
Return an individual REAL8 value from a REAL8Vector parameter.
REAL8 PulsarGetREAL8ParamErr(const PulsarParameters *pars, const CHAR *name)
Return a REAL8 parameter error value.
const REAL8Vector * PulsarGetREAL8VectorParam(const PulsarParameters *pars, const CHAR *name)
Return a REAL8Vector parameter.
REAL8 PulsarGetREAL8ParamOrZero(const PulsarParameters *pars, const CHAR *name)
Return a REAL8 parameter if it exists, otherwise return zero.
static const CHAR a2A[256]
Array for conversion from lowercase to uppercase.
#define DEFINE_CONV_FACTOR_FUNCTION(name, convfactor, type)
static PulsarParam * PulsarGetParamItemSlow(const PulsarParameters *pars, const CHAR *name)
Get a pointer to a parameter of a given name from a PulsarParameters structure.
ParConversion
static void strtoupper(CHAR *s)
Convert string to uppercase.
@ CONVSTRING
@ CONVINT
@ CONVDMS
@ CONVFLOAT
@ CONVMJD
@ CONVHMS
@ CONVBINUNITS
int PulsarCheckParam(const PulsarParameters *pars, const CHAR *name)
Check for the existence of the parameter name in the PulsarParameters structure.
void PulsarSetREAL8VectorParamErr(PulsarParameters *pars, const CHAR *name, const REAL8Vector *value, const UINT4 *fitFlag)
Set the error values for a REAL8Vector parameter.
static PulsarParam * PulsarGetParamItem(const PulsarParameters *pars, const CHAR *name)
Get a pointer to a parameter of a given name from a PulsarParameters structure.
REAL8 XLALTCBMJDtoGPS(REAL8 MJD)
If you have an MJD arrival time on the Earth then this will convert it to the equivalent GPS time in ...
const UINT4Vector * PulsarGetParamFitFlagAsVector(const PulsarParameters *pars, const CHAR *name)
Get the fit flag array for a given parameter from the PulsarParameters structure.
void PulsarClearParams(PulsarParameters *pars)
Free all the parameters from a PulsarParameters structure.
void PulsarSetParamErr(PulsarParameters *pars, const CHAR *name, void *value, const UINT4 *fitFlag, UINT4 len)
Set the value of the error of a parameter in the PulsarParameters structure.
static UINT8 PulsarHash(const void *elem)
const CHAR * PulsarGetStringParam(const PulsarParameters *pars, const CHAR *name)
Return a string parameter.
void PrintPulsarParameters(BinaryPulsarParams params)
function to print out all the pulsar parameters read in from a par file
static INT4 ParseParLine(PulsarParameters *par, const CHAR *name, FILE *fp)
Parse a single line from a pulsar parameter file.
const REAL8Vector * PulsarGetREAL8VectorParamErr(const PulsarParameters *pars, const CHAR *name)
Return a REAL8Vector parameter error value.
void PulsarAddParam(PulsarParameters *pars, const CHAR *name, void *value, PulsarParamType type)
Add a parameter and value to the PulsarParameters structure.
REAL8 PulsarGetREAL8Param(const PulsarParameters *pars, const CHAR *name)
Return a REAL8 parameter.
void PulsarRemoveParam(PulsarParameters *pars, const CHAR *name)
Remove a given parameter from a PulsarParameters structure.
REAL8 XLALTDBMJDtoGPS(REAL8 MJD)
If you have an MJD arrival time on the Earth then this will convert it to the equivalent GPS time in ...
UINT4 PulsarGetUINT4Param(const PulsarParameters *pars, const CHAR *name)
Return a UINT4 parameter.
REAL8 XLALTTMJDtoGPS(REAL8 MJD)
This function converts a MJD format time corrected to Terrestrial Time (TT) into an equivalent GPS ti...
void PulsarFreeParams(PulsarParameters *pars)
Function to free memory from pulsar parameters.
void PulsarAddStringParam(PulsarParameters *pars, const CHAR *name, const CHAR *value)
Add a string parameter to the PulsarParameters structure.
size_t PulsarTypeSize[5]
#define NUM_PARS
void PulsarAddREAL8VectorParam(PulsarParameters *pars, const CHAR *name, const REAL8Vector *value)
Add a REAL8Vector parameter to the PulsarParameters structure.
REAL8 PulsarGetREAL8VectorParamIndividual(const PulsarParameters *pars, const CHAR *name)
Return an individual REAL8 value from a REAL8Vector parameter.
ParConversion pc[NUM_PARS]
Initialise conversion structure with most allowed TEMPO2 parameter names and conversion functions (co...
static void * new_elem(const char *name, PulsarParam *itemPtr)
void * PulsarGetParam(const PulsarParameters *pars, const CHAR *name)
Get the required parameter value from the PulsarParameters structure.
void XLALReadTEMPOParFileOrig(BinaryPulsarParams *output, CHAR *pulsarAndPath)
function to read in a TEMPO parameter file
PulsarParamType PulsarGetParamType(const PulsarParameters *pars, const char *name)
Get the required parameter's type.
UINT4 PulsarGetUINT4ParamOrZero(const PulsarParameters *pars, const CHAR *name)
Return a UINT4 parameter if it exists, otherwise return zero.
void PulsarAddUINT4Param(PulsarParameters *pars, const CHAR *name, UINT4 value)
Add a UINT4 parameter to the PulsarParameters structure.
void ParConvKpcToMetres(const CHAR *in, void *out)
Convert the input string from kiloparsecs to metres.
void ParConvToString(const CHAR *in, void *out)
Copy the input string into the output pointer.
void ParConvDegsToRads(const CHAR *in, void *out)
Convert the input string from degrees to radians.
void ParConvInvArcsecsToInvRads(const CHAR *in, void *out)
Convert the input string from 1/acrseconds to 1/radians.
void ParConvDegPerYrToRadPerSec(const CHAR *in, void *out)
Convert the input string from degrees per year to radians per second.
void ParConvSecsToRads(const CHAR *in, void *out)
Convert the input string from seconds to radians.
void ParConvBinaryUnits(const CHAR *in, void *out)
Convert the binary system parameter from a string to a double, but make the check (as performed by TE...
#define GPS_TDT
#define LALPULSAR_TEMPO2_MSUN_SI
void ParConvDaysToSecs(const CHAR *in, void *out)
Convert the input string from days to seconds.
void ParConvSolarMassToKg(const CHAR *in, void *out)
Convert the input string from solar masses to kilograms.
PulsarParamType
An enumerated type for denoting the type of a variable.
@ PULSARTYPE_REAL8Vector_t
@ PULSARTYPE_UINT4_t
@ PULSARTYPE_string_t
@ PULSARTYPE_REAL8_t
void ParConvMicrosecToSec(const CHAR *in, void *out)
Convert an input string from microseconds into seconds.
void ParConvMasPerYrToRadPerSec(const CHAR *in, void *out)
Convert the input string from milliarcsecs per year to radians per second.
void ParConvMasToRads(const CHAR *in, void *out)
Convert the input string from milliarcsecs to radians.
void ParConvToInt(const CHAR *in, void *out)
Convert the input string into a unsigned integer number.
void ParConvMJDToGPS(const CHAR *in, void *out)
Convert the input string from a TT MJD value into a GPS time.
void ParConvRAToRads(const CHAR *in, void *out)
Convert a right ascension input string in the format "hh:mm:ss.s" into radians.
void ParConvToFloat(const CHAR *in, void *out)
Conversion functions from units used in TEMPO parameter files into SI units.
#define GPS0MJD
void ParConvDecToRads(const CHAR *in, void *out)
Convert a declination input string in the format "dd:mm:ss.s" into radians.
#define PULSAR_PARNAME_MAX
void ParConvArcsecsToRads(const CHAR *in, void *out)
Convert the input string from arcseconds to radians.
const char * name
Definition: SearchTiming.c:93
#define fscanf
#define fprintf
int s
double e
REAL8Array * XLALResizeREAL8Array(REAL8Array *, UINT4Vector *)
#define XLAL_MJD_REF
#define XLAL_EPOCH_J2000_0_JD
#define LAL_PI_180
#define LAL_TWOPI
uint64_t UINT8
double REAL8
char CHAR
uint32_t UINT4
int32_t INT4
UINT8 XLALCityHash64(const char *buf, size_t len)
int XLALHashTblFind(const LALHashTbl *ht, const void *x, const void **y)
LALHashTbl * XLALHashTblCreate(LALHashTblDtorFcn dtor, LALHashTblHashFcn hash, LALHashTblCmpFcn cmp)
int XLALHashTblAdd(LALHashTbl *ht, void *x)
int XLALHashTblRemove(LALHashTbl *ht, const void *x)
void XLALHashTblDestroy(LALHashTbl *ht)
void * XLALCalloc(size_t m, size_t n)
void * XLALMalloc(size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
int XLALStringCaseCompare(const char *s1, const char *s2)
size_t XLALStringCopy(char *dst, const char *src, size_t size)
char char * XLALStringDuplicate(const char *s)
int char * XLALStringAppend(char *s, const char *append)
LALStringVector * XLALAppendString2Vector(LALStringVector *vect, const CHAR *string)
void XLALDestroyStringVector(LALStringVector *vect)
int XLALTranslateHMStoRAD(REAL8 *radians, const CHAR *hms)
int XLALTranslateDMStoRAD(REAL8 *radians, const CHAR *dms)
LIGOTimeGPS * XLALTranslateMJDTTtoGPS(LIGOTimeGPS *gps, INT4 mjdDays, REAL8 mjdFracDays)
void XLALDestroyUINT4Vector(UINT4Vector *vector)
UINT4Vector * XLALCreateUINT4Vector(UINT4 length)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
#define XLAL_ERROR_VOID(...)
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR_NULL(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_PRINT_WARNING(...)
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_PRINT_ERROR(...)
#define XLAL_PRINT_DEPRECATION_WARNING(replacement)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EINVAL
XLAL_EFAILED
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
T
out
A structure to contain all pulsar parameters and associated errors.
The PulsarParam list node structure.
void * value
Parameter value.
struct tagPulsarParam * next
void * err
Parameter error/uncertainty.
UINT4Vector * fitFlag
Set to 1 if the parameter has been fit in the par file.
PulsarParamType type
Parameter type e.g.
The PulsarParameters structure to contain a set of pulsar parameters.
PulsarParam * head
A linked list of PulsarParam structures.
LALHashTbl * hash_table
Hash table of parameters.
INT4 nparams
The total number of parameters in the structure.
REAL8 * data
REAL8 * data
UINT4 * data
LALInferenceVariableItem * itemPtr
const char * name
double ra
double dec