//Test LALPriorFunction
REAL8 ASinOmegaTPrior(LALInferenceRunState *runState, LALInferenceVariables *params)
/****************************************/
/* Prior for two-parameter				*/
/* waveform family ASinOmegaT			*/
/* Assumes the following parameters		*/
/* exist:	A, Omega					*/
/* Prior is flat if within range		*/
/****************************************/
{
  (void) runState; /* avoid warning about unused parameter */
  REAL8 A, Omega;
  REAL8 logdensity;
  
  A     = *(REAL8*) LALInferenceGetVariable(params, "A");				/* dim-less	   */
  Omega = *(REAL8*) LALInferenceGetVariable(params, "Omega");			/* rad/sec     */
  
  if ((A>0.0) & (Omega>0))
    logdensity = 0.0;
  else
    logdensity = -HUGE_VAL;

  return logdensity;
}
void LALInferenceTemplateSinc(LALInferenceModel *model)
/*****************************************************/
/* Sinc function (burst) template.                   */
/* Signal is linearly polarized,                     */
/* i.e., cross term is zero.                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/* The (plus-) waveform is a sinc function of given  */
/* frequency:                                        */
/*   a * sinc(2*pi*f*(t-time))                       */
/*   = a * sin(2*pi*f*(t-time)) / (2*pi*f*(t-time))  */
/* where "time" is the time parameter denoting the   */
/* signal's central peak location.                   */
/* * * * * * * * * * * * * * * * * * * * * * * * * * *************************/
/* Required (`model->params') parameters are:                         */
/*   - "time"       (the instant at which the signal peaks; REAL8, GPS sec.) */
/*   - "frequency"  (frequency of the sine part; REAL8, Hertz)               */
/*   - "amplitude"  (amplitude, REAL8)                                       */
/*****************************************************************************/
{
  double endtime  = *(REAL8*) LALInferenceGetVariable(model->params, "time");       /* time parameter ("mu"), GPS sec.  */
  double f     = *(REAL8*) LALInferenceGetVariable(model->params, "frequency");  /* frequency, Hz                    */
  double a     = *(REAL8*) LALInferenceGetVariable(model->params, "amplitude");  /* amplitude                        */
  double t, sinArg, sinc, twopif = LAL_TWOPI*f;
  double epochGPS = XLALGPSGetREAL8(&(model->timehPlus->epoch));
  unsigned long i;
  if (f < 0.0)
    fprintf(stderr, " WARNING in templateSinc(): negative \"frequency\" parameter (f=%e).\n", f);
  for (i=0; i<model->timehPlus->data->length; ++i){
    t = ((double)i)*model->deltaT + (epochGPS-endtime);  /* t-mu       */
    sinArg = twopif*t;
    sinc = (sinArg==0.0) ? 1.0 : sin(sinArg)/sinArg;    
    model->timehPlus->data->data[i] = a * sinc;
    model->timehCross->data->data[i] = 0.0;
  }
  model->domain = LAL_SIM_DOMAIN_TIME;
  return;
}
Exemple #3
0
/**
 * \brief Split the data into segments
 *
 * This function is deprecated to \c chop_n_merge, but gives the functionality of the old code.
 *
 * It cuts the data into as many contiguous segments of data as possible of length \c chunkMax. Where contiguous is
 * defined as containing consecutive point within 180 seconds of each other. The length of segments that do not fit into
 * a \c chunkMax length are also included.
 *
 * \param ifo [in] the LALInferenceIFOModel variable
 * \param chunkMax [in] the maximum length of a data chunk/segment
 *
 * \return A vector of chunk/segment lengths
 */
UINT4Vector *get_chunk_lengths( LALInferenceIFOModel *ifo, UINT4 chunkMax ){
  UINT4 i = 0, j = 0, count = 0;
  UINT4 length;

  REAL8 t1, t2;

  UINT4Vector *chunkLengths = NULL;

  length = ifo->times->length;

  chunkLengths = XLALCreateUINT4Vector( length );

  REAL8 dt = *(REAL8*)LALInferenceGetVariable( ifo->params, "dt" );

  /* create vector of data segment length */
  while( 1 ){
    count++; /* counter */

    /* break clause */
    if( i > length - 2 ){
      /* set final value of chunkLength */
      chunkLengths->data[j] = count;
      j++;
      break;
    }

    i++;

    t1 = XLALGPSGetREAL8( &ifo->times->data[i-1] );
    t2 = XLALGPSGetREAL8( &ifo->times->data[i] );

    /* if consecutive points are within two sample times of each other count as in the same chunk */
    if( t2 - t1 > 2.*dt || count == chunkMax ){
      chunkLengths->data[j] = count;
      count = 0; /* reset counter */

      j++;
    }
  }

  chunkLengths = XLALResizeUINT4Vector( chunkLengths, j );

  return chunkLengths;
}
Exemple #4
0
/** \brief Compute the noise variance for each data segment
 *
 * Once the data has been split into segments calculate the noise variance (using
 * both the real and imaginary parts) in each segment and fill in the associated
 * noise vector. To calculate the noise the running median should first be
 * subtracted from the data.
 *
 * \param data [in] the LALInferenceIFOData variable
 * \param model [in] the LALInferenceIFOModel variable
 */
void compute_variance( LALInferenceIFOData *data, LALInferenceIFOModel *model ){
  REAL8 chunkLength = 0.;

  INT4 i = 0, j = 0, length = 0, cl = 0, counter = 0;

  COMPLEX16Vector *meddata = NULL; /* data with running median removed */

  /* subtract a running median value from the data to remove any underlying
     trends (e.g. caused by a strong signal) */
  meddata = subtract_running_median( data->compTimeData->data );

  UINT4Vector *chunkLengths = NULL;
  chunkLengths = *(UINT4Vector **)LALInferenceGetVariable( model->params, "chunkLength" );

  length = data->compTimeData->data->length;

  for ( i = 0, counter = 0; i < length; i+=chunkLength, counter++ ){
    REAL8 vari = 0., meani = 0.;

    chunkLength = (REAL8)chunkLengths->data[counter];
    cl = i + (INT4)chunkLength;

    /* get the mean (should be close to zero given the running median subtraction), but
     * probably worth doing anyway) */
    for ( j = i ; j < cl ; j++ ){
      meani += (creal(meddata->data[j]) + cimag(meddata->data[j]));
    }

    meani /= (2.*chunkLength);

    for ( j = i ; j < cl ; j++ ){
      vari += SQUARE( (creal(meddata->data[j]) - meani) );
      vari += SQUARE( (cimag(meddata->data[j]) - meani) );
    }

    vari /= (2.*chunkLength - 1.); /* unbiased sample variance */

    /* fill in variance vector */
    for ( j = i ; j < cl ; j++ ){ data->varTimeData->data->data[j] = vari; }
  }
}
/**
 * \brief The prior function
 *
 * This function calculates the natural logarithm of the prior for a set of parameters. If the prior on a particular
 * parameter is uniform over a given range then \f$p(\theta) = 1/(\theta_{\rm max} - \theta_{\rm min})\f$. If the
 * prior is Gaussian then the probability of that value given the mean and standard deviation of the Gaussian is
 * calculated.
 *
 * \param runState [in] A pointer to the LALInferenceRunState
 * \param params [in] The set of parameter values
 *
 * \return The natural logarithm of the prior value for a set of parameters
 */
REAL8 priorFunction( LALInferenceRunState *runState, LALInferenceVariables *params ){
  LALInferenceIFOData *data = runState->data;
  (void)runState;
  LALInferenceVariableItem *item = params->head;
  REAL8 min, max, mu, sigma, prior = 0, value = 0.;

  REAL8Vector *corVals = NULL;
  UINT4 cori = 0;

  const CHAR *fn = __func__;

  /* check that parameters are within their prior ranges */
  if( !in_range( runState->priorArgs, params ) ) { return -INFINITY; }

  /* if a k-d tree prior exists ONLY use that */
  if( LALInferenceCheckVariable( runState->priorArgs, "kDTreePrior" ) &&
      LALInferenceCheckVariable( runState->priorArgs, "kDTreePriorTemplate" ) ){
    /* get tree */
    LALInferenceKDTree *tree = *(LALInferenceKDTree **)LALInferenceGetVariable(runState->priorArgs, "kDTreePrior");

    /* get parameter template */
    LALInferenceVariables *template =*(LALInferenceVariables **)LALInferenceGetVariable(runState->priorArgs,
//Test LALInferencePriorFunction
REAL8 BasicUniformLALPrior(LALInferenceRunState *runState, LALInferenceVariables *params)
/****************************************/
/* Returns unnormalized (!),            */
/* logarithmic (!) prior density.      	*/
/****************************************/
/* Assumes the following parameters	*/
/* exist (e.g., for TaylorT1):		*/
/* chirpmass, massratio, inclination,	*/
/* phase, time, rightascension,		*/
/* desclination, polarisation, distance.*/
/* Prior is flat if within range	*/
/****************************************/
{
  (void) runState; /* avoid warning about unused parameter */
  REAL8 eta, iota, phi, ra, dec, psi;
  REAL8 logdensity;
  
  // UNUSED!!: REAL8 mc   = *(REAL8*) LALInferenceGetVariable(params, "chirpmass");		/* solar masses*/
  eta  = *(REAL8*) LALInferenceGetVariable(params, "eta");		/* dim-less    */
  iota = *(REAL8*) LALInferenceGetVariable(params, "inclination");		/* radian      */
  // UNUSED!!: REAL8 tc   = *(REAL8*) LALInferenceGetVariable(params, "time");			/* GPS seconds */
  phi  = *(REAL8*) LALInferenceGetVariable(params, "phase");		/* radian      */
  ra   = *(REAL8*) LALInferenceGetVariable(params, "rightascension");	/* radian      */
  dec  = *(REAL8*) LALInferenceGetVariable(params, "declination");		/* radian      */
  psi  = *(REAL8*) LALInferenceGetVariable(params, "polarisation"); 	/* radian      */
  // UNUSED!!: REAL8  dist = *(REAL8*) LALInferenceGetVariable(params, "distance");		/* Mpc         */

  if(eta>0.0 && eta<=0.25 && iota>=0.0 && iota<=LAL_PI && phi>=0.0 && phi<=LAL_TWOPI 
     && ra>=0.0 && ra<=LAL_TWOPI && dec>=-LAL_PI_2 && dec<=LAL_PI_2 && psi>=0.0 && psi<=LAL_PI)	
    logdensity = 0.0;
  else
    logdensity = -HUGE_VAL;
  //TODO: should be properly normalized; pass in range via priorArgs?	

  return(logdensity);
}
void LALInferenceTemplateXLALSimInspiralChooseWaveform(LALInferenceModel *model)
/*************************************************************************************************************************/
/* Wrapper for LALSimulation waveforms:						                                                             */
/* XLALSimInspiralChooseFDWaveform() and XLALSimInspiralChooseTDWaveform().                                              */
/*                                                                                                                       */
/*  model->params parameters are:										                                                 */
/*  - "name" description; type OPTIONAL (default value)										                             */
/*										                                                                                 */
/*   MODEL PARAMETERS										                                                             */
/*   - "LAL_APPROXIMANT     Approximant;        Approximant                                                              */
/*   - "LAL_PNORDER"        Phase PN order;     INT4                                                                     */
/*   - "LAL_AMPORDER"       Amplitude PN order; INT4 OPTIONAL (-1)                                                       */
/*   - "spinO"              Spin order;         LALSimInspiralSpinOrder OPTIONAL (LAL_SIM_INSPIRAL_SPIN_ORDER_DEFAULT)   */
/*   - "tideO"              Tidal order;        LALSimInspiralTidalOrder OPTIONAL (LAL_SIM_INSPIRAL_TIDAL_ORDER_DEFAULT) */
/*   - "f_ref"               frequency at which the (frequency dependent) parameters are defined; REAL8 OPTIONAL (0.0)    */
/*   - "fLow"               lower frequency bound; REAL8 OPTIONAL (model->fLow)                                          */
/*                                                                                                                       */
/*   MASS PARAMETERS; either:                                                                                            */
/*      - "mass1"           mass of object 1 in solar mass; REAL8								                         */
/*      - "mass2"		        mass of object 1 in solar mass; REAL8								                     */
/*      OR                                                                                                               */
/*      - "chirpmass"       chirpmass in solar mass; REAL8                                                               */
/*      - "q"  asymmetric mass ratio m2/m1, 0<q<1; REAL8                                      */
/*      OR                                                                                                               */
/*      - "chirpmass"       chirpmass in solar mass; REAL8                                                               */
/*      - "eta"             symmetric mass ratio (m1*m2)/(m1+m2)^2; REAL8                                                */
/*                                                                                                                       */
/*   ORIENTATION AND SPIN PARAMETERS                                                                                     */
/*   - "phi0"               reference phase as per LALSimulation convention; REAL8                                       */
/*   - "distance"           distance in Mpc                                                                              */
/*   - "costheta_jn");      cos of zenith angle between J and N in radians;            REAL8                                    */
/*   - "phi_jl");        azimuthal angle of L_N on its cone about J radians; REAL8                                    */
/*   - "tilt_spin1");    zenith angle between S1 and LNhat in radians;       REAL8                                    */
/*   - "tilt_spin2");    zenith angle between S2 and LNhat in radians;       REAL8                                    */
/*   - "phi12");         difference in azimuthal angle between S1, S2 in radians;   REAL8                             */
/*   - "a_spin1"            magnitude of spin 1 in general configuration, -1<a_spin1<1; REAL8 OPTIONAL (0.0)              */
/*   - "a_spin2"            magnitude of spin 2 in general configuration, -1<a_spin1<1; REAL8 OPTIONAL (0.0)              */
/*                                                                                                                       */
/*   OTHER PARAMETERS                                                                                                    */
/*   - "lambda1"            tidal parameter of object 1; REAL8  OPTIONAL (0.0)                                           */
/*   - "lambda2"            tidal parameter of object 1; REAL8  OPTIONAL (0.0)                                           */
/*                                                                                                                       */
/*   - "time"               used as an OUTPUT only; REAL8								                                 */
/*                                                                                                                       */
/*                                                                                                                       */
/*   model needs to also contain:                                                                                        */
/*   - model->fLow Unless  - "fLow" OPTIONAL                                                                             */
/*   - model->deltaT                                                                                                     */
/*   - if model->domain == LAL_SIM_DOMAIN_FREQUENCY                                                                      */
/*      - model->deltaF                                                                                                  */
/*      - model->freqhCross                                                                                              */
/*      - model->freqhPlus                                                                                               */
/*   - else                                                                                                              */
/*      - model->timehPlus                                                                                               */
/*      - model->timehCross                                                                                              */
/*************************************************************************************************************************/
{

  Approximant approximant = (Approximant) 0;
  INT4 order=-1;
  INT4 amporder;

  static int sizeWarning = 0;
  int ret=0;
  INT4 errnum=0;
  
  REAL8TimeSeries *hplus=NULL;  /**< +-polarization waveform [returned] */
  REAL8TimeSeries *hcross=NULL; /**< x-polarization waveform [returned] */
  COMPLEX16FrequencySeries *hptilde=NULL, *hctilde=NULL;
  REAL8 mc;
  REAL8 phi0, deltaT, m1, m2, f_low, f_start, distance, inclination;
  
  REAL8 *m1_p,*m2_p;
  REAL8 deltaF, f_max;
  
  /* Sampling rate for time domain models */
  deltaT = model->deltaT;
  
  if (LALInferenceCheckVariable(model->params, "LAL_APPROXIMANT"))
    approximant = *(Approximant*) LALInferenceGetVariable(model->params, "LAL_APPROXIMANT");
  else {
    XLALPrintError(" ERROR in templateLALGenerateInspiral(): (INT4) \"LAL_APPROXIMANT\" parameter not provided!\n");
    XLAL_ERROR_VOID(XLAL_EDATA);
  }
	
  if (LALInferenceCheckVariable(model->params, "LAL_PNORDER"))
    order = *(INT4*) LALInferenceGetVariable(model->params, "LAL_PNORDER");
  else {
    XLALPrintError(" ERROR in templateLALGenerateInspiral(): (INT4) \"LAL_PNORDER\" parameter not provided!\n");
    XLAL_ERROR_VOID(XLAL_EDATA);
  }

  /* Explicitly set the default amplitude order if one is not specified.
   *   This serves two purposes:
   *     1) The default behavior of the code won't change unexpectedly due to changes in LALSimulation.
   *     2) We need to know the amplitude order in order to set the starting frequency of the waveform properly. */
  if (LALInferenceCheckVariable(model->params, "LAL_AMPORDER"))
    amporder = *(INT4*) LALInferenceGetVariable(model->params, "LAL_AMPORDER");
  else
    amporder = -1;
    
  REAL8 f_ref = 100.0;
  if (LALInferenceCheckVariable(model->params, "f_ref")) f_ref = *(REAL8 *)LALInferenceGetVariable(model->params, "f_ref");

  REAL8 fTemp = f_ref;

  if(LALInferenceCheckVariable(model->params,"chirpmass"))
    {
      mc  = *(REAL8*) LALInferenceGetVariable(model->params, "chirpmass");
      if (LALInferenceCheckVariable(model->params,"q")) {
	REAL8 q = *(REAL8 *)LALInferenceGetVariable(model->params,"q");
	q2masses(mc, q, &m1, &m2);
      } else {
	REAL8 eta = *(REAL8*) LALInferenceGetVariable(model->params, "eta");
	mc2masses(mc, eta, &m1, &m2);
      }
    }
  else if((m1_p=(REAL8 *)LALInferenceGetVariable(model->params, "mass1")) && (m2_p=(REAL8 *)LALInferenceGetVariable(model->params, "mass2")))
    {
      m1=*m1_p;
      m2=*m2_p;
    }
  else
    {
      fprintf(stderr,"No mass parameters found!");
      exit(0);
    }

  distance	= LALInferenceGetREAL8Variable(model->params,"distance")* LAL_PC_SI * 1.0e6;        /* distance (1 Mpc) in units of metres */
  
  phi0		= LALInferenceGetREAL8Variable(model->params, "phase"); /* START phase as per lalsimulation convention, radians*/
  
  /* Zenith angle between J and N in radians. Also known as inclination angle when spins are aligned */
  REAL8 thetaJN = acos(LALInferenceGetREAL8Variable(model->params, "costheta_jn"));     /* zenith angle between J and N in radians */

  /* Check if fLow is a model parameter, otherwise use data structure definition */
  if(LALInferenceCheckVariable(model->params, "flow"))
    f_low = *(REAL8*) LALInferenceGetVariable(model->params, "flow");
  else
    f_low = model->fLow;

  f_start = fLow2fStart(f_low, amporder, approximant);
  f_max = 0.0; /* for freq domain waveforms this will stop at ISCO. Previously found using model->fHigh causes NaNs in waveform (see redmine issue #750)*/

  /* ==== SPINS ==== */
  /* We will default to spinless signal and then add in the spin components if required */
  /* If there are non-aligned spins, we must convert between the System Frame coordinates
   * and the cartestian coordinates */

  /* The cartesian spin coordinates (default 0), as passed to LALSimulation */
  REAL8 spin1x = 0.0;
  REAL8 spin1y = 0.0;
  REAL8 spin1z = 0.0;
  REAL8 spin2x = 0.0;
  REAL8 spin2y = 0.0;
  REAL8 spin2z = 0.0;
  
  /* System frame coordinates as used for jump proposals */
  REAL8 a_spin1 = 0.0;  /* Magnitude of spin1 */
  REAL8 a_spin2 = 0.0;  /* Magnitude of spin2 */
  REAL8 phiJL  = 0.0;  /* azimuthal angle of L_N on its cone about J radians */ 
  REAL8 tilt1   = 0.0;  /* zenith angle between S1 and LNhat in radians */
  REAL8 tilt2   = 0.0;  /* zenith angle between S2 and LNhat in radians */
  REAL8 phi12   = 0.0;  /* difference in azimuthal angle btwn S1, S2 in radians */

  /* Now check if we have spin amplitudes */
  if(LALInferenceCheckVariable(model->params, "a_spin1"))    a_spin1   = *(REAL8*) LALInferenceGetVariable(model->params, "a_spin1");
  if(LALInferenceCheckVariable(model->params, "a_spin2"))    a_spin2   = *(REAL8*) LALInferenceGetVariable(model->params, "a_spin2");

  /* Check if we have spin angles too */
  if(LALInferenceCheckVariable(model->params, "phi_jl"))
      phiJL = LALInferenceGetREAL8Variable(model->params, "phi_jl");
  if(LALInferenceCheckVariable(model->params, "tilt_spin1"))
      tilt1 = LALInferenceGetREAL8Variable(model->params, "tilt_spin1");
  if(LALInferenceCheckVariable(model->params, "tilt_spin2"))
      tilt2 = LALInferenceGetREAL8Variable(model->params, "tilt_spin2");
  if(LALInferenceCheckVariable(model->params, "phi12"))
      phi12 = LALInferenceGetREAL8Variable(model->params, "phi12");

  /* If we have tilt angles zero, then the spins are aligned and we just set the z component */
  /* However, if the waveform supports precession then we still need to get the right coordinate components */
  SpinSupport spin_support=XLALSimInspiralGetSpinSupportFromApproximant(approximant);
  if(tilt1==0.0 && tilt2==0.0 && (spin_support==LAL_SIM_INSPIRAL_SPINLESS || spin_support==LAL_SIM_INSPIRAL_ALIGNEDSPIN))
  {
      spin1z=a_spin1;
      spin2z=a_spin2;
      inclination = thetaJN; /* Inclination angle is just thetaJN */
  }
  else
  {   /* Template is not aligned-spin only. */
      /* Set all the other spin components according to the angles we received above */
      /* The transformation function doesn't know fLow, so f_ref==0 isn't interpretted as a request to use the starting frequency for reference. */
      if(fTemp==0.0)
        fTemp = f_start;

      XLAL_TRY(ret=XLALSimInspiralTransformPrecessingNewInitialConditions(
                    &inclination, &spin1x, &spin1y, &spin1z, &spin2x, &spin2y, &spin2z,
                    thetaJN, phiJL, tilt1, tilt2, phi12, a_spin1, a_spin2, m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, fTemp), errnum);
      if (ret == XLAL_FAILURE)
      {
        XLALPrintError(" ERROR in XLALSimInspiralTransformPrecessingNewInitialConditions(): error converting angles. errnum=%d\n",errnum );
        return;
      }
  }

  
  /* ==== TIDAL PARAMETERS ==== */  
  REAL8 lambda1 = 0.;
  if(LALInferenceCheckVariable(model->params, "lambda1")) lambda1 = *(REAL8*) LALInferenceGetVariable(model->params, "lambda1");
  REAL8 lambda2 = 0.;
  if(LALInferenceCheckVariable(model->params, "lambda2")) lambda2 = *(REAL8*) LALInferenceGetVariable(model->params, "lambda2");
  REAL8 lambdaT = 0.;
  REAL8 dLambdaT = 0.;
  REAL8 sym_mass_ratio_eta = 0.;
  if(LALInferenceCheckVariable(model->params, "lambdaT")&&LALInferenceCheckVariable(model->params, "dLambdaT")){
    lambdaT = *(REAL8*) LALInferenceGetVariable(model->params, "lambdaT");
    dLambdaT = *(REAL8*) LALInferenceGetVariable(model->params, "dLambdaT");
    sym_mass_ratio_eta = m1*m2/((m1+m2)*(m1+m2));
    LALInferenceLambdaTsEta2Lambdas(lambdaT,dLambdaT,sym_mass_ratio_eta,&lambda1,&lambda2);
  }


  /* Only use GR templates */
  LALSimInspiralTestGRParam *nonGRparams = NULL;
  
  

  /* ==== Call the waveform generator ==== */
  if(model->domain == LAL_SIM_DOMAIN_FREQUENCY) {
    deltaF = model->deltaF;
    
	XLAL_TRY(ret=XLALSimInspiralChooseFDWaveformFromCache(&hptilde, &hctilde, phi0,
            deltaF, m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, spin1x, spin1y, spin1z,
            spin2x, spin2y, spin2z, f_start, f_max, f_ref, distance, inclination,lambda1, lambda2, model->waveFlags, nonGRparams, amporder, order,
            approximant,model->waveformCache, NULL), errnum);

     
    /* if the waveform failed to generate, fill the buffer with zeros
     * so that the previous waveform is not left there
     */
    if (ret != XLAL_SUCCESS || hptilde == NULL || hctilde == NULL)
    {
	    XLALPrintError(" ERROR in XLALSimInspiralChooseWaveformFromCache(): error generating waveform. errnum=%d\n",errnum );
	    memset(model->freqhPlus->data->data,0,sizeof(model->freqhPlus->data->data[0])*model->freqhPlus->data->length);
	    memset(model->freqhCross->data->data,0,sizeof(model->freqhCross->data->data[0])*model->freqhCross->data->length);
        if ( hptilde ) XLALDestroyCOMPLEX16FrequencySeries(hptilde);
        if ( hctilde ) XLALDestroyCOMPLEX16FrequencySeries(hctilde);
        XLALSimInspiralDestroyTestGRParam(nonGRparams);
	    XLAL_ERROR_VOID(XLAL_FAILURE);
    }
	if (hptilde==NULL || hptilde->data==NULL || hptilde->data->data==NULL ) {
	  XLALPrintError(" ERROR in LALInferenceTemplateXLALSimInspiralChooseWaveform(): encountered unallocated 'hptilde'.\n");
	  XLAL_ERROR_VOID(XLAL_EFAULT);
	}
	if (hctilde==NULL || hctilde->data==NULL || hctilde->data->data==NULL ) {
	  XLALPrintError(" ERROR in LALInferenceTemplateXLALSimInspiralChooseWaveform(): encountered unallocated 'hctilde'.\n");
	  XLAL_ERROR_VOID(XLAL_EFAULT);
	}

    INT4 rem=0;
    UINT4 size=hptilde->data->length;
    if(size>model->freqhPlus->data->length) size=model->freqhPlus->data->length;
    memcpy(model->freqhPlus->data->data,hptilde->data->data,sizeof(hptilde->data->data[0])*size);
    if( (rem=(model->freqhPlus->data->length - size)) > 0)
        memset(&(model->freqhPlus->data->data[size]),0, rem*sizeof(hptilde->data->data[0]) );

    size=hctilde->data->length;
    if(size>model->freqhCross->data->length) size=model->freqhCross->data->length;
    memcpy(model->freqhCross->data->data,hctilde->data->data,sizeof(hctilde->data->data[0])*size);
    if( (rem=(model->freqhCross->data->length - size)) > 0)
        memset(&(model->freqhCross->data->data[size]),0, rem*sizeof(hctilde->data->data[0]) );
    
    
    /* Destroy the nonGr params */
    XLALSimInspiralDestroyTestGRParam(nonGRparams);
    
    REAL8 instant = model->freqhPlus->epoch.gpsSeconds + 1e-9*model->freqhPlus->epoch.gpsNanoSeconds;
    LALInferenceSetVariable(model->params, "time", &instant);
    
  } else {

    XLAL_TRY(ret=XLALSimInspiralChooseTDWaveformFromCache(&hplus, &hcross, phi0, deltaT,
            m1*LAL_MSUN_SI, m2*LAL_MSUN_SI, spin1x, spin1y, spin1z,
            spin2x, spin2y, spin2z, f_start, f_ref, distance,
            inclination, lambda1, lambda2, model->waveFlags, nonGRparams,
            amporder, order, approximant,model->waveformCache), errnum);
    XLALSimInspiralDestroyTestGRParam(nonGRparams);
    if (ret == XLAL_FAILURE || hplus == NULL || hcross == NULL)
    {
            XLALPrintError(" ERROR in XLALSimInspiralChooseWaveformFromCache(): error generating waveform. errnum=%d\n",errnum );
            memset(model->timehPlus->data->data,0,sizeof(model->timehPlus->data->data[0]) * model->timehPlus->data->length);
            memset(model->timehCross->data->data,0,sizeof(model->timehCross->data->data[0]) * model->timehCross->data->length);
            if ( hplus ) XLALDestroyREAL8TimeSeries(hplus);
            if ( hcross ) XLALDestroyREAL8TimeSeries(hcross);
            XLALSimInspiralDestroyTestGRParam(nonGRparams);
            XLAL_ERROR_VOID(XLAL_FAILURE);
    }

    /* The following complicated mess is a result of the following considerations:
       
       1) The discrete time samples of the template and the timeModel
       buffers will not, in general line up.

       2) The likelihood function will timeshift the template in the
       frequency domain to align it properly with the desired tc in
       each detector (these are different because the detectors
       receive the signal at different times).  Because this
       timeshifting is done in the frequency domain, the effective
       time-domain template is periodic.  We want to avoid the
       possibility of non-zero template samples wrapping around from
       the start/end of the buffer, since real templates are not
       periodic!

       3) If the template apporaches the ends of the timeModel buffer,
       then it should be tapered in the same way as the timeData
       (currently 0.4 seconds, hard-coded! Tukey window; see
       LALInferenceReadData.c, near line 233) so that template and
       signal in the data match.  However, as an optimization, we
       perform only one tapering and FFT-ing in the likelihood
       function; subsequent timeshifts for the different detectors
       will cause the tapered regions of the template and data to
       become mis-aligned.

       The algorthim we use is the following:

       1) Inject the template to align with the nearest sample in the
       timeModel buffer to the desired geocent_end time.

       2) Check whether either the start or the end of the template
       overlaps the tapered region, plus a safety buffer corresponding
       to a conservative estimate of the largest geocenter <-->
       detector timeshift.
       
         a) If there is no overlap at the start or end of the buffer,
         we're done.

	 b) If there is an overlap, issue one warning per process
	 (which can be disabled by setting the LAL debug level) about
	 a too-short segment length, and return.
*/

    size_t waveLength = hplus->data->length;
    size_t bufLength = model->timehPlus->data->length;

    /* 2*Rearth/(c*deltaT)---2 is safety factor---is the maximum time
       shift for any earth-based detector. */
    size_t maxShift = (size_t)lround(4.255e-2/deltaT); 

    /* Taper 0.4 seconds at start and end (hard-coded! in
       LALInferenceReadData.c, around line 233). */
    size_t taperLength = (size_t)lround(0.4/deltaT); 

    /* Within unsafeLength of ends of buffer, possible danger of
       wrapping and/or tapering interactions. */
    size_t unsafeLength = taperLength + maxShift;

    REAL8 desiredTc = *(REAL8 *)LALInferenceGetVariable(model->params, "time");
    REAL8 tStart = XLALGPSGetREAL8(&(model->timehPlus->epoch));
    REAL8 tEnd = tStart + deltaT * model->timehPlus->data->length;

    if (desiredTc < tStart || desiredTc > tEnd) {
      XLALDestroyREAL8TimeSeries(hplus);
      XLALDestroyREAL8TimeSeries(hcross);

      XLAL_PRINT_ERROR("desired tc (%.4f) outside data buffer\n", desiredTc);
      XLAL_ERROR_VOID(XLAL_EDOM);
    }

    /* The nearest sample in model buffer to the desired tc. */
    size_t tcSample = (size_t)lround((desiredTc - XLALGPSGetREAL8(&(model->timehPlus->epoch)))/deltaT);

    /* The acutal coalescence time that corresponds to the buffer
       sample on which the waveform's tC lands. */
    REAL8 injTc = XLALGPSGetREAL8(&(model->timehPlus->epoch)) + tcSample*deltaT;

    /* The sample at which the waveform reaches tc. */
    size_t waveTcSample = (size_t)lround(-XLALGPSGetREAL8(&(hplus->epoch))/deltaT);

    /* 1 + (number of samples post-tc in waveform) */
    size_t wavePostTc = waveLength - waveTcSample;

    size_t bufStartIndex = (tcSample >= waveTcSample ? tcSample - waveTcSample : 0);
    size_t bufEndIndex = (wavePostTc + tcSample <= bufLength ? wavePostTc + tcSample : bufLength);
    size_t bufWaveLength = bufEndIndex - bufStartIndex;
    size_t waveStartIndex = (tcSample >= waveTcSample ? 0 : waveTcSample - tcSample);    

    if (bufStartIndex < unsafeLength || (bufLength - bufEndIndex) <= unsafeLength) {
      /* The waveform could be timeshifted into a region where it will
	 be tapered improperly, or even wrap around from the periodic
	 timeshift.  Issue warning. */
      if (!sizeWarning) {
	fprintf(stderr, "WARNING: Generated template is too long to guarantee that it will not\n");
	fprintf(stderr, "WARNING:  (a) lie in a tapered region of the time-domain buffer\n");
	fprintf(stderr, "WARNING:  (b) wrap periodically when timeshifted in likelihood computation\n");
	fprintf(stderr, "WARNING: Either of these may cause differences between the template and the\n");
	fprintf(stderr, "WARNING: correct GW waveform in each detector.\n");
	fprintf(stderr, "WARNING: Parameter estimation will continue, but you should consider\n");
	fprintf(stderr, "WARNING: increasing the data segment length (using the --seglen) option.\n");
	sizeWarning = 1;
      }
    }

    /* Clear model buffers */
    memset(model->timehPlus->data->data, 0, sizeof(REAL8)*model->timehPlus->data->length);
    memset(model->timehCross->data->data, 0, sizeof(REAL8)*model->timehCross->data->length);
    
    /* Inject */
    memcpy(model->timehPlus->data->data + bufStartIndex,
	   hplus->data->data + waveStartIndex,
	   bufWaveLength*sizeof(REAL8));
    memcpy(model->timehCross->data->data + bufStartIndex,
	   hcross->data->data + waveStartIndex,
	   bufWaveLength*sizeof(REAL8));

    LALInferenceSetVariable(model->params, "time", &injTc);
  }

  if ( hplus ) XLALDestroyREAL8TimeSeries(hplus);
  if ( hcross ) XLALDestroyREAL8TimeSeries(hcross);
  if ( hptilde ) XLALDestroyCOMPLEX16FrequencySeries(hptilde);
  if ( hctilde ) XLALDestroyCOMPLEX16FrequencySeries(hctilde);
  
  return;
}
void LALInferenceTemplateROQ(LALInferenceModel *model)
{
double m1,m2,mc,eta,q,iota=0;
/* Prefer m1 and m2 if available (i.e. for injection template) */
  if(LALInferenceCheckVariable(model->params,"mass1")&&LALInferenceCheckVariable(model->params,"mass2"))
  {
    m1=*(REAL8 *)LALInferenceGetVariable(model->params,"mass1");
    m2=*(REAL8 *)LALInferenceGetVariable(model->params,"mass2");
    eta=m1*m2/((m1+m2)*(m1+m2));
    mc=pow(eta , 0.6)*(m1+m2);
  }
  else
  {
    if (LALInferenceCheckVariable(model->params,"q")) {
      q = *(REAL8 *)LALInferenceGetVariable(model->params,"q");
      q2eta(q, &eta);
    }
    else
      eta = *(REAL8*) LALInferenceGetVariable(model->params, "eta");
    mc       = *(REAL8*) LALInferenceGetVariable(model->params, "chirpmass");
    mc2masses(mc, eta, &m1, &m2);
  }

  iota = acos(LALInferenceGetREAL8Variable(model->params, "costheta_jn"));     /* zenith angle between J and N in radians */

  double cosiota = cos(iota);
  double plusCoef  = 0.5 * (1.0 + cosiota*cosiota);
  double crossCoef = cosiota;
  /* external: SI; internal: solar masses */
  const REAL8 m = m1 + m2;
  const REAL8 m_sec = m * LAL_MTSUN_SI;  /* total mass in seconds */
  const REAL8 etap2 = eta * eta;
  const REAL8 etap3 = etap2 * eta;
  const REAL8 piM = LAL_PI * m_sec;
  const REAL8 mSevenBySix = -7./6.;
  const REAL8 phic = *(REAL8 *)LALInferenceGetVariable(model->params,"phase");
  const REAL8 r = 1e6*LAL_PC_SI;
  REAL8 logv0 = log(1.); //the standard tf2 definition is log(v0), but I've changed it to reflect Scott's convention
  REAL8 shft, amp0;//, f_max;
  REAL8 psiNewt, psi2, psi3, psi4, psi5, psi6, psi6L, psi7, psi3S, psi4S, psi5S;
  REAL8 eta_fac = -113. + 76. * eta;
  REAL8 chi=0; //NOTE: chi isn't used here yet, so we just set it to zero
  gsl_complex h_i;

  /* extrinsic parameters */
  amp0 = -pow(m_sec, 5./6.) * sqrt(5.*eta / 24.) / (Pi_p2by3 * r / LAL_C_SI);
  shft = 0;//LAL_TWOPI * (tStart.gpsSeconds + 1e-9 * tStart.gpsNanoSeconds);

  /* spin terms in the amplitude and phase (in terms of the reduced
   * spin parameter */
  psi3S = 113.*chi/3.;
  psi4S = 63845.*(-81. + 4.*eta)*chi*chi/(8. * eta_fac * eta_fac);
  psi5S = -565.*(-146597. + 135856.*eta + 17136.*etap2)*chi/(2268.*eta_fac);

  /* coefficients of the phase at PN orders from 0 to 3.5PN */
  psiNewt = 3./(128.*eta);
  psi2 = 3715./756. + 55.*eta/9.;
  psi3 = psi3S - 16.*LAL_PI;
  psi4 = 15293365./508032. + 27145.*eta/504. + 3085.*eta*eta/72. + psi4S;
  psi5 = (38645.*LAL_PI/756. - 65.*LAL_PI*eta/9. + psi5S);
  psi6 = 11583231236531./4694215680. - (640.*Pi_p2)/3. - (6848.*LAL_GAMMA)/21.
           + (-5162.983708047263 + 2255.*Pi_p2/12.)*eta
           + (76055.*etap2)/1728. - (127825.*etap3)/1296.;
  psi6L = -6848./21.;
  psi7 = (77096675.*LAL_PI)/254016. + (378515.*LAL_PI*eta)/1512.
           - (74045.*LAL_PI*eta*eta)/756.;

  for (unsigned int i = 0; i < model->roq->frequencyNodes->size; i++) {
    /* fourier frequency corresponding to this bin */
    const REAL8 f = gsl_vector_get(model->roq->frequencyNodes, i);
    const REAL8 v3 = piM*f;

    /* PN expansion parameter */
    REAL8 v, v2, v4, v5, v6, v7, logv, Psi, amp;
    v = cbrt(v3);
    v2 = v*v; v4 = v3*v; v5 = v4*v; v6 = v3*v3; v7 = v6*v;
    logv = log(v);

    /* compute the phase and amplitude */
    Psi = psiNewt / v5 * (1.
         + psi2 * v2 + psi3 * v3 + psi4 * v4
         + psi5 * v5 * (1. + 3. * (logv - logv0))
         + (psi6 + psi6L * (log4 + logv)) * v6 + psi7 * v7);

    amp = amp0 * pow(f, mSevenBySix);

    GSL_SET_COMPLEX(&h_i, amp * cos(Psi + shft * f - 2.*phic - LAL_PI_4), - amp * sin(Psi + shft * f - 2.*phic - LAL_PI_4));

    gsl_vector_complex_set(model->roq->hplus, i, gsl_complex_mul_real(h_i,plusCoef));
    gsl_vector_complex_set(model->roq->hcross, i, gsl_complex_mul_real(gsl_complex_mul_imag(h_i,-1.0),crossCoef));

  }
	return;
}
/**
 * \brief The log likelihood function
 *
 * This function calculates natural logarithm of the likelihood of a signal model (specified by a given set of
 * parameters) given the data from a set of detectors.
 *
 * The likelihood is the joint likelihood of chunks of data over which the noise is assumed stationary and Gaussian. For
 * each chunk a Gaussian likelihood for the noise and data has been marginalised over the unknown noise standard
 * deviation using a Jeffreys prior on the standard deviation. Given the data consisting of independent real and
 * imaginary parts this gives a Students-t distribution for each chunk (of length \f$m\f$) with \f$m/2\f$ degrees of
 * freedom:
 * \f[
 * p(\mathbf{\theta}|\mathbf{B}) = \prod_{j=1}^M \frac{(m_j-1)!}{2\pi^{m_j}}
 * \left( \sum_{k=k_0}^{k_0+(m_j-1)} |B_k - y(\mathbf{\theta})_k|^2
 * \right)^{-m_j},
 * \f]
 * where \f$\mathbf{B}\f$ is a vector of the complex data, \f$y(\mathbf{\theta})\f$ is the model for a set of parameters
 * \f$\mathbf{\theta}\f$, \f$M\f$ is the total number of independent data chunks with lengths \f$m_j\f$ and \f$k_0 =
 * \sum_{i=1}^j 1 + m_{i-1}\f$ (with \f$m_0 = 0\f$) is the index of the first data point in each chunk. The product of
 * this for each detector will give the full joint likelihood. In the calculation here the unnecessary proportionality
 * factors are left out (this would effect the actual value of the marginal likelihood/evidence, but since we are only
 * interested in evidence ratios/Bayes factors these factors would cancel out anyway. See \cite DupuisWoan2005 for a
 * more detailed description.
 *
 * In this function data in chunks smaller than a certain minimum length \c chunkMin are ignored.
 *
 * \param vars [in] The parameter values
 * \param data [in] The detector data and initial signal phase template
 * \param get_model [in] The signal template/model function
 *
 * \return The natural logarithm of the likelihood function
 */
REAL8 pulsar_log_likelihood( LALInferenceVariables *vars, LALInferenceIFOData *data,
                             LALInferenceTemplateFunction get_model){
  REAL8 loglike = 0.; /* the log likelihood */
  UINT4 i = 0;
  REAL8Vector *freqFactors = *(REAL8Vector **)LALInferenceGetVariable( data->dataParams, "freqfactors" );

  LALInferenceIFOData *datatemp1 = data, *datatemp2 = data, *datatemp3 = data;

  /* copy model parameters to data parameters */
  while( datatemp1 ){
    LALInferenceCopyVariables( vars, datatemp1->modelParams );
    datatemp1 = datatemp1->next;
  }

  /* get pulsar model */
  while( datatemp2 ){
    get_model( datatemp2 );

    for( i = 0; i < freqFactors->length; i++ ) { datatemp2 = datatemp2->next; }
  }

  while ( datatemp3 ){
    UINT4 j = 0, count = 0, cl = 0;
    UINT4 length = 0, chunkMin;
    REAL8 chunkLength = 0.;
    REAL8 logliketmp = 0.;

    REAL8 sumModel = 0., sumDataModel = 0.;
    REAL8 chiSquare = 0.;
    COMPLEX16 B, M;

    REAL8Vector *sumDat = NULL;
    UINT4Vector *chunkLengths = NULL;

    sumDat = *(REAL8Vector **)LALInferenceGetVariable( datatemp3->dataParams, "sumData" );
    chunkLengths = *(UINT4Vector **)LALInferenceGetVariable( datatemp3->dataParams, "chunkLength" );
    chunkMin = *(INT4*)LALInferenceGetVariable( datatemp3->dataParams, "chunkMin" );

    length = datatemp3->compTimeData->data->length;

    for( i = 0 ; i < length ; i += chunkLength ){
      chunkLength = (REAL8)chunkLengths->data[count];

      /* skip section of data if its length is less than the minimum allowed chunk length */
      if( chunkLength < chunkMin ){
        count++;
        continue;
      }

      sumModel = 0.;
      sumDataModel = 0.;

      cl = i + (INT4)chunkLength;

      for( j = i ; j < cl ; j++ ){
        B = datatemp3->compTimeData->data->data[j];

        M = datatemp3->compModelData->data->data[j];

        /* sum over the model */
        sumModel += creal(M)*creal(M) + cimag(M)*cimag(M);

        /* sum over that data and model */
        sumDataModel += creal(B)*creal(M) + cimag(B)*cimag(M);
      }

      chiSquare = sumDat->data[count];
      chiSquare -= 2.*sumDataModel;
      chiSquare += sumModel;

      logliketmp -= chunkLength*log(chiSquare) + LAL_LN2 * (chunkLength-1.) + gsl_sf_lnfact(chunkLength);

      count++;
    }
    loglike += logliketmp;
    datatemp3 = datatemp3->next;
  }
  return loglike;
}
int LALInferenceDrawFromPriorTest(void)
{
	TEST_HEADER();

	int errnum;
	const char *name;
	gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
	gsl_rng_set(rng, 0);

	LALInferenceVariables *output = XLALCalloc(1, sizeof(LALInferenceVariables));
	LALInferenceVariables *priorArgs = XLALCalloc(1, sizeof(LALInferenceVariables));

	// Null reference checks.
	int outcome = 1;
	XLAL_TRY(LALInferenceDrawFromPrior(NULL, priorArgs, rng), errnum);
	outcome &= errnum == XLAL_EFAULT;
	XLAL_TRY(LALInferenceDrawFromPrior(output, NULL, rng), errnum);
	outcome &= errnum == XLAL_EFAULT;
	XLAL_TRY(LALInferenceDrawFromPrior(output, priorArgs, NULL), errnum);
	outcome &= errnum == XLAL_EFAULT;
	if (!outcome)
		TEST_FAIL("Null reference check failed.");

	int i;
	const char *varyName=NULL;
	char caseTag[VARNAME_MAX];
	LALInferenceVariableType type = LALINFERENCE_REAL8_t;
	LALInferenceParamVaryType vary=-1;
	for (i = 0; i < 2; i++)
	{
		switch (i)
		{
			case 0:
				vary = LALINFERENCE_PARAM_LINEAR;
				varyName = "linear";
				break;
			case 1:
				vary = LALINFERENCE_PARAM_CIRCULAR;
				varyName = "circular";
				break;
		}
		sprintf(caseTag, "[%s] ", varyName);

		// Try and generate some normally distributed variables for various mu and sigma.
		REAL8 gaussian = 0;
		REAL8 mu;
		REAL8 sigma;
		name = "gaussian";
		LALInferenceAddVariable(output, name, &gaussian, type, vary);

		// Zero standard deviation; should always equal mean.
		mu = -50;
		sigma = 0;
		LALInferenceRemoveGaussianPrior(priorArgs, name);
		LALInferenceAddGaussianPrior(priorArgs, name, &mu, &sigma, type);
		XLAL_TRY(LALInferenceDrawFromPrior(output, priorArgs, rng), errnum);
		gaussian = *(REAL8*)LALInferenceGetVariable(output, name);
		if (errnum != XLAL_SUCCESS)
		{
			TEST_FAIL("%sFailed to generate Gaussian variable; XLAL error: %s.", caseTag, XLALErrorString(errnum));
		}
		else if (!compareFloats(gaussian, mu, EPSILON))
		{
			TEST_FAIL("%sGaussian variable with zero standard deviation did not match the mean; X = %f, mu = %f.", caseTag, gaussian, mu);
		}

		LALInferenceRemoveVariable(output, name);
		LALInferenceRemoveGaussianPrior(priorArgs, name);

		// Try a uniform variable!
		REAL8 uniform = 0;
		REAL8 min;
		REAL8 max;
		name = "uniform";
		LALInferenceAddVariable(output, name, &uniform, type, vary);

		min = -1;
		max = 1;
		LALInferenceRemoveMinMaxPrior(priorArgs, name);
		LALInferenceAddMinMaxPrior(priorArgs, name, &min, &max, type);
		XLAL_TRY(LALInferenceDrawFromPrior(output, priorArgs, rng), errnum);
		if (errnum != XLAL_SUCCESS)
			TEST_FAIL("%sFailed to generate uniform variable; XLAL error: %s.", caseTag, XLALErrorString(errnum));

		LALInferenceRemoveVariable(output, name);
		LALInferenceRemoveMinMaxPrior(priorArgs, name);

		// Try a correlated variable!
		REAL8 correlated = 0;
		UINT4 idx = 0;
		name = "correlated";
		gsl_matrix *covariance = gsl_matrix_calloc(3, 3);
		LALInferenceAddVariable(output, name, &correlated, type, vary);
		LALInferenceRemoveCorrelatedPrior(priorArgs);

		// See what happens when we try to add a non-positive-definite covariance matrix
                gsl_matrix_set(covariance, 0, 0, -1);
                XLAL_TRY(LALInferenceAddCorrelatedPrior(priorArgs, name, &covariance, &mu, &sigma, &idx), errnum);
                if (errnum == XLAL_SUCCESS)
                        TEST_FAIL("%sNon-positive-definite covariance matrix was not rejected.", caseTag);
                LALInferenceRemoveCorrelatedPrior(priorArgs);

		// Now try a positive-semi-definite matrix; this should be accepted
                covariance = gsl_matrix_calloc(3, 3);
                gsl_matrix_set(covariance, 0, 0, 1);
                XLAL_TRY(LALInferenceAddCorrelatedPrior(priorArgs, name, &covariance, &mu, &sigma, &idx), errnum);
                if (errnum != XLAL_SUCCESS)
                        TEST_FAIL("%sCould not add semi-positive-definite covariance matrix.", caseTag);
		LALInferenceRemoveCorrelatedPrior(priorArgs);

		// Try a legitimate positive-definite covariance matrix.
                covariance = gsl_matrix_calloc(3, 3);
		gsl_matrix_set(covariance, 0, 0, 2);
		gsl_matrix_set(covariance, 0, 1, 1);
		gsl_matrix_set(covariance, 0, 2, 0);
		gsl_matrix_set(covariance, 1, 0, 1);
		gsl_matrix_set(covariance, 1, 1, 5);
		gsl_matrix_set(covariance, 1, 2, 1);
		gsl_matrix_set(covariance, 2, 0, 0);
		gsl_matrix_set(covariance, 2, 1, 1);
		gsl_matrix_set(covariance, 2, 2, 1);
                XLAL_TRY(LALInferenceAddCorrelatedPrior(priorArgs, name, &covariance, &mu, &sigma, &idx), errnum);
                if (errnum != XLAL_SUCCESS)
                        TEST_FAIL("%sCould not add correlated prior.", caseTag);
                XLAL_TRY(LALInferenceDrawFromPrior(output, priorArgs, rng), errnum);
		if (errnum != XLAL_SUCCESS)
			TEST_FAIL("%sCould not generate correlated variable from positive-definite matrix; XLAL error: %s.", caseTag, XLALErrorString(errnum));

		LALInferenceRemoveVariable(output, name);
		LALInferenceRemoveCorrelatedPrior(priorArgs);

		//gsl_matrix_free(covariance);
		LALInferenceRemoveVariable(output, "gaussian");
		LALInferenceRemoveVariable(output, "uniform");
		LALInferenceRemoveVariable(output, "correlated");
	}

	XLALFree(output);
	XLALFree(priorArgs);
	TEST_FOOTER();
}
int LALInferenceCyclicReflectiveBoundTest(void)
{
	TEST_HEADER();

	int errnum;
	int outcome;

	const LALInferenceVariableType type = LALINFERENCE_REAL8_t;
	REAL8 a;
	REAL8 b;
	REAL8 a_2;
	REAL8 b_2;
	REAL8 a_min;
	REAL8 a_max;
	REAL8 a_delta;
	REAL8 b_min;
	REAL8 b_max;
	REAL8 b_delta;
	LALInferenceVariables *parameters = XLALCalloc(1, sizeof(LALInferenceVariables));
	LALInferenceVariables *priorArgs = XLALCalloc(1, sizeof(LALInferenceVariables));

	// A basic null reference check.
	outcome = 1;
	XLAL_TRY(LALInferenceCyclicReflectiveBound(NULL, priorArgs), errnum);
	outcome &= errnum == XLAL_EFAULT;
	XLAL_TRY(LALInferenceCyclicReflectiveBound(parameters, NULL), errnum);
	outcome &= errnum == XLAL_EFAULT;
	if (!outcome)
		TEST_FAIL("Null reference check failed.");
	
	// Check some (meaningful) minima/maxima.
	a_min = -LAL_PI;
	a_max = LAL_PI;
	a_delta = a_max - a_min;
	b_min = -1;
	b_max = 1;
	b_delta = b_max - b_min;
	LALInferenceRemoveMinMaxPrior(priorArgs, "a");
	LALInferenceRemoveMinMaxPrior(priorArgs, "b");
	LALInferenceAddMinMaxPrior(priorArgs, "a", &a_min, &a_max, type);
	LALInferenceAddMinMaxPrior(priorArgs, "b", &b_min, &b_max, type);

	// Variables within [min,max]: should remain unchanged.
	a = a_min + (a_max - a_min) / 2;
	b = b_min + (b_max - b_min) / 2;
	LALInferenceAddVariable(parameters, "a", &a, type, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceAddVariable(parameters, "b", &b, type, LALINFERENCE_PARAM_LINEAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	a_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "a");
	b_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "b");
	if (!compareFloats(a, a_2, EPSILON) || !compareFloats(b, b_2, EPSILON))
		TEST_FAIL("Values within bounds should remain unchanged.");

	// Boundary cases (circular): variables on [min, max] boundaries should be equal modulo period.
	outcome = 1;
	a = a_min;
	LALInferenceAddVariable(parameters, "a", &a, type, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	a_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "a");
	outcome &= compareFloats(fmod(a - a_2, a_delta), 0, EPSILON);
	a = a_max;
	LALInferenceAddVariable(parameters, "a", &a, type, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	a_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "a");
	outcome &= compareFloats(fmod(a - a_2, a_delta), 0, EPSILON);
	if (!outcome)
		TEST_FAIL("Circular boundary values should remain equal modulo their period.");

	// Boundary cases (linear): variables on [min, max] boundaries should be equal modulo period.
	outcome = 1;
	b = b_min;
	LALInferenceAddVariable(parameters, "b", &b, type, LALINFERENCE_PARAM_LINEAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	b_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "b");
	outcome &= compareFloats(b, b_2, EPSILON);
	b = b_max;
	LALInferenceAddVariable(parameters, "b", &b, type, LALINFERENCE_PARAM_LINEAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	b_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "b");
	outcome &= compareFloats(b, b_2, EPSILON);
	if (!outcome)
		TEST_FAIL("Linear boundary values should remain unchanged.");

	// Outside range (circular).
	outcome = 1;
	a = a_min - a_delta / 3;
	LALInferenceAddVariable(parameters, "a", &a, type, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	a_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "a");
	outcome &= compareFloats(a_2, a_max - a_delta / 3, EPSILON);
	a = a_max + a_delta / 3;
	LALInferenceAddVariable(parameters, "a", &a, type, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	a_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "a");
	outcome &= compareFloats(a_2, a_min + a_delta / 3, EPSILON);
	if (!outcome)
		TEST_FAIL("Circular values outside range should be correctly modded into range.");
	
	// Outside range (linear).
	outcome = 1;
	b = b_min - 10 * b_delta / 3;
	LALInferenceAddVariable(parameters, "b", &b, type, LALINFERENCE_PARAM_LINEAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	b_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "b");
	outcome &= compareFloats(b_2, b_max - b_delta / 3, EPSILON);
	b = b_max + 7 * b_delta / 5;
	LALInferenceAddVariable(parameters, "b", &b, type, LALINFERENCE_PARAM_LINEAR);
	LALInferenceCyclicReflectiveBound(parameters, priorArgs);
	b_2 = *(REAL8 *)LALInferenceGetVariable(parameters, "b");
	outcome &= compareFloats(b_2, b_min + 2 * b_delta / 5, EPSILON);
	if (!outcome)
		TEST_FAIL("Linear values outside range should be correctly reflected into range.");

	XLALFree(parameters);
	XLALFree(priorArgs);
	TEST_FOOTER();
}
int LALInferenceRotateInitialPhaseTest(void)
{
	TEST_HEADER();

	int errnum;

	// A basic null reference check.
	XLAL_TRY(LALInferenceRotateInitialPhase(NULL), errnum);
	if (errnum != XLAL_EFAULT)
		TEST_FAIL("Null reference check failed.");

	// Construct a variable list containing phi0 and psi.
	REAL8 psi = 0;
	REAL8 phi0 = 0;
	REAL8 phi0_2 = 0;
	LALInferenceVariables *variables = XLALCalloc(1, sizeof(LALInferenceVariables));
	LALInferenceAddVariable(variables, "psi", &psi, LALINFERENCE_REAL8_t, LALINFERENCE_PARAM_CIRCULAR);
	LALInferenceAddVariable(variables, "phi0", &phi0, LALINFERENCE_REAL8_t, LALINFERENCE_PARAM_CIRCULAR);

	// Check that if psi is in [0,2pi], phi0 remains unchanged.
	psi = LAL_PI;
	phi0 = 0;
	LALInferenceSetVariable(variables, "psi", &psi);
	LALInferenceSetVariable(variables, "phi0", &phi0);
	LALInferenceRotateInitialPhase(variables);
	phi0_2 = *(REAL8 *)LALInferenceGetVariable(variables, "phi0");
	if (!compareFloats(phi0_2, phi0, EPSILON))
		TEST_FAIL("Psi in [0,2pi] but phi0 has changed!");

	// Check that if psi is outside [0,2pi], phi0 is rotated.
	psi = -2 * LAL_TWOPI;
	phi0 = 0;
	LALInferenceSetVariable(variables, "psi", &psi);
	LALInferenceSetVariable(variables, "phi0", &phi0);
	LALInferenceRotateInitialPhase(variables);
	phi0_2 = *(REAL8 *)LALInferenceGetVariable(variables, "phi0");
	if (!compareFloats(phi0_2, phi0 + LAL_PI, EPSILON))
		TEST_FAIL("Psi outside [0,2pi] but phi0 not rotated by 2pi!");
	psi = 2 * LAL_TWOPI;
	phi0 = 0;
	LALInferenceSetVariable(variables, "psi", &psi);
	LALInferenceSetVariable(variables, "phi0", &phi0);
	LALInferenceRotateInitialPhase(variables);
	phi0_2 = *(REAL8 *)LALInferenceGetVariable(variables, "phi0");
	if (!compareFloats(phi0_2, phi0 + LAL_PI, EPSILON))
		TEST_FAIL("Psi outside [0,2pi] but phi0 not rotated by 2pi!");

	// Check boundary cases: if psi=0 or psi=2pi, phi0 shouldn't be rotated.
	psi = 0;
	phi0 = 0;
	LALInferenceSetVariable(variables, "psi", &psi);
	LALInferenceSetVariable(variables, "phi0", &phi0);
	LALInferenceRotateInitialPhase(variables);
	phi0_2 = *(REAL8 *)LALInferenceGetVariable(variables, "phi0");
	if (phi0 != phi0_2) // Should be exact.)
		TEST_FAIL("Psi on boundary of [0,2pi] but phi0 has changed!");
	psi = LAL_TWOPI;
	phi0 = 0;
	LALInferenceSetVariable(variables, "psi", &psi);
	LALInferenceSetVariable(variables, "phi0", &phi0);
	LALInferenceRotateInitialPhase(variables);
	phi0_2 = *(REAL8 *)LALInferenceGetVariable(variables, "phi0");
	if (phi0 != phi0_2) // Should be exact.)
		TEST_FAIL("Psi on boundary of [0,2pi] but phi0 has changed!");

	XLALFree(variables);
	TEST_FOOTER();
}