INT4 XLALMCMCDifferentialEvolution(
	LALMCMCInput *inputMCMC,
	LALMCMCParameter *parameter)
{
	static LALStatus status;
	LALMCMCParameter **Live=inputMCMC->Live;
	int i=0, j=0, UNUSED dim=0, same=1;
	REAL4 randnum;
	int Nlive = (int)inputMCMC->Nlive;
	LALMCMCParam *paraHead=NULL;
	LALMCMCParam *paraA=NULL;
	LALMCMCParam *paraB=NULL;

	dim = parameter->dimension;
	if(inputMCMC->randParams==NULL) LALCreateRandomParams(&status,&(inputMCMC->randParams),0);
	/* Select two other samples A and B*/
	LALUniformDeviate(&status,&randnum,inputMCMC->randParams);
	i=(int)(Nlive*randnum);
	/* Draw two different samples from the basket. Will loop back here if the original sample is chosen*/
	drawtwo:
	do {LALUniformDeviate(&status,&randnum,inputMCMC->randParams); j=(int)(Nlive*randnum);} while(j==i);
	paraHead=parameter->param;
	paraA=Live[i]->param; paraB=Live[j]->param;
		/* Add the vector B-A */
	same=1;
	while(paraHead)
	{
		paraHead->value+=paraB->value;
		paraHead->value-=paraA->value;
		if(paraHead->value!=paraA->value && paraHead->value!=paraB->value && paraA->value!=paraB->value) same=0;
		paraB=paraB->next; paraA=paraA->next;
		paraHead=paraHead->next;
	}
	if(same==1) goto drawtwo;
	/* Bring the sample back into bounds */
	XLALMCMCCyclicReflectiveBound(parameter);
	return(0);
}
int main( int argc, char *argv[] )
{
  LALStatus             status = blank_status;
#if 0
  const INT4            S2StartTime = 729273613; /* Feb 14 2003 16:00:00 UTC */
  const INT4            S2StopTime  = 734367613; /* Apr 14 2003 15:00:00 UTC */
#endif
  /* command line options */
  LIGOTimeGPS   gpsStartTime = {S2StartTime, 0};
  LIGOTimeGPS   gpsEndTime   = {S2StopTime, 0};
  REAL8         meanTimeStep = 2630 / LAL_PI;
  REAL8         timeInterval = 0;
  UINT4         randSeed = 1;
  CHAR         *userTag = NULL;
  REAL4         minMass = 3.0;       /* minimum component mass */
  REAL4         maxMass = 20.0;      /* maximum component mass */
  REAL4         sumMaxMass = 0.0;    /* maximum total mass sum */
  UINT4         sumMaxMassUse=0;     /* flag indicating to use the sumMaxMass */
  REAL4         dmin = 1.0;          /* minimum distance from earth (kpc) */
  REAL4         dmax = 20000.0 ;     /* maximum distance from earth (kpc) */
  REAL4         fLower = 0;          /* default value for th lower cut off frequency */
/* REAL4         Rcore = 0.0; */
  UINT4         ddistr = 0, mdistr=0;

  /* program variables */
  RandomParams *randParams = NULL;
  REAL4  u, exponent, d2;
  REAL4  deltaM, mtotal;


  /* waveform */
  CHAR waveform[LIGOMETA_WAVEFORM_MAX];

#if 0
  int i, stat;

  double d, cosphi, sinphi;
#endif

/*  GalacticInspiralParamStruc galacticPar; */

  /* xml output data */
  CHAR                  fname[256];
  MetadataTable         proctable;
  MetadataTable         procparams;
  MetadataTable         injections;
  ProcessParamsTable   *this_proc_param;
  SimInspiralTable     *this_inj = NULL;
  LIGOLwXMLStream       xmlfp;
  UINT4                 outCompress = 0;

  /* getopt arguments */
  struct option long_options[] =
  {
    {"help",                    no_argument,       0,                'h'},
    {"verbose",                 no_argument,       &vrbflg,           1 },
    {"write-compress",          no_argument,       &outCompress,      1 },
    {"version",                 no_argument,       0,                'V'},
    {"f-lower",                        required_argument, 0,                'f'},
    {"gps-start-time",          required_argument, 0,                'a'},
    {"gps-end-time",            required_argument, 0,                'b'},
    {"time-step",               required_argument, 0,                't'},
    {"time-interval",           required_argument, 0,                'i'},
    {"seed",                    required_argument, 0,                's'},
    {"min-mass",                required_argument, 0,                'A'},
    {"max-mass",                required_argument, 0,                'B'},
    {"max-total-mass",          required_argument, 0,                'x'},
    {"min-distance",            required_argument, 0,                'p'},
    {"max-distance",            required_argument, 0,                'r'},
    {"d-distr",                 required_argument, 0,                'd'},
    {"m-distr",                 required_argument, 0,                'm'},
    {"waveform",                required_argument, 0,                'w'},
    {"user-tag",                required_argument, 0,                'Z'},
    {"userTag",                 required_argument, 0,                'Z'},
    {0, 0, 0, 0}
  };
  int c;

  /* set up inital debugging values */
  lal_errhandler = LAL_ERR_EXIT;


  /* create the process and process params tables */
  proctable.processTable = (ProcessTable *) 
    calloc( 1, sizeof(ProcessTable) );
  XLALGPSTimeNow(&(proctable.processTable->start_time));
  if (strcmp(CVS_REVISION,"$Revi" "sion$"))
    {
      XLALPopulateProcessTable(proctable.processTable,
          PROGRAM_NAME, CVS_REVISION, CVS_SOURCE, CVS_DATE, 0);
    }
  else
    {
      XLALPopulateProcessTable(proctable.processTable,
          PROGRAM_NAME, lalappsGitCommitID,
          lalappsGitGitStatus,
          lalappsGitCommitDate, 0);
    }
  snprintf( proctable.processTable->comment, LIGOMETA_COMMENT_MAX, " " );
  this_proc_param = procparams.processParamsTable = (ProcessParamsTable *) 
    calloc( 1, sizeof(ProcessParamsTable) );

  /* clear the waveform field */
  memset( waveform, 0, LIGOMETA_WAVEFORM_MAX * sizeof(CHAR) );
  

  /*
   *
   * parse command line arguments
   *
   */

     
  while ( 1 )
  {
    /* getopt_long stores long option here */
    int option_index = 0;
    long int gpsinput;
    size_t optarg_len;

    c = getopt_long_only( argc, argv, 
        "a:A:b:B:d:f:hi:m:p:q:r:s:t:vZ:w:", long_options, &option_index );

    /* detect the end of the options */
    if ( c == - 1 )
    {
      break;
    }

    switch ( c )
    {
      case 0:
        /* if this option set a flag, do nothing else now */
        if ( long_options[option_index].flag != 0 )
        {
          break;
        }
        else
        {
          fprintf( stderr, "error parsing option %s with argument %s\n",
              long_options[option_index].name, optarg );
          exit( 1 );
        }
        break;

      case 'a':
        gpsinput = atol( optarg );
        if ( gpsinput < 441417609 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "GPS start time is prior to " 
              "Jan 01, 1994  00:00:00 UTC:\n"
              "(%ld specified)\n",
              long_options[option_index].name, gpsinput );
          exit( 1 );
        }
        gpsStartTime.gpsSeconds = gpsinput;

        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%ld", gpsinput );
        break;

      case 'b':
        gpsinput = atol( optarg );
        if ( gpsinput < 441417609 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "GPS start time is prior to " 
              "Jan 01, 1994  00:00:00 UTC:\n"
              "(%ld specified)\n",
              long_options[option_index].name, gpsinput );
          exit( 1 );
        }
        gpsEndTime.gpsSeconds = gpsinput;
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%ld", gpsinput );
        break;

      case 'f':
        fLower = atof( optarg );
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "float", 
              "%f", fLower );
        break;

      case 's':
        randSeed = atoi( optarg );
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%d", randSeed );
        break;

      case 't':
        meanTimeStep = (REAL8) atof( optarg );
        if ( meanTimeStep <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "time step must be > 0: (%e seconds specified)\n",
              long_options[option_index].name, meanTimeStep );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "float", 
              "%e", meanTimeStep );
        break;

      case 'i':
        timeInterval = atof( optarg );
        if ( timeInterval < 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "time interval must be >= 0: (%e seconds specified)\n",
              long_options[option_index].name, meanTimeStep );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", timeInterval );
        break;

      case 'A':
        /* minimum component mass */
        minMass = (REAL4) atof( optarg );
        if ( minMass <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "miniumum component mass must be > 0: "
              "(%f solar masses specified)\n",
              long_options[option_index].name, minMass );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", minMass );
        break;

      case 'B':
        /* maximum component mass */
        maxMass = (REAL4) atof( optarg );
        if ( maxMass <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "maxiumum component mass must be > 0: "
              "(%f solar masses specified)\n",
              long_options[option_index].name, maxMass );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", maxMass );
        break;

    case 'x':
      /* maximum sum of components */
      sumMaxMass = (REAL4) atof( optarg );
      if ( sumMaxMass <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "sum of two component masses must be > 0: "
                   "(%f solar masses specified)\n",
                   long_options[option_index].name, sumMaxMass );
          exit( 1 );
        }
      sumMaxMassUse=1;
        this_proc_param = this_proc_param->next =
          next_process_param( long_options[option_index].name,
                              "float", "%e", sumMaxMass );
        break;

      case 'p':
        /* minimum distance from earth */
        dmin = (REAL4) atof( optarg );
        if ( dmin <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "minimum distance must be > 0: "
              "(%f kpc specified)\n",
              long_options[option_index].name, dmin );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", dmin );
        break;

      case 'r':
        /* max distance from earth */
        dmax = (REAL4) atof( optarg );
        if ( dmax <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "maximum distance must be greater than 0: "
              "(%f kpc specified)\n",
              long_options[option_index].name, dmax );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", dmax );
        break;

      case 'd':
        ddistr = (UINT4) atoi( optarg );
        if ( ddistr != 0 && ddistr != 1 && ddistr != 2)
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "DDISTR must be either 0 or 1 or 2\n",
              long_options[option_index].name);
          exit(1);
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "int", "%d", ddistr );

        break;

      case 'm':
        mdistr = (UINT4) atoi( optarg );
        if ( mdistr != 0 && mdistr != 1 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "MDISTR must be either 0 or 1\n",
              long_options[option_index].name);
          exit(1);
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "int", "%d", mdistr );

  
        break;

      case 'Z':
        /* create storage for the usertag */
        optarg_len = strlen( optarg ) + 1;
        userTag = (CHAR *) calloc( optarg_len, sizeof(CHAR) );
        memcpy( userTag, optarg, optarg_len );
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "string", "%s", optarg );
        break;

      case 'w':
        snprintf( waveform, LIGOMETA_WAVEFORM_MAX, "%s", optarg);
        this_proc_param = this_proc_param->next =
          next_process_param( long_options[option_index].name, "string",
              "%s", optarg);
        break;

      case 'V':
        /* print version information and exit */
        fprintf( stdout, "Binary Black Hole INJection generation routine\n" 
            "Duncan A Brown and Eirini Messaritaki\n"
            "CVS Version: " CVS_ID_STRING "\n"
            "CVS Tag: " CVS_NAME_STRING "\n" );
        fprintf( stdout, lalappsGitID );
        exit( 0 );
        break;
        
      case 'h':
      case '?':
        fprintf( stderr, USAGE );
        exit( 0 );
        break;

      default:
        fprintf( stderr, "unknown error while parsing options\n" );
        fprintf( stderr, USAGE );
        exit( 1 );
    }
  }

  if ( optind < argc )
  {
    fprintf( stderr, "extraneous command line arguments:\n" );
    while ( optind < argc )
    {
      fprintf ( stderr, "%s\n", argv[optind++] );
    }
    exit( 1 );
  }


  if ( !*waveform )
  {
    /* use EOBtwoPN as the default waveform */
    snprintf( waveform, LIGOMETA_WAVEFORM_MAX, "EOBtwoPN");
  }

  if ( !fLower )
  {
    fprintf( stderr, "--f-lower must be specified and non-zero\n" );
    exit( 1 );
  }

  /*
   *
   * initialization
   *
   */


  /* initialize the random number generator */
  LAL_CALL( LALCreateRandomParams( &status, &randParams, randSeed ), &status );

  /* mass range, per component */
  deltaM = maxMass - minMass;

  /* null out the head of the linked list */
  injections.simInspiralTable = NULL;

  /* create the output file name */
  if ( userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d_%s-%d-%d.xml.gz",
        randSeed, userTag, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( userTag && !outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d_%s-%d-%d.xml",
        randSeed, userTag, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( !userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d-%d-%d.xml.gz",
        randSeed, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d-%d-%d.xml",
        randSeed, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }


  /*
   *
   * loop over duration of desired output times
   *
   */


  while ( XLALGPSCmp( &gpsStartTime, &gpsEndTime ) < 0 )
  {

    /* rho, z and lGal are the galactocentric galactic axial coordinates */
    /* r and phi are the geocentric galactic spherical coordinates       */
#if 0
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    galacticPar.lGal = LAL_TWOPI * u;
    
    galacticPar.z = r * sinphi ;
    galacticPar.rho = 0.0 - Rcore * cos(galacticPar.lGal) +
      sqrt( r * r - galacticPar.z * galacticPar.z - 
      Rcore * Rcore * sin(galacticPar.lGal) * sin(galacticPar.lGal) );
#endif

#if 0
    if ( vrbflg ) fprintf( stdout, "%e %e %e %e %e\n", 
        galacticPar.m1, galacticPar.m2,
        galacticPar.rho * cos( galacticPar.lGal ),
        galacticPar.rho * sin( galacticPar.lGal ),
        galacticPar.z );
#endif

    /* create the sim_inspiral table */
    if ( injections.simInspiralTable )
    {
      this_inj = this_inj->next = (SimInspiralTable *)
        LALCalloc( 1, sizeof(SimInspiralTable) );
    }
    else
    {
      injections.simInspiralTable = this_inj = (SimInspiralTable *)
        LALCalloc( 1, sizeof(SimInspiralTable) );
    }

    /* set the geocentric end time of the injection */
    /* XXX CHECK XXX */
    this_inj->geocent_end_time = gpsStartTime;
    if ( timeInterval )
    {
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      XLALGPSAdd( &(this_inj->geocent_end_time), u * timeInterval );
    }

    /* set gmst */
    this_inj->end_time_gmst = fmod(XLALGreenwichMeanSiderealTime(
        &this_inj->geocent_end_time), LAL_TWOPI) * 24.0 / LAL_TWOPI; /* hours */
    if( XLAL_IS_REAL8_FAIL_NAN(this_inj->end_time_gmst) )
    {
      fprintf(stderr, "XLALGreenwichMeanSiderealTime() failed\n");
      exit(1);
    }
    /* XXX END CHECK XXX */

    /* populate the sim_inspiral table */

    if (mdistr == 1)
    /* uniformly distributed mass1 and uniformly distributed mass2 */
    {
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      this_inj->mass1 = minMass + u * deltaM;
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      this_inj->mass2 = minMass + u * deltaM;
      mtotal = this_inj->mass1 + this_inj->mass2 ;
      this_inj->eta = this_inj->mass1 * this_inj->mass2 / ( mtotal * mtotal );
      this_inj->mchirp = (this_inj->mass1 + this_inj->mass2) * 
        pow(this_inj->eta, 0.6);
    }
    else if (mdistr == 0)
    /*uniformly distributed total mass */
    {
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status);
      mtotal = 2.0 * minMass + u * 2.0 *deltaM ;

      if (sumMaxMassUse==1) {
        while (mtotal > sumMaxMass) {
          LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status);
          mtotal = 2.0 * minMass + u * 2.0 *deltaM ;          
        }
      }

      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      this_inj->mass1 = minMass + u * deltaM;
      this_inj->mass2 = mtotal - this_inj->mass1;

      while (this_inj->mass1 >= mtotal || 
          this_inj->mass2 >= maxMass || this_inj->mass2 <= minMass )
      {
        LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
        this_inj->mass1 = minMass + u * deltaM;
        this_inj->mass2 = mtotal - this_inj->mass1;
      }
      this_inj->eta = this_inj->mass1 * this_inj->mass2 / ( mtotal * mtotal );
      this_inj->mchirp = (this_inj->mass1 + this_inj->mass2) * 
        pow(this_inj->eta, 0.6);

    }

     /* spatial distribution */

#if 0
     LAL_CALL( LALUniformDeviate( &status, &u, randParams ),
            &status );
     sinphi = 2.0 * u - 1.0;
     cosphi = sqrt( 1.0 - sinphi*sinphi );
#endif

     if (ddistr == 0)
     /* uniform distribution in distance */
     {
       REAL4 deltaD = dmax - dmin ;
       LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
       this_inj->distance = dmin + deltaD * u ;
      }
      else if (ddistr == 1)
      /* uniform distribution in log(distance) */
      {
        REAL4 lmin = log10(dmin);
        REAL4 lmax = log10(dmax);
        REAL4 deltaL = lmax - lmin;
        LAL_CALL(  LALUniformDeviate(&status,&u,randParams),&status );
        exponent = lmin + deltaL * u;
        this_inj->distance = pow(10.0,(REAL4) exponent);
      }
     else if (ddistr == 2)
     /* uniform volume distribution */
     {
       REAL4 d2min = pow(dmin,3.0) ;
       REAL4 d2max = pow(dmax,3.0) ;
       REAL4 deltad2 = d2max - d2min ;
       LAL_CALL(  LALUniformDeviate(&status,&u,randParams),&status );
       d2 = d2min + u * deltad2 ;
       this_inj->distance = pow(d2,1.0/3.0);
     }

     this_inj->distance = this_inj->distance / 1000.0; /*convert to Mpc */
       

      /* compute random longitude and latitude */
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      this_inj->latitude = asin( 2.0 * u - 1.0 ) ;
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      this_inj->longitude = LAL_TWOPI * u ;
     

#if 0
    LAL_CALL( LALGalacticInspiralParamsToSimInspiralTable( &status,
          this_inj, &galacticPar, randParams ), &status );
    if (vrbflg)
    { 
      fprintf( stdout, "%e\n",
      sqrt(galacticPar.z*galacticPar.z+galacticPar.rho*galacticPar.rho
          + Rcore*Rcore + 2.0*Rcore*galacticPar.rho*cos(galacticPar.lGal))-
      this_inj->distance*1000.0);
    }
#endif


    /* set the source and waveform fields */
    snprintf( this_inj->source, LIGOMETA_SOURCE_MAX, "???" );
    memcpy( this_inj->waveform, waveform, LIGOMETA_WAVEFORM_MAX *
        sizeof(CHAR));

    /* XXX CHECK XXX */
    /* compute random inclination, polarization and coalescence phase */
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    this_inj->inclination = acos( 2.0 * u - 1.0 );
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    this_inj->polarization = LAL_TWOPI * u ;
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    this_inj->coa_phase = LAL_TWOPI * u ;
    
    /* populate the site specific information */
    LAL_CALL(LALPopulateSimInspiralSiteInfo( &status, this_inj ), 
        &status);
    
    /* increment the injection time */
    XLALGPSAdd( &gpsStartTime, meanTimeStep );

    /* finally populate the flower */
    if (fLower > 0)         
    {
        this_inj->f_lower = fLower;
    }
    else
    {
        this_inj->f_lower = 0;
    }
    /* XXX END CHECK XXX */

  } /* end loop over injection times */

  /* destroy random parameters */
  LAL_CALL( LALDestroyRandomParams( &status, &randParams ), &status );


  /*
   *
   * write output to LIGO_LW XML file
   *
   */


  /* open the xml file */
  memset( &xmlfp, 0, sizeof(LIGOLwXMLStream) );
  LAL_CALL( LALOpenLIGOLwXMLFile( &status, &xmlfp, fname ), &status );

  /* write the process table */
  snprintf( proctable.processTable->ifos, LIGOMETA_IFOS_MAX, "H1H2L1" );
  XLALGPSTimeNow(&(proctable.processTable->end_time));
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, process_table ), 
      &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, proctable, 
        process_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
  free( proctable.processTable );

  /* free the unused process param entry */
  this_proc_param = procparams.processParamsTable;
  procparams.processParamsTable = procparams.processParamsTable->next;
  free( this_proc_param );

  /* write the process params table */
  if ( procparams.processParamsTable )
  {
    LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, process_params_table ), 
        &status );
    LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, procparams, 
          process_params_table ), &status );
    LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
    while( procparams.processParamsTable )
    {
      this_proc_param = procparams.processParamsTable;
      procparams.processParamsTable = this_proc_param->next;
      free( this_proc_param );
    }
  }

  /* write the sim_inspiral table */
  if ( injections.simInspiralTable )
  {
    LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, sim_inspiral_table ), 
        &status );
    LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, injections, 
          sim_inspiral_table ), &status );
    LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
  }
  while ( injections.simInspiralTable )
  {
    this_inj = injections.simInspiralTable;
    injections.simInspiralTable = injections.simInspiralTable->next;
    LALFree( this_inj );
  }

  /* close the injection file */
  LAL_CALL( LALCloseLIGOLwXMLFile ( &status, &xmlfp ), &status );

  /* check for memory leaks and exit */
  LALCheckMemoryLeaks();
  return 0;
}
UINT4
XLALMCMCSample(
  LALMCMCInput *inputMCMC,
  LALMCMCParameter **paraPtr,
  REAL4  *oldLogPosterior,
  gsl_matrix *covMat
  )
{

  static LALStatus status;

  LALMCMCParameter *parameter=NULL; /* parameter value    */
  LALMCMCParameter *proposal=NULL;  /* proposal  value    */
  LALMCMCParameter *help=NULL;      /* help parameter set */
  LALMCMCParam* paraHead = NULL;

  REAL4 alpha, my_random, s;
  REAL4 logPrior, logLikelihood, logPosterior;
  UINT4 move, accept, c;
  INT4 UNUSED testPrior;

  /* set the parameter */
  parameter=*paraPtr;
  move=0;

  /* allocate spec for proposal set */
  proposal=(LALMCMCParameter*)LALMalloc( sizeof(LALMCMCParameter) );

  do {
    accept = 1;
    XLALMCMCCopyPara( &proposal, parameter);
    XLALMCMCJump( inputMCMC, proposal, covMat);

    for (paraHead = proposal->param,c=0; paraHead; paraHead=paraHead->next,c++ )
    {
      /* check if parameter lies in valid range */
      if (paraHead->value < paraHead->core->minVal ||
          paraHead->value > paraHead->core->maxVal)
      {
        accept=0;
        /*
        if ( inputMCMC->verbose )
          printf("MCMCSAMPLE Parameter %10s outside range. Value: %8.3f  Range: %8.3f - %8.3f \n",
                 paraHead->core->name, paraHead->value,
                 paraHead->core->minVal,  paraHead->core->maxVal );
        */
      }
    }
  } while ( !accept );

  /* calculate the log Prior */
  testPrior = inputMCMC->funcPrior( inputMCMC, proposal );
  logPrior = proposal->logPrior;

  /*-- determine likelihood if prior gives something reasonable:   --*/
  if ( logPrior>-HUGE_VAL )
  {

    /* calculate the new posterior value for the proposal parameter set */
    logLikelihood = inputMCMC->funcLikelihood( inputMCMC, proposal );
    logPosterior = logLikelihood + logPrior;

    /* calculate the alpha-value and draw a random number */
    s=inputMCMC->scaling;
    alpha=exp( s*(logPosterior - *oldLogPosterior) );
    LALUniformDeviate( &status, &my_random, inputMCMC->randParams );

    /* now check accept/reject criterion */
    if ( my_random<=alpha )
    {
      /* accept the proposal set */
      move = 1;

      /* just swap the two pointers */
      help=proposal;
      proposal=parameter;
      parameter=help;

      /* return the new log posterior value */
      *oldLogPosterior = logPosterior;
    }

    /* output */
    if ( inputMCMC->verbose )
    {
      if (move==1)
        printf("MCMCSAMPLE: ++JumpIsAccepted ");
      else
        printf("MCMCSAMPLE: --JumpNotAccepted ");
      printf("current logPost: %6.3f  proposal logPost: %6.3f alpha: %6.3f  "
             "u: %6.3f\n",
             *oldLogPosterior, logPosterior, alpha, my_random);
    }
  }

  /* test printout */
  if ( inputMCMC->verbose )
  {
    printf("MCMCPARAMETER: ");
    printf("| SNR: %f  ", *oldLogPosterior);
    for (paraHead=parameter->param; paraHead; paraHead=paraHead->next) {
      printf(" | %s: %9.5f", paraHead->core->name, paraHead->value);
    }
    fprintf(stdout, "\n");
  }


  /* recopy the correct parameter structure */
  *paraPtr=parameter;

  /* free proposal parameter set */
  XLALMCMCFreePara( proposal );

  return move;
}
int
main( int argc, char **argv )
{
  int arg;                      /* command-line argument counter */
  BOOLEAN xyz = 0;              /* whether -x, -y, or -z options were given */
  INT4 verbosity = 0;           /* verbosity level */
  REAL8 x_1 = 0.0, x_2 = 0.0, dx; /* range and increment in x */
  REAL8 y_1 = 0.0, y_2 = 0.0, dy; /* range and increment in y */
  REAL8 z_1 = 0.0, z_2 = 0.0, dz; /* range and increment in z */
  INT4 nx = 1, ny = 1, nz = 1;  /* number of steps in each direction */
  INT4 i, j, k;                 /* index in each direction */
  REAL8 x, y, z, ddx, ddy, ddz; /* position and error in each direction */
  REAL8 ddr, ddmax = 0.0;       /* overall and maximum position error */
  static LALStatus stat;        /* status structure */
  EarthPosition earth;          /* terrestrial coordinates */


  /*******************************************************************
   * PARSE ARGUMENTS (arg stores the current position)               *
   *******************************************************************/

  arg = 1;
  while ( arg < argc ) {

    /* Parse range options. */
    if ( !strcmp( argv[arg], "-x" ) ) {
      if ( argc > arg + 3 ) {
	arg++;
	xyz = 1;
	x_1 = atof( argv[arg++] );
	x_2 = atof( argv[arg++] );
	nx = atoi( argv[arg++] );
      } else {
	ERROR( GEOCENTRICGEODETICTESTC_EARG,
	       GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return GEOCENTRICGEODETICTESTC_EARG;
      }
    } else if ( !strcmp( argv[arg], "-y" ) ) {
      if ( argc > arg + 3 ) {
	arg++;
	xyz = 1;
	y_1 = atof( argv[arg++] );
	y_2 = atof( argv[arg++] );
	ny = atoi( argv[arg++] );
      } else {
	ERROR( GEOCENTRICGEODETICTESTC_EARG,
	       GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return GEOCENTRICGEODETICTESTC_EARG;
      }
    } else if ( !strcmp( argv[arg], "-z" ) ) {
      if ( argc > arg + 3 ) {
	arg++;
	xyz = 1;
	z_1 = atof( argv[arg++] );
	z_2 = atof( argv[arg++] );
	nz = atoi( argv[arg++] );
      } else {
	ERROR( GEOCENTRICGEODETICTESTC_EARG,
	       GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return GEOCENTRICGEODETICTESTC_EARG;
      }
    }

    /* Parse verbosity option. */
    else if ( !strcmp( argv[arg], "-v" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
	verbosity = atoi( argv[arg++] );
      } else {
	ERROR( GEOCENTRICGEODETICTESTC_EARG,
	       GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return GEOCENTRICGEODETICTESTC_EARG;
      }
    }

    /* Parse debug level option. */
    else if ( !strcmp( argv[arg], "-d" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
      } else {
	ERROR( GEOCENTRICGEODETICTESTC_EARG,
	       GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return GEOCENTRICGEODETICTESTC_EARG;
      }
    }

    /* Check for unrecognized options. */
    else if ( argv[arg][0] == '-' ) {
      ERROR( GEOCENTRICGEODETICTESTC_EARG,
	     GEOCENTRICGEODETICTESTC_MSGEARG, 0 );
      LALPrintError( USAGE, *argv );
      return GEOCENTRICGEODETICTESTC_EARG;
    }
  } /* End of argument parsing loop. */

  /*******************************************************************
   * SET PARAMETERS                                                  *
   *******************************************************************/

  /* If none of -x, -y, -z were given, generate a random position. */
  if ( !xyz ) {
    REAL4 lon, coslat, sinlat, rad; /* polar coordinates */
    RandomParams *rparams = NULL;   /* pseudorandom sequence parameters */
    SUB( LALCreateRandomParams( &stat, &rparams, 0 ), &stat );
    SUB( LALUniformDeviate( &stat, &lon, rparams ), &stat );
    lon *= LAL_TWOPI;
    SUB( LALUniformDeviate( &stat, &sinlat, rparams ), &stat );
    coslat = sqrt( 1.0 - sinlat*sinlat );
    SUB( LALUniformDeviate( &stat, &rad, rparams ), &stat );
    rad = 1.5*rad + 0.5;
    x_1 = x_2 = rad*coslat*cos( lon );
    y_1 = y_2 = rad*coslat*sin( lon );
    z_1 = z_2 = rad*sinlat;
    SUB( LALDestroyRandomParams( &stat, &rparams ), &stat );
  }

  /* Compute stepsizes. */
  dx = dy = dz = 0.0;
  if ( nx > 1 )
    dx = ( x_2 - x_1 )/( nx - 1.0 );
  if ( ny > 1 )
    dy = ( y_2 - y_1 )/( ny - 1.0 );
  if ( nz > 1 )
    dz = ( z_2 - z_1 )/( nz - 1.0 );

  /*******************************************************************
   * PERFORM TEST                                                    *
   *******************************************************************/

  /* Loop over each direction. */
  for ( i = 0; i < nx; i++ ) {
    x = LAL_REARTH_SI*( x_1 + i*dx );
    for ( j = 0; j < ny; j++ ) {
      y = LAL_REARTH_SI*( y_1 + j*dy );
      for ( k = 0; k < nz; k++ ) {
	z = LAL_REARTH_SI*( z_1 + k*dz );

	/* Do transformation. */
	earth.x = x;
	earth.y = y;
	earth.z = z;
	SUB( LALGeocentricToGeodetic( &stat, &earth ), &stat );
 	SUB( LALGeodeticToGeocentric( &stat, &earth ), &stat );

	/* Compute difference. */
	ddx = x - earth.x;
	ddy = y - earth.y;
	ddz = z - earth.z;
	ddr = sqrt( ddx*ddx + ddy*ddy + ddz*ddz );
	if ( ddr > ddmax )
	  ddmax = ddr;
	if ( verbosity == 1 )
	  fprintf( stdout, "%+23.16e\n", ddr );
	else if ( verbosity == 2 )
	  fprintf( stdout, "%+23.16e %+23.16e\n", earth.elevation, ddr );
	else if ( verbosity == 3 )
	  fprintf( stdout, "%+23.16e %+23.16e %+23.16e %+23.16e\n",
		   x, y, z, ddr );
	else if ( verbosity == 4 )
	  fprintf( stdout, "%+23.16e %+23.16e %+23.16e"
		   " %+23.16e %+23.16e %+23.16e %+23.16e\n", x, y, z,
		   earth.elevation, LAL_180_PI*earth.geodetic.latitude,
		   LAL_180_PI*earth.geodetic.longitude, ddr );
      }
    }
  }

  /* Print maximum. */
  fprintf( stdout, "Maximum error: %.16em\n", ddmax );
  if ( !xyz && ddmax > 1.0e-6 ) {
    ERROR( GEOCENTRICGEODETICTESTC_ETEST,
	   GEOCENTRICGEODETICTESTC_MSGETEST, 0 );
    return GEOCENTRICGEODETICTESTC_ETEST;
  }
  LALCheckMemoryLeaks();
  INFO( GEOCENTRICGEODETICTESTC_MSGENORM );
  return GEOCENTRICGEODETICTESTC_ENORM;
}
Exemple #5
0
int main ( int argc, char *argv[] )
{
  /* lal function variables */
  LALStatus             status = blank_status;

  /* templates */
  RandomParams         *randParams = NULL;
  InspiralTemplate      newTmplt;
  SnglInspiralTable    *thisTmplt  = NULL;

  /* output data */
  MetadataTable         templateBank;
  MetadataTable         proctable;
  MetadataTable         procparams;
  MetadataTable         searchsummvars;
  SearchSummvarsTable  *this_search_summvar = NULL;
  ProcessParamsTable   *this_proc_param = NULL;
  LIGOLwXMLStream       results;

  /* counters and other variables */
  INT4 i;
  CHAR  fname[256];


  /*
   *
   * initialization
   *
   */


  /* set up inital debugging values */
  lal_errhandler = LAL_ERR_EXIT;

  /* create the process and process params tables */
  proctable.processTable = (ProcessTable *)
    calloc( 1, sizeof(ProcessTable) );
  XLALGPSTimeNow(&(proctable.processTable->start_time));
  XLALPopulateProcessTable(proctable.processTable, PROGRAM_NAME, lalAppsVCSIdentInfo.vcsId,
      lalAppsVCSIdentInfo.vcsStatus, lalAppsVCSIdentInfo.vcsDate, 0);
  this_proc_param = procparams.processParamsTable = (ProcessParamsTable *)
    calloc( 1, sizeof(ProcessParamsTable) );

  /* call the argument parse and check function */
  arg_parse_check( argc, argv, procparams );

  /* can use LALMalloc() / LALCalloc() from here */


  /*
   *
   * create the radom number seed
   *
   */


  /* store the seed in the search summvars table */
  this_search_summvar = searchsummvars.searchSummvarsTable =
    (SearchSummvarsTable *) LALCalloc( 1, sizeof(SearchSummvarsTable) );
  snprintf( this_search_summvar->name,
      LIGOMETA_NAME_MAX, "template bank simulation seed" );

  if ( randSeedType == urandom )
  {
    FILE   *fpRand = NULL;
    INT4    randByte;

    if ( vrbflg )
      fprintf( stdout, "obtaining random seed from /dev/urandom: " );

    randomSeed = 0;
    fpRand = fopen( "/dev/urandom", "r" );
    if ( fpRand )
    {
      for ( randByte = 0; randByte < 4 ; ++randByte )
      {
        INT4 tmpSeed = (INT4) fgetc( fpRand );
        randomSeed += tmpSeed << ( randByte * 8 );
      }
      fclose( fpRand );
    }
    else
    {
      perror( "error obtaining random seed from /dev/urandom" );
      exit( 1 );
    }
  }
  else if ( randSeedType == user )
  {
    if ( vrbflg )
      fprintf( stdout, "using user specified random seed: " );
  }

  this_search_summvar->value = randomSeed;
  snprintf( this_search_summvar->string, LIGOMETA_STRING_MAX,
      "%d", randomSeed );
  if ( vrbflg ) fprintf( stdout, "%d\n", randomSeed );

  /* create the tmplt bank random parameter structure */
  LAL_CALL( LALCreateRandomParams( &status, &randParams, randomSeed ),
      &status );


  /*
   *
   * create a random template bank
   *
   */


  /* make sure the pointer to the first template is null */
  templateBank.snglInspiralTable = NULL;

  for ( i = 0; i < numTmplts; ++i )
  {
    memset( &newTmplt, 0, sizeof(InspiralTemplate) );
    newTmplt.massChoice = m1Andm2;
    newTmplt.order = LAL_PNORDER_TWO;
    newTmplt.fLower = fLow;

    /* set up the injection masses */
    if ( maxMass == minMass )
    {
      newTmplt.mass1 = (REAL8) maxMass;
      newTmplt.mass2 = (REAL8) maxMass;
    }
    else
    {
      REAL4 mass;
      /* generate random parameters for the injection */
      LAL_CALL( LALUniformDeviate( &status, &mass, randParams ), &status );
      newTmplt.mass1 = (maxMass - minMass) * mass;
      newTmplt.mass1 += minMass;

      LAL_CALL( LALUniformDeviate( &status, &mass, randParams ), &status );
      newTmplt.mass2 = (maxMass - minMass) * mass;
      newTmplt.mass2 += minMass;
    }

    LAL_CALL( LALInspiralParameterCalc( &status, &newTmplt ), &status );

    if ( ! templateBank.snglInspiralTable )
    {
      thisTmplt = templateBank.snglInspiralTable =
        (SnglInspiralTable *) LALCalloc(1, sizeof(SnglInspiralTable));
    }
    else
    {
      thisTmplt = thisTmplt->next =
        (SnglInspiralTable *) LALCalloc(1, sizeof(SnglInspiralTable));
    }

    thisTmplt->mass1 = newTmplt.mass1;
    thisTmplt->mass2 = newTmplt.mass2;
    thisTmplt->mchirp = newTmplt.chirpMass;
    thisTmplt->eta = newTmplt.eta;
    thisTmplt->tau0 = newTmplt.t0;
    thisTmplt->tau2 = newTmplt.t2;
    thisTmplt->tau3 = newTmplt.t3;
    thisTmplt->tau4 = newTmplt.t4;
    thisTmplt->tau5 = newTmplt.t5;
    thisTmplt->ttotal = newTmplt.tC;
    thisTmplt->psi0 = newTmplt.psi0;
    thisTmplt->psi3 = newTmplt.psi3;
    thisTmplt->f_final = newTmplt.fFinal;
    thisTmplt->eta = newTmplt.eta;
    thisTmplt->beta = newTmplt.beta;
    snprintf( thisTmplt->ifo, LIGOMETA_IFO_MAX, "P1" );
    snprintf( thisTmplt->search, LIGOMETA_SEARCH_MAX, "randombank" );
    snprintf( thisTmplt->channel, LIGOMETA_CHANNEL_MAX, "SIM-BANK" );
  }


  /*
   *
   * write the output data
   *
   */

  /* open the output xml file */
  memset( &results, 0, sizeof(LIGOLwXMLStream) );
  if ( userTag && !outCompress )
  {
    snprintf( fname, sizeof(fname), "P1-TMPLTBANK_%s-%d-%d.xml",
        userTag, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "P1-TMPLTBANK_%s-%d-%d.xml.gz",
        userTag, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( !userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "P1-TMPLTBANK-%d-%d.xml.gz",
        gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else
  {
    snprintf( fname, sizeof(fname), "P1-TMPLTBANK-%d-%d.xml",
        gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  LAL_CALL( LALOpenLIGOLwXMLFile( &status, &results, fname ), &status );

  /* write the process table */
  snprintf( proctable.processTable->ifos, LIGOMETA_IFO_MAX, "P1" );
  XLALGPSTimeNow(&(proctable.processTable->end_time));
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &results, process_table ),
      &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &results, proctable,
        process_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &results ), &status );
  free( proctable.processTable );

  /* erase the first empty process params entry */
  {
    ProcessParamsTable *emptyPPtable = procparams.processParamsTable;
    procparams.processParamsTable = procparams.processParamsTable->next;
    free( emptyPPtable );
  }

  /* write the process params table */
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &results, process_params_table ),
      &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &results, procparams,
        process_params_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &results ), &status );
  while( procparams.processParamsTable )
  {
    this_proc_param = procparams.processParamsTable;
    procparams.processParamsTable = this_proc_param->next;
    free( this_proc_param );
  }

  /* write the search summvars table */
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &results,
        search_summvars_table ), &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &results, searchsummvars,
        search_summvars_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &results ), &status );
  while( searchsummvars.searchSummvarsTable )
  {
    this_search_summvar = searchsummvars.searchSummvarsTable;
    searchsummvars.searchSummvarsTable = this_search_summvar->next;
    LALFree( this_search_summvar );
  }

  /* write the template bank to the file */
  if ( templateBank.snglInspiralTable )
  {
    LAL_CALL( LALBeginLIGOLwXMLTable( &status, &results, sngl_inspiral_table ),
        &status );
    LAL_CALL( LALWriteLIGOLwXMLTable( &status, &results, templateBank,
          sngl_inspiral_table ), &status );
    LAL_CALL( LALEndLIGOLwXMLTable ( &status, &results ), &status );
  }
  while ( templateBank.snglInspiralTable )
  {
    thisTmplt = templateBank.snglInspiralTable;
    templateBank.snglInspiralTable = templateBank.snglInspiralTable->next;
    LALFree( thisTmplt );
  }

  /* close the output xml file */
  LAL_CALL( LALCloseLIGOLwXMLFile ( &status, &results ), &status );

  /* free the rest of the memory, check for memory leaks and exit */
  LAL_CALL( LALDestroyRandomParams( &status, &randParams ), &status );
  LALCheckMemoryLeaks();
  exit( 0 );
}
Exemple #6
0
int main( int argc, char *argv[] )
{
  LALStatus             status = blank_status;
  const INT4            S2StartTime = 729273613; /* Feb 14 2003 16:00:00 UTC */
  const INT4            S2StopTime  = 734367613; /* Apr 14 2003 15:00:00 UTC */

  /* command line options */
  LIGOTimeGPS   gpsStartTime = {S2StartTime, 0};
  LIGOTimeGPS   gpsEndTime   = {S2StopTime, 0};
  REAL8         meanTimeStep = 2630 / LAL_PI;
  REAL8         timeInterval = 0;
  UINT4         randSeed = 1;
  CHAR         *userTag = NULL;
  REAL4         minMass = 0.1;
  REAL4         maxMass = 1.0;
  REAL4         r_core = 5.0;     /* kpc core radius */
  REAL4         r_max = 50.0;     /* kpc halo radius */
  REAL4         q = 1.0;          /* flatten halo */

  /* program variables */
  RandomParams *randParams = NULL;
  REAL4  u;
  REAL4  deltaM;

  int i, stat;
  const int maxIter = 1000;
  const double tol = 1e-6;
  const gsl_root_fsolver_type *solver_type;
  gsl_root_fsolver *solver;
  gsl_function pdf;

  struct halo_pdf_params pdf_params;

  double r_lo, r_hi, r;
  double cosphi, sinphi;
  double pdf_norm;

  GalacticInspiralParamStruc galacticPar;

  /* xml output data */
  CHAR                  fname[256];
  MetadataTable         proctable;
  MetadataTable         procparams;
  MetadataTable         injections;
  ProcessParamsTable   *this_proc_param;
  SimInspiralTable     *this_inj = NULL;
  LIGOLwXMLStream       xmlfp;
  UINT4                 outCompress = 0;

  /* LALgetopt arguments */
  struct LALoption long_options[] =
  {
    {"help",                    no_argument,       0,                'h'},
    {"verbose",                 no_argument,       &vrbflg,           1 },
    {"write-compress",          no_argument,       &outCompress,      1 },
    {"gps-start-time",          required_argument, 0,                'a'},
    {"gps-end-time",            required_argument, 0,                'b'},
    {"time-step",               required_argument, 0,                't'},
    {"time-interval",                required_argument, 0,                     'i'},
    {"seed",                    required_argument, 0,                's'},
    {"minimum-mass",            required_argument, 0,                'A'},
    {"maximum-mass",            required_argument, 0,                'B'},
    {"core-radius",             required_argument, 0,                'p'},
    {"flatten-halo",            required_argument, 0,                'q'},
    {"halo-radius",             required_argument, 0,                'r'},
    {"user-tag",                required_argument, 0,                'Z'},
    {"userTag",                 required_argument, 0,                'Z'},
    {0, 0, 0, 0}
  };
  int c;

  /* set up inital debugging values */
  lal_errhandler = LAL_ERR_EXIT;

  /* create the process and process params tables */
  proctable.processTable = (ProcessTable *) 
    calloc( 1, sizeof(ProcessTable) );
  XLALGPSTimeNow(&(proctable.processTable->start_time));
  if (strcmp(CVS_REVISION,"$Revi" "sion$"))
    {
      XLALPopulateProcessTable(proctable.processTable, PROGRAM_NAME,
          CVS_REVISION, CVS_SOURCE, CVS_DATE, 0);
    }
  else
    {
      XLALPopulateProcessTable(proctable.processTable, PROGRAM_NAME,
          lalappsGitCommitID, lalappsGitGitStatus, lalappsGitCommitDate, 0);
    }
  snprintf( proctable.processTable->comment, LIGOMETA_COMMENT_MAX, " " );
  this_proc_param = procparams.processParamsTable = (ProcessParamsTable *) 
    calloc( 1, sizeof(ProcessParamsTable) );
  

  /*
   *
   * parse command line arguments
   *
   */

     
  while ( 1 )
  {
    /* LALgetopt_long stores long option here */
    int option_index = 0;
    long int gpsinput;
    size_t LALoptarg_len;

    c = LALgetopt_long_only( argc, argv,
        "a:A:b:B:hi:p:q:r:s:t:vZ:", long_options, &option_index );

    /* detect the end of the options */
    if ( c == - 1 )
    {
      break;
    }

    switch ( c )
    {
      case 0:
        /* if this option set a flag, do nothing else now */
        if ( long_options[option_index].flag != 0 )
        {
          break;
        }
        else
        {
          fprintf( stderr, "error parsing option %s with argument %s\n",
              long_options[option_index].name, LALoptarg );
          exit( 1 );
        }
        break;

      case 'a':
        gpsinput = atol( LALoptarg );
        if ( gpsinput < 441417609 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "GPS start time is prior to " 
              "Jan 01, 1994  00:00:00 UTC:\n"
              "(%ld specified)\n",
              long_options[option_index].name, gpsinput );
          exit( 1 );
        }
        gpsStartTime.gpsSeconds = gpsinput;

        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%ld", gpsinput );
        break;

      case 'b':
        gpsinput = atol( LALoptarg );
        if ( gpsinput < 441417609 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "GPS start time is prior to " 
              "Jan 01, 1994  00:00:00 UTC:\n"
              "(%ld specified)\n",
              long_options[option_index].name, gpsinput );
          exit( 1 );
        }
        gpsEndTime.gpsSeconds = gpsinput;
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%ld", gpsinput );
        break;

      case 's':
        randSeed = atoi( LALoptarg );
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "int", 
              "%d", randSeed );
        break;

      case 't':
        meanTimeStep = (REAL8) atof( LALoptarg );
        if ( meanTimeStep <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "time step must be > 0: (%le seconds specified)\n",
              long_options[option_index].name, meanTimeStep );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, "float", 
              "%le", meanTimeStep );
        break;

      case 'i':
        timeInterval = atof( LALoptarg );
        if ( timeInterval < 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "time interval must be >= 0: (%le seconds specified)\n",
              long_options[option_index].name, meanTimeStep );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%le", timeInterval );
        break;

      case 'A':
        minMass = (REAL4) atof( LALoptarg );
        if ( minMass <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "miniumum component mass must be > 0: "
              "(%f solar masses specified)\n",
              long_options[option_index].name, minMass );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", minMass );
        break;

      case 'B':
        maxMass = (REAL4) atof( LALoptarg );
        if ( maxMass <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "maxiumum component mass must be > 0: "
              "(%f solar masses specified)\n",
              long_options[option_index].name, maxMass );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", maxMass );
        break;

      case 'p':
        /* core-radius */
        r_core = (REAL4) atof( LALoptarg );
        if ( r_core <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "galactic core radius must be > 0: "
              "(%f kpc specified)\n",
              long_options[option_index].name, r_core );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", r_core );
        break;

      case 'q':
        /* flatten-halo */
        q = (REAL4) atof( LALoptarg );
        if ( q <= 0 || q > 1 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "halo flattening parameter must be in range (0,1]: "
              "(%f specified)\n",
              long_options[option_index].name, q );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", q );
        break;

      case 'r':
        /* max halo radius */
        r_max = (REAL4) atof( LALoptarg );
        if ( r_max <= 0 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "halo radius must be greater than 0: "
              "(%f kpc specified)\n",
              long_options[option_index].name, r_max );
          exit( 1 );
        }
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "float", "%e", r_max );
        break;

      case 'Z':
        /* create storage for the usertag */
        LALoptarg_len = strlen( LALoptarg ) + 1;
        userTag = (CHAR *) calloc( LALoptarg_len, sizeof(CHAR) );
        memcpy( userTag, LALoptarg, LALoptarg_len );
        this_proc_param = this_proc_param->next = 
          next_process_param( long_options[option_index].name, 
              "string", "%s", LALoptarg );
        break;

      case 'v':
        vrbflg = 1;
        break;

      case 'h':
        fprintf( stderr, USAGE );
        exit( 0 );
        break;

      case '?':
        fprintf( stderr, USAGE );
        exit( 1 );
        break;

      default:
        fprintf( stderr, "unknown error while parsing options\n" );
        fprintf( stderr, USAGE );
        exit( 1 );
    }
  }

  if ( LALoptind < argc )
  {
    fprintf( stderr, "extraneous command line arguments:\n" );
    while ( LALoptind < argc )
    {
      fprintf ( stderr, "%s\n", argv[LALoptind++] );
    }
    exit( 1 );
  }


  /*
   *
   * initialization
   *
   */


  /* initialize the random number generator */
  LAL_CALL( LALCreateRandomParams( &status, &randParams, randSeed ), &status );

  /* initialize the gsl solver with the spatial pdf */
  pdf.function = &halo_pdf;
  pdf.params   = &pdf_params;
  solver_type = gsl_root_fsolver_bisection;
  solver = gsl_root_fsolver_alloc( solver_type );
  pdf_params.a = r_core;

  /* normalization for the spatial pdf */
  pdf_norm = r_max - r_core * atan2( r_max, r_core );

  /* mass range */
  deltaM = maxMass - minMass;

  /* null out the head of the linked list */
  injections.simInspiralTable = NULL;

  /* create the output file name */
  if ( userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d_%s-%d-%d.xml.gz",
        randSeed, userTag, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( userTag && !outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d_%s-%d-%d.xml", 
        randSeed, userTag, gpsStartTime.gpsSeconds, 
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else if ( !userTag && outCompress )
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d-%d-%d.xml.gz",
        randSeed, gpsStartTime.gpsSeconds,
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }
  else
  {
    snprintf( fname, sizeof(fname), "HL-INJECTIONS_%d-%d-%d.xml", 
        randSeed, gpsStartTime.gpsSeconds, 
        gpsEndTime.gpsSeconds - gpsStartTime.gpsSeconds );
  }


  /*
   *
   * loop over duration of desired output times
   *
   */


  while ( XLALGPSCmp( &gpsStartTime, &gpsEndTime ) < 0 )
  {
    /* uniformly distributed masses */
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    galacticPar.m1 = minMass + u * deltaM;
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    galacticPar.m2 = minMass + u * deltaM;
    
    /* spatial distribution */
    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    pdf_params.u = u * pdf_norm;

    r_lo = 0.0;
    r_hi = r_max;
    gsl_root_fsolver_set( solver, &pdf, r_lo, r_hi );

    for ( i = 0; i < maxIter; ++i )
    {
      gsl_root_fsolver_iterate( solver );
      r = gsl_root_fsolver_root( solver );
      r_lo = gsl_root_fsolver_x_lower( solver );
      r_hi = gsl_root_fsolver_x_upper( solver );
      stat = gsl_root_test_interval( r_lo, r_hi, 0, tol );
      if ( stat == GSL_SUCCESS )
        break;
    }

    if ( stat != GSL_SUCCESS )
    {
      fprintf( stderr, "could not find root after %d iterations\n", maxIter );
      exit( 1 );
    }

    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    sinphi = 2.0 * u - 1.0;
    cosphi = sqrt( 1.0 - sinphi*sinphi );
    
    galacticPar.rho = r * cosphi;
    galacticPar.z   = q * r * sinphi;

    LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
    galacticPar.lGal = LAL_TWOPI * u;    

    if ( vrbflg ) fprintf( stdout, "%e %e %e %e %e\n", 
        galacticPar.m1, galacticPar.m2,
        galacticPar.rho * cos( galacticPar.lGal ),
        galacticPar.rho * sin( galacticPar.lGal ),
        galacticPar.z );

    /* create the sim_inspiral table */
    if ( injections.simInspiralTable )
    {
      this_inj = this_inj->next = (SimInspiralTable *)
        LALCalloc( 1, sizeof(SimInspiralTable) );
    }
    else
    {
      injections.simInspiralTable = this_inj = (SimInspiralTable *)
        LALCalloc( 1, sizeof(SimInspiralTable) );
    }

    /* set the geocentric end time of the injection */
    galacticPar.geocentEndTime = gpsStartTime;
    if ( timeInterval )
    {
      LAL_CALL( LALUniformDeviate( &status, &u, randParams ), &status );
      XLALGPSAdd( &(galacticPar.geocentEndTime), u * timeInterval );
    }

    /* populate the sim_inspiral table */
    LAL_CALL( LALGalacticInspiralParamsToSimInspiralTable( &status,
          this_inj, &galacticPar, randParams ), &status );

    /* set the source and waveform fields */
    snprintf( this_inj->source, LIGOMETA_SOURCE_MAX, "MW" );
    snprintf( this_inj->waveform, LIGOMETA_WAVEFORM_MAX, 
        "GeneratePPNtwoPN" );

    /* increment the injection time */
    XLALGPSAdd( &gpsStartTime, meanTimeStep );
  } /* end loop over injection times */

  /* destroy random parameters */
  LAL_CALL( LALDestroyRandomParams( &status, &randParams ), &status );


  /*
   *
   * write output to LIGO_LW XML file
   *
   */


  /* open the xml file */
  memset( &xmlfp, 0, sizeof(LIGOLwXMLStream) );
  LAL_CALL( LALOpenLIGOLwXMLFile( &status, &xmlfp, fname ), &status );

  /* write the process table */
  snprintf( proctable.processTable->ifos, LIGOMETA_IFOS_MAX, "H1H2L1" );
  XLALGPSTimeNow(&(proctable.processTable->end_time));
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, process_table ), 
      &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, proctable, 
        process_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
  free( proctable.processTable );

  /* free the unused process param entry */
  this_proc_param = procparams.processParamsTable;
  procparams.processParamsTable = procparams.processParamsTable->next;
  free( this_proc_param );

  /* write the process params table */
  if ( procparams.processParamsTable )
  {
    LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, process_params_table ), 
        &status );
    LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, procparams, 
          process_params_table ), &status );
    LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
    while( procparams.processParamsTable )
    {
      this_proc_param = procparams.processParamsTable;
      procparams.processParamsTable = this_proc_param->next;
      free( this_proc_param );
    }
  }

  /* write the sim_inspiral table */
  if ( injections.simInspiralTable )
  {
    LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlfp, sim_inspiral_table ), 
        &status );
    LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlfp, injections, 
          sim_inspiral_table ), &status );
    LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlfp ), &status );
  }
  while ( injections.simInspiralTable )
  {
    this_inj = injections.simInspiralTable;
    injections.simInspiralTable = injections.simInspiralTable->next;
    LALFree( this_inj );
  }

  /* close the injection file */
  LAL_CALL( LALCloseLIGOLwXMLFile ( &status, &xmlfp ), &status );

  /* check for memory leaks and exit */
  LALCheckMemoryLeaks();
  return 0;
}
/* void RunGeneratePulsarSignalTest(LALStatus *status, int argc, char **argv) */ /* 02/02/05 gam */
void RunGeneratePulsarSignalTest(LALStatus *status)
{
  INT4    i, j, k;         /* all purpose indices */
  INT4    iSky = 0;        /* for loop over sky positions */
  INT4    jDeriv = 0;      /* for loop over spindowns */
  INT4    testNumber = 0;  /* which test is being run */

  /* The input and output structs used by the functions being tested */
  PulsarSignalParams *pPulsarSignalParams = NULL;
  REAL4TimeSeries *signalvec = NULL;
  SFTParams *pSFTParams = NULL;
  SkyConstAndZeroPsiAMResponse *pSkyConstAndZeroPsiAMResponse;
  SFTandSignalParams *pSFTandSignalParams;
  SFTVector *outputSFTs = NULL;
  SFTVector *fastOutputSFTs = NULL;
  REAL4 renorm; /* to renormalize SFTs to account for different effective sample rates */

  /* containers for detector and ephemeris data */
  LALDetector cachedDetector;
  CHAR IFO[6] = "LHO";
  EphemerisData *edat = NULL;

  char earthFile[] = TEST_DATA_DIR "earth00-19-DE405.dat.gz";
  char sunFile[]   = TEST_DATA_DIR "sun00-19-DE405.dat.gz";

  /* containers for sky position and spindown data */
  REAL8 **skyPosData;
  REAL8 **freqDerivData;
  INT4 numSkyPosTotal = 8;
  INT4 numSpinDown = 1;
  INT4 numFreqDerivTotal = 2;
  INT4 numFreqDerivIncludingNoSpinDown; /* set below */
  INT4 iFreq = 0;
  REAL8 cosTmpDEC;
  REAL8 tmpDeltaRA;
  REAL8 DeltaRA = 0.01;
  REAL8 DeltaDec = 0.01;
  REAL8 DeltaFDeriv1 = -1.0e-10;
  REAL8 DeltaFDeriv2 = 0.0;
  REAL8 DeltaFDeriv3 = 0.0;
  REAL8 DeltaFDeriv4 = 0.0;
  REAL8 DeltaFDeriv5 = 0.0;

  /* containers for number of SFTs, times to generate SFTs, reference time, and gap */
  INT4 numSFTs = 4;
  REAL8 f0SFT = 943.12;
  REAL8 bandSFT = 0.5;
  UINT4 gpsStartTimeSec = 765432109; /* GPS start time of data requested seconds; example = Apr 08 2004 04:01:36 UTC */
  UINT4 gpsStartTimeNan = 0;          /* GPS start time of data requested nanoseconds */
  LIGOTimeGPSVector *timeStamps;
  LIGOTimeGPS GPSin;   /* holder for reference-time for pulsar parameters at the detector; will convert to SSB! */
  REAL8 sftGap = 73.0; /* extra artificial gap between SFTs */
  REAL8 tSFT   = 1800.0;
  REAL8 duration = tSFT + (numSFTs - 1)*(tSFT + sftGap);
  INT4 nBinsSFT = (INT4)(bandSFT*tSFT + 0.5);

  /* additional parameters that determine what signals to test; note f0SGNL and bandSGNL must be compatible with f0SFT and bandSFT */
  REAL8 f0SGNL = f0SFT + bandSFT/2.0;
  REAL8 dfSGNL = 1.0/tSFT;
  REAL8 bandSGNL = 0.005;
  INT4  nBinsSGNL = (INT4)(bandSGNL*tSFT + 0.5);
  INT4  nsamples = 18000; /* nsamples from SFT header; 2 x this would be the effective number of time samples used to create an SFT from raw data */
  INT4  Dterms = 3;       /* 09/07/05 gam; use Dterms to fill in SFT bins with fake data as per LALDemod else fill in bin with zero */
  REAL8 h_0 = 7.0e-22;    /* Source amplitude; use arbitrary small number for default */
  REAL8 cosIota;        /* cosine of inclination angle iota of the source */

  /* variables for comparing differences */
  REAL4 maxDiffSFTMod, diffAtMaxPower;
  REAL4 overallMaxDiffSFTMod;
  REAL4 maxMod, fastMaxMod;
  INT4  jMaxMod, jFastMaxMod;
  REAL4 tmpDiffSFTMod, sftMod, fastSFTMod;
  REAL4 smallMod = 1.e-30;
  REAL4 epsDiffMod;
  REAL4 epsBinErrorRate;   /* 10/12/04 gam; Allowed bin error rate */
  INT4  binErrorCount = 0; /* 10/12/04 gam; Count number of bin errors  */

  /* randval is always set to a default value or given a random value to generate certain signal parameters or mismatch */
  REAL4 randval;
  #ifdef INCLUDE_RANDVAL_MISMATCH
   INT4 seed=0;
   INT4 rndCount;
   RandomParams *randPar=NULL;
   FILE *fpRandom;
  #endif

  INITSTATUS(status);
  ATTATCHSTATUSPTR(status);

  /* generate timeStamps */
  timeStamps = (LIGOTimeGPSVector *)LALMalloc(sizeof(LIGOTimeGPSVector));
  timeStamps->data =(LIGOTimeGPS *)LALMalloc (numSFTs*sizeof(LIGOTimeGPS));
  timeStamps->length = numSFTs;
  for (i = 0; i < numSFTs; i++) {
      timeStamps->data[i].gpsSeconds = gpsStartTimeSec + (UINT4)(i*(tSFT + sftGap));
      timeStamps->data[i].gpsNanoSeconds = 0;
  } /* for i < numSFTs */

  /* generate skyPosData */
  skyPosData=(REAL8 **)LALMalloc(numSkyPosTotal*sizeof(REAL8 *));
  for(iSky=0;iSky<numSkyPosTotal;iSky++)
  {
        skyPosData[iSky] = (REAL8 *)LALMalloc(2*sizeof(REAL8));
        /* Try fairly random sky positions skyPosData[iSky][0] = RA, skyPosData[iSky][1] = DEC */
        if (iSky == 0) {
          skyPosData[iSky][0] = 0.02*LAL_TWOPI;
          skyPosData[iSky][1] = 0.03*LAL_PI/2.0;
        } else if (iSky == 1) {
          skyPosData[iSky][0] = 0.23*LAL_TWOPI;
          skyPosData[iSky][1] = -0.57*LAL_PI/2.0;
        } else if (iSky == 2) {
          skyPosData[iSky][0] = 0.47*LAL_TWOPI;
          skyPosData[iSky][1] = 0.86*LAL_PI/2.0;
        } else if (iSky == 3) {
          skyPosData[iSky][0] = 0.38*LAL_TWOPI;
          skyPosData[iSky][1] = -0.07*LAL_PI/2.0;
        } else if (iSky == 4) {
          skyPosData[iSky][0] = 0.65*LAL_TWOPI;
          skyPosData[iSky][1] = 0.99*LAL_PI/2.0;
        } else if (iSky == 5) {
          skyPosData[iSky][0] = 0.72*LAL_TWOPI;
          skyPosData[iSky][1] = -0.99*LAL_PI/2.0;
        } else if (iSky == 6) {
          skyPosData[iSky][0] = 0.81*LAL_TWOPI;
          skyPosData[iSky][1] = 0.19*LAL_PI/2.0;
        } else if (iSky == 7) {
          skyPosData[iSky][0] = 0.99*LAL_TWOPI;
          skyPosData[iSky][1] = 0.01*LAL_PI/2.0;
        } else {
          skyPosData[iSky][0] = 0.0;
          skyPosData[iSky][1] = 0.0;
        } /* END if (k == 0) ELSE ... */
  } /* END for(iSky=0;iSky<numSkyPosTotal;iSky++) */

  freqDerivData = NULL; /* 02/02/05 gam */
  if (numSpinDown > 0) {
    freqDerivData=(REAL8 **)LALMalloc(numFreqDerivTotal*sizeof(REAL8 *));
    for(jDeriv=0;jDeriv<numFreqDerivTotal;jDeriv++) {
        freqDerivData[jDeriv] = (REAL8 *)LALMalloc(numSpinDown*sizeof(REAL8));
        if (jDeriv == 0) {
          for(k=0;k<numSpinDown;k++) {
            freqDerivData[jDeriv][k] = 0.0;
          }
        } else if (jDeriv == 1) {
          for(k=0;k<numSpinDown;k++) {
            freqDerivData[jDeriv][k] = 1.e-9; /* REALLY THIS IS ONLY GOOD FOR numSpinDown = 1; */
          }
        } else {
          for(k=0;k<numSpinDown;k++) {
            freqDerivData[jDeriv][k] = 0.0;
          }
        } /* END if (k == 0) ELSE ... */
    } /* END for(jDeriv=0;jDeriv<numFreqDerivTotal;jDeriv++) */
    numFreqDerivIncludingNoSpinDown = numFreqDerivTotal;
  } else {
    numFreqDerivIncludingNoSpinDown = 1;  /* Even if numSpinDown = 0 still need to count case of zero spindown. */
  }  /* END if (numSpinDown > 0) ELSE ... */

  /* Initialize ephemeris data */
  XLAL_CHECK_LAL (status, ( edat = XLALInitBarycenter( earthFile, sunFile ) ) != NULL, XLAL_EFUNC);

  /* Allocate memory for PulsarSignalParams and initialize */
  pPulsarSignalParams = (PulsarSignalParams *)LALMalloc(sizeof(PulsarSignalParams));
  pPulsarSignalParams->pulsar.position.system = COORDINATESYSTEM_EQUATORIAL;
  pPulsarSignalParams->pulsar.spindown = NULL;
  if (numSpinDown > 0) {
    LALDCreateVector(status->statusPtr, &(pPulsarSignalParams->pulsar.spindown),((UINT4)numSpinDown));
    CHECKSTATUSPTR (status);
  }
  pPulsarSignalParams->orbit.asini = 0 /* isolated pulsar */;
  pPulsarSignalParams->transfer = NULL;
  pPulsarSignalParams->dtDelayBy2 = 0;
  pPulsarSignalParams->dtPolBy2 = 0;
  /* Set up pulsar site */
  if (strstr(IFO, "LHO")) {
       cachedDetector = lalCachedDetectors[LALDetectorIndexLHODIFF];
  } else if (strstr(IFO, "LLO")) {
       cachedDetector = lalCachedDetectors[LALDetectorIndexLLODIFF];
  } else if (strstr(IFO, "GEO")) {
      cachedDetector = lalCachedDetectors[LALDetectorIndexGEO600DIFF];
  } else if (strstr(IFO, "VIRGO")) {
      cachedDetector = lalCachedDetectors[LALDetectorIndexVIRGODIFF];
  } else if (strstr(IFO, "TAMA")) {
      cachedDetector = lalCachedDetectors[LALDetectorIndexTAMA300DIFF];
  } else {
      /* "Invalid or null IFO" */
      ABORT( status, GENERATEPULSARSIGNALTESTC_EIFO, GENERATEPULSARSIGNALTESTC_MSGEIFO);
  }
  pPulsarSignalParams->site = &cachedDetector;
  pPulsarSignalParams->ephemerides = edat;
  pPulsarSignalParams->startTimeGPS.gpsSeconds = (INT4)gpsStartTimeSec;
  pPulsarSignalParams->startTimeGPS.gpsNanoSeconds = (INT4)gpsStartTimeNan;
  pPulsarSignalParams->duration = (UINT4)duration;
  pPulsarSignalParams->samplingRate = (REAL8)ceil(2.0*bandSFT); /* Make sampleRate an integer so that T*samplingRate = integer for integer T */
  pPulsarSignalParams->fHeterodyne = f0SFT;

  GPSin.gpsSeconds = timeStamps->data[0].gpsSeconds;
  GPSin.gpsNanoSeconds = timeStamps->data[0].gpsNanoSeconds;

  /* Allocate memory for SFTParams and initialize */
  pSFTParams = (SFTParams *)LALCalloc(1, sizeof(SFTParams));
  pSFTParams->Tsft = tSFT;
  pSFTParams->timestamps = timeStamps;
  pSFTParams->noiseSFTs = NULL;

  #ifdef INCLUDE_RANDVAL_MISMATCH
    /* Initial seed and randPar to use LALUniformDeviate to generate random mismatch during Monte Carlo. */
    fpRandom = fopen("/dev/urandom","r");
    rndCount = fread(&seed, sizeof(INT4),1, fpRandom);
    fclose(fpRandom);
    /* seed = 1234; */ /* Test value */
    LALCreateRandomParams(status->statusPtr, &randPar, seed);
    CHECKSTATUSPTR (status);
  #endif

  /* allocate memory for structs needed by LALComputeSkyAndZeroPsiAMResponse and LALFastGeneratePulsarSFTs */
  pSkyConstAndZeroPsiAMResponse = (SkyConstAndZeroPsiAMResponse *)LALMalloc(sizeof(SkyConstAndZeroPsiAMResponse));
  pSkyConstAndZeroPsiAMResponse->skyConst = (REAL8 *)LALMalloc((2*numSpinDown*(numSFTs+1)+2*numSFTs+3)*sizeof(REAL8));
  pSkyConstAndZeroPsiAMResponse->fPlusZeroPsi = (REAL4 *)LALMalloc(numSFTs*sizeof(REAL4));
  pSkyConstAndZeroPsiAMResponse->fCrossZeroPsi = (REAL4 *)LALMalloc(numSFTs*sizeof(REAL4));
  pSFTandSignalParams = (SFTandSignalParams *)LALMalloc(sizeof(SFTandSignalParams));
  /* create lookup table (LUT) values for doing trig */
  /* pSFTandSignalParams->resTrig = 64; */ /* length sinVal and cosVal; resolution of trig functions = 2pi/resTrig */
  /* pSFTandSignalParams->resTrig = 128; */ /* 10/08/04 gam; length sinVal and cosVal; domain = -2pi to 2pi inclusive; resolution = 4pi/resTrig */
  pSFTandSignalParams->resTrig = 0; /* 10/12/04 gam; turn off using LUTs since this is more typical. */
  /* 02/02/05 gam; if NOT pSFTandSignalParams->resTrig > 0 should not create trigArg etc... */
  if (pSFTandSignalParams->resTrig > 0) {
    pSFTandSignalParams->trigArg = (REAL8 *)LALMalloc((pSFTandSignalParams->resTrig+1)*sizeof(REAL8));
    pSFTandSignalParams->sinVal  = (REAL8 *)LALMalloc((pSFTandSignalParams->resTrig+1)*sizeof(REAL8));
    pSFTandSignalParams->cosVal  = (REAL8 *)LALMalloc((pSFTandSignalParams->resTrig+1)*sizeof(REAL8));
    for (k=0; k<=pSFTandSignalParams->resTrig; k++) {
       /* pSFTandSignalParams->trigArg[k]= ((REAL8)LAL_TWOPI) * ((REAL8)k) / ((REAL8)pSFTandSignalParams->resTrig); */ /* 10/08/04 gam */
       pSFTandSignalParams->trigArg[k]= -1.0*((REAL8)LAL_TWOPI) + 2.0 * ((REAL8)LAL_TWOPI) * ((REAL8)k) / ((REAL8)pSFTandSignalParams->resTrig);
       pSFTandSignalParams->sinVal[k]=sin( pSFTandSignalParams->trigArg[k] );
       pSFTandSignalParams->cosVal[k]=cos( pSFTandSignalParams->trigArg[k] );
    }
  }
  pSFTandSignalParams->pSigParams = pPulsarSignalParams;
  pSFTandSignalParams->pSFTParams = pSFTParams;
  pSFTandSignalParams->nSamples = nsamples;
  pSFTandSignalParams->Dterms = Dterms;  /* 09/07/05 gam */

  /* ********************************************************/
  /*                                                       */
  /* START SECTION: LOOP OVER SKY POSITIONS                */
  /*                                                       */
  /* ********************************************************/
  for(iSky=0;iSky<numSkyPosTotal;iSky++) {

    /* set source sky position declination (DEC) */
    randval = 0.5; /* Gives default value */
    #ifdef INCLUDE_SEQUENTIAL_MISMATCH
      randval = ( (REAL4)(iSky) )/( (REAL4)(numSkyPosTotal) );
    #endif
    #ifdef INCLUDE_RANDVAL_MISMATCH
       LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
    #endif
    pPulsarSignalParams->pulsar.position.latitude = skyPosData[iSky][1] + (((REAL8)randval) - 0.5)*DeltaDec;
    cosTmpDEC = cos(skyPosData[iSky][1]);
    if (cosTmpDEC != 0.0) {
          tmpDeltaRA = DeltaRA/cosTmpDEC;
    } else {
          tmpDeltaRA = 0.0; /* We are at a celestial pole */
    }

    /* set source sky position right ascension (RA) */
    randval = 0.5; /* Gives default value */
    #ifdef INCLUDE_SEQUENTIAL_MISMATCH
      randval = ( (REAL4)(iSky) )/( (REAL4)(numSkyPosTotal) );
    #endif
    #ifdef INCLUDE_RANDVAL_MISMATCH
      LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
    #endif
    pPulsarSignalParams->pulsar.position.longitude = skyPosData[iSky][0] + (((REAL8)randval) - 0.5)*tmpDeltaRA;

    /* Find reference time in SSB for this sky positions */
    int ret = XLALConvertGPS2SSB ( &(pPulsarSignalParams->pulsar.refTime), GPSin, pPulsarSignalParams );
    if ( ret != XLAL_SUCCESS ) {
      XLALPrintError ("XLALConvertGPS2SSB() failed with xlalErrno = %d\n", xlalErrno );
      ABORTXLAL (status);
    }

    /* one per sky position fill in SkyConstAndZeroPsiAMResponse for use with LALFastGeneratePulsarSFTs */
    LALComputeSkyAndZeroPsiAMResponse (status->statusPtr, pSkyConstAndZeroPsiAMResponse, pSFTandSignalParams);
    CHECKSTATUSPTR (status);

    /* ********************************************************/
    /*                                                       */
    /* START SECTION: LOOP OVER SPINDOWN                     */
    /*                                                       */
    /* ********************************************************/
    for(jDeriv=0;jDeriv<numFreqDerivIncludingNoSpinDown;jDeriv++) {
     /* source spindown parameters */
     if (numSpinDown > 0) {
       for(k=0;k<numSpinDown;k++) {
         randval = 0.5; /* Gives default value */
         #ifdef INCLUDE_SEQUENTIAL_MISMATCH
            if (freqDerivData[jDeriv][k] < 0.0) {
               randval = ( (REAL4)(iSky) )/( (REAL4)(numSkyPosTotal) );
            } else {
               randval = 0.5; /* If derivative is not negative (i.e., it is zero) then do not add in mismatch; keep it zero. */
            }
         #endif
         #ifdef INCLUDE_RANDVAL_MISMATCH
           LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
         #endif
         if (k == 0) {
          pPulsarSignalParams->pulsar.spindown->data[k] = freqDerivData[jDeriv][k] + (((REAL8)randval) - 0.5)*DeltaFDeriv1;
         } else if (k == 1) {
          pPulsarSignalParams->pulsar.spindown->data[k] = freqDerivData[jDeriv][k] + (((REAL8)randval) - 0.5)*DeltaFDeriv2;
         } else if (k == 2) {
          pPulsarSignalParams->pulsar.spindown->data[k] = freqDerivData[jDeriv][k] + (((REAL8)randval) - 0.5)*DeltaFDeriv3;
         } else if (k == 3) {
          pPulsarSignalParams->pulsar.spindown->data[k] = freqDerivData[jDeriv][k] + (((REAL8)randval) - 0.5)*DeltaFDeriv4;
         } else if (k == 4) {
          pPulsarSignalParams->pulsar.spindown->data[k] = freqDerivData[jDeriv][k] + (((REAL8)randval) - 0.5)*DeltaFDeriv5;
         } /* END if (k == 0) ELSE ... */
       }
     }

     /* ***************************************************/
     /*                                                  */
     /* START SECTION: LOOP OVER FREQUENCIES             */
     /*                                                  */
     /* ***************************************************/
     for(iFreq=0;iFreq<nBinsSGNL;iFreq++) {

       /* set source orientation psi */
       randval = 0.5; /* Gives default value */
       #ifdef INCLUDE_SEQUENTIAL_MISMATCH
            randval = ( (REAL4)(iFreq) )/( (REAL4)(nBinsSGNL) );
       #endif
       #ifdef INCLUDE_RANDVAL_MISMATCH
          LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
       #endif
       pPulsarSignalParams->pulsar.psi = (randval - 0.5) * ((REAL4)LAL_PI_2);

       /* set angle between source spin axis and direction from source to SSB, cosIota */
       randval = 1.0; /* Gives default value */
       #ifdef INCLUDE_SEQUENTIAL_MISMATCH
            randval = ( (REAL4)(iFreq) )/( (REAL4)(nBinsSGNL) );
       #endif
       #ifdef INCLUDE_RANDVAL_MISMATCH
          LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
       #endif
       cosIota = 2.0*((REAL8)randval) - 1.0;

       /* h_0 is fixed above; get A_+ and A_x from h_0 and cosIota */
       pPulsarSignalParams->pulsar.aPlus = (REAL4)(0.5*h_0*(1.0 + cosIota*cosIota));
       pPulsarSignalParams->pulsar.aCross = (REAL4)(h_0*cosIota);

       /* get random value for phi0 */
       randval = 0.125; /* Gives default value pi/4*/
       #ifdef INCLUDE_SEQUENTIAL_MISMATCH
            randval = ( (REAL4)(iFreq) )/( (REAL4)(nBinsSGNL) );
       #endif
       #ifdef INCLUDE_RANDVAL_MISMATCH
          LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
       #endif
       pPulsarSignalParams->pulsar.phi0 = ((REAL8)randval) * ((REAL8)LAL_TWOPI);

       /* randval steps through various mismatches to frequencies centered on a bin */
       /* Note that iFreq = nBinsSGNL/2 gives randval = 0.5 gives no mismatch from frequency centered on a bin */
       randval = ( (REAL4)(iFreq) )/( (REAL4)(nBinsSGNL) );
       #ifdef INCLUDE_RANDVAL_MISMATCH
          LALUniformDeviate(status->statusPtr, &randval, randPar); CHECKSTATUSPTR (status);
       #endif
       pPulsarSignalParams->pulsar.f0 = f0SGNL + iFreq*dfSGNL + (((REAL8)randval) - 0.5)*dfSGNL;

       testNumber++; /* Update count of which test we about to do. */

       /* FIRST: Use LALGeneratePulsarSignal and LALSignalToSFTs to generate outputSFTs */
       signalvec = NULL;
       LALGeneratePulsarSignal(status->statusPtr, &signalvec, pPulsarSignalParams);
       CHECKSTATUSPTR (status);
       outputSFTs = NULL;
       LALSignalToSFTs(status->statusPtr, &outputSFTs, signalvec, pSFTParams);
       CHECKSTATUSPTR (status);

       #ifdef PRINT_OUTPUTSFT
           if (testNumber == TESTNUMBER_TO_PRINT) {
              i=SFTINDEX_TO_PRINT; /* index of which outputSFT to output */
              fprintf(stdout,"iFreq = %i, inject h_0 = %23.10e \n",iFreq,h_0);
              fprintf(stdout,"iFreq = %i, inject cosIota = %23.10e, A_+ = %23.10e, A_x = %23.10e \n",iFreq,cosIota,pPulsarSignalParams->pulsar.aPlus,pPulsarSignalParams->pulsar.aCross);
              fprintf(stdout,"iFreq = %i, inject psi = %23.10e \n",iFreq,pPulsarSignalParams->pulsar.psi);
              fprintf(stdout,"iFreq = %i, inject phi0 = %23.10e \n",iFreq,pPulsarSignalParams->pulsar.phi0);
              fprintf(stdout,"iFreq = %i, search f0 = %23.10e, inject f0 = %23.10e \n",iFreq,f0SGNL + iFreq*dfSGNL,pPulsarSignalParams->pulsar.f0);
              fprintf(stdout,"outputSFTs->data[%i].data->length = %i \n",i,outputSFTs->data[i].data->length);
              renorm = ((REAL4)nsamples)/((REAL4)(outputSFTs->data[i].data->length - 1));
              for(j=0;j<nBinsSFT;j++) {
                /* fprintf(stdout,"%i %g %g \n", j, renorm*outputSFTs->data[i].data->data[j].re, renorm*outputSFTs->data[i].data->data[j].im); */
                fprintf(stdout,"%i %g \n",j,renorm*renorm*outputSFTs->data[i].data->data[j].re*outputSFTs->data[i].data->data[j].re + renorm*renorm*outputSFTs->data[i].data->data[j].im*outputSFTs->data[i].data->data[j].im);
                fflush(stdout);
              }
           }
       #endif

       /* SECOND: Use LALComputeSkyAndZeroPsiAMResponse and LALFastGeneratePulsarSFTs to generate outputSFTs */
       LALFastGeneratePulsarSFTs (status->statusPtr, &fastOutputSFTs, pSkyConstAndZeroPsiAMResponse, pSFTandSignalParams);
       CHECKSTATUSPTR (status);

       #ifdef PRINT_FASTOUTPUTSFT
          if (testNumber == TESTNUMBER_TO_PRINT) {
            REAL4  fPlus;
            REAL4  fCross;
            i=SFTINDEX_TO_PRINT; /* index of which outputSFT to output */
            fPlus = pSkyConstAndZeroPsiAMResponse->fPlusZeroPsi[i]*cos(2.0*pPulsarSignalParams->pulsar.psi) + pSkyConstAndZeroPsiAMResponse->fCrossZeroPsi[i]*sin(2.0*pPulsarSignalParams->pulsar.psi);
            fCross = pSkyConstAndZeroPsiAMResponse->fCrossZeroPsi[i]*cos(2.0*pPulsarSignalParams->pulsar.psi) - pSkyConstAndZeroPsiAMResponse->fPlusZeroPsi[i]*sin(2.0*pPulsarSignalParams->pulsar.psi);
            fprintf(stdout,"iFreq = %i, inject h_0 = %23.10e \n",iFreq,h_0);
            fprintf(stdout,"iFreq = %i, inject cosIota = %23.10e, A_+ = %23.10e, A_x = %23.10e \n",iFreq,cosIota,pPulsarSignalParams->pulsar.aPlus,pPulsarSignalParams->pulsar.aCross);
            fprintf(stdout,"iFreq = %i, inject psi = %23.10e \n",iFreq,pPulsarSignalParams->pulsar.psi);
            fprintf(stdout,"iFreq = %i, fPlus, fCross = %23.10e,  %23.10e \n",iFreq,fPlus,fCross);
            fprintf(stdout,"iFreq = %i, inject phi0 = %23.10e \n",iFreq,pPulsarSignalParams->pulsar.phi0);
            fprintf(stdout,"iFreq = %i, search f0 = %23.10e, inject f0 = %23.10e \n",iFreq,f0SGNL + iFreq*dfSGNL,pPulsarSignalParams->pulsar.f0);
            fprintf(stdout,"fastOutputSFTs->data[%i].data->length = %i \n",i,fastOutputSFTs->data[i].data->length);
            fflush(stdout);
            for(j=0;j<nBinsSFT;j++) {
               /* fprintf(stdout,"%i %g %g \n",j,fastOutputSFTs->data[i].data->data[j].re,fastOutputSFTs->data[i].data->data[j].im); */
               fprintf(stdout,"%i %g \n",j,fastOutputSFTs->data[i].data->data[j].re*fastOutputSFTs->data[i].data->data[j].re + fastOutputSFTs->data[i].data->data[j].im*fastOutputSFTs->data[i].data->data[j].im);
               fflush(stdout);
            }
          }
       #endif

       /* find maximum difference in power */
       epsDiffMod = 0.20; /* maximum allowed percent difference */ /* 10/12/04 gam */
       overallMaxDiffSFTMod = 0.0;
       for (i = 0; i < numSFTs; i++) {
          renorm = ((REAL4)nsamples)/((REAL4)(outputSFTs->data[i].data->length - 1));
          maxDiffSFTMod = 0.0;
          diffAtMaxPower = 0.0;
          maxMod = 0.0;
          fastMaxMod = 0.0;
          jMaxMod = -1;
          jFastMaxMod = -1;
          /* Since doppler shifts can move the signal by an unknown number of bins search the whole band for max modulus: */
          for(j=0;j<nBinsSFT;j++) {
               sftMod = renorm*renorm*crealf(outputSFTs->data[i].data->data[j])*crealf(outputSFTs->data[i].data->data[j]) + renorm*renorm*cimagf(outputSFTs->data[i].data->data[j])*cimagf(outputSFTs->data[i].data->data[j]);
               sftMod = sqrt(sftMod);
               fastSFTMod = crealf(fastOutputSFTs->data[i].data->data[j])*crealf(fastOutputSFTs->data[i].data->data[j]) + cimagf(fastOutputSFTs->data[i].data->data[j])*cimagf(fastOutputSFTs->data[i].data->data[j]);
               fastSFTMod = sqrt(fastSFTMod);
               if (fabs(sftMod) > smallMod) {
                   tmpDiffSFTMod = fabs((sftMod - fastSFTMod)/sftMod);
                   if (tmpDiffSFTMod > maxDiffSFTMod) {
                       maxDiffSFTMod = tmpDiffSFTMod;
                   }
                   if (tmpDiffSFTMod > overallMaxDiffSFTMod) {
                       overallMaxDiffSFTMod = tmpDiffSFTMod;
                   }
                   if (sftMod > maxMod) {
                       maxMod = sftMod;
                       jMaxMod = j;
                   }
                   if (fastSFTMod > fastMaxMod) {
                       fastMaxMod = fastSFTMod;
                       jFastMaxMod = j;
                   }
               }
          }
          if (fabs(maxMod) > smallMod) {
             diffAtMaxPower = fabs((maxMod - fastMaxMod)/maxMod);
          }
          #ifdef PRINT_MAXSFTPOWER
            fprintf(stdout,"maxSFTMod, testNumber %i, SFT %i, bin %i = %g \n",testNumber,i,jMaxMod,maxMod);
            fprintf(stdout,"maxFastSFTMod, testNumber %i, SFT %i, bin %i = %g \n",testNumber,i,jFastMaxMod,fastMaxMod);
            fflush(stdout);
          #endif
          #ifdef PRINT_MAXDIFFSFTPOWER
            fprintf(stdout,"maxDiffSFTMod, testNumber %i, SFT %i, bin %i = %g \n",testNumber,i,jMaxDiff,maxDiffSFTMod);
            fflush(stdout);
          #endif
          #ifdef PRINT_DIFFATMAXPOWER
            fprintf(stdout,"diffAtMaxPower, testNumber %i, SFT %i, bins %i and %i = %g \n",testNumber,i,jMaxMod,jFastMaxMod,diffAtMaxPower);
            fflush(stdout);
          #endif
          #ifdef PRINT_ERRORATMAXPOWER
            if (diffAtMaxPower > epsDiffMod) {
              fprintf(stdout,"diffAtMaxPower, testNumber %i, SFT %i, bins %i and %i = %g exceeded epsDiffMod = %g \n",testNumber,i,jMaxMod,jFastMaxMod,diffAtMaxPower,epsDiffMod);
              fflush(stdout);
              /* break; */ /* only report 1 error per test */
            }
            if (jMaxMod != jFastMaxMod) {
              fprintf(stdout,"MaxPower occurred in different bins: testNumber %i, SFT %i, bins %i and %i\n",testNumber,i,jMaxMod,jFastMaxMod);
              fflush(stdout);
              /* break; */ /* only report 1 error per test */
            }
          #endif
          if (jMaxMod != jFastMaxMod) {
              binErrorCount++; /* 10/12/04 gam; count up bin errors; if too ABORT at bottom of code */
          }
          if ( diffAtMaxPower > epsDiffMod ) {
            ABORT( status, GENERATEPULSARSIGNALTESTC_EMOD, GENERATEPULSARSIGNALTESTC_MSGEMOD);
          }
          /* 10/12/04 gam; turn on test above and add test below */
          if ( fabs(((REAL8)(jMaxMod - jFastMaxMod))) >  1.1 ) {
            ABORT( status, GENERATEPULSARSIGNALTESTC_EBIN,   GENERATEPULSARSIGNALTESTC_MSGEBIN);
          }
       } /* END for(i = 0; i < numSFTs; i++) */
       #ifdef PRINT_OVERALLMAXDIFFSFTPOWER
         fprintf(stdout,"overallMaxDiffSFTMod, testNumber = %i, SFT %i, bin %i = %g \n",testNumber,iOverallMaxDiffSFTMod,jOverallMaxDiff,overallMaxDiffSFTMod);
         fflush(stdout);
       #endif

       /* 09/07/05 gam; Initialize fastOutputSFTs since only 2*Dterms bins are changed by LALFastGeneratePulsarSFTs */
       for (i = 0; i < numSFTs; i++) {
          for(j=0;j<nBinsSFT;j++) {
             fastOutputSFTs->data[i].data->data[j] = 0.0;
          }
       }

       XLALDestroySFTVector( outputSFTs);

       LALFree(signalvec->data->data);
       LALFree(signalvec->data);
       LALFree(signalvec);

     } /* END for(iFreq=0;iFreq<nBinsSGNL;iFreq++) */
     /* ***************************************************/
     /*                                                  */
     /* END SECTION: LOOP OVER FREQUENCIES               */
     /*                                                  */
     /* ***************************************************/
   } /* END for(jDeriv=0;jDeriv<numFreqDerivIncludingNoSpinDown;jDeriv++) */
  /* ********************************************************/
  /*                                                       */
  /* END SECTION: LOOP OVER SPINDOWN                       */
  /*                                                       */
  /* ********************************************************/

  } /* END for(iSky=0;iSky<numSkyPosTotal;iSky++) */
  /* ********************************************************/
  /*                                                       */
  /* END SECTION: LOOP OVER SKY POSITIONS                  */
  /*                                                       */
  /* ********************************************************/

  /* 10/12/04 gam; check if too many bin errors */
  epsBinErrorRate = 0.20;  /* 10/12/04 gam; maximum allowed bin errors */
  if ( (((REAL4)binErrorCount)/((REAL4)testNumber)) > epsBinErrorRate ) {
            ABORT( status, GENERATEPULSARSIGNALTESTC_EBINS, GENERATEPULSARSIGNALTESTC_MSGEBINS);
  }

  #ifdef INCLUDE_RANDVAL_MISMATCH
    LALDestroyRandomParams(status->statusPtr, &randPar);
    CHECKSTATUSPTR (status);
  #endif

  /* fprintf(stdout,"Total number of tests completed = %i. \n", testNumber);
  fflush(stdout); */

  LALFree(pSFTParams);
  if (numSpinDown > 0) {
    LALDDestroyVector(status->statusPtr, &(pPulsarSignalParams->pulsar.spindown));
    CHECKSTATUSPTR (status);
  }
  LALFree(pPulsarSignalParams);

  /* deallocate memory for structs needed by LALComputeSkyAndZeroPsiAMResponse and LALFastGeneratePulsarSFTs */
  XLALDestroySFTVector( fastOutputSFTs);
  LALFree(pSkyConstAndZeroPsiAMResponse->fCrossZeroPsi);
  LALFree(pSkyConstAndZeroPsiAMResponse->fPlusZeroPsi);
  LALFree(pSkyConstAndZeroPsiAMResponse->skyConst);
  LALFree(pSkyConstAndZeroPsiAMResponse);
  /* 02/02/05 gam; if NOT pSFTandSignalParams->resTrig > 0 should not create trigArg etc... */
  if (pSFTandSignalParams->resTrig > 0) {
    LALFree(pSFTandSignalParams->trigArg);
    LALFree(pSFTandSignalParams->sinVal);
    LALFree(pSFTandSignalParams->cosVal);
  }
  LALFree(pSFTandSignalParams);

  /* deallocate skyPosData */
  for(i=0;i<numSkyPosTotal;i++)
  {
      LALFree(skyPosData[i]);
  }
  LALFree(skyPosData);

  if (numSpinDown > 0) {
    /* deallocate freqDerivData */
    for(i=0;i<numFreqDerivTotal;i++)
    {
        LALFree(freqDerivData[i]);
    }
    LALFree(freqDerivData);
  }

  LALFree(timeStamps->data);
  LALFree(timeStamps);

  XLALDestroyEphemerisData(edat);

  CHECKSTATUSPTR (status);
  DETATCHSTATUSPTR (status);
}
int
main( int argc, char **argv )
{
  static LALStatus stat;       /* status structure */
  int arg;                     /* command-line argument counter */
  UINT4 n = SIZE, i, j;        /* array size and indecies */
  CHAR *infile = NULL;         /* input filename */
  CHAR *outfile = NULL;        /* output filename */
  BOOLEAN timing = 0;          /* whether -t option was given */
  BOOLEAN single = 0;          /* whether -s option was given */
  BOOLEAN invert = 0;          /* whether -v option was given */
  REAL4 sDet = 0.0;            /* determinant if -s option is given */
  REAL8 dDet = 0.0;            /* determinant if -s option isn't given */
  REAL4Array *sMatrix = NULL;  /* matrix if -s option is given */
  REAL8Array *dMatrix = NULL;  /* matrix if -s option is not given */
  REAL4Array *sInverse = NULL; /* inverse if -s option is given */
  REAL8Array *dInverse = NULL; /* inverse if -s option isn't given */
  UINT4Vector dimLength;       /* dimensions used to create matrix */
  UINT4 dims[2];               /* dimLength.data array */
  clock_t start = 0, stop = 0; /* start and stop times for timing */
  FILE *fp = NULL;             /* input/output file pointer */


  /*******************************************************************
   * PARSE ARGUMENTS (arg stores the current position)               *
   *******************************************************************/

  arg = 1;
  while ( arg < argc ) {

    /* Parse matrix size option. */
    if ( !strcmp( argv[arg], "-n" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
	n = atoi( argv[arg++] );
      } else {
	ERROR( DETINVERSETESTC_EARG, DETINVERSETESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return DETINVERSETESTC_EARG;
      }
    }

    /* Parse input option. */
    else if ( !strcmp( argv[arg], "-i" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
	infile = argv[arg++];
      } else {
	ERROR( DETINVERSETESTC_EARG, DETINVERSETESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return DETINVERSETESTC_EARG;
      }
    }

    /* Parse output option. */
    else if ( !strcmp( argv[arg], "-o" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
	outfile = argv[arg++];
      } else {
	ERROR( DETINVERSETESTC_EARG, DETINVERSETESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return DETINVERSETESTC_EARG;
      }
    }

    /* Parse inversion, single-precision, and timing options. */
    else if ( !strcmp( argv[arg], "-v" ) ) {
      arg++;
      invert = 1;
    }
    else if ( !strcmp( argv[arg], "-s" ) ) {
      arg++;
      single = 1;
    }
    else if ( !strcmp( argv[arg], "-t" ) ) {
      arg++;
      timing = 1;
    }

    /* Parse debug level option. */
    else if ( !strcmp( argv[arg], "-d" ) ) {
      if ( argc > arg + 1 ) {
	arg++;
      }else{
	ERROR( DETINVERSETESTC_EARG, DETINVERSETESTC_MSGEARG, 0 );
        LALPrintError( USAGE, *argv );
        return DETINVERSETESTC_EARG;
      }
    }

    /* Check for unrecognized options. */
    else {
      ERROR( DETINVERSETESTC_EARG, DETINVERSETESTC_MSGEARG, 0 );
      LALPrintError( USAGE, *argv );
      return DETINVERSETESTC_EARG;
    }
  } /* End of argument parsing loop. */


  /*******************************************************************
   * GET INPUT MATRIX                                                *
   *******************************************************************/

  /* Set up array creation vector. */
  dimLength.length = 2;
  dimLength.data = dims;

  /* Read input matrix file. */
  if ( infile ) {

    /* Open input file. */
    if ( !strcmp( infile, "stdin" ) )
      fp = stdin;
    else if ( !( fp = fopen( infile, "r" ) ) ) {
      ERROR( DETINVERSETESTC_EFILE, "- " DETINVERSETESTC_MSGEFILE, infile );
      return DETINVERSETESTC_EFILE;
    }

    /* Single-precision mode: */
    if ( single ) {
      REAL4Vector *vec = NULL; /* parsed input line */

      /* Read first non-comment line and create array. */
      do {
	SUB( LALSReadVector( &stat, &vec, fp, 0 ), &stat );
      } while ( ( n = vec->length ) == 0 );
      dimLength.data[0] = dimLength.data[1] = n;
      SUB( LALSCreateArray( &stat, &sMatrix, &dimLength ), &stat );
      for ( j = 0; j < n; j++ )
	sMatrix->data[j] = vec->data[j];
      SUB( LALSDestroyVector( &stat, &vec ), &stat );

      /* Read remaining lines. */
      for ( i = 1; i < n; i++ ) {
	SUB( LALSReadVector( &stat, &vec, fp, 1 ), &stat );
	if ( vec->length != n ) {
	  ERROR( DETINVERSETESTC_EFMT, DETINVERSETESTC_MSGEFMT, 0 );
	  return DETINVERSETESTC_EFMT;
	}
	for ( j = 0; j < n; j++ )
	  sMatrix->data[i*n+j] = vec->data[j];
	SUB( LALSDestroyVector( &stat, &vec ), &stat );
      }
    }

    /* Double-precision mode: */
    else {
      REAL8Vector *vec = NULL; /* parsed input line */

      /* Read first non-comment line and create array. */
      do {
	SUB( LALDReadVector( &stat, &vec, fp, 0 ), &stat );
      } while ( ( n = vec->length ) == 0 );
      dimLength.data[0] = dimLength.data[1] = n;
      SUB( LALDCreateArray( &stat, &dMatrix, &dimLength ), &stat );
      for ( j = 0; j < n; j++ )
	dMatrix->data[j] = vec->data[j];
      SUB( LALDDestroyVector( &stat, &vec ), &stat );

      /* Read remaining lines. */
      for ( i = 1; i < n; i++ ) {
	SUB( LALDReadVector( &stat, &vec, fp, 1 ), &stat );
	if ( vec->length != n ) {
	  ERROR( DETINVERSETESTC_EFMT, DETINVERSETESTC_MSGEFMT, 0 );
	  return DETINVERSETESTC_EFMT;
	}
	for ( j = 0; j < n; j++ )
	  dMatrix->data[i*n+j] = vec->data[j];
	SUB( LALDDestroyVector( &stat, &vec ), &stat );
      }
    }
  }

  /* Generate random matrix. */
  else {
    RandomParams *params = NULL;
    SUB( LALCreateRandomParams( &stat, &params, 0 ), &stat );
    dimLength.data[0] = dimLength.data[1] = n;

    /* Single-precision mode: */
    if ( single ) {
      SUB( LALSCreateArray( &stat, &sMatrix, &dimLength ), &stat );
      for ( i = 0; i < n; i++ ) {
	REAL4 x;
	for ( j = 0; j < n; j++ ) {
	  SUB( LALUniformDeviate( &stat, &x, params ), &stat );
	  sMatrix->data[i*n+j] = 2.0*x - 1.0;
	}
      }
    }

    /* Double-precision mode: */
    else {
      SUB( LALDCreateArray( &stat, &dMatrix, &dimLength ), &stat );
      for ( i = 0; i < n; i++ ) {
	REAL4 x;
	for ( j = 0; j < n; j++ ) {
	  SUB( LALUniformDeviate( &stat, &x, params ), &stat );
	  dMatrix->data[i*n+j] = 2.0*(REAL8)( x ) - 1.0;
	}
      }
    }

    SUB( LALDestroyRandomParams( &stat, &params ), &stat );
  }

  /* Write input matrix to output file. */
  if ( outfile ) {

    /* Open output file. */
    if ( !strcmp( outfile, "stdout" ) )
      fp = stdout;
    else if ( !strcmp( outfile, "stderr" ) )
      fp = stderr;
    else if ( !( fp = fopen( outfile, "r" ) ) ) {
      ERROR( DETINVERSETESTC_EFILE, "- " DETINVERSETESTC_MSGEFILE, outfile );
      return DETINVERSETESTC_EFILE;
    }

    /* Single-precision mode: */
    if ( single ) {
      for ( i = 0; i < n; i++ ) {
	fprintf( fp, "%16.9e", sMatrix->data[i*n] );
	for ( j = 1; j < n; j++ )
	  fprintf( fp, " %16.9e", sMatrix->data[i*n+j] );
	fprintf( fp, "\n" );
      }
    }

    /* Double-precision mode: */
    else {
      for ( i = 0; i < n; i++ ) {
	fprintf( fp, "%25.17e", dMatrix->data[i*n] );
	for ( j = 1; j < n; j++ )
	  fprintf( fp, " %25.17e", dMatrix->data[i*n+j] );
	fprintf( fp, "\n" );
      }
    }
  }


  /*******************************************************************
   * COMPUTE INVERSE                                                 *
   *******************************************************************/

  if ( timing )
    start = clock();

  /* Single-precision mode: */
  if ( single ) {
    if ( invert ) {
      SUB( LALSCreateArray( &stat, &sInverse, &dimLength ), &stat );
      SUB( LALSMatrixInverse( &stat, &sDet, sMatrix, sInverse ),
	   &stat );
    }
  }

  /* Double-precision mode: */
  else {
    if ( invert ) {
      SUB( LALDCreateArray( &stat, &dInverse, &dimLength ), &stat );
      SUB( LALDMatrixInverse( &stat, &dDet, dMatrix, dInverse ),
	   &stat );
    } else {
      SUB( LALDMatrixDeterminant( &stat, &dDet, dMatrix ), &stat );
    }
  }

  if ( timing ) {
    stop = clock();
    fprintf( stderr, "Elapsed time: %.2f s\n",
	     (double)( stop - start )/CLOCKS_PER_SEC );
  }

  /* Write output. */
  if ( outfile ) {

    /* Write determinant. */
    fprintf( fp, "\n" );
    if ( single )
      fprintf( fp, "%16.9e\n", sDet );
    else
      fprintf( fp, "%25.17e\n", dDet );

    /* Write inverse. */
    if ( invert ) {
      fprintf( fp, "\n" );
      if ( single ) {
	for ( i = 0; i < n; i++ ) {
	  fprintf( fp, "%16.9e", sInverse->data[i*n] );
	  for ( j = 1; j < n; j++ )
	    fprintf( fp, " %16.9e", sInverse->data[i*n+j] );
	  fprintf( fp, "\n" );
	}
      } else {
	for ( i = 0; i < n; i++ ) {
	  fprintf( fp, "%25.17e", dInverse->data[i*n] );
	  for ( j = 1; j < n; j++ )
	    fprintf( fp, " %25.17e", dInverse->data[i*n+j] );
	  fprintf( fp, "\n" );
	}
      }
    }

    /* Finished output. */
    if ( fp != stdout && fp != stderr )
      fclose( fp );
  }

  /* Clean up and exit. */
  if ( single ) {
    SUB( LALSDestroyArray( &stat, &sMatrix ), &stat );
    if ( invert ) {
      SUB( LALSDestroyArray( &stat, &sInverse ), &stat );
    }
  } else {
    SUB( LALDDestroyArray( &stat, &dMatrix ), &stat );
    if ( invert ) {
      SUB( LALDDestroyArray( &stat, &dInverse ), &stat );
    }
  }
  LALCheckMemoryLeaks();
  INFO( DETINVERSETESTC_MSGENORM );
  return DETINVERSETESTC_ENORM;
}