示例#1
0
文件: vis.c 项目: Solaro/lalsuite
int main(int argc, char *argv[])
{
    LALFrStream *stream;
    REAL8TimeSeries *series;
    LIGOTimeGPS start;

    XLALSetErrorHandler(XLALAbortErrorHandler);

    parseargs(argc, argv);

    /* get the data */
    stream = XLALFrStreamCacheOpen(cache);
    XLALGPSSetREAL8(&start, t0 - pad);
    series = XLALFrStreamInputREAL8TimeSeries(stream, channel, &start, dt + 2.0 * pad, 0);
    XLALFrStreamClose(stream);

    /* manipulate the data */
    if (srate > 0)
        XLALResampleREAL8TimeSeries(series, 1.0 / srate);
    if (minfreq > 0)
        XLALHighPassREAL8TimeSeries(series, minfreq, 0.9, 8);
    if (maxfreq > 0)
        XLALLowPassREAL8TimeSeries(series, maxfreq, 0.9, 8);
    if (pad > 0)
        series = XLALResizeREAL8TimeSeries(series, pad / series->deltaT, dt / series->deltaT);

    if (df > 0) { /* we are computing a spectrum */
        REAL8FrequencySeries *spectrum;
        REAL8FFTPlan *plan;
        REAL8Window *window;
        size_t seglen = 1.0 / (df * series->deltaT);

        /* make sure that the time series length is commensurate with seglen */
        if (((2 * series->data->length) % seglen) != 0) {
            size_t newlen = ((2 * series->data->length) / seglen) * seglen;
            series = XLALResizeREAL8TimeSeries(series, 0, newlen);
        }

        spectrum = XLALCreateREAL8FrequencySeries(series->name, &series->epoch, 0.0, df, &lalDimensionlessUnit, seglen/2 + 1);
        plan = XLALCreateForwardREAL8FFTPlan(seglen, 0);
        window = XLALCreateHannREAL8Window(seglen);
        XLALREAL8AverageSpectrumWelch(spectrum, series, seglen, seglen/2, window, plan);
        if (minfreq > 0 || maxfreq > 0) {
            size_t first = minfreq / spectrum->deltaF;
            size_t last = maxfreq > 0 ? maxfreq / spectrum->deltaF : spectrum->data->length;
            spectrum = XLALResizeREAL8FrequencySeries(spectrum, first, last - first);
        }
        output_fs(outfile, spectrum);
        XLALDestroyREAL8Window(window);
        XLALDestroyREAL8FFTPlan(plan);
        XLALDestroyREAL8FrequencySeries(spectrum);
    } else { /* we are outputting a time series */
        output_ts(outfile, series);
    }

    XLALDestroyREAL8TimeSeries(series);
    return 0;
}
示例#2
0
文件: sgwb.c 项目: ahnitz/lalsuite
int main(int argc, char *argv[])
{
	char tstr[32]; // string to hold GPS time -- 31 characters is enough
	const double H0 = 0.72 * LAL_H0FAC_SI; // Hubble's constant in seconds
	const size_t length = 65536; // number of points in a segment
	const size_t stride = length / 2; // number of points in a stride
	size_t i, n;
	REAL8FrequencySeries *OmegaGW = NULL;
	REAL8TimeSeries **seg = NULL;
	LIGOTimeGPS epoch;
	gsl_rng *rng;

	XLALSetErrorHandler(XLALAbortErrorHandler);

	parseargs(argc, argv);

	XLALGPSSetREAL8(&epoch, tstart);
	gsl_rng_env_setup();
	rng = gsl_rng_alloc(gsl_rng_default);
	OmegaGW = XLALSimSGWBOmegaGWFlatSpectrum(Omega0, flow, srate/length, length/2 + 1);

	n = duration * srate;
	seg = LALCalloc(numDetectors, sizeof(*seg));
	printf("# time (s)");
	for (i = 0; i < numDetectors; ++i) {
		char name[LALNameLength];
		snprintf(name, sizeof(name), "%s:STRAIN", detectors[i].frDetector.prefix);
		seg[i] = XLALCreateREAL8TimeSeries(name, &epoch, 0.0, 1.0/srate, &lalStrainUnit, length);
		printf("\t%s (strain)", name);
	}
	printf("\n");

	XLALSimSGWB(seg, detectors, numDetectors, 0, OmegaGW, H0, rng); // first time to initilize

	while (1) { // infinite loop
		size_t j;
		for (j = 0; j < stride; ++j, --n) { // output first stride points
			LIGOTimeGPS t = seg[0]->epoch;
			if (n == 0) // check if we're done
				goto end;
			printf("%s", XLALGPSToStr(tstr, XLALGPSAdd(&t, j * seg[0]->deltaT)));
			for (i = 0; i < numDetectors; ++i)
				printf("\t%e", seg[i]->data->data[j]);
			printf("\n");
		}
		XLALSimSGWB(seg, detectors, numDetectors, stride, OmegaGW, H0, rng); // make more data
	}

end:
	for (i = 0; i < numDetectors; ++i)
		XLALDestroyREAL8TimeSeries(seg[i]);
	XLALFree(seg);
	XLALDestroyREAL8FrequencySeries(OmegaGW);
	LALCheckMemoryLeaks();

	return 0;
}
示例#3
0
int main(int argc, char *argv[])
{
	const double H0 = 0.72 * LAL_H0FAC_SI; // Hubble's constant in seconds
	const double srate = 16384.0; // sampling rate in Hertz
	const size_t length = 65536; // number of points in a segment
	const size_t stride = length / 2; // number of points in a stride
	size_t i, n;
	REAL8FrequencySeries *OmegaGW = NULL;
	REAL8TimeSeries **seg = NULL;
	LIGOTimeGPS epoch;
	gsl_rng *rng;

	XLALSetErrorHandler(XLALAbortErrorHandler);

	parseargs(argc, argv);

	XLALGPSSetREAL8(&epoch, tstart);
	gsl_rng_env_setup();
	rng = gsl_rng_alloc(gsl_rng_default);
	OmegaGW = XLALSimSGWBOmegaGWFlatSpectrum(Omega0, flow, srate/length, length/2 + 1);

	n = duration * srate;
	seg = LALCalloc(numDetectors, sizeof(*seg));
	for (i = 0; i < numDetectors; ++i)
		seg[i] = XLALCreateREAL8TimeSeries("STRAIN", &epoch, 0.0, 1.0/srate, &lalStrainUnit, length);

	XLALSimSGWB(seg, detectors, numDetectors, 0, OmegaGW, H0, rng); // first time to initilize
	while (1) { // infinite loop
		double t0 = XLALGPSGetREAL8(&seg[0]->epoch);
		size_t j;
		for (j = 0; j < stride; ++j, --n) { // output first stride points
			if (n == 0) // check if we're done
				goto end;
			printf("%.9f", t0 + j * seg[0]->deltaT);
			for (i = 0; i < numDetectors; ++i)
				printf("\t%e", seg[i]->data->data[j]);
			printf("\n");
		}
		XLALSimSGWB(seg, detectors, numDetectors, stride, OmegaGW, H0, rng); // make more data
	}

end:
	for (i = 0; i < numDetectors; ++i)
		XLALDestroyREAL8TimeSeries(seg[i]);
	XLALFree(seg);
	XLALDestroyREAL8FrequencySeries(OmegaGW);
	LALCheckMemoryLeaks();

	return 0;
}
示例#4
0
REAL8 calculate_snr_from_strain_and_psd_real8(  REAL8TimeSeries *strain,
                                       REAL8FrequencySeries  *psd,
                                       REAL8                 startFreq,
                                       const CHAR            ifo[3])
{

  REAL8 ret = -1, snrSq, freq, psdValue;
  REAL8 deltaF;
  REAL8FFTPlan *pfwd;
  COMPLEX16FrequencySeries *fftData;
  UINT4 k;

  /* create the time series */
  deltaF  = strain->deltaT * strain->data->length;
  fftData = XLALCreateCOMPLEX16FrequencySeries( strain->name,  &(strain->epoch),
                                               0, deltaF, &lalDimensionlessUnit,
                                               strain->data->length/2 + 1 );

  /* perform the fft */
  pfwd = XLALCreateForwardREAL8FFTPlan( strain->data->length, 0 );
  XLALREAL8TimeFreqFFT( fftData, strain, pfwd );

  /* The PSD, if provided, comes in as it was in the original file  */
  /* since we don't know deltaF until we get here.  Interpolate now */
  if ( psd )
  {
    psd = XLALInterpolatePSD(psd, 1.0 / deltaF);
  }

  /* compute the SNR for initial LIGO at design */
  for ( snrSq = 0, k = 0; k < fftData->data->length; k++ )
  {
    freq = fftData->deltaF * k;

    if ( psd )
    {
      if ( freq < startFreq || k > psd->data->length )
        continue;
      psdValue  = psd->data->data[k];
      psdValue /= 9e-46;
    }
    else if ( ifo[0] == 'V' )
    {
      if (freq < 35)
        continue;
      LALVIRGOPsd( NULL, &psdValue, freq );
      psdValue /= 9e-46;
    }
    else
    {
      if (freq < 40)
        continue;
      LALLIGOIPsd( NULL, &psdValue, freq );
    }

    fftData->data->data[k] /= 3e-23;

    snrSq += creal(fftData->data->data[k]) * creal(fftData->data->data[k]) / psdValue;
    snrSq += cimag(fftData->data->data[k]) * cimag(fftData->data->data[k]) / psdValue;
  }

  snrSq *= 4*fftData->deltaF;

  XLALDestroyREAL8FFTPlan( pfwd );
  XLALDestroyCOMPLEX16FrequencySeries( fftData );

  if ( psd )
    XLALDestroyREAL8FrequencySeries( psd );

  ret = sqrt(snrSq);

  printf("Obtained snr=%f\n", ret);
  return ret;
}
示例#5
0
/*============================================================
 * FUNCTION definitions
 *============================================================*/
int
main(int argc, char *argv[])
{
  static LALStatus       status;  /* LALStatus pointer */
  UserVariables_t XLAL_INIT_DECL(uvar);
  ConfigVariables_t XLAL_INIT_DECL(cfg);

  UINT4 k, numBins, numIFOs, maxNumSFTs, X, alpha;
  REAL8 Freq0, dFreq, normPSD;
  UINT4 finalBinSize, finalBinStep, finalNumBins;

  REAL8Vector *overSFTs = NULL; /* one frequency bin over SFTs */
  REAL8Vector *overIFOs = NULL; /* one frequency bin over IFOs */
  REAL8Vector *finalPSD = NULL; /* math. operation PSD over SFTs and IFOs */
  REAL8Vector *finalNormSFT = NULL; /* normalised SFT power */

  vrbflg = 1;	/* verbose error-messages */

  /* set LAL error-handler */
  lal_errhandler = LAL_ERR_EXIT;

  /* register and read user variables */
  if (initUserVars(argc, argv, &uvar) != XLAL_SUCCESS)
    return EXIT_FAILURE;

  MultiSFTVector *inputSFTs = NULL;
  if ( ( inputSFTs = XLALReadSFTs ( &cfg, &uvar ) ) == NULL )
    {
      XLALPrintError ("Call to XLALReadSFTs() failed with xlalErrno = %d\n", xlalErrno );
      return EXIT_FAILURE;
    }

  /* clean sfts if required */
  if ( XLALUserVarWasSet( &uvar.linefiles ) )
    {
      RandomParams *randPar=NULL;
      FILE *fpRand=NULL;
      INT4 seed, ranCount;

      if ( (fpRand = fopen("/dev/urandom", "r")) == NULL ) {
	fprintf(stderr,"Error in opening /dev/urandom" );
	return EXIT_FAILURE;
      }

      if ( (ranCount = fread(&seed, sizeof(seed), 1, fpRand)) != 1 ) {
	fprintf(stderr,"Error in getting random seed" );
	return EXIT_FAILURE;
      }

      LAL_CALL ( LALCreateRandomParams (&status, &randPar, seed), &status );

      LAL_CALL( LALRemoveKnownLinesInMultiSFTVector ( &status, inputSFTs, uvar.maxBinsClean, uvar.blocksRngMed, uvar.linefiles, randPar), &status);
      LAL_CALL ( LALDestroyRandomParams (&status, &randPar), &status);
      fclose(fpRand);
    } /* end cleaning */

  LogPrintf (LOG_DEBUG, "Computing spectrogram and PSD ... ");

  /* get power running-median rngmed[ |data|^2 ] from SFTs */
  MultiPSDVector *multiPSD = NULL;
  XLAL_CHECK_MAIN( ( multiPSD = XLALNormalizeMultiSFTVect ( inputSFTs, uvar.blocksRngMed, NULL ) ) != NULL, XLAL_EFUNC);
  /* restrict this PSD to just the "physical" band if requested using {--Freq, --FreqBand} */
  if ( ( XLALCropMultiPSDandSFTVectors ( multiPSD, inputSFTs, cfg.firstBin, cfg.lastBin )) != XLAL_SUCCESS ) {
    XLALPrintError ("%s: XLALCropMultiPSDandSFTVectors (inputPSD, inputSFTs, %d, %d) failed with xlalErrno = %d\n", __func__, cfg.firstBin, cfg.lastBin, xlalErrno );
    return EXIT_FAILURE;
  }

  /* start frequency and frequency spacing */
  Freq0 = multiPSD->data[0]->data[0].f0;
  dFreq = multiPSD->data[0]->data[0].deltaF;

  /* number of raw bins in final PSD */
  numBins = multiPSD->data[0]->data[0].data->length;
  if ( (finalPSD = XLALCreateREAL8Vector ( numBins )) == NULL ) {
    LogPrintf (LOG_CRITICAL, "Out of memory!\n");
    return EXIT_FAILURE;
  }

  /* number of IFOs */
  numIFOs = multiPSD->length;
  if ( (overIFOs = XLALCreateREAL8Vector ( numIFOs )) == NULL ) {
    LogPrintf (LOG_CRITICAL, "Out of memory!\n");
    return EXIT_FAILURE;
  }

  /* maximum number of SFTs */
  maxNumSFTs = 0;
  for (X = 0; X < numIFOs; ++X) {
    maxNumSFTs = GSL_MAX(maxNumSFTs, multiPSD->data[X]->length);
  }
  if ( (overSFTs = XLALCreateREAL8Vector ( maxNumSFTs )) == NULL ) {
    LogPrintf (LOG_CRITICAL, "Out of memory!\n");
    return EXIT_FAILURE;
  }

  /* normalize rngmd(power) to get proper *single-sided* PSD: Sn = (2/Tsft) rngmed[|data|^2]] */
  normPSD = 2.0 * dFreq;

  /* loop over frequency bins in final PSD */
  for (k = 0; k < numBins; ++k) {

    /* loop over IFOs */
    for (X = 0; X < numIFOs; ++X) {

      /* number of SFTs for this IFO */
      UINT4 numSFTs = multiPSD->data[X]->length;

      /* copy PSD frequency bins and normalise multiPSD for later use */
      for (alpha = 0; alpha < numSFTs; ++alpha) {
	multiPSD->data[X]->data[alpha].data->data[k] *= normPSD;
	overSFTs->data[alpha] = multiPSD->data[X]->data[alpha].data->data[k];
      }

      /* compute math. operation over SFTs for this IFO */
      overIFOs->data[X] = math_op(overSFTs->data, numSFTs, uvar.PSDmthopSFTs);
      if ( isnan( overIFOs->data[X] ) )
        XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in overIFOs->data[X=%d] = NAN ... exiting\n", X );

    } /* for IFOs X */

    /* compute math. operation over IFOs for this frequency */
    finalPSD->data[k] = math_op(overIFOs->data, numIFOs, uvar.PSDmthopIFOs);
    if ( isnan ( finalPSD->data[k] ) )
      XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in finalPSD->data[k=%d] = NAN ... exiting\n", k );

  } /* for freq bins k */
  LogPrintfVerbatim ( LOG_DEBUG, "done.\n");

  /* compute normalised SFT power */
  if (uvar.outputNormSFT) {
    LogPrintf (LOG_DEBUG, "Computing normalised SFT power ... ");

    if ( (finalNormSFT = XLALCreateREAL8Vector ( numBins )) == NULL ) {
      LogPrintf (LOG_CRITICAL, "Out of memory!\n");
      return EXIT_FAILURE;
    }

    /* loop over frequency bins in SFTs */
    for (k = 0; k < numBins; ++k) {

      /* loop over IFOs */
      for (X = 0; X < numIFOs; ++X) {

	/* number of SFTs for this IFO */
	UINT4 numSFTs = inputSFTs->data[X]->length;

	/* compute SFT power */
	for (alpha = 0; alpha < numSFTs; ++alpha) {
	  COMPLEX8 bin = inputSFTs->data[X]->data[alpha].data->data[k];
	  overSFTs->data[alpha] = crealf(bin)*crealf(bin) + cimagf(bin)*cimagf(bin);
	}

	/* compute math. operation over SFTs for this IFO */
	overIFOs->data[X] = math_op(overSFTs->data, numSFTs, uvar.nSFTmthopSFTs);
	if ( isnan ( overIFOs->data[X] ))
          XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in overIFOs->data[X=%d] = NAN ... exiting\n", X );

      } /* over IFOs */

      /* compute math. operation over IFOs for this frequency */
      finalNormSFT->data[k] = math_op(overIFOs->data, numIFOs, uvar.nSFTmthopIFOs);
      if ( isnan( finalNormSFT->data[k] ) )
        XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in bin finalNormSFT->data[k=%d] = NAN ... exiting\n", k );

    } /* over freq bins */
    LogPrintfVerbatim ( LOG_DEBUG, "done.\n");
  }

  /* output spectrograms */
  if ( uvar.outputSpectBname ) {
    LAL_CALL ( LALfwriteSpectrograms ( &status, uvar.outputSpectBname, multiPSD ), &status );
  }

  /* ---------- if user requested it, output complete MultiPSDVector over IFOs X, timestamps and freq-bins into ASCI file(s) */
  if ( uvar.dumpMultiPSDVector ) {
    if ( XLALDumpMultiPSDVector ( uvar.outputPSD, multiPSD ) != XLAL_SUCCESS ) {
      XLALPrintError ("%s: XLALDumpMultiPSDVector() failed, xlalErrnor = %d\n", __func__, xlalErrno );
      return EXIT_FAILURE;
    }
  } /* if uvar.dumpMultiPSDVector */

  /* ----- if requested, compute data-quality factor 'Q' -------------------- */
  if ( uvar.outputQ )
    {
      REAL8FrequencySeries *Q;
      if ( (Q = XLALComputeSegmentDataQ ( multiPSD, cfg.dataSegment )) == NULL ) {
        XLALPrintError ("%s: XLALComputeSegmentDataQ() failed with xlalErrno = %d\n", __func__, xlalErrno );
        return EXIT_FAILURE;
      }
      if ( XLAL_SUCCESS != XLALWriteREAL8FrequencySeries_to_file ( Q, uvar.outputQ ) ) {
        return EXIT_FAILURE;
      }
      XLALDestroyREAL8FrequencySeries ( Q );
    } /* if outputQ */

  /* ---------- BINNING if requested ---------- */
  /* work out bin size */
  if (XLALUserVarWasSet(&uvar.binSize)) {
    finalBinSize = uvar.binSize;
  }
  else if (XLALUserVarWasSet(&uvar.binSizeHz)) {
    finalBinSize = (UINT4)floor(uvar.binSizeHz / dFreq + 0.5); /* round to nearest bin */
  }
  else {
    finalBinSize = 1;
  }

  /* work out bin step */
  if (XLALUserVarWasSet(&uvar.binStep)) {
    finalBinStep = uvar.binStep;
  }
  else if (XLALUserVarWasSet(&uvar.binStepHz)) {
    finalBinStep = (UINT4)floor(uvar.binStepHz / dFreq + 0.5); /* round to nearest bin */
  }
  else {
    finalBinStep = finalBinSize;
  }

  /* work out total number of bins */
  finalNumBins = (UINT4)floor((numBins - finalBinSize) / finalBinStep) + 1;

  /* write final PSD to file */
  if (XLALUserVarWasSet(&uvar.outputPSD)) {

    FILE *fpOut = NULL;

    if ((fpOut = fopen(uvar.outputPSD, "wb")) == NULL) {
      LogPrintf ( LOG_CRITICAL, "Unable to open output file %s for writing...exiting \n", uvar.outputPSD );
      return EXIT_FAILURE;
    }

    /* write header info in comments */
    if ( XLAL_SUCCESS != XLALOutputVersionString ( fpOut, 0 ) )
      XLAL_ERROR ( XLAL_EFUNC );

    /* write the command-line */
    for (int a = 0; a < argc; a++)
      fprintf(fpOut,"%%%% argv[%d]: '%s'\n", a, argv[a]);

    /* write column headings */
    fprintf(fpOut,"%%%% columns:\n%%%% FreqBinStart");
    if (uvar.outFreqBinEnd)
      fprintf(fpOut," FreqBinEnd");
    fprintf(fpOut," PSD");
    if (uvar.outputNormSFT)
      fprintf(fpOut," normSFTpower");
    fprintf(fpOut,"\n");

    LogPrintf(LOG_DEBUG, "Printing PSD to file ... ");
    for (k = 0; k < finalNumBins; ++k) {
      UINT4 b = k * finalBinStep;

      REAL8 f0 = Freq0 + b * dFreq;
      REAL8 f1 = f0 + finalBinStep * dFreq;
      fprintf(fpOut, "%f", f0);
      if (uvar.outFreqBinEnd)
	fprintf(fpOut, "   %f", f1);

      REAL8 psd = math_op(&(finalPSD->data[b]), finalBinSize, uvar.PSDmthopBins);
      if ( isnan ( psd ))
        XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in psd[k=%d] = NAN ... exiting\n", k );

      fprintf(fpOut, "   %e", psd);

      if (uvar.outputNormSFT) {
	REAL8 nsft = math_op(&(finalNormSFT->data[b]), finalBinSize, uvar.nSFTmthopBins);
	if ( isnan ( nsft ))
          XLAL_ERROR ( EXIT_FAILURE, "Found Not-A-Number in nsft[k=%d] = NAN ... exiting\n", k );

	fprintf(fpOut, "   %f", nsft);
      }

      fprintf(fpOut, "\n");
    } // k < finalNumBins
    LogPrintfVerbatim ( LOG_DEBUG, "done.\n");

    fclose(fpOut);

  }

  /* we are now done with the psd */
  XLALDestroyMultiPSDVector  ( multiPSD);
  XLALDestroyMultiSFTVector  ( inputSFTs);

  XLALDestroyUserVars();

  XLALDestroyREAL8Vector ( overSFTs );
  XLALDestroyREAL8Vector ( overIFOs );
  XLALDestroyREAL8Vector ( finalPSD );
  XLALDestroyREAL8Vector ( finalNormSFT );

  LALCheckMemoryLeaks();

  return EXIT_SUCCESS;

} /* main() */
示例#6
0
/**
 * Compute the "data-quality factor" \f$\mathcal{Q}(f) = \sum_X \frac{\epsilon_X}{\mathcal{S}_X(f)}\f$ over the given SFTs.
 * The input \a multiPSD is a pre-computed PSD map \f$\mathcal{S}_{X,i}(f)\f$, over IFOs \f$X\f$, SFTs \f$i\f$
 * and frequency \f$f\f$.
 *
 * \return the output is a vector \f$\mathcal{Q}(f)\f$.
 *
 */
REAL8FrequencySeries *
XLALComputeSegmentDataQ ( const MultiPSDVector *multiPSDVect, 	/**< input PSD map over IFOs, SFTs, and frequencies */
                          LALSeg segment		  	/**< segment to compute Q for */
                          )
{
  /* check input consistency */
  if ( multiPSDVect == NULL ) {
    XLALPrintError ("%s: NULL input 'multiPSDVect'\n", __func__ );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }
  if ( multiPSDVect->length == 0 || multiPSDVect->data==0 ) {
    XLALPrintError ("%s: invalid multiPSDVect input (length=0 or data=NULL)\n", __func__ );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  REAL8 Tseg = XLALGPSDiff ( &segment.end, &segment.start );
  if ( Tseg <= 0 ) {
    XLALPrintError ("%s: negative segment-duration '%g'\n", __func__, Tseg );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  REAL8 Tsft 	 = 1.0 / multiPSDVect->data[0]->data[0].deltaF;
  REAL8 f0       = multiPSDVect->data[0]->data[0].f0;
  REAL8 dFreq    = multiPSDVect->data[0]->data[0].deltaF;
  UINT4 numFreqs = multiPSDVect->data[0]->data[0].data->length;

  REAL8FrequencySeries *Q, *SXinv;
  if ( (Q = XLALCreateREAL8FrequencySeries ( "Qfactor", &segment.start, f0, dFreq, &lalHertzUnit, numFreqs )) == NULL ) {
    XLALPrintError ("%s: Q = XLALCreateREAL8FrequencySeries(numFreqs=%d) failed with xlalErrno = %d\n", __func__, numFreqs, xlalErrno );
    XLAL_ERROR_NULL ( XLAL_EFUNC );
  }
  if ( (SXinv = XLALCreateREAL8FrequencySeries ( "SXinv", &segment.start, f0, dFreq, &lalHertzUnit, numFreqs )) == NULL ) {
    XLALPrintError ("%s: SXinv = XLALCreateREAL8FrequencySeries(numFreqs=%d) failed with xlalErrno = %d\n", __func__, numFreqs, xlalErrno );
    XLAL_ERROR_NULL ( XLAL_EFUNC );
  }
  /* initialize Q-array to zero, as we'll keep adding to it */
  memset ( Q->data->data, 0, Q->data->length * sizeof(Q->data->data[0]) );

  /* ----- loop over IFOs ----- */
  UINT4 numIFOs = multiPSDVect->length;
  UINT4 X;
  for ( X = 0; X < numIFOs; X ++ )
    {
      PSDVector *thisPSDVect = multiPSDVect->data[X];

      /* initialize SXinv-array to zero, as we'll keep adding to it */
      memset ( SXinv->data->data, 0, SXinv->data->length * sizeof(SXinv->data->data[0]) );
      UINT4 numSFTsInSeg = 0;	/* reset counter of SFTs within this segment */

      /* ----- loop over all timestamps ----- */
      /* find SFTs inside segment, count them and combine their PSDs */
      UINT4 numTS = thisPSDVect->length;
      UINT4 iTS;
      for ( iTS = 0; iTS < numTS; iTS++ )
        {
          REAL8FrequencySeries *thisPSD = &thisPSDVect->data[iTS];

          /* some internal consistency/paranoia checks */
          if ( ( f0 != thisPSD->f0) || ( dFreq != thisPSD->deltaF ) || (numFreqs != thisPSD->data->length ) ) {
            XLALPrintError ("%s: %d-th timestamp %f: inconsistent PSDVector: f0 = %g : %g,  dFreq = %g : %g, numFreqs = %d : %d \n",
                            __func__, iTS, XLALGPSGetREAL8( &thisPSD->epoch ), f0, thisPSD->f0, dFreq, thisPSD->deltaF, numFreqs, thisPSD->data->length );
            XLAL_ERROR_NULL ( XLAL_EDOM );
          }

          int cmp = XLALCWGPSinRange( thisPSD->epoch, &segment.start, &segment.end );

          if ( cmp < 0 )	/* SFT-end before segment => advance to the next one */
            continue;
          if ( cmp > 0 )	/* SFT-start past end of segment: ==> terminate loop */
            break;

          if ( cmp == 0 )	/* this SFT is inside segment */
            {
              numSFTsInSeg ++;
              /* add SXinv(f) += 1/SX_i(f) over all frequencies */
              UINT4 iFreq;
              for ( iFreq = 0; iFreq < numFreqs; iFreq++ )
                SXinv->data->data[iFreq] += 1.0 / thisPSD->data->data[iFreq] ;

            }	/* if SFT inside segment */

        } /* for iTS < numTS */

      /* compute duty-cycle eps_X = nX * Tsft / Tseg for this IFO */
      REAL8 duty_X = numSFTsInSeg * Tsft / Tseg;
      /* sanity check: eps in [0, 1]*/
      if ( (duty_X < 0) && (duty_X > 1 ) ) {
        XLALPrintError ("%s: something is WRONG: duty-cyle = %g not within [0,1]!\n", __func__, duty_X );
        XLAL_ERROR_NULL ( XLAL_EFAILED );
      }

      /* add duty_X-weighted SXinv to Q */
      UINT4 iFreq;
      for ( iFreq = 0; iFreq < numFreqs; iFreq ++ )
        Q->data->data[iFreq] += duty_X * SXinv->data->data[iFreq] / numSFTsInSeg;

    } /* for X < numIFOs */

  /* clean up, free memory */
  XLALDestroyREAL8FrequencySeries ( SXinv );


  return Q;

} /* XLALComputeSegmentDataQ() */
int main( int argc, char *argv[] )
{
  LALStatus                     status = blank_status;

  UINT4                         k;
  UINT4                         kLow;
  UINT4                         kHi;
  INT4                          numPoints       = 524288;
  REAL4                         fSampling       = 2048.;
  REAL4                         fLow            = 70.;
  REAL4                         fLowInj         = 40.;
  REAL8                         deltaT          = 1./fSampling;
  REAL8                         deltaF          = fSampling / numPoints;

  REAL4                          statValue;
 
  /* vars required to make freq series */
  LIGOTimeGPS                   epoch = { 0, 0 };
  LIGOTimeGPS                   gpsStartTime = {0, 0}; 
  REAL8                         f0 = 0.;
  REAL8                         offset = 0.;
  INT8                          waveformStartTime = 0;

  /* files contain PSD info */
  CHAR                         *injectionFile = NULL;         
  CHAR                         *outputFile    = NULL;         
  CHAR                         *specFileH1    = NULL;         
  CHAR                         *specFileH2    = NULL;         
  CHAR                         *specFileL1    = NULL;         

  COMPLEX8Vector               *unity = NULL;
  const LALUnit strainPerCount = {0,{0,0,0,0,0,1,-1},{0,0,0,0,0,0,0}};

  int                           numInjections = 0;
  int                           numTriggers = 0;

  /* template bank simulation variables */
  INT4                         injSimCount = 0;
  SimInspiralTable            *injectionHead  = NULL;
  SimInspiralTable            *thisInjection  = NULL;
  SnglInspiralTable           *snglHead       = NULL;
  SearchSummaryTable          *searchSummHead = NULL;
  /*SummValueTable              *summValueHead  = NULL;    */

  /* raw input data storage */
  REAL8FrequencySeries          *specH1        = NULL;
  REAL8FrequencySeries          *specH2        = NULL;
  REAL8FrequencySeries          *specL1        = NULL;
  REAL8FrequencySeries          *thisSpec      = NULL;
  COMPLEX8FrequencySeries       *resp          = NULL;
  COMPLEX8FrequencySeries       *detTransDummy = NULL;
  REAL4TimeSeries               *chan          = NULL;
  RealFFTPlan                   *pfwd          = NULL;
  COMPLEX8FrequencySeries       *fftData       = NULL;
  REAL8                          thisSnrsq     = 0;
  REAL8                          thisSnr       = 0;
  REAL8                          thisCombSnr   = 0;
  REAL8                          snrVec[3];
  REAL8                          dynRange      = 1./(3.0e-23);

  /* needed for inj */
  CoherentGW                 waveform;
  PPNParamStruc              ppnParams;
  DetectorResponse           detector;
  InterferometerNumber       ifoNumber   = LAL_UNKNOWN_IFO;

  /* output data */
  LIGOLwXMLStream       xmlStream;
  MetadataTable         proctable;
  MetadataTable         outputTable;
  MetadataTable         procparams;
  CHAR                  fname[256];         
  CHAR                  comment[LIGOMETA_COMMENT_MAX];
  ProcessParamsTable   *this_proc_param = NULL;

  CHAR   chanfilename[FILENAME_MAX];

  REAL4 sum = 0;
  REAL4 bitten_H1 = 0;
  REAL4 bitten_H2 = 0;
  REAL4 thisCombSnr_H1H2 = 0;

  /* create the process and process params tables */
  proctable.processTable = (ProcessTable *) calloc( 1, sizeof(ProcessTable) );
  XLALGPSTimeNow(&(proctable.processTable->start_time));
  XLALPopulateProcessTable(proctable.processTable, PROGRAM_NAME, lalAppsVCSIdentId,
      lalAppsVCSIdentStatus, lalAppsVCSIdentDate, 0);
  this_proc_param = procparams.processParamsTable = (ProcessParamsTable *) 
                                      calloc( 1, sizeof(ProcessParamsTable) );
  memset( comment, 0, LIGOMETA_COMMENT_MAX * sizeof(CHAR) );

  /* look at input args, write process params where required */
  while ( 1 )
  {

  /* getopt arguments */
  static struct option long_options[] =
  {
    /* these options set a flag */
    /* these options do not set a flag */
    {"help",                    no_argument,       0,                'h'},
    {"verbose",                 no_argument,       &vrbflg,           1 },
    {"version",                 no_argument,       0,                'V'},
    {"spectrum-H1",             required_argument, 0,                'a'},
    {"spectrum-H2",             required_argument, 0,                'b'},
    {"spectrum-L1",             required_argument, 0,                'c'},
    {"inj-file",                required_argument, 0,                'd'},
    {"comment",                 required_argument, 0,                'e'},
    {"output-file",             required_argument, 0,                'f'},
    {"coire-flag",              no_argument,       &coireflg,         1 },
    {"ligo-srd",                no_argument,       &ligosrd,          1 },
    {"write-chan",              no_argument,       &writechan,        1 },
    {"inject-overhead",         no_argument,       &injoverhead,      1 },
    {"f-lower",                 required_argument, 0,                'g'},
    {0, 0, 0, 0}
  };
  int c;
  
  /*
   *
   * parse command line arguments
   *
   */

    /* getopt_long stores long option here */
    int option_index = 0;
    size_t optarg_len;

    c = getopt_long_only( argc, argv, "a:b:c:d:e:f:g:hV", long_options, &option_index );

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

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

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

      case 'a':
        /* create storage for the spectrum file name */
        optarg_len = strlen( optarg ) + 1;
        specFileH1 = (CHAR *) calloc( optarg_len, sizeof(CHAR));
        memcpy( specFileH1, optarg, optarg_len );
        ADD_PROCESS_PARAM( "string", "%s", optarg );
        break;

      case 'b':
        /* create storage for the spectrum file name */
        optarg_len = strlen( optarg ) + 1;
        specFileH2 = (CHAR *) calloc( optarg_len, sizeof(CHAR));
        memcpy( specFileH2, optarg, optarg_len );
        ADD_PROCESS_PARAM( "string", "%s", optarg );
        break;

      case 'c':
        /* create storage for the spectrum file name */
        optarg_len = strlen( optarg ) + 1;
        specFileL1 = (CHAR *) calloc( optarg_len, sizeof(CHAR));
        memcpy( specFileL1, optarg, optarg_len );
        ADD_PROCESS_PARAM( "string", "%s", optarg );
        break;

      case 'd':
        /* create storage for the injection file name */
        optarg_len = strlen( optarg ) + 1;
        injectionFile = (CHAR *) calloc( optarg_len, sizeof(CHAR));
        memcpy( injectionFile, optarg, optarg_len );
        ADD_PROCESS_PARAM( "string", "%s", optarg );
        break;

      case 'f':
        /* create storage for the output file name */
        optarg_len = strlen( optarg ) + 1;
        outputFile = (CHAR *) calloc( optarg_len, sizeof(CHAR));
        memcpy( outputFile, optarg, optarg_len );
        ADD_PROCESS_PARAM( "string", "%s", optarg );
        break;
    
      case 'g':
        fLow = (INT4) atof( optarg );
        if ( fLow < 40 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "f-lower must be > 40Hz (%e specified)\n",
              long_options[option_index].name, fLow );
          exit( 1 );
        }
        ADD_PROCESS_PARAM( "float", "%e", fLow );
        break;


     case 'e':
        if ( strlen( optarg ) > LIGOMETA_COMMENT_MAX - 1 )
        {
          fprintf( stderr, "invalid argument to --%s:\n"
              "comment must be less than %d characters\n",
              long_options[option_index].name, LIGOMETA_COMMENT_MAX );
          exit( 1 );
        }
        else
        {
          snprintf( comment, LIGOMETA_COMMENT_MAX, "%s", optarg);
        }
        break;

      case 'V':
        /* print version information and exit */
        fprintf( stdout, "calculation of expected SNR of injections\n"
            "Gareth Jones\n");
        XLALOutputVersionString(stderr, 0);
        exit( 0 );
        break;

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

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

  /* check the input arguments */
  if ( injectionFile == NULL )
  {
    fprintf( stderr, "Must specify the --injection-file\n" );
    exit( 1 );
  }

  if ( outputFile == NULL )
  {
    fprintf( stderr, "Must specify the --output-file\n" );
    exit( 1 );
  }

  if ( !ligosrd && specFileH1 == NULL )
  {
    fprintf( stderr, "Must specify the --spectrum-H1\n" );
    exit( 1 );
  }

  if ( !ligosrd && specFileH2 == NULL )
  {
    fprintf( stderr, "Must specify the --spectrum-H2\n" );
    exit( 1 );
  }

  if ( !ligosrd && specFileL1 == NULL )
  {
    fprintf( stderr, "Must specify the --spectrum-L1\n" );
    exit( 1 );
  }

  if ( ligosrd && (specFileH1 || specFileH2 || specFileL1 ))
  {
    fprintf( stdout, "WARNING: using LIGOI SRD power spectral density \n" );
  } 
 
  if ( vrbflg ){
    fprintf( stdout, "injection file is %s\n", injectionFile );
    fprintf( stdout, "output file is %s\n", outputFile );
    fprintf( stdout, "H1 spec file is   %s\n", specFileH1 );
    fprintf( stdout, "H2 spec file is   %s\n", specFileH2 );
    fprintf( stdout, "L1 spec file is   %s\n", specFileL1 );
  }

  /* create vector for H1, H2 and L1 spectrums */
  specH1 = XLALCreateREAL8FrequencySeries ( "",&epoch, f0, deltaF, &lalADCCountUnit, (numPoints / 2 + 1) );
  specH2 = XLALCreateREAL8FrequencySeries ( "",&epoch, f0, deltaF, &lalADCCountUnit, (numPoints / 2 + 1) );
  specL1 = XLALCreateREAL8FrequencySeries ( "",&epoch, f0, deltaF, &lalADCCountUnit, (numPoints / 2 + 1) );
  if (!specH1 || !specH2 || !specL1){
    XLALDestroyREAL8FrequencySeries ( specH1 );
    XLALDestroyREAL8FrequencySeries ( specH2 );
    XLALDestroyREAL8FrequencySeries ( specL1 );
    XLALPrintError("failure allocating H1, H2 and L1 spectra");
    exit(1);
  }

  if (!ligosrd){
    /* read in H1 spectrum */ 
    LAL_CALL( LALDReadFrequencySeries(&status, specH1, specFileH1), &status );
    if ( vrbflg ){
       fprintf( stdout, "read in H1 spec file\n" );
       fflush( stdout );
    } 

    /* read in H2 spectrum */ 
    LAL_CALL( LALDReadFrequencySeries(&status, specH2, specFileH2), &status );
    if ( vrbflg ){
       fprintf( stdout, "read in H2 spec file\n" );
       fflush( stdout );
    }

    /* read in L1 spectrum */ 
    LAL_CALL( LALDReadFrequencySeries(&status, specL1, specFileL1), &status );
    if ( vrbflg ){
       fprintf( stdout, "read in L1 spec file\n" );
       fflush( stdout );
     }
  }

  chan = XLALCreateREAL4TimeSeries( "", &epoch, f0, deltaT, 
                                     &lalADCCountUnit, numPoints );
  if ( !chan ){
    XLALPrintError("failure allocating chan");
    exit(1);
  }

  /*
   *
   * set up the response function
   *
   */
  resp = XLALCreateCOMPLEX8FrequencySeries( chan->name, 
     &chan->epoch, f0, deltaF, &strainPerCount, (numPoints / 2 + 1) );
  if ( !resp ){
    XLALPrintError("failure allocating response function");
    exit(1);
  }

  /* create vector that will contain detector.transfer info, since this 
   * is constant I calculate it once outside of all the loops and pass it 
   * in to detector.transfer when required 
   */
  detTransDummy = XLALCreateCOMPLEX8FrequencySeries( chan->name, &chan->epoch,
                  f0, deltaF, &strainPerCount, (numPoints / 2 + 1) );
  if ( !detTransDummy ){
    XLALPrintError("failure allocating detector.transfer info");
    exit(1);
  }

  /* invert the response function to get the transfer function */
  unity = XLALCreateCOMPLEX8Vector( resp->data->length );
  for ( k = 0; k < unity->length; ++k )
     {
        unity->data[k] = 1.0;
     }

  /* set response */
  for ( k = 0; k < resp->data->length; ++k )
  {
      resp->data->data[k] = 1.0;
  }

  XLALCCVectorDivide( detTransDummy->data, unity, resp->data );
  XLALDestroyCOMPLEX8Vector( unity );

  /* read in injections from injection file */
  /* set endtime to 0 so that we read in all events */
  if ( vrbflg ) fprintf( stdout, "Reading sim_inspiral table of %s\n", injectionFile );
  LAL_CALL(numInjections = SimInspiralTableFromLIGOLw( &injectionHead, injectionFile, 0, 0), &status);
  if ( vrbflg ) fprintf( stdout, "Read %d injections from sim_inspiral table of %s\n", 
                                    numInjections, injectionFile );

  if (coireflg){
     if ( vrbflg ) fprintf( stdout, "Reading sngl_inspiral table of %s\n", injectionFile );
     LAL_CALL(numTriggers = LALSnglInspiralTableFromLIGOLw(&snglHead, injectionFile, 0, -1), &status);
     if ( vrbflg ) fprintf( stdout, "Read %d triggers from sngl_inspiral table of %s\n", 
                                    numTriggers, injectionFile );
     if ( vrbflg ) {
           fprintf( stdout, "Reading search_summary table of %s ...", injectionFile );
           fflush( stdout );
           }
     searchSummHead = XLALSearchSummaryTableFromLIGOLw (injectionFile);
     if ( vrbflg ) fprintf( stdout, " done\n");
  }

 /* make sure we start at head of linked list */
 thisInjection = injectionHead;

  /* setting fixed waveform injection parameters */
  memset( &ppnParams, 0, sizeof(PPNParamStruc) );
  ppnParams.deltaT   = deltaT;
  ppnParams.lengthIn = 0;
  ppnParams.ppn      = NULL;

  /* loop over injections */
  injSimCount = 0;
    
        
  do
  {
     fprintf( stdout, "injection %d/%d\n", injSimCount+1, numInjections );

     /* reset waveform structure */
     memset( &waveform, 0, sizeof(CoherentGW) );

     /* reset chan structure */
     memset( chan->data->data, 0, chan->data->length * sizeof(REAL4) );

     if (thisInjection->f_lower == 0){
        fprintf( stdout, "WARNING: f_lower in sim_inpiral = 0, ");
        fprintf( stdout, "changing this to %e\n ", fLowInj);
        thisInjection->f_lower = fLowInj;
     }

     /* create the waveform, amp, freq phase etc */
     LAL_CALL( LALGenerateInspiral(&status, &waveform, thisInjection, &ppnParams), &status);
     if (vrbflg) fprintf( stdout, "ppnParams.tc %e\n ", ppnParams.tc);

    statValue = 0.;
  
    /* calc lower index for integration */
    kLow = ceil(fLow / deltaF);
    if ( vrbflg ) {
        fprintf( stdout, "starting integration to find SNR at frequency %e ", fLow);
        fprintf( stdout, "at index %d \n", kLow);
    }
    /* calc upper index for integration */
    kHi = floor(fSampling / (2. * deltaF));
    if ( vrbflg ) {
        fprintf( stdout, "ending integration to find SNR at frequency %e ", fSampling / 2.);
        fprintf( stdout, "at index %d \n", kHi);
    }

    /* loop over ifo */
    for ( ifoNumber = 1; ifoNumber < 4; ifoNumber++ )
    {
        /* allocate memory and copy the parameters describing the freq series */
        memset( &detector, 0, sizeof( DetectorResponse ) );
        detector.site = (LALDetector *) LALMalloc( sizeof(LALDetector) );

        if (injoverhead){ 
           if ( vrbflg ) fprintf( stdout, "WARNING: perform overhead injections\n");
           /* setting detector.site to NULL causes SimulateCoherentGW to
            * perform overhead injections */  
           detector.site = NULL; 
        }
        else {
           /* if not overhead, set detector.site using ifonumber */  
           XLALReturnDetector( detector.site, ifoNumber );
        } 

        switch ( ifoNumber )
        {
        case 1:
           if ( vrbflg ) fprintf( stdout, "looking at H1 \n");
           thisSpec = specH1;
           break;
        case 2:
           if ( vrbflg ) fprintf( stdout, "looking at H2 \n");
           thisSpec = specH2;
           break;
        case 3:
           if ( vrbflg ) fprintf( stdout, "looking at L1 \n");
           thisSpec = specL1;
           break;
        default:
           fprintf( stderr, "Error: ifoNumber %d does not correspond to H1, H2 or L1: \n", ifoNumber );
           exit( 1 );
        }

        /* get the gps start time of the signal to inject */
        waveformStartTime = XLALGPSToINT8NS( &(thisInjection->geocent_end_time) );
        waveformStartTime -= (INT8) ( 1000000000.0 * ppnParams.tc );

        offset = (chan->data->length / 2.0) * chan->deltaT;
        gpsStartTime.gpsSeconds     = thisInjection->geocent_end_time.gpsSeconds - offset;
        gpsStartTime.gpsNanoSeconds = thisInjection->geocent_end_time.gpsNanoSeconds;
        chan->epoch = gpsStartTime;


       if (vrbflg) fprintf(stdout, "offset start time of injection by %f seconds \n", offset ); 
       
       /* is this okay? copying in detector transfer which so far only contains response info  */
       detector.transfer = detTransDummy;

       XLALUnitInvert( &(detector.transfer->sampleUnits), &(resp->sampleUnits) );

       /* set the start times for injection */
       XLALINT8NSToGPS( &(waveform.a->epoch), waveformStartTime );
       memcpy(&(waveform.f->epoch), &(waveform.a->epoch), sizeof(LIGOTimeGPS) );
       memcpy(&(waveform.phi->epoch), &(waveform.a->epoch), sizeof(LIGOTimeGPS) );
 
       /* perform the injection */
       LAL_CALL( LALSimulateCoherentGW(&status, chan, &waveform, &detector ), &status); 

       if (writechan){ 
          /* write out channel data */
          if (vrbflg) fprintf(stdout, "writing channel data to file... \n" ); 
          switch ( ifoNumber )
          {
          case 1:
             snprintf( chanfilename, FILENAME_MAX, "chanTest_H1_inj%d.dat", injSimCount+1);
             if (vrbflg) fprintf( stdout, "writing H1 channel time series out to %s\n", chanfilename );
             LALSPrintTimeSeries(chan, chanfilename );
             break;
          case 2:
             snprintf( chanfilename, FILENAME_MAX, "chanTest_H2_inj%d.dat", injSimCount+1);
             if (vrbflg) fprintf( stdout, "writing H2 channel time series out to %s\n", chanfilename );
             LALSPrintTimeSeries(chan, chanfilename );
             break;
          case 3:
             snprintf( chanfilename, FILENAME_MAX, "chanTest_L1_inj%d.dat", injSimCount+1);
             if (vrbflg) fprintf( stdout, "writing L1 channel time series out to %s\n", chanfilename );
             LALSPrintTimeSeries(chan, chanfilename );
             break;
         default:
             fprintf( stderr, "Error: ifoNumber %d does not correspond to H1, H2 or L1: \n", ifoNumber );
             exit( 1 );
         }  
      } 

      LAL_CALL( LALCreateForwardRealFFTPlan( &status, &pfwd, chan->data->length, 0), &status);

      fftData = XLALCreateCOMPLEX8FrequencySeries( chan->name, &chan->epoch, f0, deltaF, 
                                                   &lalDimensionlessUnit, (numPoints / 2 + 1) );
      if ( !fftData ){
        XLALPrintError("failure allocating fftData");
        exit(1);
      }
   
      LAL_CALL( LALTimeFreqRealFFT( &status, fftData, chan, pfwd ), &status);
   
      LAL_CALL( LALDestroyRealFFTPlan( &status, &pfwd ), &status);
      pfwd = NULL;

       /* compute the SNR */
       thisSnrsq = 0;
       /* avoid f=0 part of psd */  

       if (ligosrd){
          if (vrbflg) fprintf( stdout, "using LIGOI PSD \n");
          for ( k = kLow; k < kHi; k++ )
          {
           REAL8 freq;
           REAL8 sim_psd_value;
           freq = fftData->deltaF * k;
           LALLIGOIPsd( NULL, &sim_psd_value, freq ); 

           thisSnrsq += ((crealf(fftData->data->data[k]) * dynRange) * 
                      (crealf(fftData->data->data[k]) * dynRange)) / sim_psd_value;
           thisSnrsq += ((cimagf(fftData->data->data[k]) * dynRange) * 
                      (cimagf(fftData->data->data[k]) * dynRange)) / sim_psd_value;
           }
       }
       else {
          if (vrbflg) fprintf( stdout, "using input spectra \n");
          for ( k = kLow; k < kHi; k++ )
          {
           thisSnrsq += ((crealf(fftData->data->data[k]) * dynRange) * 
              (crealf(fftData->data->data[k]) * dynRange))  /
              (thisSpec->data->data[k] * dynRange * dynRange);
           thisSnrsq += ((cimagf(fftData->data->data[k]) * dynRange) * 
              (cimagf(fftData->data->data[k]) * dynRange)) /
              (thisSpec->data->data[k] * dynRange * dynRange);
        } 
      }

       thisSnrsq *= 4*fftData->deltaF;
       thisSnr    = pow(thisSnrsq, 0.5);
       /* Note indexing on snrVec, ifoNumber runs from 1..3 to get source correct,
        * we must index snrVec 0..2 
        */ 
       snrVec[ifoNumber-1] = thisSnr; 
       XLALDestroyCOMPLEX8FrequencySeries(fftData);

       if ( vrbflg ){
          fprintf( stdout, "thisSnrsq %e\n", thisSnrsq );
          fprintf( stdout, "snrVec    %e\n", snrVec[ifoNumber-1] );
          fflush( stdout );
       }

       /* sum thisSnrsq to eventually get combined snr*/
       statValue += thisSnrsq; 

       /* free some memory */
       if (detector.transfer) detector.transfer = NULL;
       if ( detector.site ) {LALFree( detector.site); detector.site = NULL;}
     }
     /* end loop over ifo */
  
    destroyCoherentGW( &waveform );

    /* store inverse eff snrs in eff_dist columns */
    thisInjection->eff_dist_h = 1./snrVec[0];
    thisInjection->eff_dist_g = 1./snrVec[1];
    thisInjection->eff_dist_l = 1./snrVec[2];

    /* store inverse sum of squares snr in eff_dist_t */
    thisCombSnr = pow(statValue, 0.5);
    if ( vrbflg ) fprintf( stdout, "thisCombSnr %e\n", thisCombSnr);
    thisInjection->eff_dist_t = 1./thisCombSnr;

    /* calc inverse bittenL snr for H1H2 and store in eff_dist_v */
    thisCombSnr_H1H2 = 0.;
    sum = snrVec[0] * snrVec[0] + snrVec[1] * snrVec[1];
    bitten_H1 = 3 * snrVec[0] -3;
    bitten_H2 = 3 * snrVec[1] -3;

    if (sum < bitten_H1){
       thisCombSnr_H1H2 = sum;
    }
    else
    {
       thisCombSnr_H1H2 = bitten_H1;
    }

    if (bitten_H2 < thisCombSnr_H1H2){
       thisCombSnr_H1H2 = bitten_H2;
    }
    thisInjection->eff_dist_v = 1./thisCombSnr_H1H2;


    /* increment the bank sim sim_inspiral table if necessary */
    if ( injectionHead )
    {
      thisInjection = thisInjection->next;
    }

  } while ( ++injSimCount < numInjections ); 
  /* end loop over injections */

  /* try opening, writing and closing an xml file */

  /* open the output xml file */
  memset( &xmlStream, 0, sizeof(LIGOLwXMLStream) );
  snprintf( fname, sizeof(fname), "%s", outputFile);
  LAL_CALL( LALOpenLIGOLwXMLFile  ( &status, &xmlStream, fname), &status);

  /* write out the process and process params tables */
  if ( vrbflg ) fprintf( stdout, "process... " );
  XLALGPSTimeNow(&(proctable.processTable->end_time));
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlStream, process_table ), &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlStream, proctable, process_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlStream ), &status );
  free( proctable.processTable );
  /* Just being pedantic here ... */
  proctable.processTable = NULL;
 
  /* free the unused process param entry */
  this_proc_param = procparams.processParamsTable;
  procparams.processParamsTable = procparams.processParamsTable->next;
  free( this_proc_param );
  this_proc_param = NULL;

  /* write the process params table */
  if ( vrbflg ) fprintf( stdout, "process_params... " );
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlStream, process_params_table ), &status );
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlStream, procparams, process_params_table ), &status );
  LAL_CALL( LALEndLIGOLwXMLTable ( &status, &xmlStream ), &status );

  /* write the search summary table */
  if ( coireflg ){
     if ( vrbflg ) fprintf( stdout, "search_summary... " );
     outputTable.searchSummaryTable = searchSummHead;
     LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlStream, search_summary_table), &status);
     LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlStream, outputTable, search_summary_table), &status);
     LAL_CALL( LALEndLIGOLwXMLTable  ( &status, &xmlStream), &status);
   }

  /* write the sim inspiral table */
  if ( vrbflg ) fprintf( stdout, "sim_inspiral... " );
  outputTable.simInspiralTable = injectionHead;
  LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlStream, sim_inspiral_table), &status);
  LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlStream, outputTable, sim_inspiral_table), &status);
  LAL_CALL( LALEndLIGOLwXMLTable  ( &status, &xmlStream), &status);

  /* write the sngl inspiral table */
  if ( coireflg ){
     if ( vrbflg ) fprintf( stdout, "sngl_inspiral... " );
     outputTable.snglInspiralTable = snglHead;
     LAL_CALL( LALBeginLIGOLwXMLTable( &status, &xmlStream, sngl_inspiral_table), &status);
     LAL_CALL( LALWriteLIGOLwXMLTable( &status, &xmlStream, outputTable, sngl_inspiral_table), &status);
     LAL_CALL( LALEndLIGOLwXMLTable  ( &status, &xmlStream), &status);
  } 

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

  /* Freeing memory */
  XLALDestroyREAL4TimeSeries(chan);
  XLALDestroyCOMPLEX8FrequencySeries(resp);
  XLALDestroyCOMPLEX8FrequencySeries(detTransDummy);
  XLALDestroyREAL8FrequencySeries ( specH1 );
  XLALDestroyREAL8FrequencySeries ( specH2 );
  XLALDestroyREAL8FrequencySeries ( specL1 );


  free( specFileH1 );
  specFileH1 = NULL;
  free( specFileH2 );
  specFileH2 = NULL;
  free( specFileL1 );
  specFileL1 = NULL;
  free( injectionFile ); 
  injectionFile = NULL;

  /* free the process params */
  while( procparams.processParamsTable )
  {
    this_proc_param = procparams.processParamsTable;
    procparams.processParamsTable = this_proc_param->next;
    free( this_proc_param );
    this_proc_param = NULL;
  }

  /* free the sim inspiral tables */
  while ( injectionHead )
  {
    thisInjection = injectionHead;
    injectionHead = injectionHead->next;
    LALFree( thisInjection );
  }

  /*check for memory leaks */
  LALCheckMemoryLeaks(); 

  exit( 0 ); 
}
int main(int argc, char *argv[])
{
	char tstr[32]; // string to hold GPS time -- 31 characters is enough
	size_t length;
	size_t stride;
	size_t n;
	REAL8FrequencySeries *psd = NULL;
	REAL8TimeSeries *seg = NULL;
	gsl_rng *rng;

	XLALSetErrorHandler(XLALAbortErrorHandler);

	parseargs(argc, argv);
	if (overrideflow > 0.0)
		flow = overrideflow;
	length = segdur * srate;
	stride = length / 2;

	/* handle 0noise case first */
	if (strcmp(detector, "0noise") == 0) {
		/* just print out a bunch of zeros */
		if (psdonly) {
			double deltaF = srate / length;
			size_t klow = flow / deltaF;
			size_t k;
			fprintf(stdout, "# freq (s^-1)\tPSD (strain^2 s)\n");
			for (k = klow; k < length/2 - 1; ++k)
				fprintf(stdout, "%e\t%e\n", k * deltaF, 0.0);
		} else {
			size_t j;
			fprintf(stdout, "# time (s)\tNOISE (strain)\n");
			n = duration * srate;
			for (j = 0; j < n; ++j) { 
				LIGOTimeGPS t = tstart;
				fprintf(stdout, "%s\t%e\n", XLALGPSToStr(tstr, XLALGPSAdd(&t, j/srate)), 0.0);
			}
		}
		return 0;
	}

	gsl_rng_env_setup();
	rng = gsl_rng_alloc(gsl_rng_default);
	psd = XLALCreateREAL8FrequencySeries(detector, &tstart, 0.0, srate/length, &strainSquaredPerHertzUnit, length/2 + 1);
	if (asdfile)
		XLALSimNoisePSDFromFile(psd, flow, asdfile);
	else if (official && opsdfunc)
		opsdfunc(psd, flow);
	else
		XLALSimNoisePSD(psd, flow, psdfunc);
	if (verbose) {
		double Mpc = 1e6 * LAL_PC_SI;
		double horizon_distance;
		fprintf(stderr, "%-39s %s\n", "detector: ", detector);
		fprintf(stderr, "%-39s %g Hz\n", "low-frequency cutoff: ", flow);
		horizon_distance = XLALMeasureStandardSirenHorizonDistance(psd, flow, -1.0);
		fprintf(stderr, "%-39s %g Mpc\n", "standard siren horizon distance: ", horizon_distance / Mpc);
		fprintf(stderr, "%-39s %g Mpc\n", "sense-monitor range: ", horizon_distance / Mpc / LAL_HORIZON_DISTANCE_OVER_SENSEMON_RANGE);
		fprintf(stderr, "%-39s GSL_RNG_TYPE=%s\n", "GSL random number generator:", gsl_rng_name(rng));
		fprintf(stderr, "%-39s GSL_RNG_SEED=%lu\n", "GSL random number seed:", gsl_rng_default_seed);
	}
	if (psdonly) { // output PSD and exit
		size_t klow = flow / psd->deltaF;
		size_t k;
		fprintf(stdout, "# freq (s^-1)\tPSD (strain^2 s)\n");
		for (k = klow; k < length/2 - 1; ++k)
			fprintf(stdout, "%e\t%e\n", k * psd->deltaF, sqrt(psd->data->data[k]));
		goto end;
	}

	n = duration * srate;
	seg = XLALCreateREAL8TimeSeries("STRAIN", &tstart, 0.0, 1.0/srate, &lalStrainUnit, length);
	XLALSimNoise(seg, 0, psd, rng); // first time to initialize
	fprintf(stdout, "# time (s)\tNOISE (strain)\n");
	while (1) { // infinite loop
		size_t j;
		for (j = 0; j < stride; ++j, --n) { // output first stride points
			LIGOTimeGPS t = seg->epoch;
			if (n == 0) // check if we're done
				goto end;
			fprintf(stdout, "%s\t%e\n", XLALGPSToStr(tstr, XLALGPSAdd(&t, j * seg->deltaT)), seg->data->data[j]);
		}
		XLALSimNoise(seg, stride, psd, rng); // make more data
	}

end:
	XLALDestroyREAL8TimeSeries(seg);
	XLALDestroyREAL8FrequencySeries(psd);
	LALCheckMemoryLeaks();

	return 0;
}