// compare two SFTs, return XLAL_SUCCESS if OK, error otherwise
int
XLALCompareSFTs ( const SFTtype *sft1, const SFTtype *sft2, const VectorComparison *tol )
{
  // check input sanity
  XLAL_CHECK ( sft1 != NULL, XLAL_EINVAL );
  XLAL_CHECK ( sft2 != NULL, XLAL_EINVAL );
  XLAL_CHECK ( tol  != NULL, XLAL_EINVAL );

  XLAL_CHECK ( XLALGPSCmp ( &(sft1->epoch), &(sft2->epoch) ) == 0, XLAL_ETOL );
  REAL8 tolFreq = 10 * LAL_REAL8_EPS;
  REAL8 err_f0 = sft1->f0 - sft2->f0;
  XLAL_CHECK ( err_f0 < tolFreq, XLAL_ETOL, "f0_1 = %.16g, f0_2 = %.16g, relErr_f0 = %g (tol = %g)\n", sft1->f0, sft2->f0, err_f0, tolFreq );
  REAL8 relErr_df = RELERR ( sft1->deltaF, sft2->deltaF );
  XLAL_CHECK ( relErr_df < tolFreq, XLAL_ETOL, "dFreq1 = %g, dFreq2 = %g, relErr_df = %g (tol = %g)", sft1->deltaF, sft2->deltaF, relErr_df, tolFreq );

  XLAL_CHECK ( XLALUnitCompare( &(sft1->sampleUnits), &(sft2->sampleUnits) ) == 0, XLAL_ETOL );

  XLAL_CHECK ( sft1->data->length == sft2->data->length, XLAL_ETOL, "sft1->length = %d, sft2->length = %d\n", sft1->data->length, sft2->data->length  );

  VectorComparison XLAL_INIT_DECL(cmp);
  XLAL_CHECK ( XLALCompareCOMPLEX8Vectors ( &cmp, sft1->data, sft2->data, tol ) == XLAL_SUCCESS, XLAL_EFUNC );

  return XLAL_SUCCESS;

} // XLALCompareSFTs()
Esempio n. 2
0
static int CompareSFTVectors(SFTVector *sft_vect, SFTVector *sft_vect2)
{
  UINT4 sft,bin;
  if (sft_vect->length != sft_vect2->length) {
    XLALPrintError ( "CompareSFTVectors(): vector lengths differ!\n");
    return(-1);
  }
  for(sft=0; sft < sft_vect->length; sft++) {
    SFTtype sft1 = sft_vect->data[sft];
    SFTtype sft2 = sft_vect2->data[sft];
    if ((sft1.epoch.gpsSeconds != sft1.epoch.gpsSeconds) ||
	(sft1.epoch.gpsNanoSeconds != sft1.epoch.gpsNanoSeconds)) {
      XLALPrintError ( "CompareSFTVectors(): SFT#%u epochs differ (%f/%f)!\n",
		       sft, GPS2REAL8(sft1.epoch), GPS2REAL8(sft2.epoch) );
      return(-1);
    }
    if (!sft1.name || !sft2.name || strcmp(sft1.name,sft2.name)) {
      XLALPrintError ( "CompareSFTVectors(): SFT#%u names differ!\n", sft);
      return(-1);
    }
    if (sft1.f0 != sft2.f0) {
      XLALPrintError ( "CompareSFTVectors(): f0 of SFT#%u differ (%f/%f)!\n",
		       sft, sft1.f0, sft2.f0 );
      return(-1);
    }
    if (sft1.deltaF != sft2.deltaF) {
      XLALPrintError ( "CompareSFTVectors(): deltaF of SFT#%u differ (%f/%f)!\n",
		       sft, sft1.deltaF, sft2.deltaF );
      return(-1);
    }
    if (XLALUnitCompare(&sft1.sampleUnits,&sft2.sampleUnits)) {
      CHAR buf1[256], buf2[256];
      if(!XLALUnitAsString(buf1,256,&sft1.sampleUnits))
	*buf1 = '\0';
      if(!XLALUnitAsString(buf2,256,&sft2.sampleUnits))
	*buf2 = '\0';
      XLALPrintError ( "CompareSFTVectors(): Units of SFT#%u differ (%s/%s)!\n",
		       sft,buf1,buf2 );
      return(-1);
    }
    if (sft1.data->length != sft2.data->length) {
      XLALPrintError ( "CompareSFTVectors(): lengths of SFT#%u differ!\n", sft);
      return(-1);
    }
    for(bin=0; bin < sft1.data->length; bin++) {
      if((crealf(sft1.data->data[bin]) != crealf(sft2.data->data[bin])) ||
	 (cimagf(sft1.data->data[bin]) != cimagf(sft2.data->data[bin]))) {
	XLALPrintError ( "CompareSFTVectors(): bins %u of SFT#%u differ!\n", sft, bin);
	return(-1);
      }
    }
  }
  return(0);
}
Esempio n. 3
0
int main( void )
{
  static LALStatus status;

  REAL4Sequence       *sSequenceIn;
  REAL4Sequence       *sSequenceOut;
  REAL8Sequence       *dSequenceIn;
  REAL8Sequence       *dSequenceOut;

  COMPLEX8Sequence    *cSequenceIn;
  COMPLEX8Sequence    *cSequenceOut;
  COMPLEX16Sequence   *zSequenceIn;
  COMPLEX16Sequence   *zSequenceOut;


  REAL4FrequencySeries      sFrequencySeries;
  REAL8FrequencySeries      dFrequencySeries;
  COMPLEX8FrequencySeries   cFrequencySeries;
  COMPLEX16FrequencySeries  zFrequencySeries;

  REAL4FrequencySeries      sFrequencySeries2;
  REAL8FrequencySeries      dFrequencySeries2;
  COMPLEX8FrequencySeries   cFrequencySeries2;
  COMPLEX16FrequencySeries  zFrequencySeries2;

  REAL4TimeSeries           sTimeSeries;
  REAL8TimeSeries           dTimeSeries;
  COMPLEX8TimeSeries        cTimeSeries;
  COMPLEX16TimeSeries       zTimeSeries;

  REAL4TimeSeries           sTimeSeries2;
  REAL8TimeSeries           dTimeSeries2;
  COMPLEX8TimeSeries        cTimeSeries2;
  COMPLEX16TimeSeries       zTimeSeries2;

  REAL4            *sData;
  REAL8            *dData;
  COMPLEX8         *cData;
  COMPLEX16        *zData;

  /* Boolean Vars */
  BOOLEAN     unitComp;

  /* variables for units */
  RAT4        raise;
  LALUnit     strainToMinus2;
  LALUnit     adcToMinus2;
  LALUnit     adcStrain;


  /* This routine should generate a file with data */
  /* to be read by ReadFTSeries.c*/
  LIGOTimeGPS  t;
  UINT4         i;


  /* Data Test Variable */
  UINT4   j;


  fprintf(stderr,"Testing value of LALUnitTextSize ... ");
  if ( (int)LALSupportUnitTextSize != (int)LALUnitTextSize )
  {
    fprintf(stderr,"UnitTextSize mismatch: [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  fprintf(stderr,"PASS\n");

  t.gpsSeconds = 0;
  t.gpsNanoSeconds = 0;

  fprintf(stderr,"Testing Print/Read COMPLEX8FrequencySeries ... ");

  cSequenceIn = NULL;
  LALCCreateVector(&status, &cSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }
  for ( i=1, cData=cSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, cData++ )
  {
    *(cData) = crectf( i, i+1 );
    }

  strncpy(cFrequencySeries.name,"Complex frequency series",LALNameLength);
  cFrequencySeries.sampleUnits = lalHertzUnit;
  cFrequencySeries.deltaF = 1;
  cFrequencySeries.epoch = t;
  cFrequencySeries.f0 = 5;

  cFrequencySeries.data = cSequenceIn;

  LALCPrintFrequencySeries(&cFrequencySeries, "cFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  cSequenceOut = NULL;
  LALCCreateVector( &status, &cSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  cFrequencySeries2.data = cSequenceOut;

  LALCReadFrequencySeries(&status, &cFrequencySeries2, "./cFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(cFrequencySeries.deltaF - cFrequencySeries.deltaF)/
      cFrequencySeries.deltaF > READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"DeltaF MisMatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (strcmp(cFrequencySeries.name,cFrequencySeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((cFrequencySeries.epoch.gpsSeconds) !=
      (cFrequencySeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Second Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((cFrequencySeries.epoch.gpsNanoSeconds) !=
      (cFrequencySeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch NanosecondMismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((cFrequencySeries.f0) ?
      (fabs(cFrequencySeries.f0 - cFrequencySeries2.f0)/cFrequencySeries.f0) :
      (fabs(cFrequencySeries.f0 - cFrequencySeries2.f0)  >
      READFTSERIESTEST_TOL))
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  unitComp = XLALUnitCompare(&cFrequencySeries.sampleUnits,&cFrequencySeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Units Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  for (j = 0; j < cSequenceIn->length;j++)
  {
    if ((crealf(cSequenceIn->data[j]) ?
	 fabs((crealf(cSequenceIn->data[j]) - crealf(cSequenceOut->data[j]))
	      /crealf(cSequenceIn->data[j]))
	 :fabs(crealf(cSequenceIn->data[j]) - crealf(cSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
    if ((cimagf(cSequenceIn->data[j]) ?
	 fabs((cimagf(cSequenceIn->data[j]) - cimagf(cSequenceOut->data[j]))
	      /cimagf(cSequenceIn->data[j]))
	 :fabs(cimagf(cSequenceIn->data[j]) - cimagf(cSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read COMPLEX16FrequencySeries ... ");

  /* Test case 2 */

  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  zSequenceIn = NULL;
  LALZCreateVector( &status, &zSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  for ( i=1, zData=zSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, zData++ )
  {
    *(zData) = crect( i/4.0, (i+1)/5.0 );
  }
  zFrequencySeries.sampleUnits = lalDimensionlessUnit;
  strncpy(zFrequencySeries.name,"Complex frequency series",LALNameLength);
  zFrequencySeries.deltaF = 1.3;
  zFrequencySeries.epoch = t;
  zFrequencySeries.f0 = 0;
  zFrequencySeries.data = zSequenceIn;

  LALZPrintFrequencySeries(&zFrequencySeries, "zFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  zSequenceOut = NULL;
  LALZCreateVector( &status, &zSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  zFrequencySeries2.data = zSequenceOut;

  LALZReadFrequencySeries(&status, &zFrequencySeries2, "./zFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if ((zFrequencySeries.deltaF) != (zFrequencySeries2.deltaF))
  {
    fprintf(stderr,"DeltaF Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (strcmp(zFrequencySeries.name,zFrequencySeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((zFrequencySeries.epoch.gpsSeconds) !=
      (zFrequencySeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((zFrequencySeries.epoch.gpsNanoSeconds) !=
      (zFrequencySeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch NanoSeconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (zFrequencySeries.f0 ?
       (fabs(zFrequencySeries.f0 - zFrequencySeries2.f0)/zFrequencySeries.f0)
       : (fabs(zFrequencySeries.f0 - zFrequencySeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  unitComp = XLALUnitCompare(&zFrequencySeries.sampleUnits,&zFrequencySeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Units Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  for (j = 0; j < zSequenceIn->length;j++)
  {
    if ((creal(zSequenceIn->data[j]) ?
	fabs((creal(zSequenceIn->data[j]) - creal(zSequenceOut->data[j]))
	     /creal(zSequenceIn->data[j])) :
	fabs(creal(zSequenceIn->data[j]) - creal(zSequenceOut->data[j]))) >
	READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
   if ((cimag(zSequenceIn->data[j]) ?
	fabs((cimag(zSequenceIn->data[j]) - cimag(zSequenceOut->data[j]))
	     /cimag(zSequenceIn->data[j])) :
	fabs(cimag(zSequenceIn->data[j]) - cimag(zSequenceOut->data[j]))) >
	READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read REAL8FrequencySeries ... ");

  /* Test case 3 */
  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  dSequenceIn = NULL;
  LALDCreateVector( &status, &dSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  for ( i=1, dData=dSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, dData++ )
  {
    *(dData) = 0.005;
  }

  strncpy(dFrequencySeries.name,"Complex frequency series",LALNameLength);
  /* set units */
  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&dFrequencySeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  dFrequencySeries.deltaF = 1.3;
  dFrequencySeries.epoch = t;
  dFrequencySeries.f0 = 0;
  dFrequencySeries.data = dSequenceIn;
  LALDPrintFrequencySeries(&dFrequencySeries, "dFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  dSequenceOut = NULL;
  LALDCreateVector( &status, &dSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  dFrequencySeries2.data = dSequenceOut;

  LALDReadFrequencySeries(&status, &dFrequencySeries2, "./dFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if ((dFrequencySeries.deltaF) != (dFrequencySeries.deltaF))
  {
    fprintf(stderr,"DeltaF Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (strcmp(dFrequencySeries.name,dFrequencySeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((dFrequencySeries.epoch.gpsSeconds)
      != (dFrequencySeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((dFrequencySeries.epoch.gpsSeconds)
      != (dFrequencySeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch NanoSeconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (dFrequencySeries.f0 ?
       (fabs(dFrequencySeries.f0 - dFrequencySeries2.f0)/dFrequencySeries.f0)
       : (fabs(dFrequencySeries.f0 - dFrequencySeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&dFrequencySeries.sampleUnits,&dFrequencySeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Unit Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }


  for (j = 0; j < dSequenceIn->length;j++)
  {
    if ((dSequenceIn->data[j] ?
	 fabs((dSequenceIn->data[j] - dSequenceOut->data[j])
	      /dSequenceIn->data[j])
	 :fabs(dSequenceIn->data[j] - dSequenceOut->data[j])) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }

  }


  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read REAL4FrequencySeries ... ");


 /* Test case 4 */
  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  sSequenceIn = NULL;
  LALSCreateVector( &status, &sSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  for ( i=1, sData=sSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, sData++ )
  {
    *(sData) = 0.005;
  }

  strncpy(sFrequencySeries.name,"Complex frequency series",LALNameLength);
  /* set units */
  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&sFrequencySeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  sFrequencySeries.deltaF = 1.3;
  sFrequencySeries.epoch = t;
  sFrequencySeries.f0 = 5;
  sFrequencySeries.data = sSequenceIn;

  sSequenceOut = NULL;
  LALSCreateVector( &status, &sSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  sFrequencySeries2.data = sSequenceOut;
  LALSPrintFrequencySeries(&sFrequencySeries, "sFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALSReadFrequencySeries(&status, &sFrequencySeries2, "./sFSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(sFrequencySeries.deltaF - sFrequencySeries2.deltaF)
      /sFrequencySeries.deltaF > READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"Deltaf Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if (strcmp(sFrequencySeries.name,sFrequencySeries2.name)!=0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if ((sFrequencySeries.epoch.gpsSeconds) !=
      (sFrequencySeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((sFrequencySeries.epoch.gpsNanoSeconds) !=
      (sFrequencySeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch NanoSeconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (sFrequencySeries.f0 ?
       (fabs(sFrequencySeries.f0 - sFrequencySeries2.f0)/sFrequencySeries.f0)
       : (fabs(sFrequencySeries.f0 - sFrequencySeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&sFrequencySeries.sampleUnits,&sFrequencySeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Unit Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  for (j = 0; j < sSequenceIn->length;j++)
  {
    if ((sSequenceIn->data[j] ?
	 fabs((sSequenceIn->data[j] - sSequenceOut->data[j])
	      /sSequenceIn->data[j])
	 :fabs(sSequenceIn->data[j] - sSequenceOut->data[j])) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }


  LALCDestroyVector(&status, &cSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALCDestroyVector(&status, &cSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALZDestroyVector(&status, &zSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }
  LALZDestroyVector(&status, &zSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALDDestroyVector(&status, &dSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALDDestroyVector(&status, &dSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALSDestroyVector(&status, &sSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALSDestroyVector(&status, &sSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  fprintf(stderr,"PASS\n");


  fprintf(stderr,"Testing Print/Read REAL4TimeSeries ... ");

  /* Here is where testing for ReadTimeSeries is done */
  /* S Case ReadTimeSeries */

  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&sTimeSeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  sSequenceIn = NULL;
  LALSCreateVector( &status, &sSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  for ( i=1, sData=sSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, sData++ )
  {
    *(sData) = 0.005;
  }
  strncpy(sTimeSeries.name,"Real4 Time series",LALNameLength);
  sTimeSeries.deltaT = 1.3;
  sTimeSeries.epoch = t;
  sTimeSeries.data = sSequenceIn;
  sTimeSeries.f0 = 5;
  LALSPrintTimeSeries(&sTimeSeries, "sTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  sSequenceOut = NULL;
  LALSCreateVector( &status, &sSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  sTimeSeries2.data = sSequenceOut;

  LALSReadTimeSeries(&status, &sTimeSeries2, "./sTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(sTimeSeries.deltaT-sTimeSeries2.deltaT) /
      sTimeSeries.deltaT > READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"DeltaT Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if (strcmp(sFrequencySeries.name,sFrequencySeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if ((sTimeSeries.epoch.gpsSeconds) != (sTimeSeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((sTimeSeries.epoch.gpsNanoSeconds) != (sTimeSeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch NanoSeconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  /*  printf("%f ... %f  f0 value\n",sTimeSeries.f0,sTimeSeries2.f0);*/
  if (sTimeSeries.f0 ?
       (fabs(sTimeSeries.f0 - sTimeSeries2.f0)/sTimeSeries.f0)
       : (fabs(sTimeSeries.f0 - sTimeSeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&sTimeSeries.sampleUnits,&sTimeSeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Units Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  for (j = 0; j < sSequenceIn->length;j++)
  {
    if ((sSequenceIn->data[j] ?
	 fabs((sSequenceIn->data[j] - sSequenceOut->data[j])
	      /sSequenceIn->data[j])
	 :fabs(sSequenceIn->data[j] - sSequenceOut->data[j])) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read COMPLEX16TimeSeries ... ");

  /* Z case ReadTimeSeries*/

  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&zTimeSeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  zSequenceIn = NULL;
  LALZCreateVector( &status, &zSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  for ( i=1, zData=zSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, zData++ )
  {
    *(zData) = crect( 0.005, 1 );
  }
  strncpy(zTimeSeries.name,"Complex16 Time series",LALNameLength);
  zTimeSeries.deltaT = 1.3;
  zTimeSeries.epoch = t;
  zTimeSeries.data = zSequenceIn;
  zTimeSeries.f0 = 0;
  LALZPrintTimeSeries(&zTimeSeries, "zTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  zSequenceOut = NULL;
  LALZCreateVector( &status, &zSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  zTimeSeries2.data = zSequenceOut;

  LALZReadTimeSeries(&status, &zTimeSeries2, "./zTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(zTimeSeries.deltaT) - (zTimeSeries2.deltaT)/zTimeSeries.deltaT >
      READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"Mismatch DeltaT [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }


  if (strcmp(zTimeSeries.name,zTimeSeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if ((zTimeSeries.epoch.gpsSeconds) != (zTimeSeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Second Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ( (zTimeSeries.epoch.gpsNanoSeconds)
       != (zTimeSeries2.epoch.gpsNanoSeconds) )
  {
    fprintf(stderr,"Epoch Nanosecond Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if (zTimeSeries.f0 ?
       (fabs(zTimeSeries.f0 - zTimeSeries2.f0)/zTimeSeries.f0)
       : (fabs(zTimeSeries.f0 - zTimeSeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&zTimeSeries.sampleUnits,&zTimeSeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Unit Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFUN;
  }

  for (j = 0; j < zSequenceIn->length;j++)
  {
    if ((creal(zSequenceIn->data[j]) ?
	 fabs((creal(zSequenceIn->data[j]) - creal(zSequenceOut->data[j]))
	      /creal(zSequenceIn->data[j]))
	 :fabs(creal(zSequenceIn->data[j]) - creal(zSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
    if ((cimag(zSequenceIn->data[j]) ?
	 fabs((cimag(zSequenceIn->data[j]) - cimag(zSequenceOut->data[j]))
	      /cimag(zSequenceIn->data[j]))
	 :fabs(cimag(zSequenceIn->data[j]) - cimag(zSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read REAL8TimeSeries ... ");

  /* D case  ReadTimeSeries*/

  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }
  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&sTimeSeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  strncpy(dTimeSeries.name,"REAL8 Time series",LALNameLength);
  dTimeSeries.sampleUnits = lalHertzUnit;
  t.gpsSeconds = 4578;
  t.gpsNanoSeconds = 890634;

  dSequenceIn = NULL;
  LALDCreateVector( &status, &dSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }


  for ( i=1, dData=dSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, dData++ )
  {
    *(dData) = 0.005;
  }

  dTimeSeries.deltaT = 1.3;
  dTimeSeries.epoch = t;
  dTimeSeries.data = dSequenceIn;
  dTimeSeries.f0 = 0;
  LALDPrintTimeSeries(&dTimeSeries, "dTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  dSequenceOut = NULL;
  LALDCreateVector( &status, &dSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  dTimeSeries2.data = dSequenceOut;
  LALDReadTimeSeries(&status, &dTimeSeries2, "./dTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(dTimeSeries.deltaT) - (dTimeSeries2.deltaT)/dTimeSeries.deltaT
      > READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"DeltaT Mismatch [ReadFTSeriesTest:%d,%s]\n",status.statusCode,
	    status.statusDescription );
    return READFTSERIESTESTC_EFLS;
  }
  if (strcmp(dTimeSeries.name,dTimeSeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%d,%s]\n",status.statusCode,
	    status.statusDescription );
    return READFTSERIESTESTC_EFLS;
  }

  if ((dTimeSeries.epoch.gpsSeconds) != (dTimeSeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if ((dTimeSeries.epoch.gpsNanoSeconds)
      != (dTimeSeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch Nanoseconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if (dTimeSeries.f0 ?
       (fabs(dTimeSeries.f0 - dTimeSeries2.f0)/dTimeSeries.f0)
       : (fabs(dTimeSeries.f0 - dTimeSeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&dTimeSeries.sampleUnits,&dTimeSeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Unit Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  for (j = 0; j < dSequenceIn->length;j++)
  {
    if ((dSequenceIn->data[j] ?
	 fabs((dSequenceIn->data[j] - dSequenceOut->data[j])
	      /dSequenceIn->data[j])
	 :fabs(dSequenceIn->data[j] - dSequenceOut->data[j])) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  fprintf(stderr,"Testing Print/Read COMPLEX8TimeSeries ... ");

  /* C case ReadTimeSeries*/

  raise.numerator = -2;
  raise.denominatorMinusOne = 0;
  if (XLALUnitRaiseRAT4(&strainToMinus2, &lalStrainUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitRaiseRAT4(&adcToMinus2, &lalADCCountUnit, &raise) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&(adcStrain), &strainToMinus2, &adcToMinus2) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (XLALUnitMultiply(&cTimeSeries.sampleUnits, &adcStrain, &lalHertzUnit) == NULL)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  t.gpsSeconds = 45678;
  t.gpsNanoSeconds = 89065834;

  cSequenceIn = NULL;
  LALCCreateVector( &status, &cSequenceIn, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  for ( i=1, cData=cSequenceIn->data; i<=READFTSERIESTEST_LEN ; i++, cData++ )
  {
    *(cData) = crectf( 0.005, 1 );
  }
  strncpy(cTimeSeries.name,"Complex8 Time series",LALNameLength);
  cTimeSeries.deltaT = 1.3;
  cTimeSeries.epoch = t;
  cTimeSeries.data = cSequenceIn;
  cTimeSeries.f0 = 0;
  cSequenceOut = NULL;
  LALCPrintTimeSeries(&cTimeSeries, "cTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }
  LALCCreateVector( &status, &cSequenceOut, READFTSERIESTEST_LEN);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  cTimeSeries2.data = cSequenceOut;

  LALCReadTimeSeries(&status, &cTimeSeries2, "./cTSInput.dat");
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  if (fabs(cTimeSeries.deltaT - cTimeSeries2.deltaT)/cTimeSeries.deltaT
      > READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"DeltaT Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  if (strcmp(cTimeSeries.name,cTimeSeries2.name) != 0)
  {
    fprintf(stderr,"Name Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((cTimeSeries.epoch.gpsSeconds) != (cTimeSeries2.epoch.gpsSeconds))
  {
    fprintf(stderr,"Epoch Seconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if ((cTimeSeries.epoch.gpsNanoSeconds)!=(cTimeSeries2.epoch.gpsNanoSeconds))
  {
    fprintf(stderr,"Epoch Nanoseconds Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }
  if (cTimeSeries.f0 ?
       (fabs(cTimeSeries.f0 - cTimeSeries2.f0)/cTimeSeries.f0)
       : (fabs(cTimeSeries.f0 - cTimeSeries2.f0)) >
       READFTSERIESTEST_TOL)
  {
    fprintf(stderr,"f0 Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  unitComp = XLALUnitCompare(&cTimeSeries.sampleUnits,&cTimeSeries2.sampleUnits);

  if (unitComp != 0)
  {
    fprintf(stderr,"Units Mismatch [ReadFTSeriesTest:%s]\n",
	    READFTSERIESTESTC_MSGEFLS);
    return READFTSERIESTESTC_EFLS;
  }

  for (j = 0; j < cSequenceIn->length;j++)
  {
    if ((crealf(cSequenceIn->data[j]) ?
	 fabs((crealf(cSequenceIn->data[j]) - crealf(cSequenceOut->data[j]))
	      /crealf(cSequenceIn->data[j]))
	 :fabs(crealf(cSequenceIn->data[j]) - crealf(cSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
    if ((cimagf(cSequenceIn->data[j]) ?
	 fabs((cimagf(cSequenceIn->data[j]) - cimagf(cSequenceOut->data[j]))
	      /cimagf(cSequenceIn->data[j]))
	 :fabs(cimagf(cSequenceIn->data[j]) - cimagf(cSequenceOut->data[j]))) >
	 READFTSERIESTEST_TOL)
    {
      fprintf(stderr,"Data Tolerance Exceeded [ReadFTSeriesTest:%s]\n",
	      READFTSERIESTESTC_MSGEFLS);
      return READFTSERIESTESTC_EFLS;
    }
  }

  fprintf(stderr,"PASS\n");

  /* *******************Deallocate all memory****************** */
  LALCDestroyVector(&status, &cSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALCDestroyVector(&status, &cSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALZDestroyVector(&status, &zSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALZDestroyVector(&status, &zSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALDDestroyVector(&status, &dSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALDDestroyVector(&status, &dSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALSDestroyVector(&status, &sSequenceIn);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALSDestroyVector(&status, &sSequenceOut);
  if (status.statusCode != 0)
  {
    fprintf(stderr,"[%i]: %s [ReadFTSeriesTest:%s]\n",status.statusCode,
	    status.statusDescription, READFTSERIESTESTC_MSGEFUN);
    return READFTSERIESTESTC_EFUN;
  }

  LALCheckMemoryLeaks();

  fprintf(stderr,"ReadFTSeries passed all tests.\n");

  return READFTSERIESTESTC_ENOM;

}
/**
 * \author Creighton, T. D.
 *
 * \brief Computes the response of a detector to a coherent gravitational wave.
 *
 * This function takes a quasiperiodic gravitational waveform given in
 * <tt>*signal</tt>, and estimates the corresponding response of the
 * detector whose position, orientation, and transfer function are
 * specified in <tt>*detector</tt>.  The result is stored in
 * <tt>*output</tt>.
 *
 * The fields <tt>output-\>epoch</tt>, <tt>output->deltaT</tt>, and
 * <tt>output-\>data</tt> must already be set, in order to specify the time
 * period and sampling rate for which the response is required.  If
 * <tt>output-\>f0</tt> is nonzero, idealized heterodyning is performed (an
 * amount \f$2\pi f_0(t-t_0)\f$ is subtracted from the phase before computing
 * the sinusoid, where \f$t_0\f$ is the heterodyning epoch defined in
 * \c detector).  For the input signal, <tt>signal-\>h</tt> is ignored,
 * and the signal is treated as zero at any time for which either
 * <tt>signal-\>a</tt> or <tt>signal-\>phi</tt> is not defined.
 *
 * This routine will convert <tt>signal-\>position</tt> to equatorial
 * coordinates, if necessary.
 *
 * ### Algorithm ###
 *
 * The routine first accounts for the time delay between the detector and
 * the solar system barycentre, based on the detector position
 * information stored in <tt>*detector</tt> and the propagation direction
 * specified in <tt>*signal</tt>.  Values of the propagation delay are
 * precomuted at fixed intervals and stored in a table, with the
 * intervals \f$\Delta T_\mathrm{delay}\f$ chosen such that the value
 * interpolated from adjacent table entries will never differ from the
 * true value by more than some timing error \f$\sigma_T\f$.  This implies
 * that:
 * \f[
 * \Delta T_\mathrm{delay} \leq \sqrt{
 * \frac{8\sigma_T}{\max\{a/c\}} } \; ,
 * \f]
 * where \f$\max\{a/c\}=1.32\times10^{-10}\mathrm{s}^{-1}\f$ is the maximum
 * acceleration of an Earth-based detector in the barycentric frame.  The
 * total propagation delay also includes Einstein and Shapiro delay, but
 * these are more slowly varying and thus do not constrain the table
 * spacing.  At present, a 400s table spacing is hardwired into the code,
 * implying \f$\sigma_T\approx3\mu\f$s, comparable to the stated accuracy of
 * <tt>LALBarycenter()</tt>.
 *
 * Next, the polarization response functions of the detector
 * \f$F_{+,\times}(\alpha,\delta)\f$ are computed for every 10 minutes of the
 * signal's duration, using the position of the source in <tt>*signal</tt>,
 * the detector information in <tt>*detector</tt>, and the function
 * <tt>LALComputeDetAMResponseSeries()</tt>.  Subsequently, the
 * polarization functions are estimated for each output sample by
 * interpolating these precomputed values.  This guarantees that the
 * interpolated value is accurate to \f$\sim0.1\%\f$.
 *
 * Next, the frequency response of the detector is estimated in the
 * quasiperiodic limit as follows:
 * <ul>
 * <li> At each sample point in <tt>*output</tt>, the propagation delay is
 * computed and added to the sample time, and the instantaneous
 * amplitudes \f$A_1\f$, \f$A_2\f$, frequency \f$f\f$, phase \f$\phi\f$, and polarization
 * shift \f$\Phi\f$ are found by interpolating the nearest values in
 * <tt>signal-\>a</tt>, <tt>signal-\>f</tt>, <tt>signal-\>phi</tt>, and
 * <tt>signal-\>shift</tt>, respectively.  If <tt>signal-\>f</tt> is not
 * defined at that point in time, then \f$f\f$ is estimated by differencing
 * the two nearest values of \f$\phi\f$, as \f$f\approx\Delta\phi/2\pi\Delta
 * t\f$.  If <tt>signal-\>shift</tt> is not defined, then \f$\Phi\f$ is treated as
 * zero.</li>
 * <li> The complex transfer function of the detector the frequency \f$f\f$
 * is found by interpolating <tt>detector-\>transfer</tt>.  The amplitude of
 * the transfer function is multiplied with \f$A_1\f$ and \f$A_2\f$, and the
 * phase of the transfer function is added to \f$\phi\f$,</li>
 * <li> The plus and cross contributions \f$o_+\f$, \f$o_\times\f$ to the
 * detector output are computed as in \eqref{eq_quasiperiodic_hpluscross}
 * of \ref PulsarSimulateCoherentGW_h, but
 * using the response-adjusted amplitudes and phase.</li>
 * <li> The final detector response \f$o\f$ is computed as
 * \f$o=(o_+F_+)+(o_\times F_\times)\f$.</li>
 * </ul>
 *
 * ### A note on interpolation: ###
 *
 * Much of the computational work in this routine involves interpolating
 * various time series to find their values at specific output times.
 * The algorithm is summarized below.
 *
 * Let \f$A_j = A( t_A + j\Delta t_A )\f$ be a sampled time series, which we
 * want to resample at new (output) time intervals \f$t_k = t_0 + k\Delta
 * t\f$.  We first precompute the following quantities:
 * \f{eqnarray}{
 * t_\mathrm{off} & = & \frac{t_0-t_A}{\Delta t_A}  \; , \\
 * dt & = & \frac{\Delta t}{\Delta t_A} \; .
 * \f}
 * Then, for each output sample time \f$t_k\f$, we compute:
 * \f{eqnarray}{
 * t & = & t_\mathrm{off} + k \times dt \; , \\
 * j & = & \lfloor t \rfloor            \; , \\
 * f & = & t - j                        \; ,
 * \f}
 * where \f$\lfloor x\rfloor\f$ is the "floor" function; i.e.\ the largest
 * integer \f$\leq x\f$.  The time series sampled at the new time is then:
 * \f[
 * A(t_k) = f \times A_{j+1} + (1-f) \times A_j \; .
 * \f]
 *
 * ### Notes ###
 *
 * The major computational hit in this routine comes from computing the
 * sine and cosine of the phase angle in
 * \eqref{eq_quasiperiodic_hpluscross} of
 * \ref PulsarSimulateCoherentGW_h.  For better online performance, these can
 * be replaced by other (approximate) trig functions.  Presently the code
 * uses the native \c libm functions by default, or the function
 * <tt>sincosp()</tt> in \c libsunmath \e if this function is
 * available \e and the constant \c ONLINE is defined.
 * Differences at the level of 0.01 begin to appear only for phase
 * arguments greater than \f$10^{14}\f$ or so (corresponding to over 500
 * years between phase epoch and observation time for frequencies of
 * around 1kHz).
 *
 * To activate this feature, be sure that <tt>sunmath.h</tt> and
 * \c libsunmath are on your system, and add <tt>-DONLINE</tt> to the
 * <tt>--with-extra-cppflags</tt> configuration argument.  In future this
 * flag may be used to turn on other efficient trig algorithms on other
 * (non-Solaris) platforms.
 *
 */
void
LALPulsarSimulateCoherentGW( LALStatus        *stat,
                       REAL4TimeSeries  *output,
                       PulsarCoherentGW       *CWsignal,
                       PulsarDetectorResponse *detector )
{
  INT4 i, n;          /* index over output->data, and its final value */
  INT4 nMax;          /* used to store limits on index ranges */
  INT4 fInit, fFinal; /* index range for which CWsignal->f is defined */
  INT4 shiftInit, shiftFinal; /* ditto for CWsignal->shift */
  UINT4 dtDelayBy2;     /* delay table half-interval (s) */
  UINT4 dtPolBy2;       /* polarization table half-interval (s) */
  REAL4 *outData;             /* pointer to output data */
  REAL8 delayMin, delayMax;   /* min and max values of time delay */
  SkyPosition source;         /* source sky position */
  BOOLEAN transfer;  /* 1 if transfer function is specified */
  BOOLEAN fFlag = 0; /* 1 if frequency left detector->transfer range */
  BOOLEAN pFlag = 0; /* 1 if frequency was estimated from phase */

  /* get delay table and polaristion tables half intervals if defined (>0) in
     the PulsarCoherentGW structure otherwise default to 400s for dtDelatBy2 and 300s
     for dtPolBy2 */
  dtDelayBy2 = CWsignal->dtDelayBy2 > 0 ? CWsignal->dtDelayBy2 : 400;
  dtPolBy2   = CWsignal->dtPolBy2   > 0 ? CWsignal->dtPolBy2   : 300;

  /* The amplitude, frequency, phase, polarization shift, polarization
     response, and propagation delay are stored in arrays that must be
     interpolated.  For a quantity x, we define a pointer xData to the
     data array.  At some time t measured in units of output->deltaT,
     the interpolation point in xData is given by ( xOff + t*xDt ),
     where xOff is an offset and xDt is a relative sampling rate. */
  LALDetAMResponseSeries polResponse;
  REAL8Vector *delay = NULL;
  REAL4 *aData, *fData, *shiftData, *plusData, *crossData;
  REAL8 *phiData, *delayData;
  REAL8 aOff, fOff, phiOff, shiftOff, polOff, delayOff;
  REAL8 aDt, fDt, phiDt, shiftDt, polDt, delayDt;

  /* Frequencies in the detector transfer function are interpolated
     similarly, except everything is normalized with respect to
     detector->transfer->deltaF. */
  REAL4Vector *aTransfer = NULL;
  REAL4Vector *phiTransfer = NULL;
  REAL4Vector *phiTemp = NULL;
  REAL4 *aTransData = NULL, *phiTransData = NULL;
  REAL8 f0 = 1.0;
  REAL8 phiFac = 1.0, fFac = 1.0;

  /* Heterodyning phase factor LAL_TWOPI*output->f0*output->deltaT,
     and phase offset at the start of the series
     LAL_TWOPI*output->f0*(time offset). */
  REAL8 heteroFac, phi0;

  /* Variables required by the TCENTRE() macro, above. */
  REAL8 realIndex;
  INT4 intIndex;
  REAL8 indexFrac;

  INITSTATUS(stat);
  ATTATCHSTATUSPTR( stat );

  /* Make sure parameter structures and their fields exist. */
  ASSERT( CWsignal, stat, SIMULATECOHERENTGWH_ENUL,
          SIMULATECOHERENTGWH_MSGENUL );
  if ( !( CWsignal->a ) ) {
    ABORT( stat, SIMULATECOHERENTGWH_ESIG,
           SIMULATECOHERENTGWH_MSGESIG );
  }
  ASSERT( CWsignal->a->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  ASSERT( CWsignal->a->data->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  if ( !( CWsignal->phi ) ) {
    ABORT( stat, SIMULATECOHERENTGWH_ESIG,
           SIMULATECOHERENTGWH_MSGESIG );
  }
  ASSERT( CWsignal->phi->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  ASSERT( CWsignal->phi->data->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  if ( CWsignal->f ) {
    ASSERT( CWsignal->f->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
    ASSERT( CWsignal->f->data->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  }
  if ( CWsignal->shift ) {
    ASSERT( CWsignal->shift->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
    ASSERT( CWsignal->shift->data->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  }
  ASSERT( detector, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  if ( ( transfer = ( detector->transfer != NULL ) ) ) {
    ASSERT( detector->transfer->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
    ASSERT( detector->transfer->data->data, stat,
            SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  }
  ASSERT( output, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  ASSERT( output->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );
  ASSERT( output->data->data, stat,
          SIMULATECOHERENTGWH_ENUL, SIMULATECOHERENTGWH_MSGENUL );

  /* Check dimensions of amplitude array. */
  ASSERT( CWsignal->a->data->vectorLength == 2, stat,
          SIMULATECOHERENTGWH_EDIM, SIMULATECOHERENTGWH_MSGEDIM );

  /* Make sure we never divide by zero. */
  ASSERT( CWsignal->a->deltaT != 0.0, stat,
          SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  ASSERT( CWsignal->phi->deltaT != 0.0, stat,
          SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  aDt = output->deltaT / CWsignal->a->deltaT;
  phiDt = output->deltaT / CWsignal->phi->deltaT;
  ASSERT( aDt != 0.0, stat,
          SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  ASSERT( phiDt != 0.0, stat,
          SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  if ( CWsignal->f ) {
    ASSERT( CWsignal->f->deltaT != 0.0, stat,
            SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
    fDt = output->deltaT / CWsignal->f->deltaT;
    ASSERT( fDt != 0.0, stat,
            SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  } else
    fDt = 0.0;
  if ( CWsignal->shift ) {
    ASSERT( CWsignal->shift->deltaT != 0.0, stat,
            SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
    shiftDt = output->deltaT / CWsignal->shift->deltaT;
    ASSERT( shiftDt != 0.0, stat,
            SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  } else
    shiftDt = 0.0;
  if ( transfer ) {
    ASSERT( detector->transfer->deltaF != 0.0, stat,
            SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
    fFac = 1.0 / detector->transfer->deltaF;
    phiFac = fFac / ( LAL_TWOPI*CWsignal->phi->deltaT );
    f0 = detector->transfer->f0/detector->transfer->deltaF;
  }
  heteroFac = LAL_TWOPI*output->f0*output->deltaT;
  phi0 = (REAL8)( output->epoch.gpsSeconds -
                  detector->heterodyneEpoch.gpsSeconds );
  phi0 += 0.000000001*(REAL8)( output->epoch.gpsNanoSeconds -
                               detector->heterodyneEpoch.gpsNanoSeconds );
  phi0 *= LAL_TWOPI*output->f0;
  if ( phi0 > 1.0/LAL_REAL8_EPS ) {
    LALWarning( stat, "REAL8 arithmetic is not sufficient to maintain"
                " heterodyne phase to within a radian." );
  }

  /* Check units on input, and set units on output. */
  {
    ASSERT( XLALUnitCompare( &(CWsignal->f->sampleUnits), &lalHertzUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
    ASSERT( XLALUnitCompare( &(CWsignal->phi->sampleUnits), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
    if( CWsignal->shift ) {
      ASSERT( XLALUnitCompare( &(CWsignal->shift->sampleUnits), &lalDimensionlessUnit ) == 0, stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
    }
    if ( transfer ) {
      if ( XLALUnitMultiply( &(output->sampleUnits), &(CWsignal->a->sampleUnits), &(detector->transfer->sampleUnits) ) == NULL ) {
        ABORT( stat, SIMULATECOHERENTGWH_EUNIT, SIMULATECOHERENTGWH_MSGEUNIT );
      }
    } else {
      output->sampleUnits = CWsignal->a->sampleUnits;
    }
    snprintf( output->name, LALNameLength, "response to %s", CWsignal->a->name );
  }

  /* Define temporary variables to access the data of CWsignal->a,
     CWsignal->f, and CWsignal->phi. */
  aData = CWsignal->a->data->data;
  INT4 aLen = CWsignal->a->data->length * CWsignal->a->data->vectorLength;
  phiData = CWsignal->phi->data->data;
  INT4 phiLen = CWsignal->phi->data->length;
  outData = output->data->data;
  INT4 fLen=0, shiftLen=0;
  if ( CWsignal->f )
    {
      fData = CWsignal->f->data->data;
      fLen = CWsignal->f->data->length;
    }
  else
    {
      fData = NULL;
    }

  if ( CWsignal->shift )
    {
      shiftData = CWsignal->shift->data->data;
      shiftLen = CWsignal->shift->data->length;
    }
  else
    {
      shiftData = NULL;
    }

  /* Convert source position to equatorial coordinates, if
     required. */
  if ( detector->site ) {
    source = CWsignal->position;
    if ( source.system != COORDINATESYSTEM_EQUATORIAL ) {
      ConvertSkyParams params; /* parameters for conversion */
      EarthPosition location;  /* location of detector */
      params.gpsTime = &( output->epoch );
      params.system = COORDINATESYSTEM_EQUATORIAL;
      if ( source.system == COORDINATESYSTEM_HORIZON ) {
        params.zenith = &( location.geodetic );
        location.x = detector->site->location[0];
        location.y = detector->site->location[1];
        location.z = detector->site->location[2];
        TRY( LALGeocentricToGeodetic( stat->statusPtr, &location ),
             stat );
      }
      TRY( LALConvertSkyCoordinates( stat->statusPtr, &source,
                                     &source, &params ), stat );
    }
  }

  /* Generate the table of propagation delays.
     dtDelayBy2 = (UINT4)( 38924.9/sqrt( output->f0 +
     1.0/output->deltaT ) ); */
  delayDt = output->deltaT/( 2.0*dtDelayBy2 );
  nMax = (UINT4)( output->data->length*delayDt ) + 3;
  TRY( LALDCreateVector( stat->statusPtr, &delay, nMax ), stat );
  delayData = delay->data;

  /* Compute delay from solar system barycentre. */
  if ( detector->site && detector->ephemerides ) {
    LIGOTimeGPS gpsTime;   /* detector time when we compute delay */
    EarthState state;      /* Earth position info at that time */
    BarycenterInput input; /* input structure to LALBarycenter() */
    EmissionTime emit;     /* output structure from LALBarycenter() */

    /* Arrange nested pointers, and set initial values. */
    gpsTime = input.tgps = output->epoch;
    gpsTime.gpsSeconds -= dtDelayBy2;
    input.tgps.gpsSeconds -= dtDelayBy2;
    input.site = *(detector->site);
    for ( i = 0; i < 3; i++ )
      input.site.location[i] /= LAL_C_SI;
    input.alpha = source.longitude;
    input.delta = source.latitude;
    input.dInv = 0.0;
    delayMin = delayMax = 1.1*LAL_AU_SI/( LAL_C_SI*output->deltaT );
    delayMax *= -1;

    /* Compute table. */
    for ( i = 0; i < nMax; i++ ) {
      REAL8 tDelay; /* propagation time */
      LALBarycenterEarth( stat->statusPtr, &state, &gpsTime,
                          detector->ephemerides );
      BEGINFAIL( stat )
        TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
      ENDFAIL( stat );
      LALBarycenter( stat->statusPtr, &emit, &input, &state );
      BEGINFAIL( stat )
        TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
      ENDFAIL( stat );
      delayData[i] = tDelay = emit.deltaT/output->deltaT;
      if ( tDelay < delayMin )
        delayMin = tDelay;
      if ( tDelay > delayMax )
        delayMax = tDelay;
      gpsTime.gpsSeconds += 2*dtDelayBy2;
      input.tgps.gpsSeconds += 2*dtDelayBy2;
    }
  }

  /* No information from which to compute delays. */
  else {
    LALInfo( stat, "Detector site and ephemerides absent; simulating hplus with no"
             " propagation delays" );
    memset( delayData, 0, nMax*sizeof(REAL8) );
    delayMin = delayMax = 0.0;
  }

  /* Generate the table of polarization response functions. */
  polDt = output->deltaT/( 2.0*dtPolBy2 );
  nMax = (UINT4)( output->data->length*polDt ) + 3;
  memset( &polResponse, 0, sizeof( LALDetAMResponseSeries ) );
  polResponse.pPlus = (REAL4TimeSeries *)
    LALMalloc( sizeof(REAL4TimeSeries) );
  polResponse.pCross = (REAL4TimeSeries *)
    LALMalloc( sizeof(REAL4TimeSeries) );
  polResponse.pScalar = (REAL4TimeSeries *)
    LALMalloc( sizeof(REAL4TimeSeries) );
  if ( !polResponse.pPlus || !polResponse.pCross ||
       !polResponse.pScalar ) {
    if ( polResponse.pPlus )
      LALFree( polResponse.pPlus );
    if ( polResponse.pCross )
      LALFree( polResponse.pCross );
    if ( polResponse.pScalar )
      LALFree( polResponse.pScalar );
    TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
    ABORT( stat, SIMULATECOHERENTGWH_EMEM,
           SIMULATECOHERENTGWH_MSGEMEM );
  }
  memset( polResponse.pPlus, 0, sizeof(REAL4TimeSeries) );
  memset( polResponse.pCross, 0, sizeof(REAL4TimeSeries) );
  memset( polResponse.pScalar, 0, sizeof(REAL4TimeSeries) );
  LALSCreateVector( stat->statusPtr, &( polResponse.pPlus->data ),
                    nMax );
  BEGINFAIL( stat ) {
    LALFree( polResponse.pPlus );
    LALFree( polResponse.pCross );
    LALFree( polResponse.pScalar );
    TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
  } ENDFAIL( stat );
  LALSCreateVector( stat->statusPtr, &( polResponse.pCross->data ),
                    nMax );
  BEGINFAIL( stat ) {
    TRY( LALSDestroyVector( stat->statusPtr,
                            &( polResponse.pPlus->data ) ), stat );
    LALFree( polResponse.pPlus );
    LALFree( polResponse.pCross );
    LALFree( polResponse.pScalar );
    TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
  } ENDFAIL( stat );
  LALSCreateVector( stat->statusPtr, &( polResponse.pScalar->data ),
                    nMax );
  BEGINFAIL( stat ) {
    TRY( LALSDestroyVector( stat->statusPtr,
                            &( polResponse.pPlus->data ) ), stat );
    TRY( LALSDestroyVector( stat->statusPtr,
                            &( polResponse.pCross->data ) ), stat );
    LALFree( polResponse.pPlus );
    LALFree( polResponse.pCross );
    LALFree( polResponse.pScalar );
    TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
  } ENDFAIL( stat );
  plusData = polResponse.pPlus->data->data;
  crossData = polResponse.pCross->data->data;
  INT4 plusLen = polResponse.pPlus->data->length;
  INT4 crossLen = polResponse.pCross->data->length;
  if ( plusLen != crossLen ) {
    XLALPrintError ("plusLen = %d != crossLen = %d\n", plusLen, crossLen );
    ABORT ( stat, SIMULATECOHERENTGWH_EBAD, SIMULATECOHERENTGWH_MSGEBAD );
  }

  if ( detector->site ) {
    LALSource polSource;     /* position and polarization angle */
    LALDetAndSource input;            /* response input structure */
    LALTimeIntervalAndNSample params; /* response parameter structure */

    /* Arrange nested pointers, and set initial values. */
    polSource.equatorialCoords = source;
    polSource.orientation = (REAL8)( CWsignal->psi );
    input.pSource = &polSource;
    input.pDetector = detector->site;
    params.epoch = output->epoch;
    params.epoch.gpsSeconds -= dtPolBy2;
    params.deltaT = 2.0*dtPolBy2;
    params.nSample = nMax;

    /* Compute table of responses. */
    LALComputeDetAMResponseSeries( stat->statusPtr, &polResponse,
                                   &input, &params );
    BEGINFAIL( stat ) {
      TRY( LALSDestroyVector( stat->statusPtr,
                              &( polResponse.pPlus->data ) ), stat );
      TRY( LALSDestroyVector( stat->statusPtr,
                              &( polResponse.pCross->data ) ), stat );
      TRY( LALSDestroyVector( stat->statusPtr,
                              &( polResponse.pScalar->data ) ), stat );
      LALFree( polResponse.pPlus );
      LALFree( polResponse.pCross );
      LALFree( polResponse.pScalar );
      TRY( LALDDestroyVector( stat->statusPtr, &delay ), stat );
    } ENDFAIL( stat );
  } else {
/* Actually, we don't need it -- JTW
struct tagRealFFTPlan
{
  INT4  sign;
  UINT4 size;
  void* junk;
};
*/
int
main( int argc, char *argv[] )
{

   static LALStatus         status;

   UINT4      i;
   REAL8      f;


   const REAL4    testInputDataData[SZEROPADANDFFTTESTC_LENGTH]
                     = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};

   COMPLEX8 expectedOutputDataData[SZEROPADANDFFTTESTC_LENGTH]
                     = {crectf(+3.600000000000000e+01, 0.0),
                        crectf(-1.094039137097177e+01, -2.279368601990178e+01),
                        crectf(+3.693524635113721e-01, +9.326003289238411e+00),
                        crectf(-8.090169943749448e-01, -7.918722831227928e+00),
                        crectf(+3.502214272222959e-01, +5.268737078678177e+00),
                        crectf(+5.329070518200751e-15, -5.196152422706625e+00),
                        crectf(+3.090169943749475e-01, +4.306254604896173e+00),
                        crectf(+2.208174802380956e-01, -4.325962305777781e+00)};

   REAL4TimeSeries             goodInput;
   COMPLEX8FrequencySeries     goodOutput;

   int                    result;
   LALUnit                expectedUnit;
   CHAR                   unitString[LALUnitTextSize];

   SZeroPadAndFFTParameters   goodParams;


   goodParams.window = NULL;
   goodParams.fftPlan = NULL;
   goodParams.length = SZEROPADANDFFTTESTC_FULLLENGTH;

   /* build window */
   goodParams.window = XLALCreateRectangularREAL4Window(SZEROPADANDFFTTESTC_LENGTH);
#ifndef LAL_NDEBUG
   SZeroPadAndFFTParameters badParams = goodParams;
#endif

   /* Fill in expected output */

   for (i=0; i<SZEROPADANDFFTTESTC_LENGTH; ++i)
   {
     expectedOutputDataData[i] *= SZEROPADANDFFTTESTC_DELTAT;
   }

   ParseOptions( argc, argv );

   /* TEST INVALID DATA HERE ------------------------------------------- */

   /* define valid parameters */
   goodInput.f0                   = 0.0;
   goodInput.deltaT               = SZEROPADANDFFTTESTC_DELTAT;
   goodInput.epoch.gpsSeconds     = SZEROPADANDFFTTESTC_EPOCHSEC;
   goodInput.epoch.gpsNanoSeconds = SZEROPADANDFFTTESTC_EPOCHNS;
   goodInput.data                 = NULL;
   goodOutput.data                = NULL;

#ifndef LAL_NDEBUG
   REAL4TimeSeries badInput = goodInput;
   COMPLEX8FrequencySeries badOutput = goodOutput;
#endif

   /* construct plan */
   LALCreateForwardRealFFTPlan(&status, &(goodParams.fftPlan),
			       SZEROPADANDFFTTESTC_FULLLENGTH,
			       SZEROPADANDFFTTESTC_FALSE);
   if ( ( code = CheckStatus( &status, 0 , "",
			      SZEROPADANDFFTTESTC_EFLS,
			      SZEROPADANDFFTTESTC_MSGEFLS ) ) )
   {
     return code;
   }
   /* allocate input and output vectors */
   LALSCreateVector(&status, &(goodInput.data), SZEROPADANDFFTTESTC_LENGTH);
   if ( ( code = CheckStatus( &status, 0 , "",
			      SZEROPADANDFFTTESTC_EFLS,
			      SZEROPADANDFFTTESTC_MSGEFLS ) ) )
   {
     return code;
   }
   LALCCreateVector(&status, &(goodOutput.data), SZEROPADANDFFTTESTC_LENGTH);
   if ( ( code = CheckStatus( &status, 0 , "",
			      SZEROPADANDFFTTESTC_EFLS,
			      SZEROPADANDFFTTESTC_MSGEFLS ) ) )
   {
     return code;
   }

#ifndef LAL_NDEBUG
   if ( ! lalNoDebug )
   {
     /* test behavior for null pointer to output series */
     LALSZeroPadAndFFT(&status, NULL, &goodInput, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to output series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

     /* test behavior for null pointer to input series */
     LALSZeroPadAndFFT(&status, &goodOutput, NULL, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to input series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

     /* test behavior for null pointer to parameter structure */
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, NULL);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to parameter structure results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

     /* test behavior for null pointer to FFT plan */
     badParams.fftPlan = NULL;
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &badParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to FFT plan results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);
     badParams.fftPlan = goodParams.fftPlan;

     /* test behavior for null pointer to data member of output series */
     LALSZeroPadAndFFT(&status, &badOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to data member of output series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

     /* test behavior for null pointer to data member of input series */
     LALSZeroPadAndFFT(&status, &goodOutput, &badInput, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to data member of input series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

     /* test behavior for null pointer to data member of data member of output series */
     LALCCreateVector(&status, &(badOutput.data), SZEROPADANDFFTTESTC_LENGTH);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }
     COMPLEX8                *cPtr;
     cPtr = badOutput.data->data;
     badOutput.data->data = NULL;
     LALSZeroPadAndFFT(&status, &badOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to data member of data member of output series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);
     badOutput.data->data = cPtr;
     LALCDestroyVector(&status, &(badOutput.data));
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     /* test behavior for null pointer to data member of data member of output series */
     LALSCreateVector(&status, &(badInput.data), SZEROPADANDFFTTESTC_LENGTH);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }
     REAL4                   *sPtr;
     sPtr = badInput.data->data;
     badInput.data->data = NULL;
     LALSZeroPadAndFFT(&status, &goodOutput, &badInput, &goodParams);
     if ( ( code = CheckStatus( &status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
				STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
				SZEROPADANDFFTTESTC_ECHK,
				SZEROPADANDFFTTESTC_MSGECHK ) ) )
     {
       return code;
     }
     printf("  PASS: null pointer to data member of data member of input series results in error:\n       \"%s\"\n", STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);
     badInput.data->data = sPtr;
     LALSDestroyVector(&status, &(badInput.data));
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     /* test behavior for zero length */
     goodInput.data->length = goodOutput.data->length = 0;
     /* plan->size = -1; */
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EZEROLEN,
			       STOCHASTICCROSSCORRELATIONH_MSGEZEROLEN,
			       SZEROPADANDFFTTESTC_ECHK,
			       SZEROPADANDFFTTESTC_MSGECHK) ) )
     {
       return code;
     }
     printf("  PASS: zero length results in error:\n       \"%s\"\n",
            STOCHASTICCROSSCORRELATIONH_MSGEZEROLEN);
     /* reassign valid length */
     goodInput.data->length = goodOutput.data->length
       = SZEROPADANDFFTTESTC_LENGTH;
     /* plan->size = SZEROPADANDFFTTESTC_FULLLENGTH; */

     /* test behavior for negative time spacing */
     goodInput.deltaT = -SZEROPADANDFFTTESTC_DELTAT;
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus(&status,
			       STOCHASTICCROSSCORRELATIONH_ENONPOSDELTAT,
			       STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAT,
			       SZEROPADANDFFTTESTC_ECHK,
			       SZEROPADANDFFTTESTC_MSGECHK) ) )
     {
       return code;
     }
     printf("  PASS: negative time spacing results in error:\n       \"%s\"\n",
            STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAT);

     /* test behavior for zero time spacing */
     goodInput.deltaT = 0;
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus(&status,
			       STOCHASTICCROSSCORRELATIONH_ENONPOSDELTAT,
			       STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAT,
			       SZEROPADANDFFTTESTC_ECHK,
			       SZEROPADANDFFTTESTC_MSGECHK) ) )
     {
       return code;
     }
     printf("  PASS: zero time spacing results in error:\n       \"%s\"\n",
            STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAT);
     /* reassign valid time spacing */
     goodInput.deltaT = SZEROPADANDFFTTESTC_DELTAT;

   } /* if ( ! lalNoDebug ) */
#endif /* NDEBUG */

   /* test behavior for negative heterodyning frequency */
   goodInput.f0 = -100.0;
   LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
   if ( ( code = CheckStatus(&status,
			     STOCHASTICCROSSCORRELATIONH_ENONZEROHETERO,
			     STOCHASTICCROSSCORRELATIONH_MSGENONZEROHETERO,
			     SZEROPADANDFFTTESTC_ECHK,
			     SZEROPADANDFFTTESTC_MSGECHK) ) )
   {
     return code;
   }
   printf("  PASS: negative heterodyning frequency results in error:\n       \"%s\"\n",
            STOCHASTICCROSSCORRELATIONH_MSGENONZEROHETERO);
   /* test behavior for positive heterodyning frequency */
   goodInput.f0 = 100.0;
   LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
   if ( ( code = CheckStatus(&status,
			     STOCHASTICCROSSCORRELATIONH_ENONZEROHETERO,
			     STOCHASTICCROSSCORRELATIONH_MSGENONZEROHETERO,
			     SZEROPADANDFFTTESTC_ECHK,
			     SZEROPADANDFFTTESTC_MSGECHK) ) )
   {
     return code;
   }
   printf("  PASS: positive heterodyning frequency results in error:\n       \"%s\"\n",
          STOCHASTICCROSSCORRELATIONH_MSGENONZEROHETERO);
   goodInput.f0 = 0.0;

   /* test behavior for length mismatch between input series and output series */
   goodOutput.data->length = SZEROPADANDFFTTESTC_LENGTH + 1;
   LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
   if ( ( code = CheckStatus(&status,
			     STOCHASTICCROSSCORRELATIONH_EMMLEN,
			     STOCHASTICCROSSCORRELATIONH_MSGEMMLEN,
			     SZEROPADANDFFTTESTC_ECHK,
			     SZEROPADANDFFTTESTC_MSGECHK) ) )
   {
     return code;
   }
   printf("  PASS: length mismatch between input series and output series results in error:\n       \"%s\"\n",
          STOCHASTICCROSSCORRELATIONH_MSGEMMLEN);
   goodOutput.data->length = SZEROPADANDFFTTESTC_LENGTH;

   /* TEST VALID DATA HERE --------------------------------------------- */

   /* fill input time-series parameters */
   strncpy(goodInput.name,"Dummy test data",LALNameLength);
   goodInput.sampleUnits  = lalDimensionlessUnit;
   goodInput.sampleUnits.unitNumerator[LALUnitIndexADCCount] = 1;

     /* fill input time-series data */
   for (i=0; i<SZEROPADANDFFTTESTC_LENGTH; ++i)
   {
     goodInput.data->data[i] = testInputDataData[i];
   }

   /* zero-pad and FFT */
   LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
   if ( ( code = CheckStatus( &status, 0 , "",
			      SZEROPADANDFFTTESTC_EFLS,
			      SZEROPADANDFFTTESTC_MSGEFLS) ) )
   {
     return code;
   }

   /* check output f0 */
   if (optVerbose)
   {
     printf("f0=%g, should be 0\n", goodOutput.f0);
   }
   if (goodOutput.f0)
   {
     printf("  FAIL: Valid data test\n");
     if (optVerbose)
     {
       printf("Exiting with error: %s\n", SZEROPADANDFFTTESTC_MSGEFLS);
     }
     return SZEROPADANDFFTTESTC_EFLS;
   }

   /* check output deltaF */
   if (optVerbose)
   {
     printf("deltaF=%g, should be %g\n", goodOutput.deltaF,
            SZEROPADANDFFTTESTC_DELTAF);
   }
   if ( fabs(goodOutput.deltaF-SZEROPADANDFFTTESTC_DELTAF)
        / SZEROPADANDFFTTESTC_DELTAF > SZEROPADANDFFTTESTC_TOL )
   {
     printf("  FAIL: Valid data test\n");
     if (optVerbose)
     {
       printf("Exiting with error: %s\n", SZEROPADANDFFTTESTC_MSGEFLS);
     }
     return SZEROPADANDFFTTESTC_EFLS;
   }

   /* check output epoch */
   if (optVerbose)
   {
     printf("epoch=%d seconds, %d nanoseconds; should be %d seconds, %d nanoseconds\n",
            goodOutput.epoch.gpsSeconds, goodOutput.epoch.gpsNanoSeconds,
            SZEROPADANDFFTTESTC_EPOCHSEC, SZEROPADANDFFTTESTC_EPOCHNS);
   }
   if ( goodOutput.epoch.gpsSeconds != SZEROPADANDFFTTESTC_EPOCHSEC
        || goodOutput.epoch.gpsNanoSeconds != SZEROPADANDFFTTESTC_EPOCHNS )
   {
     printf("  FAIL: Valid data test\n");
     if (optVerbose)
     {
       printf("Exiting with error: %s\n", SZEROPADANDFFTTESTC_MSGEFLS);
     }
     return SZEROPADANDFFTTESTC_EFLS;
   }

   /* check output units */
   expectedUnit = lalDimensionlessUnit;
   expectedUnit.unitNumerator[LALUnitIndexADCCount] = 1;
   expectedUnit.unitNumerator[LALUnitIndexSecond] = 1;
   result = XLALUnitCompare(&expectedUnit, &(goodOutput.sampleUnits));
   if (optVerbose)
   {
     if ( XLALUnitAsString( unitString, LALUnitTextSize, &(goodOutput.sampleUnits)) == NULL ) {
       return SZEROPADANDFFTTESTC_EFLS;
     }
     printf( "Units are \"%s\", ", unitString );
     if ( XLALUnitAsString( unitString, LALUnitTextSize, &expectedUnit) == NULL ) {
       return SZEROPADANDFFTTESTC_EFLS;
     }
     printf( "should be \"%s\"\n", unitString );
   }

   if (result != 0)
   {
     printf("  FAIL: Valid data test #1\n");
     if (optVerbose)
     {
       printf("Exiting with error: %s\n",
              SZEROPADANDFFTTESTC_MSGEFLS);
     }
     return SZEROPADANDFFTTESTC_EFLS;
   }

   /* check output values */
   if (optVerbose)
   {
     printf("hBarTilde(0)=%g + %g i, should be %g\n",
            crealf(goodOutput.data->data[0]), cimagf(goodOutput.data->data[0]),
            crealf(expectedOutputDataData[0]));
   }
   if ( fabsf(crealf(goodOutput.data->data[0]) - crealf(expectedOutputDataData[0]))
        /* / expectedOutputDataData[0].re */> SZEROPADANDFFTTESTC_TOL
        || fabsf(cimagf(goodOutput.data->data[0])) > SZEROPADANDFFTTESTC_TOL )
   {
     printf("  FAIL: Valid data test\n");
     if (optVerbose)
       {
         printf("Exiting with error: %s\n", SZEROPADANDFFTTESTC_MSGEFLS);
       }
     return SZEROPADANDFFTTESTC_EFLS;
   }

   for (i=1; i<SZEROPADANDFFTTESTC_LENGTH; ++i)
   {
     f = i * SZEROPADANDFFTTESTC_DELTAF;
     if (optVerbose)
     {
       printf("hBarTilde(%f Hz)=%g + %g i, should be %g + %g i\n",
              f, crealf(goodOutput.data->data[i]), cimagf(goodOutput.data->data[i]),
              crealf(expectedOutputDataData[i]), cimagf(expectedOutputDataData[i]));
     }
     if (fabsf(crealf(goodOutput.data->data[i]) - crealf(expectedOutputDataData[i]))
         /* / expectedOutputDataData[0].re */> SZEROPADANDFFTTESTC_TOL
         || fabsf(cimagf(goodOutput.data->data[i]) - cimagf(expectedOutputDataData[i]))
         /* / expectedOutputDataData[0].re */> SZEROPADANDFFTTESTC_TOL)
     {
       printf("  FAIL: Valid data test\n");
       if (optVerbose)
       {
         printf("Exiting with error: %s\n", SZEROPADANDFFTTESTC_MSGEFLS);
       }
       return SZEROPADANDFFTTESTC_EFLS;
     }
   }

    /* write results to output file
   LALSPrintTimeSeries(&input, "zeropadgoodInput.dat");
   LALCPrintFrequencySeries(&output, "zeropadgoodOutput.dat");*/

   /* clean up valid data */
   LALSDestroyVector(&status, &goodInput.data);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
   {
     return code;
   }
   LALCDestroyVector(&status, &goodOutput.data);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
   {
     return code;
   }
   LALDestroyRealFFTPlan(&status, &(goodParams.fftPlan));
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
   {
     return code;
   }
   XLALDestroyREAL4Window(goodParams.window);

   LALCheckMemoryLeaks();

   printf("PASS: all tests\n");

   /**************** Process User-Entered Data, If Any **************/

   /* ::TODO:: Fix this with length and window type to be specified */

   if (optInputFile[0] && optOutputFile[0]){
     /* construct plan*/
     LALCreateForwardRealFFTPlan(&status, &(goodParams.fftPlan), 2*optLength - 1,
				   optMeasurePlan);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     goodInput.data  = NULL;
     goodOutput.data = NULL;

     LALSCreateVector(&status, &goodInput.data, optLength);
     if ( ( code = CheckStatus( &status, 0 , "",
				SZEROPADANDFFTTESTC_EUSE,
				SZEROPADANDFFTTESTC_MSGEUSE) ) )
     {
       return code;
     }
     LALCCreateVector(&status, &goodOutput.data, optLength);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     /* Read input file */
     LALSReadTimeSeries(&status, &goodInput, optInputFile);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     /* calculate zero-pad and FFT */
     LALSZeroPadAndFFT(&status, &goodOutput, &goodInput, &goodParams);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }

     LALCPrintFrequencySeries(&goodOutput, optOutputFile);

     printf("===== FFT of Zero-Padded User-Specified Data Written to File %s =====\n", optOutputFile);

     /* clean up valid data */
     LALSDestroyVector(&status, &goodInput.data);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }
     LALCDestroyVector(&status, &goodOutput.data);
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }
     LALDestroyRealFFTPlan(&status, &(goodParams.fftPlan));
     if ( ( code = CheckStatus(&status, 0 , "",
			       SZEROPADANDFFTTESTC_EFLS,
			       SZEROPADANDFFTTESTC_MSGEFLS) ) )
     {
       return code;
     }
     LALCheckMemoryLeaks();
   }
   return SZEROPADANDFFTTESTC_ENOM;
}
int main( int argc, char *argv[] )
{
  static LALStatus                status;

  StochasticCrossCorrelationInput           input;
  REAL4WithUnits           output;

  COMPLEX8FrequencySeries  goodData1;
  COMPLEX8FrequencySeries  goodData2;
  COMPLEX8FrequencySeries  goodFilter;

  LIGOTimeGPS              epoch0 = {0,0};
  LIGOTimeGPS              epoch1 = {630720000,123456789};
  LIGOTimeGPS              epoch2 = {630720000,987654321};
  LIGOTimeGPS              epoch3 = {630722222,123456789};

  int                      result;

  CHAR                     unitString[LALUnitTextSize];
  
  UINT4 i;
  REAL4 f, x;
  INT4 code;


  ParseOptions( argc, argv );

  /* define valid parameters */

  goodFilter.f0     = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0;
  goodFilter.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;
  goodFilter.epoch  = epoch0;
  goodFilter.data   = NULL;

#ifndef LAL_NDEBUG
  COMPLEX8FrequencySeries  badFilter = goodFilter;
#endif

  goodData1 = goodFilter;

  goodData1.epoch = epoch1;
  goodData2 = goodData1;
#ifndef LAL_NDEBUG
  COMPLEX8FrequencySeries  badData1 = goodData2;
  COMPLEX8FrequencySeries  badData2 = badData1;
#endif

  LALCCreateVector(&status, &(goodData1.data),
                          STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH);
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  LALCCreateVector(&status, &(goodData2.data),
                          STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH);
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  LALCCreateVector(&status, &(goodFilter.data),
                          STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH);
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  input.hBarTildeOne  = &goodData1;
  input.hBarTildeTwo  = &goodData2;
  input.optimalFilter = &goodFilter;

#ifndef LAL_NDEBUG
  if ( ! lalNoDebug )
  {
    /* test behavior for null pointer to output structure */
    LALStochasticCrossCorrelationStatistic(&status, NULL, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
      {
        return code;
      }
    printf("  PASS: null pointer to output structure results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* test behavior for null pointer to input structure */
    LALStochasticCrossCorrelationStatistic(&status, &output, NULL, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to input structure results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* test behavior for null pointer to first data stream */
    input.hBarTildeOne = NULL;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to first data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to second data stream */
    input.hBarTildeOne = &goodData1;

    /* test behavior for null pointer to second data stream */
    input.hBarTildeTwo = NULL;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to second data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to second data stream */
    input.hBarTildeTwo = &goodData2;

    /* test behavior for null pointer to optimal filter */
    input.optimalFilter = NULL;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to optimal filter results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to optimal filter */
    input.optimalFilter = &goodFilter;

    /* test behavior for null pointer to data member of first data stream */
    input.hBarTildeOne = &badData1;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of first data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of first data stream */
    input.hBarTildeOne = &goodData1;

    /* test behavior for null pointer to data member of second data stream */
    input.hBarTildeTwo = &badData2;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of second data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of second data stream */
    input.hBarTildeTwo = &goodData2;

    /* test behavior for null pointer to data member of optimal filter */
    input.optimalFilter = &badFilter;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of optimal filter results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of optimal filter */
    input.optimalFilter = &goodFilter;

    /* Create a vector for testing null data-data pointers */
    LALCCreateVector(&status, &(badFilter.data),
                          STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
    {
      return code;
    }
    COMPLEX8                *tempPtr;
    tempPtr = badFilter.data->data;
    badFilter.data->data = NULL;
    badData1.data = badData2.data = badFilter.data;

    /* test behavior for null pointer to data member of data member of first data stream */
    input.hBarTildeOne = &badData1;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of data member of first data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of data member of first data stream */
    input.hBarTildeOne = &goodData1;

    /* test behavior for null pointer to data member of data member of second data stream */
    input.hBarTildeTwo = &badData2;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of data member of second data stream results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of data member of second data stream */
    input.hBarTildeTwo = &goodData2;

    /* test behavior for null pointer to data member of data member of optimal filter */
    input.optimalFilter = &badFilter;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENULLPTR,
			      STOCHASTICCROSSCORRELATIONH_MSGENULLPTR,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
     {
      return code;
    }
    printf("  PASS: null pointer to data member of data member of optimal filter results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENULLPTR);

    /* assign valid pointer to data member of data member of optimal filter */
    input.optimalFilter = &goodFilter;

    /* clean up */

    badFilter.data->data = tempPtr;
    LALCDestroyVector(&status, &(badFilter.data));
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
    {
      return code;
    }
    badData1.data = badData2.data = badFilter.data;

    /* test behavior for zero length */
    goodData1.data->length = goodData2.data->length
      = goodFilter.data->length = 0;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EZEROLEN,
			      STOCHASTICCROSSCORRELATIONH_MSGEZEROLEN,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
    {
      return code;
    }
    printf("  PASS: zero length results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGEZEROLEN);
    /* reassign valid length */
    goodData1.data->length = goodData2.data->length
      = goodFilter.data->length = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH;

    /* test behavior for negative frequency spacing */
    goodData1.deltaF = goodData2.deltaF
      = goodFilter.deltaF = -STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENONPOSDELTAF,
			      STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAF,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
    {
      return code;
    }
    printf("  PASS: negative frequency spacing results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAF);

    /* test behavior for zero frequency spacing */
    goodData1.deltaF = goodData2.deltaF
      = goodFilter.deltaF = 0;
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
    if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENONPOSDELTAF,
			      STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAF,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
    {
      return code;
    }
    printf("  PASS: zero frequency spacing results in error:\n       \"%s\"\n",
           STOCHASTICCROSSCORRELATIONH_MSGENONPOSDELTAF);
    /* reassign valid frequency spacing */
    goodData1.deltaF = goodData2.deltaF
      = goodFilter.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;
   } /* if ( ! lalNoDebug ) */
#endif /* LAL_NDEBUG */

  /* test behavior for negative start frequency */
  goodData1.f0 = goodData2.f0
    = goodFilter.f0 = -20.0;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_ENEGFMIN,
			    STOCHASTICCROSSCORRELATIONH_MSGENEGFMIN,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: negative start frequency results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGENEGFMIN);

  /* reassign valid start frequency */
  goodData1.f0 = goodData2.f0
    = goodFilter.f0 = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0;

  /* test behavior for length mismatch
     between optimal filter and first data stream */
  goodData1.data->length = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH - 1;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMLEN,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMLEN,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: length mismatch between optimal filter and first data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMLEN);

  /* reassign correct length */
  goodData1.data->length = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH;

  /* test behavior for length mismatch
     between optimal filter and first data stream */
  goodData2.data->length = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH - 1;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMLEN,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMLEN,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: length mismatch between optimal filter and second data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMLEN);

  /* reassign correct length */
  goodData2.data->length = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH;

  /* test behavior for frequency spacing mismatch
     between optimal filter and first data stream */
  goodData1.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF * 2.0;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMDELTAF,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMDELTAF,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: frequency spacing mismatch between optimal filter and first data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMDELTAF);

  /* reassign correct frequency spacing */
  goodData1.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;

  /* test behavior for frequency spacing mismatch
     between optimal filter and second data stream */
  goodData2.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF * 2.0;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMDELTAF,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMDELTAF,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: frequency spacing mismatch between optimal filter and second data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMDELTAF);

  /* reassign correct frequency spacing */
  goodData2.deltaF = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;

  /* test behavior for start frequency mismatch
     between optimal filter and first data stream */
  goodData1.f0 = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0 + 2.0;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMFMIN,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMFMIN,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: start frequency mismatch between optimal filter and first data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMFMIN);

  /* reassign correct start frequency */
  goodData1.f0 = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0;

  /* test behavior for start frequency mismatch
     between optimal filter and second data stream */
  goodData2.f0 = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0 + 2.0;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMFMIN,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMFMIN,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: start frequency mismatch between optimal filter and second data stream results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMFMIN);

  /* reassign correct start frequency */
  goodData2.f0 = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0;

  /* test behavior for mismatch between epochs of data streams */
  goodData2.epoch = epoch2;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMTIME,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMTIME,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  goodData2.epoch = epoch3;
  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, STOCHASTICCROSSCORRELATIONH_EMMTIME,
			    STOCHASTICCROSSCORRELATIONH_MSGEMMTIME,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ECHK,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGECHK) ) )
  {
    return code;
  }
  printf("  PASS: mismatch between epochs of data streams results in error:\n       \"%s\"\n",
         STOCHASTICCROSSCORRELATIONH_MSGEMMTIME);

  /* reassign correct epoch */
  goodData2.epoch = epoch1;

  /******************** Test Valid Data Case #1 ***********************/
  goodData1.sampleUnits = lalDimensionlessUnit;
  goodData1.sampleUnits.unitNumerator[LALUnitIndexStrain] = 1;
  goodData1.sampleUnits.unitNumerator[LALUnitIndexSecond] = 1;
  goodData2.sampleUnits = goodData1.sampleUnits;
  goodFilter.sampleUnits = lalDimensionlessUnit;
  goodFilter.sampleUnits.unitNumerator[LALUnitIndexStrain] = -1;

  goodData1.f0 = goodData2.f0 = goodFilter.f0 = 0.0;

  goodData1.data->data[0] = goodData2.data->data[0] = goodFilter.data->data[0] = 0.0;

  for (i=1; i<STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH; ++i)
  {
    f = i * STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;
    x = f / (STOCHASTICCROSSCORRELATIONSTATISTICTESTC_FLIM / 2.0);
    goodData1.data->data[i] = crectf( x*x, x );
    goodData2.data->data[i] = crectf( 1.0/crealf(goodData1.data->data[i]), -1.0/cimagf(goodData1.data->data[i]) );
    goodFilter.data->data[i] = crectf( x * (2-x), 0.0 );
  }

  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  if (optVerbose) printf("Y=%g, should be 0\n",output.value);
  if (fabsf(output.value)/STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF
      > STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TOL)
  {
    printf("  FAIL: Valid data test #1\n");
    if (optVerbose)
    {
      printf("Exiting with error: %s\n",
             STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS);
    }
    return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
  }

  result = XLALUnitCompare(&(goodData1.sampleUnits), &(output.units));
  if (optVerbose)
  {
    if ( XLALUnitAsString( unitString, LALUnitTextSize, &(output.units)) == NULL ) {
      return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
    }
    printf( "Units are \"%s\", ", unitString );
    if ( XLALUnitAsString( unitString, LALUnitTextSize, &(goodData1.sampleUnits)) == NULL ) {
      return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
    }
    printf( "should be \"%s\"\n", unitString );
  }

  if (result != 0)
  {
    printf("  FAIL: Valid data test #1\n");
    if (optVerbose)
    {
      printf("Exiting with error: %s\n",
             STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS);
    }
    return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
  }

  printf("  PASS: Valid data test #1\n");


  /********************** Test Valid Data Case #2 *****************/
  goodData1.sampleUnits = lalDimensionlessUnit;
  goodData1.sampleUnits.unitNumerator[LALUnitIndexStrain] = 1;
  goodData1.sampleUnits.unitNumerator[LALUnitIndexSecond] = 1;
  goodData2.sampleUnits = lalDimensionlessUnit;
  goodData2.sampleUnits.unitNumerator[LALUnitIndexADCCount] = 1;
  goodData2.sampleUnits.unitNumerator[LALUnitIndexSecond] = 1;
  goodFilter.sampleUnits = lalDimensionlessUnit;
  goodFilter.sampleUnits.unitNumerator[LALUnitIndexStrain] = -1;
  goodFilter.sampleUnits.unitNumerator[LALUnitIndexADCCount] = -1;

  goodData1.f0 = goodData2.f0 = goodFilter.f0
    = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0;

  for (i=0; i<STOCHASTICCROSSCORRELATIONSTATISTICTESTC_LENGTH; ++i)
  {
    f = STOCHASTICCROSSCORRELATIONSTATISTICTESTC_F0
      + i * STOCHASTICCROSSCORRELATIONSTATISTICTESTC_DELTAF;
    goodData1.data->data[i] = crectf( f/STOCHASTICCROSSCORRELATIONSTATISTICTESTC_FLIM, 0.0 );
    goodData2.data->data[i] = crectf( 1 - crealf(goodData1.data->data[i]), 0.0 );
    if ( f > STOCHASTICCROSSCORRELATIONSTATISTICTESTC_WINMIN
         && f < STOCHASTICCROSSCORRELATIONSTATISTICTESTC_WINMAX )
    {
      goodFilter.data->data[i] = 1.0;
    }
    else
    {
      goodFilter.data->data[i] = 0.0;
    }
  }

  LALStochasticCrossCorrelationStatistic(&status, &output, &input, STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TRUE);
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  if (optVerbose)
  {
    printf("Y=%g, should be %g\n",output.value,
           STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EXP2);
  }
  if ( fabs(output.value-STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EXP2)
       / STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EXP2
       > STOCHASTICCROSSCORRELATIONSTATISTICTESTC_TOL)
  {
    printf("  FAIL: Valid data test #2\n");
    if (optVerbose)
    {
      printf("Exiting with error: %s\n",
             STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS);
    }
    return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
  }

  result = XLALUnitCompare(&lalSecondUnit, &(output.units));
  if (optVerbose)
  {
    if ( XLALUnitAsString( unitString, LALUnitTextSize, &(output.units)) == NULL ) {
      return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
    }
    printf( "Units are \"%s\", ", unitString );
    if ( XLALUnitAsString( unitString, LALUnitTextSize, &lalSecondUnit) == NULL ) {
      return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
    }
    printf( "should be \"%s\"\n", unitString );
  }

  if (result != 0)
  {
    printf("  FAIL: Valid data test #2\n");
    if (optVerbose)
    {
      printf("Exiting with error: %s\n",
             STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS);
    }
    return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
  }

  printf("  PASS: Valid data test #2\n");


  /* clean up */
  LALCDestroyVector(&status, &(goodFilter.data));
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  LALCDestroyVector(&status, &(goodData1.data));
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  LALCDestroyVector(&status, &(goodData2.data));
  if ( ( code = CheckStatus(&status, 0 , "",
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			    STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
  {
    return code;
  }

  printf("PASS: all tests\n");
  LALCheckMemoryLeaks();

  if (optData1File[0] && optData2File[0] && optFilterFile[0])
  {

    /* Allocate Memory */
    LALCCreateVector(&status, &(goodFilter.data), optLength);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    LALCCreateVector(&status, &(goodData1.data), optLength);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    LALCCreateVector(&status, &(goodData2.data), optLength);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    /* Read Data From Files */
    LALCReadFrequencySeries(&status, &(goodFilter), optFilterFile);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    LALCReadFrequencySeries(&status, &(goodData1), optData1File);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    LALCReadFrequencySeries(&status, &(goodData2), optData2File);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }
    /* Calculate CC Statistic */
    LALStochasticCrossCorrelationStatistic(&status, &output, &input, optMatch);
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EUSE,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEUSE) ) )
    {
      return code;
    }

    /* Convert Unit Structure to String */
    if ( XLALUnitAsString( unitString, LALUnitTextSize, &(output.units)) == NULL ) {
      return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS;
    }

    printf("=========== Cross-Correlation Statistic for User-Specified Data Is =======\n");
    printf("     %g %s\n", output.value, unitString);

    /* Deallocate Memory */
    LALCDestroyVector(&status, &(goodFilter.data));
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
    {
      return code;
    }
    LALCDestroyVector(&status, &(goodData1.data));
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
    {
      return code;
    }
    LALCDestroyVector(&status, &(goodData2.data));
    if ( ( code = CheckStatus(&status, 0 , "",
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_EFLS,
			      STOCHASTICCROSSCORRELATIONSTATISTICTESTC_MSGEFLS) ) )
    {
      return code;
    }
  }


  /* normal exit */
  LALCheckMemoryLeaks();
  return STOCHASTICCROSSCORRELATIONSTATISTICTESTC_ENOM;
}