diff --git a/lalapps/src/pulsar/MakeData/ComputePSDFunction.c b/lalapps/src/pulsar/MakeData/ComputePSDFunction.c
new file mode 100644
index 0000000000000000000000000000000000000000..bd494f7ef76e10f75726bd1a605bc315bbe974db
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/ComputePSDFunction.c
@@ -0,0 +1,654 @@
+/*
+*  Copyright (C) 2007, 2010 Karl Wette
+*  Copyright (C) 2007 Badri Krishnan, Iraj Gholami, Reinhard Prix, Alicia Sintes
+*  Copyright (C) 2017-2021 Benjamin Steltner
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+/**
+ * \file
+ * \ingroup lalapps_pulsar_SFTTools
+ * \author Badri Krishnan, Iraj Gholami, Reinhard Prix, Alicia Sintes, Karl Wette, Benjamin Steltner
+ * \brief Compute power spectral densities
+ */
+
+/**
+ * This file is a copy of ComputePSD.c ( https://lscsoft.docs.ligo.org/lalsuite/lalapps/_compute_p_s_d_8c_source.html ).
+ * Most file I/O is removed, the main method takes an in-memory SFT and computes & returns an in-memory PSD to the caller.
+ */
+
+#include <glob.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gsl/gsl_sort.h>
+#include <gsl/gsl_math.h>
+#include <lal/LALStdlib.h>
+#include <lal/LALConstants.h>
+#include <lal/AVFactories.h>
+#include <lal/SeqFactories.h>
+#include <lal/SFTfileIO.h>
+#include <lal/Random.h>
+#include <lal/PulsarDataTypes.h>
+#include <lal/UserInput.h>
+#include <lal/NormalizeSFTRngMed.h>
+#include <lal/LALInitBarycenter.h>
+#include <lal/SFTClean.h>
+#include <lal/Segments.h>
+#include <lal/FrequencySeries.h>
+#include <lal/Units.h>
+
+#include <lal/LogPrintf.h>
+
+#include <LALAppsVCSInfo.h>
+#include "ComputePSDFunction.h"
+
+/* ---------- Error codes and messages ---------- */
+#define COMPUTEPSDC_ENORM 0
+#define COMPUTEPSDC_ESUB  1
+#define COMPUTEPSDC_EARG  2
+#define COMPUTEPSDC_EBAD  3
+#define COMPUTEPSDC_EFILE 4
+#define COMPUTEPSDC_ENULL 5
+#define COMPUTEPSDC_EMEM  6
+
+#define COMPUTEPSDC_MSGENORM "Normal exit"
+#define COMPUTEPSDC_MSGESUB  "Subroutine failed"
+#define COMPUTEPSDC_MSGEARG  "Error parsing arguments"
+#define COMPUTEPSDC_MSGEBAD  "Bad argument values"
+#define COMPUTEPSDC_MSGEFILE "Could not create output file"
+#define COMPUTEPSDC_MSGENULL "Null Pointer"
+#define COMPUTEPSDC_MSGEMEM  "Out of memory"
+
+/*---------- local defines ---------- */
+
+#define TRUE (1==1)
+#define FALSE (1==0)
+
+/* ----- Macros ----- */
+
+/* ---------- local types ---------- */
+
+/** types of mathematical operations */
+
+
+/**
+ * Config variables 'derived' from user-input
+ */
+typedef struct
+{
+  UINT4 firstBin;		/**< first PSD bin for output */
+  UINT4 lastBin;		/**< last PSD bin for output */
+  LALSeg dataSegment;		/**< the data-segment for which PSD was computed */
+} ConfigVariables_t;
+
+/* ---------- global variables ----------*/
+extern int vrbflg;
+
+/* ---------- local prototypes ---------- */
+static REAL8 math_op(REAL8*, size_t, INT4);
+int XLALDumpMultiPSDVector ( const CHAR *outbname, const MultiPSDVector *multiPSDVect );
+
+int XLALCropMultiPSDandSFTVectors ( MultiPSDVector *multiPSDVect, MultiSFTVector *multiSFTVect, UINT4 firstBin, UINT4 lastBin );
+
+/*============================================================
+ * FUNCTION definitions
+ *============================================================*/
+int
+computePSD(PSDUserVarsTag uvar, SFTtype *sft, REAL8FrequencySeries **Fseries)  {
+  ConfigVariables_t XLAL_INIT_DECL(cfg);
+
+  uvar.PSDmthopSFTs = MATH_OP_HARMONIC_MEAN;
+  uvar.PSDmthopIFOs = MATH_OP_HARMONIC_SUM;
+
+  uvar.nSFTmthopSFTs = MATH_OP_ARITHMETIC_MEAN;
+  uvar.nSFTmthopIFOs = MATH_OP_MAXIMUM;
+
+  uvar.PSDmthopBins  = MATH_OP_ARITHMETIC_MEDIAN;
+  uvar.nSFTmthopBins = MATH_OP_MAXIMUM;
+
+  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;
+
+  MultiSFTVector *inputSFTs = NULL;
+  UINT4Vector *uint4vector = NULL;
+  XLAL_CHECK ( (uint4vector = XLALCreateUINT4Vector(1)) != NULL, XLAL_ENOMEM);
+  uint4vector->length = 1;
+  uint4vector->data[0] = 1;
+
+  XLAL_CHECK ( (inputSFTs = XLALCreateMultiSFTVector(sft->data->length, uint4vector)) != NULL, XLAL_ENOMEM );
+
+  //Input SFT into the MultiSFTVector
+  //MultiSFTVector -> SFTVector ** -> SFTtype * -> COMPLEX8Sequence * -> COMPLEX8 *
+  COMPLEX8Sequence *tmp = inputSFTs->data[0]->data->data;     //Temporarily safe the pointer to the data
+  memcpy(inputSFTs->data[0]->data, sft, sizeof(*sft));        //Copy all fields of SFT into the SFTVector
+  inputSFTs->data[0]->data->data = tmp;                       //Restore the correct data pointer
+  memcpy(inputSFTs->data[0]->data->data->data, sft->data->data, sizeof(sft->data->data[0]) * sft->data->length);    //Copy the actual sft data
+
+  cfg.firstBin = (UINT4) 0;
+  cfg.lastBin = (UINT4) inputSFTs->data[0]->data[0].data->length - 1;
+
+  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");
+  }
+
+  /* ---------- 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 */
+
+  finalBinSize = 1;
+  finalBinStep = finalBinSize;
+
+  /* work out total number of bins */
+  finalNumBins = (UINT4)floor((numBins - finalBinSize) / finalBinStep) + 1;
+
+  /* write final PSD to file */
+  if( 1==0) { // DONT WRITE PSD TO FILE
+    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 != XLALOutputVCSInfo(fpOut, lalAppsVCSInfoList, 0, "%% "))
+      XLAL_ERROR ( XLAL_EFUNC );
+
+    /* 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);
+
+  }
+//  Fseries = Fseries; //Else warning set but not used
+  for (k = 0; k < finalNumBins; ++k) {
+    UINT4 b = k * finalBinStep;
+//    REAL8 f0 = Freq0 + b * dFreq;
+    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 );
+    } else  {
+    (*Fseries)->data->data[k] = math_op(&(finalPSD->data[b]), finalBinSize, uvar.PSDmthopBins);
+    }
+  }
+
+  /* we are now done with the psd */
+  XLALDestroyMultiPSDVector  ( multiPSD);
+  XLALDestroyMultiSFTVector  ( inputSFTs);
+  XLALDestroyUINT4Vector     ( uint4vector);
+
+  XLALDestroyREAL8Vector ( overSFTs );
+  XLALDestroyREAL8Vector ( overIFOs );
+  XLALDestroyREAL8Vector ( finalPSD );
+  XLALDestroyREAL8Vector ( finalNormSFT );
+
+  return EXIT_SUCCESS;
+
+} /* main() */
+
+/** compute the various kinds of math. operation */
+REAL8 math_op(REAL8* data, size_t length, INT4 type) {
+
+  UINT4 i;
+  REAL8 res = 0.0;
+
+  switch (type) {
+
+  case MATH_OP_ARITHMETIC_SUM: /* sum(data) */
+
+    for (i = 0; i < length; ++i) res += *(data++);
+
+    break;
+
+  case MATH_OP_ARITHMETIC_MEAN: /* sum(data)/length  */
+
+    for (i = 0; i < length; ++i) res += *(data++);
+    res /= (REAL8)length;
+
+    break;
+
+  case MATH_OP_ARITHMETIC_MEDIAN: /* middle element of sort(data) */
+
+    gsl_sort(data, 1, length);
+    if (length/2 == (length+1)/2) /* length is even */ {
+      res = (data[length/2] + data[length/2+1])/2;
+    }
+    else /* length is odd */ {
+      res = data[length/2];
+    }
+
+    break;
+
+  case MATH_OP_HARMONIC_SUM: /* 1 / sum(1 / data) */
+
+    for (i = 0; i < length; ++i) res += 1.0 / *(data++);
+    res = 1.0 / res;
+
+    break;
+
+  case MATH_OP_HARMONIC_MEAN: /* length / sum(1 / data) */
+
+    for (i = 0; i < length; ++i) res += 1.0 / *(data++);
+    res = (REAL8)length / res;
+
+    break;
+
+  case MATH_OP_POWERMINUS2_SUM: /*   1 / sqrt ( sum(1 / data/data) )*/
+
+    for (i = 0; i < length; ++i) res += 1.0 / (data[i]*data[i]);
+    res = 1.0 / sqrt(res);
+
+    break;
+
+   case MATH_OP_POWERMINUS2_MEAN: /*   1 / sqrt ( sum(1/data/data) / length )*/
+
+    for (i = 0; i < length; ++i) res += 1.0 / (data[i]*data[i]);
+    res = 1.0 / sqrt(res / (REAL8)length);
+
+    break;
+
+  case MATH_OP_MINIMUM: /* first element of sort(data) */
+
+    gsl_sort(data, 1, length);
+    res = data[0];
+    break;
+
+  case MATH_OP_MAXIMUM: /* first element of sort(data) */
+
+    gsl_sort(data, 1, length);
+    res = data[length-1];
+    break;
+
+  default:
+
+    XLALPrintError("'%i' is not a valid math. operation", type);
+    XLAL_ERROR_REAL8(XLAL_EINVAL);
+
+  }
+
+  return res;
+
+}
+
+/**
+ * Dump complete multi-PSDVector over IFOs, timestamps and frequency-bins into
+ * per-IFO ASCII output-files 'outbname-IFO'
+ *
+ */
+int
+XLALDumpMultiPSDVector ( const CHAR *outbname,			/**< output basename 'outbname' */
+                         const MultiPSDVector *multiPSDVect	/**< multi-psd vector to output */
+                  )
+{
+  /* check input consistency */
+  if ( outbname == NULL ) {
+    XLALPrintError ("%s: NULL input 'outbname'\n", __func__ );
+    XLAL_ERROR ( XLAL_EINVAL );
+  }
+  if ( multiPSDVect == NULL ) {
+    XLALPrintError ("%s: NULL input 'multiPSDVect'\n", __func__ );
+    XLAL_ERROR ( XLAL_EINVAL );
+  }
+  if ( multiPSDVect->length == 0 || multiPSDVect->data==0 ) {
+    XLALPrintError ("%s: invalid multiPSDVect input (length=0 or data=NULL)\n", __func__ );
+    XLAL_ERROR ( XLAL_EINVAL );
+  }
+
+  CHAR *fname;
+  FILE *fp;
+
+  UINT4 len = strlen ( outbname ) + 4;
+  if ( ( fname = XLALMalloc ( len * sizeof(CHAR) )) == NULL ) {
+    XLALPrintError ("%s: XLALMalloc(%d) failed.\n", __func__, len );
+    XLAL_ERROR ( XLAL_ENOMEM);
+  }
+
+  UINT4 numIFOs = multiPSDVect->length;
+  UINT4 X;
+  for ( X = 0; X < numIFOs; X ++ )
+    {
+      PSDVector *thisPSDVect = multiPSDVect->data[X];
+      char buf[100];
+
+      sprintf ( fname, "%s-%c%c", outbname, thisPSDVect->data[0].name[0], thisPSDVect->data[0].name[1] );
+
+      if ( ( fp = fopen( fname, "wb" ))  == NULL ) {
+        XLALPrintError ("%s: Failed to open PSDperSFT file '%s' for writing!\n", __func__, fname );
+        XLALFree ( fname );
+        XLAL_ERROR ( XLAL_ESYS );
+      }
+
+      REAL8 f0       = thisPSDVect->data[0].f0;
+      REAL8 dFreq    = thisPSDVect->data[0].deltaF;
+      UINT4 numFreqs = thisPSDVect->data[0].data->length;
+      UINT4 iFreq;
+
+      /* write comment header line into this output file */
+      /* FIXME: output code-version/cmdline/history info */
+      fprintf(fp,"%%%% first line holds frequencies [Hz] of PSD-Columns\n");
+      /* loop over frequency and output comnment-header markers */
+      fprintf(fp,"%%%%%-17s", "dummy");
+      for ( iFreq = 0; iFreq < numFreqs; iFreq ++ )
+        {
+          sprintf (buf, "f%d [Hz]", iFreq + 1 );
+          fprintf (fp, " %-21s", buf );
+        }
+      fprintf (fp, "\n");
+
+      /* write parseable header-line giving bin frequencies for PSDs */
+      fprintf (fp, "%-19d", -1 );
+      for (iFreq = 0; iFreq < numFreqs; iFreq++ )
+        fprintf (fp, " %-21.16g", f0 + iFreq * dFreq );
+      fprintf (fp, "\n\n\n");
+
+      /* output another header line describing the following format "ti[GPS] PSD(f1) ... " */
+      fprintf(fp,"%%%%%-17s", "ti[GPS]");
+      for ( iFreq = 0; iFreq < numFreqs; iFreq ++ )
+        {
+          sprintf (buf, "PSD(f%d)", iFreq + 1 );
+          fprintf (fp, " %-21s", buf );
+        }
+      fprintf (fp, "\n");
+
+      /* loop over timestamps: dump all PSDs over frequencies into one line */
+      UINT4 numTS = thisPSDVect->length;
+      UINT4 iTS;
+      for ( iTS = 0; iTS < numTS; iTS++ )
+        {
+          REAL8FrequencySeries *thisPSD = &thisPSDVect->data[iTS];
+
+          /* first output timestamp GPS time for this line */
+          REAL8 tGPS = XLALGPSGetREAL8( &thisPSD->epoch );
+          fprintf (fp, "%-19.18g", tGPS );
+
+          /* 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, tGPS, f0, thisPSD->f0, dFreq, thisPSD->deltaF, numFreqs, thisPSD->data->length );
+            XLALFree ( fname );
+            fclose ( fp );
+            XLAL_ERROR ( XLAL_EDOM );
+          }
+
+          /* loop over all frequencies and dump PSD-value */
+          for ( iFreq = 0; iFreq < numFreqs; iFreq ++ )
+            fprintf (fp, " %-21.16g", thisPSD->data->data[iFreq] );
+
+          fprintf (fp, "\n");
+
+        } /* for iTS < numTS */
+
+      fclose ( fp );
+
+    } /* for X < numIFOs */
+
+  XLALFree ( fname );
+
+  return XLAL_SUCCESS;
+
+} /* XLALDumpMultiPSDVector() */
+
+/**
+ * Function that *truncates the PSD in place* to the requested frequency-bin interval [firstBin, lastBin] for the given multiPSDVector.
+ * Now also truncates the original SFT vector, as necessary for correct computation of normalized SFT power.
+ */
+int
+XLALCropMultiPSDandSFTVectors ( MultiPSDVector *multiPSDVect,
+                         MultiSFTVector *multiSFTVect,
+                         UINT4 firstBin,
+                         UINT4 lastBin
+                         )
+{
+  /* check user input */
+  if ( !multiPSDVect ) {
+    XLALPrintError ("%s: invalid NULL input 'multiPSDVect'\n", __func__ );
+    XLAL_ERROR ( XLAL_EINVAL );
+  }
+  if ( !multiSFTVect ) {
+    XLALPrintError ("%s: invalid NULL input 'multiSFTVect'\n", __func__ );
+    XLAL_ERROR ( XLAL_EINVAL );
+  }
+  if ( lastBin < firstBin ) {
+    XLALPrintError ("%s: empty bin interval requested [%d, %d]\n", __func__, firstBin, lastBin );
+    XLAL_ERROR ( XLAL_EDOM );
+  }
+
+  UINT4 numIFOs = multiPSDVect->length;
+  UINT4 numBins = multiPSDVect->data[0]->data[0].data->length;
+
+  if ( numIFOs != multiSFTVect->length ) {
+    XLALPrintError ("%s: inconsistent number of IFOs between PSD (%d) and SFT (%d) vectors.\n", __func__, numIFOs, multiSFTVect->length );
+    XLAL_ERROR ( XLAL_EDOM );
+  }
+
+  if ( numBins != multiSFTVect->data[0]->data[0].data->length ) {
+    XLALPrintError ("%s: inconsistent number of bins between PSD (%d bins) and SFT (%d bins) vectors.\n", __func__, numBins, multiSFTVect->data[0]->data[0].data->length );
+    XLAL_ERROR ( XLAL_EDOM );
+  }
+
+  if ( (firstBin >= numBins) || (lastBin >= numBins ) ) {
+    XLALPrintError ("%s: requested bin-interval [%d, %d] outside of PSD bins [0, %d]\n", __func__, firstBin, lastBin, numBins - 1 );
+    XLAL_ERROR ( XLAL_EDOM );
+  }
+
+  /* ----- check if there's anything to do at all? ----- */
+  if ( (firstBin == 0)  && (lastBin == numBins - 1) )
+    return XLAL_SUCCESS;
+
+  /* ----- loop over detectors, timestamps, then crop each PSD ----- */
+  UINT4 X;
+  for ( X=0; X < numIFOs; X ++ )
+    {
+      PSDVector *thisPSDVect = multiPSDVect->data[X];
+      SFTVector *thisSFTVect = multiSFTVect->data[X];
+      UINT4 numTS   = thisPSDVect->length;
+
+      UINT4 iTS;
+      for ( iTS = 0; iTS < numTS; iTS ++ )
+        {
+          REAL8FrequencySeries *thisPSD = &thisPSDVect->data[iTS];
+          COMPLEX8FrequencySeries *thisSFT = &thisSFTVect->data[iTS];
+
+          if ( numBins != thisPSD->data->length ) {
+            XLALPrintError ("%s: inconsistent number of frequency-bins across multiPSDVector: X=%d, iTS=%d: numBins = %d != %d\n",
+                            __func__, X, iTS, numBins, thisPSD->data->length );
+            XLAL_ERROR ( XLAL_EDOM );
+          }
+
+          if ( numBins != thisSFT->data->length ) {
+            XLALPrintError ("%s: inconsistent number of frequency-bins across multiSFTVector: X=%d, iTS=%d: numBins = %d != %d\n",
+                            __func__, X, iTS, numBins, thisSFT->data->length );
+            XLAL_ERROR ( XLAL_EDOM );
+          }
+
+          UINT4 numNewBins = lastBin - firstBin + 1;
+
+          /* crop PSD */
+          XLAL_CHECK(XLALResizeREAL8FrequencySeries(thisPSD, firstBin, numNewBins) != NULL, XLAL_EFUNC);
+
+          /* crop SFT */
+          XLAL_CHECK(XLALResizeCOMPLEX8FrequencySeries(thisSFT, firstBin, numNewBins) != NULL, XLAL_EFUNC);
+
+        } /* for iTS < numTS */
+
+    } /* for X < numIFOs */
+
+  /* that should be all ... */
+  return XLAL_SUCCESS;
+
+} /* XLALCropMultiPSDandSFTVectors() */
diff --git a/lalapps/src/pulsar/MakeData/ComputePSDFunction.h b/lalapps/src/pulsar/MakeData/ComputePSDFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4c4586af3d2906a0597fa6524e1eacb47f5d7d2
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/ComputePSDFunction.h
@@ -0,0 +1,51 @@
+/*
+*  Copyright (C) 2017 Benjamin Steltner
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+#ifndef _COMPUTEPSDFUNCTION_H
+#define _COMPUTEPSDFUNCTION_H
+
+#include <lal/LALDatatypes.h>
+#include "PSDConfigVars.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#elif 0
+} /* so that editors will match preceding brace */
+#endif
+
+/**
+  * \defgroup ComputePSDFunction_h Header ComputePSDFunction_h
+  * \ingroup lal_fft
+  *
+  * \brief Computes the PSD of SFT
+  *
+  * ### Synopsis ###
+  *
+  * \code
+  * #include <lal/ComputePSDFunction.h>
+  * \endcode
+  *
+  * Computes PSD
+  *
+  * ### Description ###
+**/
+
+int computePSD(PSDUserVarsTag PSDUserVars, SFTtype *sft, REAL8FrequencySeries **Fseries);
+
+#endif
diff --git a/lalapps/src/pulsar/MakeData/MakeSFTsFunction.c b/lalapps/src/pulsar/MakeData/MakeSFTsFunction.c
new file mode 100644
index 0000000000000000000000000000000000000000..cbe4ab153942aa3f236958b2551507d4835fd2c9
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/MakeSFTsFunction.c
@@ -0,0 +1,1251 @@
+/*
+*  Copyright (C) 2007 Gregory Mendell
+*  Copyright (C) 2010,2011,2016 Bernd Machenschalk
+*  Copyright (C) 2017-2021 Benjamin Steltner
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+/**
+ * \file
+ * \ingroup lalapps_pulsar_SFTTools
+ * \author Gregory Mendell, Xavier Siemens, Bruce Allen, Bernd Machenschalk, Benjamin Steltner
+ * \brief generate SFTs
+ */
+
+/**
+ * This file is a copy of MakeSFTs.c ( https://lscsoft.docs.ligo.org/lalsuite/lalapps/_make_s_f_ts_8c_source.html ).
+ * Most file I/O is removed, the main method takes an in-memory time series and computes & returns an in-memory SFT to the caller.
+ */
+
+#include <config.h>
+#if !defined HAVE_LIBGSL || !defined HAVE_LIBLALFRAME
+#include <stdio.h>
+int main(void) {fputs("disabled, no gsl or no lal frame library support.\n", stderr);return 1;}
+#else
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include <glob.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <lal/LALDatatypes.h>
+#include <lal/LALgetopt.h>
+#include <lal/LALStdlib.h>
+#include <lal/LALStdio.h>
+#include <lal/FileIO.h>
+#include <lal/AVFactories.h>
+#include <lal/LALCache.h>
+#include <lal/LALFrStream.h>
+#include <lal/Window.h>
+#include <lal/Calibration.h>
+#include <lal/LALConstants.h>
+#include <lal/TimeSeries.h>
+#include <lal/BandPassTimeSeries.h>
+#include <lal/LALStdlib.h>
+#include <lal/LALConstants.h>
+#include <lal/AVFactories.h>
+#include <lal/TimeFreqFFT.h>
+#include <lal/RealFFT.h>
+#include <lal/ComplexFFT.h>
+#include <lal/SFTfileIO.h>
+#include <lal/SFTutils.h>
+#include <lal/LALVCSInfo.h>
+#include <LALAppsVCSInfo.h>
+#include "MakeSFTsFunction.h"
+#include <lal/Sequence.h>
+
+/* track memory usage under linux */
+#define TRACKMEMUSE 0
+
+/* print the first NUMTOPRINT, middle NUMTOPRINT, and last NUMTOPRINT input/ouput data at various stages */
+#define PRINTEXAMPLEDATA 0
+#define NUMTOPRINT       2
+
+/* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+#define CHECKFORINFINITEANDNANS 1
+
+#define TESTSTATUS( pstat ) \
+  if ( (pstat)->statusCode ) { REPORTSTATUS(pstat); return 100; } else ((void)0)
+
+/***************************************************************************/
+
+/***************************************************************************/
+
+/* GLOBAL VARIABLES */
+REAL8 FMIN = 48.0; /* default start frequency */
+REAL8 DF = 2000.0; /* default band */
+
+REAL8 winFncRMS = 1.0; /* 10/05/12 gam; global variable with the RMS of the window function; default value is 1.0 */
+
+static LALStatus status;
+LALCache *framecache;         /* frame reading variables */
+LALFrStream *framestream=NULL;
+
+REAL8TimeSeries resetdataDouble;
+REAL8TimeSeries dataDouble;
+REAL4TimeSeries dataSingle;
+INT2TimeSeries dataINT2;
+INT4TimeSeries dataINT4;
+INT8TimeSeries dataINT8;
+INT4 SegmentDuration;
+LIGOTimeGPS gpsepoch;
+
+/* REAL8Vector *window; */ /* 11/02/05 gam */
+
+REAL8FFTPlan *fftPlanDouble;           /* fft plan and data container, double precision case */
+COMPLEX16Vector *fftDataDouble = NULL;
+
+REAL4FFTPlan *fftPlanSingle;           /* 11/19/05 gam; fft plan and data container, single precision case */
+COMPLEX8Vector *fftDataSingle = NULL;
+
+CHAR allargs[16384]; /* 06/26/07 gam; copy all command line args into commentField, based on /lalapps/src/calibration/ComputeStrainDriver.c */
+/***************************************************************************/
+
+/* FUNCTION PROTOTYPES */
+/* Reads the command line */
+int ReadCommandLine(int argc,char *argv[],struct SFTConfigVarsTag *CLA);
+
+/* Allocates space for data time series */
+int AllocateDataNoFileIO(struct SFTConfigVarsTag CLA);
+
+/* High passes data */
+int DoHighPass(struct SFTConfigVarsTag CLA);
+
+/* Windows data */
+int WindowData(struct SFTConfigVarsTag CLA);
+int WindowDataTukey2(struct SFTConfigVarsTag CLA);
+int WindowDataHann(struct SFTConfigVarsTag CLA);
+
+#ifdef PSS_ENABLED
+/* Time Domain Cleaning with PSS functions */
+int PSSTDCleaningDouble(struct SFTConfigVarsTag CLA);
+int PSSTDCleaningREAL8(REAL8TimeSeries *LALTS, REAL4 highpassFrequency, INT4 extendTimeseries);
+#endif
+
+/* create an SFT */
+int CreateSFT(struct SFTConfigVarsTag CLA);
+
+/* writes out an SFT */
+int WriteSFT(struct SFTConfigVarsTag CLA);
+int WriteVersion2SFT(struct SFTConfigVarsTag CLA);
+int WriteVersion2SFTNoFileIO(struct SFTConfigVarsTag CLA, SFTtype **sft);
+
+/* Frees the memory */
+int FreeMem(struct SFTConfigVarsTag CLA);
+
+/* prototypes */
+FILE* tryopen(char *name, const char *mode);
+void getSFTDescField(CHAR *sftDescField, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc);
+void mkSFTDir(CHAR *sftPath, CHAR *site, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc,CHAR *gpstime, INT4 numGPSdigits);
+void mkSFTFilename(CHAR *sftFilename, CHAR *site, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc,CHAR *gpstime);
+void mvFilenames(CHAR *filename1, CHAR *filename2);
+
+
+/* -------------------- function definitions -------------------- */
+
+
+/* This repeatedly tries to re-open a file.  This is useful on a
+   cluster because automount may fail or time out.  This allows a
+   number of tries with a bit of rest in between.
+*/
+FILE* tryopen(char *name, const char *mode){
+  int count=0;
+  FILE *fp;
+  
+  while (!(fp=fopen(name, mode))){
+    fprintf(stderr,"Unable to open file %s in mode %s.  Will retry...\n", name, mode);
+    if (count++<10)
+      sleep(10);
+    else
+      exit(3);
+  }
+  return fp;
+}
+
+
+/* 12/27/05 gam; function to create sftDescField for output directory or filename. */
+void getSFTDescField(CHAR *sftDescField, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc) {
+       strcpy(sftDescField,numSFTs);
+       strcat(sftDescField, "_");
+       strcat(sftDescField,ifo);
+       strcat(sftDescField, "_");
+       strcat(sftDescField,stringT);
+       strcat(sftDescField, "SFT");
+       if (typeMisc != NULL) {
+          strcat(sftDescField, "_");
+          strcat(sftDescField, typeMisc);
+       }
+}
+
+/* 12/27/05 gam; concat to the sftPath the directory name based on GPS time; make this directory if it does not already exist */
+void mkSFTDir(CHAR *sftPath, CHAR *site, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc,CHAR *gpstime, INT4 numGPSdigits) {
+     CHAR sftDescField[256];
+     CHAR mkdirCommand[256];
+     strcat(sftPath,"/");
+     strcat(sftPath,site);
+     strcat(sftPath,"-");
+     getSFTDescField(sftDescField, numSFTs, ifo, stringT, typeMisc);
+     strcat(sftPath,sftDescField);
+     strcat(sftPath,"-");
+     strncat(sftPath,gpstime,numGPSdigits);
+     sprintf(mkdirCommand,"mkdir -p %s",sftPath);
+     if ( system(mkdirCommand) ) XLALPrintError ("system() returned non-zero status\n");
+}
+
+/* 12/27/05 gam; make SFT file name according to LIGO T040164-01 specification */
+void mkSFTFilename(CHAR *sftFilename, CHAR *site, CHAR *numSFTs, CHAR *ifo, CHAR *stringT, CHAR *typeMisc,CHAR *gpstime) {
+     CHAR sftDescField[256];
+     strcpy(sftFilename,site);
+     strcat(sftFilename,"-");
+     getSFTDescField(sftDescField, numSFTs, ifo, stringT, typeMisc);
+     strcat(sftFilename,sftDescField);
+     strcat(sftFilename,"-");
+     strcat(sftFilename,gpstime);
+     strcat(sftFilename,"-");
+     strcat(sftFilename,stringT);
+     strcat(sftFilename,".sft");
+}
+
+/* 01/09/06 gam; move filename1 to filename2 */
+void mvFilenames(CHAR *filename1, CHAR *filename2) {
+     CHAR mvFilenamesCommand[512+4];
+     sprintf(mvFilenamesCommand,"mv %s %s",filename1,filename2);
+     if ( system(mvFilenamesCommand) ) XLALPrintError ("system() returned non-zero status\n");
+}
+
+#if TRACKMEMUSE
+void printmemuse() {
+   pid_t mypid=getpid();
+   char commandline[256];
+   fflush(NULL);
+   sprintf(commandline,"cat /proc/%d/status | /bin/grep Vm | /usr/bin/fmt -140 -u", (int)mypid);
+   if ( system(commandline) ) XLALPrintError ("system() returned non-zero status\n");
+   fflush(NULL);
+ }
+#endif
+
+#if PRINTEXAMPLEDATA
+void printExampleDataSingle() {
+      INT4 i,dataLength;
+      dataLength = dataSingle.data->length;
+      fprintf(stdout,"dataSingle.deltaT, 1.0/dataSingle.deltaT = %23.16e, %23.16e\n",dataSingle.deltaT,1.0/dataSingle.deltaT);
+      fprintf(stdout,"dataSingle.epoch.gpsSeconds,dataSingle.epoch.gpsNanoSeconds = %i, %i\n",dataSingle.epoch.gpsSeconds,dataSingle.epoch.gpsNanoSeconds);
+      for (i=0;i<NUMTOPRINT;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataSingle.data->data[i]);
+      }
+      for (i=dataLength/2;i<dataLength/2+NUMTOPRINT;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataSingle.data->data[i]);
+      }
+      for (i=dataLength-NUMTOPRINT;i<dataLength;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataSingle.data->data[i]);
+      }
+      fflush(stdout);
+}    
+
+void printExampleDataDouble() {
+      INT4 i,dataLength;
+      dataLength = dataDouble.data->length;
+      fprintf(stdout,"dataDouble.deltaT, 1.0/dataDouble.deltaT = %23.16e, %23.16e\n",dataDouble.deltaT,1.0/dataDouble.deltaT);
+      fprintf(stdout,"dataDouble.epoch.gpsSeconds,dataDouble.epoch.gpsNanoSeconds = %i, %i\n",dataDouble.epoch.gpsSeconds,dataDouble.epoch.gpsNanoSeconds);
+      for (i=0;i<NUMTOPRINT;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataDouble.data->data[i]);
+      }
+      for (i=dataLength/2;i<dataLength/2+NUMTOPRINT;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataDouble.data->data[i]);
+      }
+      for (i=dataLength-NUMTOPRINT;i<dataLength;i++) {
+        fprintf(stdout,"%i %23.16e\n",i,dataDouble.data->data[i]);
+      }
+      fflush(stdout);
+}
+
+void printExampleFFTData(struct SFTConfigVarsTag CLA)
+{
+  int firstbin=(INT4)(FMIN*CLA.T+0.5);
+  int k;
+  INT4 nsamples=(INT4)(DF*CLA.T+0.5);
+
+  if(CLA.useSingle) {
+    for (k=0; k<NUMTOPRINT; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataSingle->data[k+firstbin].re,fftDataSingle->data[k+firstbin].im);
+    }
+    for (k=nsamples/2; k<nsamples/2+NUMTOPRINT; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataSingle->data[k+firstbin].re,fftDataSingle->data[k+firstbin].im);
+    }
+    for (k=nsamples-NUMTOPRINT; k<nsamples; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataSingle->data[k+firstbin].re,fftDataSingle->data[k+firstbin].im);
+    }    
+  } else {
+    for (k=0; k<NUMTOPRINT; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataDouble->data[k+firstbin].re,fftDataDouble->data[k+firstbin].im);
+    }
+    for (k=nsamples/2; k<nsamples/2+NUMTOPRINT; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataDouble->data[k+firstbin].re,fftDataDouble->data[k+firstbin].im);
+    }
+    for (k=nsamples-NUMTOPRINT; k<nsamples; k++) {
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,fftDataDouble->data[k+firstbin].re,fftDataDouble->data[k+firstbin].im);
+    }    
+  }
+  fflush(stdout);
+}
+
+void printExampleSFTDataGoingToFile(struct SFTConfigVarsTag CLA)
+{
+  int firstbin=(INT4)(FMIN*CLA.T+0.5);
+  int k;
+  INT4 nsamples=(INT4)(DF*CLA.T+0.5);
+  REAL4 rpw,ipw;
+
+  if(CLA.useSingle) {
+    for (k=0; k<NUMTOPRINT; k++) {
+      rpw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].re;
+      ipw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }
+    for (k=nsamples/2; k<nsamples/2+NUMTOPRINT; k++) {
+      rpw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].re;
+      ipw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }
+    for (k=nsamples-NUMTOPRINT; k<nsamples; k++) {
+      rpw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].re;
+      ipw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* fftDataSingle->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }    
+  } else {
+    for (k=0; k<NUMTOPRINT; k++) {
+      rpw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].re;
+      ipw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }
+    for (k=nsamples/2; k<nsamples/2+NUMTOPRINT; k++) {
+      rpw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].re;
+      ipw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }
+    for (k=nsamples-NUMTOPRINT; k<nsamples; k++) {
+      rpw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].re;
+      ipw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* fftDataDouble->data[k+firstbin].im;
+      fprintf(stdout,"%i %23.16e %23.16e\n",k,rpw,ipw);
+    }    
+  }
+  fflush(stdout);
+}
+
+void printExampleVersion2SFTDataGoingToFile(struct SFTConfigVarsTag CLA, SFTtype *oneSFT)
+{
+  int k;
+  INT4 nsamples=(INT4)(DF*CLA.T+0.5);
+
+  for (k=0; k<NUMTOPRINT; k++) {  
+    fprintf(stdout,"%i %23.16e %23.16e\n",k,oneSFT->data->data[k].re,oneSFT->data->data[k].im);
+  }
+  for (k=nsamples/2; k<nsamples/2+NUMTOPRINT; k++) {
+    fprintf(stdout,"%i %23.16e %23.16e\n",k,oneSFT->data->data[k].re,oneSFT->data->data[k].im);
+  }
+  for (k=nsamples-NUMTOPRINT; k<nsamples; k++) {
+    fprintf(stdout,"%i %23.16e %23.16e\n",k,oneSFT->data->data[k].re,oneSFT->data->data[k].im);
+  }    
+}
+#endif
+
+
+#ifdef PSS_ENABLED
+/* debug function */
+int PrintREAL4ArrayToFile(const char*name, REAL4*array, UINT4 length);
+int PrintREAL4ArrayToFile(const char*name, REAL4*array, UINT4 length) {
+  UINT4 i;
+  FILE*fp=fopen(name,"w");
+  if(!fp) {
+    fprintf(stderr,"Could not open file '%s' for writing\n",name);
+    return -1;
+  } else {
+    for(i=0;i<length;i++)
+      fprintf(fp,"%23.16e\n",array[i]);
+    fclose(fp);
+  }
+  return 0;
+}
+#endif
+
+
+/************************************* MAIN PROGRAM *************************************/
+/**
+  * This method is a copy of the main method, but with all file reading and writing disabled for processing in memory
+  */
+int makeSFT(SFTConfigVarsTag NewSFTConfigVars, REAL8TimeSeries *Tseries, REAL8 fmin, REAL8 band, SFTtype **sft) {
+  SFTConfigVarsTag SFTConfigVars = NewSFTConfigVars;
+  FMIN = fmin;
+  DF = band;
+/** Reset everything for calling it multiple times **/
+
+  dataDouble = resetdataDouble;
+  fftPlanDouble = NULL;
+  fftDataDouble = NULL;
+
+  #if TRACKMEMUSE
+    printf("Memory use at startup is:\n"); printmemuse();
+  #endif
+
+  SegmentDuration = SFTConfigVars.GPSEnd - SFTConfigVars.GPSStart ;
+
+  if( SegmentDuration < SFTConfigVars.T)
+    {
+      fprintf(stderr,"Cannot fit an SFT of duration %d between %d and %d\n",
+        SFTConfigVars.T, SFTConfigVars.GPSStart, SFTConfigVars.GPSEnd );
+      return 0;;
+    }
+
+  gpsepoch.gpsSeconds = SFTConfigVars.GPSStart;
+  gpsepoch.gpsNanoSeconds = 0;
+
+  dataDouble = *Tseries;
+
+  /* Allocates space for data */
+  if (AllocateDataNoFileIO(SFTConfigVars)) return 2;
+
+
+  /* for(j=0; j < SegmentDuration/SFTConfigVars.T; j++) */ /* 12/28/05 gam */
+  while(gpsepoch.gpsSeconds + SFTConfigVars.T <= SFTConfigVars.GPSEnd)
+    {
+
+      /* gpsepoch.gpsSeconds = SFTConfigVars.GPSStart + j*SFTConfigVars.T;
+      gpsepoch.gpsNanoSeconds = 0; */ /* 12/28/05 gam; now updated at the bottom of while loop */
+
+      /* Reads T seconds of data */
+//      if (ReadDataNoFileIO(SFTConfigVars)) return 3;
+
+      /* High-pass data with Butterworth filter */
+      if(DoHighPass(SFTConfigVars)) return 4;
+
+      /* Window data; 12/28/05 gam; add options */
+      if (SFTConfigVars.windowOption==1) {
+         if(WindowData(SFTConfigVars)) return 5; /* SFTConfigVars.windowOption==1 is the default */
+      } else if (SFTConfigVars.windowOption==2) {
+         if(WindowDataTukey2(SFTConfigVars)) return 5;
+      } else if (SFTConfigVars.windowOption==3) {
+         if(WindowDataHann(SFTConfigVars)) return 5;
+      } else {
+        /* Continue with no windowing; parsing of command line args makes sure options are one of the above or 0 for now windowing. */
+      }
+
+#ifdef PSS_ENABLED
+      /* Time Domain cleaning procedure */
+      if (SFTConfigVars.PSSCleaning)
+        if(PSSTDCleaningDouble(SFTConfigVars))
+          return 9;
+#endif
+
+      /* create an SFT */
+      if(CreateSFT(SFTConfigVars)) return 6;
+
+      /* write out sft - dummy write in this case */ 
+      if (SFTConfigVars.sftVersion==1) {
+        if(WriteSFT(SFTConfigVars)) return 7;
+      } else if (SFTConfigVars.sftVersion==2) {
+        if(WriteVersion2SFTNoFileIO(SFTConfigVars, sft)) return 7; /* default now is to output version 2 SFTs */
+      } else {
+        fprintf( stderr, "Invalid input for 'sft-version = %d', must be either '1' or '2'\n", SFTConfigVars.sftVersion );
+        return 0;;
+      }
+
+      gpsepoch.gpsSeconds = gpsepoch.gpsSeconds + (INT4)((1.0 - SFTConfigVars.overlapFraction)*((REAL8)SFTConfigVars.T));
+      gpsepoch.gpsNanoSeconds = 0;
+    }
+  XLALDestroyCOMPLEX16Vector(fftDataDouble);
+  XLALDestroyREAL8FFTPlan(fftPlanDouble);
+
+  #if TRACKMEMUSE
+        printf("Memory use after freeing all allocated memory:\n"); printmemuse();
+  #endif
+
+  return 0;
+} /* makeSFT(args) */
+
+
+/*** FUNCTIONS ***/
+
+/*******************************************************************************/
+/**
+  * This is a copy of AllocateData, but with no file reading and/or writing
+  */
+
+int AllocateDataNoFileIO(struct SFTConfigVarsTag CLA)
+{
+  dataSingle.deltaT=dataDouble.deltaT;
+
+  /*  11/19/05 gam; will keep dataDouble or dataSingle in memory at all times, depending on whether using single or double precision */
+  if(CLA.useSingle) {
+      LALCreateVector(&status,&dataSingle.data,(UINT4)(CLA.T/dataSingle.deltaT +0.5));
+      TESTSTATUS( &status );
+
+      #if TRACKMEMUSE
+         printf("Memory use after creating dataSingle and before calling LALCreateForwardRealFFTPlan.\n"); printmemuse();
+      #endif
+
+      fftPlanSingle = XLALCreateForwardREAL4FFTPlan( dataSingle.data->length, 0 );
+      XLAL_CHECK( fftPlanSingle != NULL, XLAL_EFUNC );
+
+
+      #if TRACKMEMUSE
+        printf("Memory use after creating dataSingle and after calling XLALCreateForwardREAL4FFTPlan.\n"); printmemuse();
+      #endif
+
+  } else {
+  //    LALDCreateVector(&status,&dataDouble.data,(UINT4)(CLA.T/dataDouble.deltaT +0.5));
+  //    TESTSTATUS( &status );
+
+      #if TRACKMEMUSE
+         printf("Memory use after creating dataDouble and before calling LALCreateForwardREAL8FFTPlan.\n"); printmemuse();
+      #endif
+
+      fftPlanDouble = XLALCreateForwardREAL8FFTPlan( dataDouble.data->length, 0 );
+      XLAL_CHECK( fftPlanDouble != NULL, XLAL_EFUNC );
+
+      #if TRACKMEMUSE
+            printf("Memory use after creating dataDouble and after calling XLALCreateForwardREAL8FFTPlan.\n"); printmemuse();
+      #endif
+  }
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+int DoHighPass(struct SFTConfigVarsTag CLA)
+{
+  PassBandParamStruc filterpar;
+  char tmpname[] = "Butterworth High Pass";
+
+  filterpar.name  = tmpname;
+  filterpar.nMax  = 10;
+  filterpar.f2    = CLA.HPf;
+  filterpar.a2    = 0.5;
+  filterpar.f1    = -1.0;
+  filterpar.a1    = -1.0;
+
+  if (CLA.HPf > 0.0 )
+    {
+      if(CLA.useSingle) {
+        #if TRACKMEMUSE
+          printf("Memory use before calling LALDButterworthREAL4TimeSeries:\n"); printmemuse();
+        #endif
+
+        /* High pass the time series */
+        LALDButterworthREAL4TimeSeries(&status,&dataSingle,&filterpar);
+        TESTSTATUS( &status );
+
+        #if TRACKMEMUSE
+          printf("Memory use after calling LALDButterworthREAL4TimeSeries:\n"); printmemuse();
+        #endif
+
+        #if PRINTEXAMPLEDATA
+            printf("\nExample dataSingle values after filtering data in HighPass:\n"); printExampleDataSingle();
+        #endif
+      } else {
+        #if TRACKMEMUSE
+          printf("Memory use before calling LALButterworthREAL8TimeSeries:\n"); printmemuse();
+        #endif
+
+        /* High pass the time series */
+        LALButterworthREAL8TimeSeries(&status,&dataDouble,&filterpar);
+        TESTSTATUS( &status );
+
+        #if TRACKMEMUSE
+          printf("Memory use after calling LALButterworthREAL8TimeSeries:\n"); printmemuse();
+        #endif
+
+        #if PRINTEXAMPLEDATA
+            printf("\nExample dataDouble values after filtering data in HighPass:\n"); printExampleDataDouble();
+        #endif
+      }
+    }
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+int WindowData(struct SFTConfigVarsTag CLA)
+{
+  REAL8 r = CLA.windowR;
+  INT4 k, N, kl, kh;
+  /* 10/05/12 gam */
+  REAL8 win;
+  /* This implementation of a Tukey window is describes 
+     in the Matlab tukey window documentation */
+
+  /* initialize the RMS of the window function */
+  winFncRMS = 0.0;
+
+  /* 11/19/05 gam */
+  if(CLA.useSingle) {
+    N=dataSingle.data->length;
+    kl=r/2*(N-1)+1;
+    kh=N-r/2*(N-1)+1;
+    for(k = 1; k < kl; k++) 
+    {
+      /* dataSingle.data->data[k-1]=dataSingle.data->data[k-1]*0.5*( (REAL4)( 1.0 + cos(LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) ) ); */
+      win = 0.5*( 1.0 + cos(LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) );
+      dataSingle.data->data[k-1] *= ((REAL4) win);
+      winFncRMS += win*win;
+    }
+    for(k = kh; k <= N; k++) 
+    {
+      /*dataSingle.data->data[k-1]=dataSingle.data->data[k-1]*0.5*( (REAL4)( 1.0 + cos(LAL_TWOPI/r - LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) ) );*/
+      win = 0.5*( 1.0 + cos(LAL_TWOPI/r - LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) );
+      dataSingle.data->data[k-1] *= ((REAL4) win);
+      winFncRMS += win*win;
+    }
+
+    #if PRINTEXAMPLEDATA
+        printf("\nExample dataSingle values after windowing data in WindowData:\n"); printExampleDataSingle();
+    #endif
+  } else {
+    N=dataDouble.data->length;
+    kl=r/2*(N-1)+1;
+    kh=N-r/2*(N-1)+1;
+    for(k = 1; k < kl; k++) 
+    {
+      /* dataDouble.data->data[k-1]=dataDouble.data->data[k-1]*0.5*( 1.0 + cos(LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) ); */
+      win = 0.5*( 1.0 + cos(LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) );
+      dataDouble.data->data[k-1] *= win;
+      winFncRMS += win*win;
+    }
+    for(k = kh; k <= N; k++) 
+    {
+      /* dataDouble.data->data[k-1]=dataDouble.data->data[k-1]*0.5*( 1.0 + cos(LAL_TWOPI/r - LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) ); */
+      win = 0.5*( 1.0 + cos(LAL_TWOPI/r - LAL_TWOPI/r*(k-1)/(N-1) - LAL_PI) );
+      dataDouble.data->data[k-1] *= win;
+      winFncRMS += win*win;
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample dataDouble values after windowing data in WindowData:\n"); printExampleDataDouble();
+    #endif    
+  }
+
+  /* Add to sum of squares of the window function the parts of window which are equal to 1, and then find RMS value*/
+  winFncRMS += (REAL8) (kh - kl);
+  winFncRMS = sqrt( ( winFncRMS/((REAL8) N) ) );
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+/* Same as window function given in lalapps/src/pulsar/make_sfts.c */
+int WindowDataTukey2(struct SFTConfigVarsTag CLA)
+{  
+  /* Define the parameters to make the window */
+  INT4 WINSTART = 4096;
+  INT4 WINEND = 8192;
+  INT4 WINLEN = (WINEND-WINSTART);
+  /* INT4 i; */
+  INT4 i, N;
+  REAL8 win;
+    
+
+  /* initialize the RMS of the window function */
+  winFncRMS = 0.0;
+
+  if(CLA.useSingle) {
+        N=dataSingle.data->length;
+        /* window data.  Off portion */
+        for (i=0; i<WINSTART; i++) {
+          dataSingle.data->data[i] = 0.0;
+          dataSingle.data->data[dataSingle.data->length - 1 - i] = 0.0;
+        }
+        /* window data, smooth turn-on portion */
+        for (i=WINSTART; i<WINEND; i++) {
+          win=((sin((i - WINSTART)*LAL_PI/(WINLEN)-LAL_PI_2)+1.0)/2.0);
+          dataSingle.data->data[i] *= win;
+          dataSingle.data->data[dataSingle.data->length - 1 - i]  *= win;
+          winFncRMS += 2.0*win*win;
+        }
+        #if PRINTEXAMPLEDATA
+           printf("\nExample dataSingle values after windowing data in WindowDataTukey2:\n"); printExampleDataSingle();
+        #endif
+  } else {
+        N=dataDouble.data->length;
+        /* window data.  Off portion */
+        for (i=0; i<WINSTART; i++) {
+          dataDouble.data->data[i] = 0.0;
+          dataDouble.data->data[dataDouble.data->length - 1 - i] = 0.0;
+        }
+        /* window data, smooth turn-on portion */
+        for (i=WINSTART; i<WINEND; i++) {
+          win=((sin((i - WINSTART)*LAL_PI/(WINLEN)-LAL_PI_2)+1.0)/2.0);
+          dataDouble.data->data[i] *= win;
+          dataDouble.data->data[dataDouble.data->length - 1 - i]  *= win;
+          winFncRMS += 2.0*win*win;
+        }
+        #if PRINTEXAMPLEDATA
+            printf("\nExample dataDouble values after windowing data in WindowDataTukey2:\n"); printExampleDataDouble();
+        #endif  
+  }
+
+  /* Add to sum of squares of the window function the parts of window which are equal to 1, and then find RMS value*/
+  winFncRMS += (REAL8) (N - 2*WINEND);
+  winFncRMS = sqrt( ( winFncRMS/((REAL8) N) ) );
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+/* Hann window based on Matlab, but with C indexing: w[k] = 0.5*( 1 - cos(2*pi*k/(N-1)) ) k = 0, 1, 2,...N-1 */
+int WindowDataHann(struct SFTConfigVarsTag CLA)
+{
+  INT4 k;
+  REAL8 win,N,Nm1;
+  REAL8 real8TwoPi = 2.0*((REAL8)(LAL_PI));
+
+  /* initialize the RMS of the window function */
+  winFncRMS = 0.0;
+
+  if(CLA.useSingle) {
+        N = ((REAL8)dataSingle.data->length);
+        Nm1 = N - 1;
+        for (k=0; k<N; k++) {
+          win=0.5*( 1.0 - cos(real8TwoPi*((REAL8)(k))/Nm1) );
+          dataSingle.data->data[k] *= win;
+          winFncRMS += win*win;
+        }
+        #if PRINTEXAMPLEDATA
+           printf("\nExample dataSingle values after windowing data in WindowDataHann:\n"); printExampleDataSingle();
+        #endif
+  } else {
+        N = ((REAL8)dataDouble.data->length);
+        Nm1 = N - 1;
+        for (k=0; k<N; k++) {
+          win=0.5*( 1.0 - cos(real8TwoPi*((REAL8)(k))/Nm1) );
+          dataDouble.data->data[k] *= win;
+          winFncRMS += win*win;
+        }  
+        #if PRINTEXAMPLEDATA
+            printf("\nExample dataDouble values after windowing data in WindowDataHann:\n"); printExampleDataDouble();
+        #endif  
+  }
+
+  /* Find RMS value; note that N is REAL8 in this function */
+  winFncRMS = sqrt( (winFncRMS/N) );
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+int CreateSFT(struct SFTConfigVarsTag CLA)
+{
+
+  /* 11/19/05 gam */
+  if(CLA.useSingle) {
+      #if TRACKMEMUSE
+        printf("Memory use before creating output vector fftDataSingle and calling XLALREAL4ForwardFFT:\n"); printmemuse();
+      #endif
+
+      /* 11/02/05 gam; allocate container for SFT data */
+      LALCCreateVector( &status, &fftDataSingle, dataSingle.data->length / 2 + 1 );
+      TESTSTATUS( &status );
+
+      /* compute sft */
+      XLAL_CHECK( XLALREAL4ForwardFFT( fftDataSingle, dataSingle.data, fftPlanSingle ) == XLAL_SUCCESS, XLAL_EFUNC );
+
+      #if TRACKMEMUSE
+        printf("Memory use after creating output vector fftDataSingle and calling XLALREAL4ForwardFFT:\n"); printmemuse();
+      #endif
+
+      #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary value of fftDataSingle from CreateSFT:\n"); printExampleFFTData(CLA);
+      #endif
+  } else {
+      #if TRACKMEMUSE
+        printf("Memory use before creating output vector fftDataDouble and calling XLALREAL8ForwardFFT:\n"); printmemuse();
+      #endif
+
+      /* 11/02/05 gam; allocate container for SFT data */
+      LALZCreateVector( &status, &fftDataDouble, dataDouble.data->length / 2 + 1 );
+      TESTSTATUS( &status );
+
+      /* compute sft */
+      XLAL_CHECK( XLALREAL8ForwardFFT( fftDataDouble, dataDouble.data, fftPlanDouble ) == XLAL_SUCCESS, XLAL_EFUNC );
+
+      #if TRACKMEMUSE
+        printf("Memory use after creating output vector fftDataDouble and calling XLALREAL8ForwardFFT:\n"); printmemuse();
+      #endif
+
+      #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary value of fftDataDouble from CreateSFT:\n"); printExampleFFTData(CLA);
+      #endif      
+  }
+      return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+int WriteSFT(struct SFTConfigVarsTag CLA)
+{
+  char sftname[256];
+  char sftnameFinal[256]; /* 01/09/06 gam */
+  char numSFTs[2]; /* 12/27/05 gam */
+  char site[2];    /* 12/27/05 gam */
+  char ifo[3];     /* 12/27/05 gam; allow 3rd charactor for null termination */
+  int firstbin=(INT4)(FMIN*CLA.T+0.5), k;
+  FILE *fpsft;
+  int errorcode1=0,errorcode2=0;
+  char gpstime[11]; /* 12/27/05 gam; allow for 10 digit GPS times and null termination */
+  REAL4 rpw,ipw;
+
+  /* 12/27/05 gam; set up the number of SFTs, site, and ifo as null terminated strings */
+  numSFTs[0] = '1';
+  numSFTs[1] = '\0'; /* null terminate */
+  strncpy( site, CLA.ChannelName, 1 );
+  site[1] = '\0'; /* null terminate */
+  if (CLA.IFO != NULL) {
+    strncpy( ifo, CLA.IFO, 2 );
+  } else {
+    strncpy( ifo, CLA.ChannelName, 2 );
+  }
+  ifo[2] = '\0'; /* null terminate */
+  sprintf(gpstime,"%09d",gpsepoch.gpsSeconds);
+
+  strcpy( sftname, CLA.SFTpath );
+  /* 12/27/05 gam; add option to make directories based on gps time */
+  if (CLA.makeGPSDirs > 0) {
+     /* 12/27/05 gam; concat to the sftname the directory name based on GPS time; make this directory if it does not already exist */
+     mkSFTDir(sftname, site, numSFTs, ifo, CLA.stringT, CLA.miscDesc, gpstime, CLA.makeGPSDirs);
+  }
+
+  /* 01/09/06 gam; sftname will be temporary; will move to sftnameFinal. */
+  if(CLA.makeTmpFile) {
+    /* set up sftnameFinal with usual SFT name */
+    strcpy(sftnameFinal,sftname);
+    strcat(sftnameFinal,"/SFT_");
+    strcat(sftnameFinal,ifo);
+    strcat(sftnameFinal,".");
+    strcat(sftnameFinal,gpstime);
+    /* sftname begins with . and ends in .tmp */
+    strcat(sftname,"/.SFT_");
+    strcat(sftname,ifo);
+    strcat(sftname,".");
+    strcat(sftname,gpstime);
+    strcat(sftname,".tmp");
+  } else {
+    strcat(sftname,"/SFT_");
+    strcat(sftname,ifo);
+    strcat(sftname,".");
+    strcat(sftname,gpstime);
+  }
+
+  /* open SFT file for writing */
+  fpsft=tryopen(sftname,"w");
+
+  /* write header */
+  SFTheadertag header;
+  header.endian=1.0;
+  header.gps_sec=gpsepoch.gpsSeconds;
+  header.gps_nsec=gpsepoch.gpsNanoSeconds;
+  header.tbase=CLA.T;
+  header.firstfreqindex=firstbin;
+  header.nsamples=(INT4)(DF*CLA.T+0.5);
+  if (1!=fwrite((void*)&header,sizeof(header),1,fpsft)){
+    fprintf(stderr,"Error in writing header into file %s!\n",sftname);
+    return 7;
+  }
+
+  /* 11/19/05 gam */
+  if(CLA.useSingle) {
+    /* Write SFT */
+    for (k=0; k<header.nsamples; k++)
+    {
+      rpw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* crealf(fftDataSingle->data[k+firstbin]);
+      ipw=((REAL4)(((REAL8)DF)/(0.5*(REAL8)(1/dataSingle.deltaT))))
+	* cimagf(fftDataSingle->data[k+firstbin]);
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(rpw) || !isfinite(ipw)) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif
+      errorcode1=fwrite((void*)&rpw, sizeof(REAL4),1,fpsft);
+      errorcode2=fwrite((void*)&ipw, sizeof(REAL4),1,fpsft);
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataSingle in WriteSFT:\n"); printExampleSFTDataGoingToFile(CLA);
+    #endif     
+    LALCDestroyVector( &status, &fftDataSingle );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataSingle in WriteSFT:\n"); printmemuse();
+    #endif
+  } else {    
+    /* Write SFT */
+    for (k=0; k<header.nsamples; k++)
+    {
+      rpw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* creal(fftDataDouble->data[k+firstbin]);
+      ipw=(((REAL8)DF)/(0.5*(REAL8)(1/dataDouble.deltaT))) 
+	* cimag(fftDataDouble->data[k+firstbin]);
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(rpw) || !isfinite(ipw)) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif
+      errorcode1=fwrite((void*)&rpw, sizeof(REAL4),1,fpsft);
+      errorcode2=fwrite((void*)&ipw, sizeof(REAL4),1,fpsft);
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataDouble in WriteSFT:\n"); printExampleSFTDataGoingToFile(CLA);
+    #endif
+    LALZDestroyVector( &status, &fftDataDouble );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataDouble in WriteSFT:\n"); printmemuse();
+    #endif
+  }
+
+  /* Check that there were no errors while writing SFTS */
+  if (errorcode1-1 || errorcode2-1)
+    {
+      fprintf(stderr,"Error in writing data into SFT file %s!\n",sftname);
+      return 8;
+    }
+  
+  fclose(fpsft);
+
+  /* 01/09/06 gam; sftname is temporary; move to sftnameFinal. */
+  if(CLA.makeTmpFile) {  
+    mvFilenames(sftname,sftnameFinal);
+  }
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+/* 12/28/05 gam; write out version 2 SFT */
+int WriteVersion2SFT(struct SFTConfigVarsTag CLA) 
+{
+  char sftname[256];
+  char sftFilename[256];
+  char sftnameFinal[256]; /* 01/09/06 gam */
+  char numSFTs[2]; /* 12/27/05 gam */
+  char site[2];    /* 12/27/05 gam */
+  char ifo[3];     /* 12/27/05 gam; allow 3rd charactor for null termination */
+  int firstbin=(INT4)(FMIN*CLA.T+0.5), k;
+  char gpstime[11]; /* 12/27/05 gam; allow for 10 digit GPS times and null termination */
+  SFTtype *oneSFT = NULL;
+  INT4 nBins = (INT4)(DF*CLA.T+0.5);
+  REAL4 singleDeltaT = 0.0; /* 01/05/06 gam */
+  REAL8 doubleDeltaT = 0.0; /* 01/05/06 gam */
+
+  /* 12/27/05 gam; set up the number of SFTs, site, and ifo as null terminated strings */
+  numSFTs[0] = '1';
+  numSFTs[1] = '\0'; /* null terminate */
+  strncpy( site, CLA.ChannelName, 1 );
+  site[1] = '\0'; /* null terminate */
+  if (CLA.IFO != NULL) {
+    strncpy( ifo, CLA.IFO, 2 );
+  } else {  
+    strncpy( ifo, CLA.ChannelName, 2 );
+  }
+  ifo[2] = '\0'; /* null terminate */
+  sprintf(gpstime,"%09d",gpsepoch.gpsSeconds);
+
+  strcpy( sftname, CLA.SFTpath );
+  /* 12/27/05 gam; add option to make directories based on gps time */
+  if (CLA.makeGPSDirs > 0) {
+     /* 12/27/05 gam; concat to the sftname the directory name based on GPS time; make this directory if it does not already exist */
+     mkSFTDir(sftname, site, numSFTs, ifo, CLA.stringT, CLA.miscDesc, gpstime, CLA.makeGPSDirs);
+  }
+
+  strcat(sftname,"/");
+  mkSFTFilename(sftFilename, site, numSFTs, ifo, CLA.stringT, CLA.miscDesc, gpstime);
+  /* 01/09/06 gam; sftname will be temporary; will move to sftnameFinal. */
+  if(CLA.makeTmpFile) {
+    /* set up sftnameFinal with usual SFT name */
+    strcpy(sftnameFinal,sftname);
+    strcat(sftnameFinal,sftFilename);
+    /* sftname begins with . and ends in .tmp */
+    strcat(sftname,".");
+    strcat(sftname,sftFilename);
+    strcat(sftname,".tmp");
+  } else {
+    strcat(sftname,sftFilename);
+  }  
+
+  /* make container to store the SFT data */
+  XLAL_CHECK( ( oneSFT = XLALCreateSFT ( ((UINT4)nBins)) ) != NULL, XLAL_EFUNC );
+  #if TRACKMEMUSE
+      printf("Memory use after creating oneSFT and calling XLALCreateSFT in WriteVersion2SFT:\n"); printmemuse();
+  #endif
+  
+  /* copy the data to oneSFT */
+  strcpy(oneSFT->name,ifo);
+  oneSFT->epoch.gpsSeconds=gpsepoch.gpsSeconds;
+  oneSFT->epoch.gpsNanoSeconds=gpsepoch.gpsNanoSeconds;
+  oneSFT->f0 = FMIN;
+  oneSFT->deltaF = 1.0/((REAL8)CLA.T);
+  oneSFT->data->length=nBins;
+  
+  if(CLA.useSingle) {
+    /* singleDeltaT = ((REAL4)dataSingle.deltaT); */ /* 01/05/06 gam; and normalize SFTs using this below */
+    singleDeltaT = (REAL4)(dataSingle.deltaT/winFncRMS); /* include 1 over window function RMS */
+    for (k=0; k<nBins; k++)
+    {
+      oneSFT->data->data[k] = (((REAL4) singleDeltaT) * fftDataSingle->data[k+firstbin]);
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(crealf(oneSFT->data->data[k])) || !isfinite(cimagf(oneSFT->data->data[k]))) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif      
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataSingle in WriteVersion2SFT:\n"); printExampleVersion2SFTDataGoingToFile(CLA,oneSFT);
+    #endif
+    LALCDestroyVector( &status, &fftDataSingle );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataSingle in WriteVersion2SFT:\n"); printmemuse();
+    #endif
+  } else {
+    /*doubleDeltaT = ((REAL8)dataDouble.deltaT); */ /* 01/05/06 gam; and normalize SFTs using this below */
+    doubleDeltaT = (REAL8)(dataDouble.deltaT/winFncRMS); /* include 1 over window function RMS */
+    for (k=0; k<nBins; k++)
+    {
+      oneSFT->data->data[k] = crectf( doubleDeltaT*creal(fftDataDouble->data[k+firstbin]), doubleDeltaT*cimag(fftDataDouble->data[k+firstbin]) );
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(crealf(oneSFT->data->data[k])) || !isfinite(cimagf(oneSFT->data->data[k]))) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataDouble in WriteVersion2SFT:\n"); printExampleVersion2SFTDataGoingToFile(CLA,oneSFT);
+    #endif
+    LALZDestroyVector( &status, &fftDataDouble );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataDouble in WriteVersion2SFT:\n"); printmemuse();
+    #endif
+  }  
+
+  /* write the SFT */
+  XLAL_CHECK( XLALWriteSFT2file(oneSFT, sftname, CLA.commentField) == XLAL_SUCCESS, XLAL_EFUNC );
+
+  /* 01/09/06 gam; sftname is temporary; move to sftnameFinal. */
+  if(CLA.makeTmpFile) {  
+    mvFilenames(sftname,sftnameFinal);
+  }
+
+  XLALDestroySFT (oneSFT);
+  #if TRACKMEMUSE
+      printf("Memory use after destroying oneSFT and calling XLALDestroySFT in WriteVersion2SFT:\n"); printmemuse();
+  #endif
+
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+/**
+  * This is a copy of WriteVersion2 method, but with no File Reading / Writing, 
+  * instead saving the sft into the pointer parameter sft
+  */
+int WriteVersion2SFTNoFileIO(struct SFTConfigVarsTag CLA, SFTtype **sft) 
+{
+  char sftname[256];
+  char sftFilename[256];
+  char sftnameFinal[256]; /* 01/09/06 gam */
+  char numSFTs[2]; /* 12/27/05 gam */
+  char site[2];    /* 12/27/05 gam */
+  char ifo[3];     /* 12/27/05 gam; allow 3rd charactor for null termination */
+  int firstbin=(INT4)(FMIN*CLA.T+0.5), k;
+  char gpstime[11]; /* 12/27/05 gam; allow for 10 digit GPS times and null termination */
+  SFTtype *oneSFT = NULL;
+  INT4 nBins = (INT4)(DF*CLA.T+0.5);
+  REAL4 singleDeltaT = 0.0; /* 01/05/06 gam */
+  REAL8 doubleDeltaT = 0.0; /* 01/05/06 gam */
+
+  /* 12/27/05 gam; set up the number of SFTs, site, and ifo as null terminated strings */
+  numSFTs[0] = '1';
+  numSFTs[1] = '\0'; /* null terminate */
+  strncpy( site, CLA.ChannelName, 1 );
+  site[1] = '\0'; /* null terminate */
+  if (CLA.IFO != NULL) {
+    strncpy( ifo, CLA.IFO, 2 );
+  } else {  
+    strncpy( ifo, CLA.ChannelName, 2 );
+  }
+  ifo[2] = '\0'; /* null terminate */
+  sprintf(gpstime,"%09d",gpsepoch.gpsSeconds);
+
+  strcpy( sftname, CLA.SFTpath );
+  /* 12/27/05 gam; add option to make directories based on gps time */
+  if (CLA.makeGPSDirs > 0) {
+     /* 12/27/05 gam; concat to the sftname the directory name based on GPS time; make this directory if it does not already exist */
+     mkSFTDir(sftname, site, numSFTs, ifo, CLA.stringT, CLA.miscDesc, gpstime, CLA.makeGPSDirs);
+  }
+
+  strcat(sftname,"/");
+  mkSFTFilename(sftFilename, site, numSFTs, ifo, CLA.stringT, CLA.miscDesc, gpstime);
+  /* 01/09/06 gam; sftname will be temporary; will move to sftnameFinal. */
+  if(CLA.makeTmpFile) {
+    /* set up sftnameFinal with usual SFT name */
+    strcpy(sftnameFinal,sftname);
+    strcat(sftnameFinal,sftFilename);
+    /* sftname begins with . and ends in .tmp */
+    strcat(sftname,".");
+    strcat(sftname,sftFilename);
+    strcat(sftname,".tmp");
+  } else {
+    strcat(sftname,sftFilename);
+  }  
+
+  /* make container to store the SFT data */
+  XLAL_CHECK( ( oneSFT = XLALCreateSFT ( ((UINT4)nBins)) ) != NULL, XLAL_EFUNC );
+  #if TRACKMEMUSE
+      printf("Memory use after creating oneSFT and calling XLALCreateSFT in WriteVersion2SFT:\n"); printmemuse();
+  #endif
+  
+  /* copy the data to oneSFT */
+  strcpy(oneSFT->name,ifo);
+  oneSFT->epoch.gpsSeconds=gpsepoch.gpsSeconds;
+  oneSFT->epoch.gpsNanoSeconds=gpsepoch.gpsNanoSeconds;
+  oneSFT->f0 = FMIN;
+  oneSFT->deltaF = 1.0/((REAL8)CLA.T);
+  oneSFT->data->length=nBins;
+
+  if(CLA.useSingle) {
+    /* singleDeltaT = ((REAL4)dataSingle.deltaT); */ /* 01/05/06 gam; and normalize SFTs using this below */
+    singleDeltaT = (REAL4)(dataSingle.deltaT/winFncRMS); /* include 1 over window function RMS */
+    for (k=0; k<nBins; k++)
+    {
+      oneSFT->data->data[k] = (((REAL4) singleDeltaT) * fftDataSingle->data[k+firstbin]);
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(crealf(oneSFT->data->data[k])) || !isfinite(cimagf(oneSFT->data->data[k]))) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataSingle in WriteVersion2SFT:\n"); printExampleVersion2SFTDataGoingToFile(CLA,oneSFT);
+    #endif
+    LALCDestroyVector( &status, &fftDataSingle );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataSingle in WriteVersion2SFT:\n"); printmemuse();
+    #endif
+  } else {
+    /*doubleDeltaT = ((REAL8)dataDouble.deltaT); */ /* 01/05/06 gam; and normalize SFTs using this below */
+    doubleDeltaT = (REAL8)(dataDouble.deltaT/winFncRMS); /* include 1 over window function RMS */
+    for (k=0; k<nBins; k++)
+    {
+      oneSFT->data->data[k] = crectf( doubleDeltaT*creal(fftDataDouble->data[k+firstbin]), doubleDeltaT*cimag(fftDataDouble->data[k+firstbin]) );
+      /* 06/26/07 gam; use finite to check that data does not contains a non-FINITE (+/- Inf, NaN) values */
+      #if CHECKFORINFINITEANDNANS
+        if (!isfinite(crealf(oneSFT->data->data[k])) || !isfinite(cimagf(oneSFT->data->data[k]))) {
+          fprintf(stderr, "Infinite or NaN data at freq bin %d.\n", k);
+          return 7;
+        }
+      #endif
+    }
+    #if PRINTEXAMPLEDATA
+        printf("\nExample real and imaginary SFT values going to file from fftDataDouble in WriteVersion2SFT:\n"); printExampleVersion2SFTDataGoingToFile(CLA,oneSFT);
+    #endif
+    LALZDestroyVector( &status, &fftDataDouble );
+    TESTSTATUS( &status );
+    #if TRACKMEMUSE
+      printf("Memory use after destroying fftDataDouble in WriteVersion2SFT:\n"); printmemuse();
+    #endif
+
+  }
+
+  /* write the SFT if SFTVars says so */
+  if(CLA.writeFile == 1) {
+    XLAL_CHECK( XLALWriteSFT2file(oneSFT, sftname, CLA.commentField) == XLAL_SUCCESS, XLAL_EFUNC );
+  } else  {
+    printf("Omitting writing SFT to file, user requested no file IO in MakeSFTsFunction");
+  }
+
+  /* 01/09/06 gam; sftname is temporary; move to sftnameFinal. */
+  if(CLA.makeTmpFile) {
+    mvFilenames(sftname,sftnameFinal);
+  }
+
+  *sft = oneSFT;
+  return 0;
+}
+/*******************************************************************************/
+
+/*******************************************************************************/
+int FreeMem(struct SFTConfigVarsTag CLA)
+{
+
+  LALFrClose(&status,&framestream);
+  TESTSTATUS( &status );
+
+  /* 11/19/05 gam */
+  if(CLA.useSingle) {
+    LALDestroyVector(&status,&dataSingle.data);
+    TESTSTATUS( &status );
+    XLALDestroyREAL4FFTPlan( fftPlanSingle );
+  } else {
+    LALDDestroyVector(&status,&dataDouble.data);
+    TESTSTATUS( &status );
+    XLALDestroyREAL8FFTPlan( fftPlanDouble );
+  }
+
+  LALCheckMemoryLeaks();
+
+  return 0;
+}
+/*******************************************************************************/
+
+#endif
diff --git a/lalapps/src/pulsar/MakeData/MakeSFTsFunction.h b/lalapps/src/pulsar/MakeData/MakeSFTsFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0c9c81db9c4bb9a6cb01e3e0adf82c30850cc26
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/MakeSFTsFunction.h
@@ -0,0 +1,55 @@
+/*
+*  Copyright (C) 2017 Benjamin Steltner
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+#ifndef _MAKESFTSFUNCTION_H
+#define _MAKESFTSFUNCTION_H
+
+#include <lal/LALDatatypes.h>
+#include <lal/ComplexFFT.h>
+#include <lal/RealFFT.h>
+#include <lal/Window.h>
+#include "SFTConfigVars.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#elif 0
+} /* so that editors will match preceding brace */
+#endif
+
+/**
+  * \defgroup MakeSFTs_h Header MakeSFTs_h
+  * \ingroup lal_fft
+  *
+  * \brief Performs short fourier transforms
+  *
+  * ### Synopsis ###
+  *
+  * \code
+  * #include <lal/MakeSFTsFunction.h>
+  * \endcode
+  *
+  * Performs SFTs
+  *
+  * ### Description ###
+**/
+
+int makeSFT(SFTConfigVarsTag SFTConfigVars, REAL8TimeSeries *Tseries, REAL8 fmin, REAL8 band, SFTtype **sft);
+
+
+#endif /* _MAKESFTSFUNCTION_H */
diff --git a/lalapps/src/pulsar/MakeData/Makefile.am b/lalapps/src/pulsar/MakeData/Makefile.am
index bd03f30b3309973b550fbc1d2229595bc7d92ab7..eb336f2c3b126dca7c6920af66994901791b4e5d 100644
--- a/lalapps/src/pulsar/MakeData/Makefile.am
+++ b/lalapps/src/pulsar/MakeData/Makefile.am
@@ -15,11 +15,16 @@ EXTRA_PROGRAMS =
 
 if LALFRAME
 
-bin_PROGRAMS += lalapps_MakeSFTs
+bin_PROGRAMS += lalapps_MakeSFTs lalapps_gateStrain_v1
 
 lalapps_MakeSFTs_SOURCES = MakeSFTs.c
 lalapps_MakeSFTs_CPPFLAGS = $(AM_CPPFLAGS)
 
+lalapps_gateStrain_v1_SOURCES = gateStrain_v1.c MakeSFTsFunction.c ComputePSDFunction.c
+
+
+
+
 if PSS
 lalapps_MakeSFTs_SOURCES += XLALPSSInterface.c
 lalapps_MakeSFTs_CPPFLAGS += -DPSS_ENABLED
diff --git a/lalapps/src/pulsar/MakeData/PSDConfigVars.h b/lalapps/src/pulsar/MakeData/PSDConfigVars.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4c04946acc6e2ee54c9d1b6f43a64c26a40d15d
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/PSDConfigVars.h
@@ -0,0 +1,44 @@
+#ifndef _PSDCONFIGVARS_H
+#define _PSDCONFIGVARS_H
+
+struct PSDUserVarsTag {
+  CHAR *inputData;      /**< directory for input sfts */
+  CHAR *outputPSD;      /**< directory for output sfts */
+  CHAR *outputSpectBname;
+
+  REAL8 Freq;   /**< *physical* start frequency to compute PSD for (excluding rngmed wings) */
+  REAL8 FreqBand; /**< *physical* frequency band to compute PSD for (excluding rngmed wings) */
+
+  REAL8 startTime;  /**< earliest SFT-timestamp to include */
+  REAL8 endTime;  /**< last SFT-timestamp to include */
+  CHAR *IFO;
+  CHAR  *timeStampsFile;
+  LALStringVector *linefiles;
+  INT4 blocksRngMed;  /**< number of running-median bins to use */
+  INT4 maxBinsClean;
+
+  INT4 PSDmthopSFTs;     /**< for PSD, type of math. operation over SFTs */
+  INT4 PSDmthopIFOs;     /**< for PSD, type of math. operation over IFOs */
+  BOOLEAN outputNormSFT; /**< output normalised SFT power? */
+  INT4 nSFTmthopSFTs;    /**< for norm. SFT, type of math. operation over SFTs */
+  INT4 nSFTmthopIFOs;    /**< for norm. SFT, type of math. operation over IFOs */
+
+  REAL8 binSizeHz;       /**< output PSD bin size in Hz */
+  INT4  binSize;         /**< output PSD bin size in no. of bins */
+  INT4  PSDmthopBins;    /**< for PSD, type of math. operation over bins */
+  INT4  nSFTmthopBins;   /**< for norm. SFT, type of math. operation over bins */
+  REAL8 binStepHz;       /**< output PSD bin step in Hz */
+  INT4  binStep;         /**< output PSD bin step in no. of bins */
+  BOOLEAN outFreqBinEnd; /**< output the end frequency of each bin? */
+
+  BOOLEAN dumpMultiPSDVector; /**< output multi-PSD vector over IFOs, timestamps, and frequencies into file(s) */
+  CHAR *outputQ;  /**< output the 'data-quality factor' Q(f) into this file */
+
+  REAL8 fStart;   /**< Start Frequency to load from SFT and compute PSD, including wings (it is RECOMMENDED to use --Freq instead) */
+  REAL8 fBand;    /**< Frequency Band to load from SFT and compute PSD, including wings (it is RECOMMENDED to use --FreqBand instead) */
+
+};
+
+typedef struct PSDUserVarsTag PSDUserVarsTag;
+
+#endif
diff --git a/lalapps/src/pulsar/MakeData/SFTConfigVars.h b/lalapps/src/pulsar/MakeData/SFTConfigVars.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a3fe6fbd4965110f1bf139ee472581f8a70809a
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/SFTConfigVars.h
@@ -0,0 +1,49 @@
+#ifndef _SFTCONFIGVARS_H
+#define _SFTCONFIGVARS_H
+
+struct SFTConfigVarsTag { /* Was "CommandLineArgsTag" */
+  REAL8 HPf;              /* High pass filtering frequency */
+  INT4 T;                 /* SFT duration */
+  char *stringT;          /* 12/27/05 gam; string with SFT duration */
+  INT4 GPSStart;
+  INT4 GPSEnd;
+  INT4 makeGPSDirs;        /* 12/27/05 gam; add option to make directories based on gps time */
+  INT4 sftVersion;         /* 12/28/05 gam; output SFT version */
+  char *commentField;      /* 12/28/05 gam; string comment for version 2 SFTs */
+  BOOLEAN htdata;          /* flag that indicates we're doing h(t) data */
+  BOOLEAN makeTmpFile;     /* 01/09/06 gam */
+  char *FrCacheFile;       /* Frame cache file */
+  char *ChannelName;
+  char *IFO;               /* 01/14/07 gam */
+  char *SFTpath;           /* path to SFT file location */
+  char *miscDesc;          /* 12/28/05 gam; string giving misc. part of the SFT description field in the filename */
+  INT4 PSSCleaning;    /* 1=YES and 0=NO*/
+  REAL8 PSSCleanHPf;       /* Cut frequency for the bilateral highpass filter. It has to be used only if PSSCleaning is YES.*/
+  INT4 PSSCleanExt;        /* Extend the timeseries at the beginning before calculating the autoregressive mean */
+  INT4 windowOption;       /* 12/28/05 gam; window options; 0 = no window, 1 = default = Matlab style Tukey window; 2 = make_sfts.c Tukey window; 3 = Hann window */
+  REAL8 windowR;
+  REAL8 overlapFraction;   /* 12/28/05 gam; overlap fraction (for use with windows; e.g., use -P 0.5 with -w 3 Hann windows; default is 1.0). */
+  BOOLEAN useSingle;       /* 11/19/05 gam; use single rather than double precision */
+  char *frameStructType;   /* 01/10/07 gam */
+
+  BOOLEAN writeFile;       /* Write file or not */
+}; /* Was CommandLineArgs */
+
+//extern struct SFTConfigVarsTag SFTConfigVars;
+
+struct SFTheadertag { /* Was "headertag" */
+  REAL8 endian;
+  INT4  gps_sec;
+  INT4  gps_nsec;
+  REAL8 tbase;
+  INT4  firstfreqindex;
+  INT4  nsamples;
+}; /* Was header */
+
+//extern struct SFTheadertag SFTheader;
+typedef struct SFTConfigVarsTag SFTConfigVarsTag;
+typedef struct SFTheadertag SFTheadertag;
+
+
+
+#endif /* _SFTCONFIGVARS_H */
diff --git a/lalapps/src/pulsar/MakeData/gateStrain_v1.c b/lalapps/src/pulsar/MakeData/gateStrain_v1.c
new file mode 100644
index 0000000000000000000000000000000000000000..39a72d844a3f9eafad370fe73166ba368d3d9faf
--- /dev/null
+++ b/lalapps/src/pulsar/MakeData/gateStrain_v1.c
@@ -0,0 +1,2163 @@
+/*
+*  Copyright (C) 2017-2021 Benjamin Steltner
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+/**
+ * \file
+ * \ingroup lalapps_pulsar_SFTTools
+ * \author Benjamin Steltner, Maria Alessandra Papa, Heinz-Bernd Eggenstein
+ * \brief Remove short-lived high-powered non-Gaussian noise transients from files. Generate 'gated' Short Fourier Transforms (SFTs).
+ */
+
+/*-----------------------------------------------------------------------
+ *
+ * File Name: gateStrain_v1.c
+ * Purpose: Remove short-lived high-powered non-Gaussian noise transients from files. Generate 'gated' Short Fourier Transforms (SFTs)
+ * Authors: Benjamin Steltner, Maria Alessandra Papa, Heinz-Bernd Eggenstein
+ * based on pycbc.strain.strain.detect_loud_glitches of the pyCBC python package by Alex Nitz (2013)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+/* ---------- includes ---------- */
+
+#include "config.h"
+
+#include <sys/stat.h>
+
+#include <lal/FrequencySeries.h>
+#include <lal/TimeSeries.h>
+#include <lal/ResampleTimeSeries.h>
+#include <lal/UserInput.h>
+#include <lal/SFTfileIO.h>
+#include <lal/BandPassTimeSeries.h>
+
+#include <lal/Random.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_interp.h>
+
+#include <lal/Window.h>
+#include <lal/LALString.h>
+#include <lal/LALCache.h>
+
+#ifdef HAVE_LIBLALFRAME
+#include <lal/LALFrameIO.h>
+#include <lal/LALFrStream.h>
+#endif
+
+#include <lal/LALMalloc.h>
+
+#include <lal/TimeFreqFFT.h>
+#include <lal/Interpolate.h>
+#include <lal/Units.h>
+#include <lal/GeneratePulsarSignal.h> //Needed for time to be included
+#include <LALAppsVCSInfo.h>
+
+#include "MakeSFTsFunction.h"
+#include "ComputePSDFunction.h"
+
+#include <time.h>
+
+/** configuration-variables derived from user-variables */
+typedef struct{
+  REAL8TimeSeries *inputTS; /**< Input TimeSeries read from frame file  */
+  CHAR *VCSInfoString;          /**< LAL + LALapps Git version string */
+
+  REAL8TimeSeries *originalStrain; /**< Copy of strain to gate at the end */
+  REAL8TimeSeries *strainPadded; /**< Zero-padded strain */
+  REAL8FrequencySeries *welchPSD; /**< Average PSD computed with Welchs Method */
+  COMPLEX16FrequencySeries *strainWhitened; /**< Fourier transformed strain */
+  REAL8TimeSeries *magnitude; /**< Will be used and in the end to hold the magnitude */
+  REAL8FrequencySeries *referencePSD; /**< Harmonic Mean PSD of whole Obs run */
+
+  BOOLEAN have_PSDRefFile; /**< Was the PSD Reference file given as a parameter? */
+  CHAR *logFileName; /**< Filename of the logfile to be written */
+  LALStringVector *fileNames; /**< Currently only holding the logFileName */
+  LALStringVector *identifier;  /**< Filename identifier for multi-processing */
+  UINT4 strainPaddedLength; /**< Todo: Remove. */
+  UINT4 padStart; /**< Before this array index strain is zero*/
+  UINT4 padEnd; /**< After this array index strain is zero*/
+  /* Gating constants: */
+  REAL8 threshHigh; /**< High threshold to identify glitch as gate */
+  REAL8 threshLow;  /**< Lower threshold to identify length of glitch */
+  UINT4 nDead;  /**< Minimal distance (in samples) for two glitches to be considered seperated */
+  CHAR* SFTTukeyWindowNaming; /**< Naming constant for tukey window radius in SFT file name */
+
+} ConfigVars_t;
+
+/* ----- User variables */
+typedef struct{
+  CHAR *outLabel;
+  /* Time */
+  LIGOTimeGPS startTime;  /**< Start-time of requested signal in detector-frame (GPS seconds) */
+  INT4 duration; /**< Duration of requested signal in seconds */
+
+  /* Frame input and output */
+  CHAR *outDir;    /**< directory for writing output timeseries in frame files */
+  LALStringVector *inFrames;  /**< At the moment only ONE timeseries supported: frame glob-patterns or cache files of time-series data to be added to output (one per IFO) */
+  LALStringVector *inFrChannels;/**< At the moment only ONE timeseries supported: list of frame channels to read time-series data from (one per IFO) */
+  LALStringVector *outFrChannels;/**< At the moment only ONE timeseries supported: list of output frame channel names to write (one per IFO) */
+  LALStringVector* IFOs;   /**< At the moment only ONE timeseries supported: list of detector-names "H1,H2,L1,.." or single detector*/
+  BOOLEAN outputGWF; /**< Determines if the gated timeseries will be written into a *.gwf file if value is not zero. Default is zero and therefore no file is written. */
+  CHAR *PSDReferenceFile; /**< Reference PSD for comparing 'quality' of SFT after gating */
+
+  /* SFT params */
+  REAL8 Tsft;           /**< SFT time baseline Tsft */
+  REAL8 SFToverlap;   /**< overlap SFTs by this many seconds */
+  REAL8 tukeyWindowRadius; /**< Tukey window radius for (only) the output SFT */
+  REAL8 SFTFreqStart; /**< Start frequency of output SFT */
+  REAL8 SFTFreqBand; /**< Frequency band of output SFT */
+  REAL8 Highpass; /** */
+
+  /* Gating constants: Named mostly like pycbc/strain.py detect_loud_glitch(...) method, minus naming conventions */
+  REAL8 psdDuration;  /**< Duration of the segments for PSD estimation in seconds */
+  REAL8 psdStride;  /**< Separation between PSD estimation segments in seconds */
+  REAL8 refFreqStart; /**< Frequency start for internally calculated reference PSD */
+  REAL8 refFreqBand; /**< Frequency band for internally calculated reference PSD */
+  REAL8 refPSDRatio; /**< Ratio of reference PSD versus intermediate PSD in each frequency bin. Default 1.05 */
+  REAL8 lowFreqCutoff;  /**< Minimum frequency to include in the whitened strain */
+  REAL8 highFreqCutoff; /**< Maximum frequency to include in the whitened strain. ((If given, the input series is downsampled accordingly. If omitted, the Nyquist frequency is used. */
+  REAL8 upThreshold;  /**< Minimum magnitude of whitened strain for considering a transient to be present */
+  REAL8 sigmaFactor;  /**< Points are considered to belong to the transient if they exceed this factor times calculated sigma   */
+  REAL8 secondsDeadTime;  /**< Time in seconds outliers must be apart to be considered two discrete gates */
+  REAL8 padData; /**< Amount of time padded at the beginning and end of the input time series */
+  UINT4 taperLength; /**< Length of timeseries tapered which is between zeropadding and actual timeseries */
+  UINT4 corruptLength; /**< TODO: This is a derived variable. Get rid of it. Describes the amount of non-useable timeseries, e.g. taper. */
+  REAL8 autogatingTaper; /**< Taper of the Tukey Window to gate data */
+
+  UINT4 maxIterations; /**< Maximum number of iterations comparing intermediate PSD to best-guess PSD. Default 3 */
+  REAL8 iterReduceHighThresh; /**< Reduce the high threshold by this amount each iteration */
+  REAL8 iterReduceLowThreshFactor; /**< Reduce the lower threshold factor by this amount each iteration */
+  REAL8 iterIncreaseDeadtime; /**< Increase the dead time by this amount each iteration */
+
+  /* Or provide a file with all gates and gate that */
+  CHAR *externalGateFile; /**< Use this file of externally provided gates instead of finding gates. Format: t_start t_end. t_start and t_end are allowed to lie outside given time window. */
+  CHAR *additionalGateFile; /**< Additionally provide times of gates which are used together with found gates. Format: t_start t_end. t_start and t_end are allowed to lie outside given time window. */
+
+  /* Further analysis output options */
+  BOOLEAN outputPSD; /**< Output PSD of SFT */
+  BOOLEAN outputMagnitude; /**< Output magnitude TS*/
+  BOOLEAN outputHighpassedStrain; /**< Output highpassed input TS */
+  BOOLEAN outputWelchPSD; /**< Output Welch PSD estimate */
+  BOOLEAN outputUngatedSFT; /**< Output ungated SFT */
+  BOOLEAN outputpyCBCSFT; /**< Output SFT gated with pyCBC gating */
+  REAL8 pyCBCFixedDurationGate; /**< Fixed gate duration when using pyCBC gating */
+  BOOLEAN outputIntermediateSFT; /**< Output intermediate SFTs */
+
+// ---------- DEPRECATED and DEFUNCT options ----------
+} UserVariables_t;
+
+typedef struct {
+  UINT4 gateAmount; /**< Amount of gates. */
+  REAL8Vector* gateStart; /**< Vector of start times for gates (REAL8 repr. of GPS Time) */
+  REAL8Vector* gateEnd; /**<Vector of end times for gates */
+  REAL8Vector* gateDuration; /**< Vector of duration for each gate */
+} GateParams_t;
+
+// ---------- local prototypes ----------
+int XLALWriteREAL8TimeSeries2fp ( FILE *fp, const REAL8TimeSeries *TS );
+int XLALWriteREAL8FrequencySeries2fp ( FILE *fp, const REAL8FrequencySeries *FS );
+int XLALInitUserVars ( UserVariables_t *uvar, int argc, char *argv[] );
+int XLALFreeMem (UserVariables_t *uvar, ConfigVars_t *cfg,  GateParams_t *gtParams );
+BOOLEAN is_directory ( const CHAR *fname );
+UINT4 nextPowerOf2(UINT4);
+
+int XLALInitgateStrain ( ConfigVars_t *cfg, UserVariables_t *uvar );
+int outputTimeSeriesToFile(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *Tseries);
+int taperStrain(UserVariables_t *uvar, REAL8TimeSeries *Tseries);
+int zeroPadStrain(ConfigVars_t *cfg, REAL8TimeSeries *mseries, REAL8TimeSeries **strain);
+int estimateWelchPSD(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *unPaddedTseries, REAL8TimeSeries *paddedTseries, REAL8FrequencySeries **psd);
+int copyReferencePSDFromWelchsPSD(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8FrequencySeries **referencePSD );
+int fftAndWhitenStrain(UserVariables_t *uvar, REAL8TimeSeries *Tseries, COMPLEX16FrequencySeries **CFseries, REAL8FrequencySeries *psdFseries);
+int ifft(REAL8TimeSeries **Tseries, COMPLEX16FrequencySeries *CFseries);
+COMPLEX16FrequencySeries *WhitenCOMPLEX16FrequencySeries(UserVariables_t *uvar, REAL8 strainSampleRate, COMPLEX16FrequencySeries *fseries, const REAL8FrequencySeries *psd);
+int HighPass(ConfigVars_t *cfg, REAL8TimeSeries *Tseries, REAL8 frequency);
+int findGlitchesAndDuration(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *magnitude, REAL8TimeSeries *Tseries, GateParams_t *gtParams);
+int compMagnitudeStatistics(ConfigVars_t *cfg, REAL8TimeSeries *Tseries, REAL8 *mean, REAL8 *std, REAL8 *max, UINT2 segments);
+int getGlitchDuration(ConfigVars_t *cfg, REAL8TimeSeries *magnitude, GateParams_t *gtParams);
+int gateData(UserVariables_t *uvar, REAL8TimeSeries *Tseries, GateParams_t *gtParams);
+int callMakeSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries, SFTtype **sft, BOOLEAN write2File, char* description, REAL8 tukeyWindowRadius);
+int callComputePSD(REAL8 freqStart, REAL8 freqBand, UINT2 blocksRngMed, SFTtype *sft, REAL8FrequencySeries **Fseries);
+int gateWithExternalGatesFile(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *Tseries);
+int loadAndMergeAdditionalGatesFile(UserVariables_t *uvar, GateParams_t *gtParams);
+int loadHMeanPSD(UserVariables_t *uvar, ConfigVars_t *cfg);
+int compareHMeanToThis(ConfigVars_t *cfg, REAL8FrequencySeries *sftPsd, REAL8 *sftRatio);
+int SpectrumInvertTruncate(REAL8FrequencySeries *spectrum, REAL8 lowfreq, UINT4 seglen, UINT4 trunclen, REAL8FFTPlan *fwdplan, REAL8FFTPlan *revplan);
+
+// ---------- debug and comparison prototypes ----------
+int producepyCBCGatedSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries, REAL8TimeSeries *magnitude);
+int produceUngatedSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries);
+int pycbcGateDataMethod(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *Magnitude, GateParams_t *gtParams);
+
+#define TRUE (1==1)
+#define FALSE (1==0)
+
+/* track memory usage under linux */
+#define TRACKMEMUSE 0
+
+/* Copied from MakeSFTs.c - https://lscsoft.docs.ligo.org/lalsuite/lalapps/_make_s_f_ts_8c_source.html */
+#if TRACKMEMUSE
+#include <sys/types.h>
+#include <unistd.h>
+void printmemuse(void);
+void printmemuse() {
+   pid_t mypid=getpid();
+   char commandline[256];
+   fflush(NULL);
+   sprintf(commandline,"cat /proc/%d/status | /bin/grep Vm | /usr/bin/fmt -140 -u", (int)mypid);
+   if ( system(commandline) ) XLALPrintError ("system() returned non-zero status\n");
+   fflush(NULL);
+ }
+#endif
+
+#define MEASURETIMING 0
+#if MEASURETIMING
+void measure_time(const char* method_name, clock_t begin, clock_t* single_begin);
+void measure_time(const char* method_name, clock_t begin, clock_t* single_begin)  {
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen("./timing.txt","a")) != NULL, XLAL_EFUNC, "Could not open timing file");
+  fprintf(fp, "%s %.3f %.3f\n", method_name, ((double) (clock()-begin)) / CLOCKS_PER_SEC, ((double) (clock()-*single_begin)) / CLOCKS_PER_SEC);
+  fclose(fp);
+  *single_begin = clock();
+}
+#endif
+
+/*----------------------------------------------------------------------*
+ * main function
+ *----------------------------------------------------------------------*/
+int main(int argc, char *argv[]){
+  //Compile time info
+  printf("Program build on: %s %s\n", __DATE__, __TIME__);
+  XLALClobberDebugLevel(LALMEMDBG | LALMEMTRACE | LALALLDBG);
+  printf("Debug Level: %d\n", XLALGetDebugLevel());
+
+  clock_t begin = clock();
+#if TRACKMEMUSE
+  printf("\nMemory use at startup is:\n"); printmemuse();
+#endif
+
+  UserVariables_t XLAL_INIT_DECL(uvar);
+  ConfigVars_t XLAL_INIT_DECL(cfg);
+  GateParams_t XLAL_INIT_DECL(gtParams);
+
+  XLAL_CHECK ( XLALInitUserVars (&uvar, argc, argv) == XLAL_SUCCESS, XLAL_EFUNC );
+  XLAL_CHECK ( XLALInitgateStrain ( &cfg, &uvar ) == XLAL_SUCCESS, XLAL_EFUNC );
+
+#if TRACKMEMUSE
+  printf("\nMemory use after init and reading in strain is:\n"); printmemuse();
+#endif
+  FILE* fp;
+  char buffer[100];
+
+  /* Applying Highpass */
+  XLAL_CHECK(HighPass(&cfg, cfg.inputTS, uvar.Highpass) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  if (uvar.outputHighpassedStrain)  {
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_HighpassedStrain", *cfg.identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8TimeSeries2fp(fp, cfg.inputTS);
+    fclose(fp);
+  }
+
+  XLAL_CHECK( (cfg.originalStrain = XLALCutREAL8TimeSeries(cfg.inputTS, 0, \
+               cfg.inputTS->data->length)) != NULL, XLAL_ENOMEM);
+
+#if TRACKMEMUSE
+  printf("Memory use after copy to originalStrain:\n"); printmemuse();
+#endif
+
+  /* Tapering Strain */
+  XLAL_CHECK ( taperStrain(&uvar, cfg.inputTS) == XLAL_SUCCESS, XLAL_EFUNC );
+
+  /* Downsampling strain if high freq cutoff */
+  if(XLALUserVarWasSet ( &uvar.highFreqCutoff )){
+    XLAL_CHECK ( XLALResampleREAL8TimeSeries(cfg.inputTS, 0.5 / uvar.highFreqCutoff) == XLAL_SUCCESS, XLAL_EFUNC );
+    uvar.corruptLength = (UINT4) uvar.padData * 1.0 / (cfg.inputTS->deltaT);
+#if TRACKMEMUSE
+    printf("Memory use after downsample is:\n"); printmemuse();
+#endif
+  }
+
+  /* Zero pad strain to a power-of-2 length */
+  XLAL_CHECK( zeroPadStrain(&cfg, cfg.inputTS, &cfg.strainPadded) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Make a copy of the TimeSeries with padding */
+  XLAL_CHECK( (cfg.magnitude = XLALCutREAL8TimeSeries(cfg.strainPadded, 0, \
+      cfg.strainPadded->data->length) ) != NULL, XLAL_ENOMEM);
+
+#if TRACKMEMUSE
+  printf("Memory use after copying into magnitude is:\n"); printmemuse();
+#endif
+
+/* Estimating PSD with Welchs Method. Use non-padded TimeSeries with cut corrupt length */
+  REAL8TimeSeries *psdTSeries;
+  UINT4 psdTStart = cfg.padStart + uvar.corruptLength;
+  UINT4 psdTDur = cfg.padEnd - cfg.padStart - 2 * uvar.corruptLength;
+
+  XLAL_CHECK( (psdTSeries = XLALCutREAL8TimeSeries(cfg.strainPadded, psdTStart, \
+      psdTDur) ) != NULL, XLAL_ENOMEM);
+
+  XLAL_CHECK ( estimateWelchPSD(&uvar, &cfg, psdTSeries, cfg.strainPadded, &cfg.welchPSD) == XLAL_SUCCESS, XLAL_EFUNC );
+  XLALDestroyREAL8TimeSeries(psdTSeries);
+
+  if (uvar.outputPSD || uvar.outputWelchPSD) {
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_WelchPSD", *cfg.identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8FrequencySeries2fp(fp, cfg.welchPSD);
+    fclose(fp);
+  }
+
+  /* If requested copy and save a portion of the PSD to have a reference for the intermediate resulting PSD */
+  if(!cfg.have_PSDRefFile)  {
+    XLAL_CHECK( copyReferencePSDFromWelchsPSD(&uvar, &cfg, &cfg.referencePSD) == XLAL_SUCCESS, XLAL_EFUNC );
+    if (uvar.outputWelchPSD)  {
+      snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/dbg_referencePSD", *cfg.identifier->data, ".txt");
+      XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+      XLALWriteREAL8FrequencySeries2fp(fp, cfg.referencePSD);
+      fclose(fp);
+    }
+  } else {
+  /* Load harmonic mean of e.g. whole obs to compare against this */
+    XLAL_CHECK(loadHMeanPSD(&uvar, &cfg) == XLAL_SUCCESS, XLAL_EFUNC);
+  }
+
+  /* FFT and whiten Strain */
+  XLAL_CHECK ( fftAndWhitenStrain(&uvar, cfg.magnitude, &cfg.strainWhitened, cfg.welchPSD) == XLAL_SUCCESS, XLAL_EFUNC );
+
+  /* iFFT Whitened Strain */
+  XLAL_CHECK ( ifft(&cfg.magnitude, cfg.strainWhitened) == XLAL_SUCCESS, XLAL_EFUNC );
+
+  /* Resize: Padding of power-2 isnt necessary anymore */
+  UINT4 magStart = cfg.padStart + uvar.corruptLength;
+  UINT4 magDur = cfg.padEnd - cfg.padStart - 2 * uvar.corruptLength;
+
+  XLAL_CHECK( (cfg.magnitude = XLALResizeREAL8TimeSeries(cfg.magnitude, magStart, \
+      magDur) ) != NULL, XLAL_ENOMEM);
+
+  if (uvar.outputMagnitude) {
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_WhitenedMagnitude", *cfg.identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8TimeSeries2fp(fp, cfg.magnitude);
+    fclose(fp);
+  }
+
+  /* Produce ungated or pyCBC-gated SFTs */
+  if (uvar.outputUngatedSFT)  {
+    XLAL_CHECK( ( produceUngatedSFT(&uvar, &cfg, uvar.SFTFreqStart, uvar.SFTFreqBand, cfg.originalStrain)) == XLAL_SUCCESS, XLAL_EFUNC);
+  }
+  if (uvar.outputpyCBCSFT)  {
+    XLAL_CHECK( ( producepyCBCGatedSFT(&uvar, &cfg, uvar.SFTFreqStart, uvar.SFTFreqBand, cfg.originalStrain, cfg.magnitude)) == XLAL_SUCCESS, XLAL_EFUNC);
+  }
+  /* Gate once with externally given gating file */
+  if ( XLALUserVarWasSet(&uvar.externalGateFile) ) {
+    XLAL_CHECK( ( gateWithExternalGatesFile(&uvar, &cfg, cfg.originalStrain)) == XLAL_SUCCESS, XLAL_EFUNC);
+  }
+
+  /* Find glitches and their duration */
+  XLAL_CHECK( findGlitchesAndDuration(&uvar, &cfg, cfg.magnitude, cfg.strainPadded, &gtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Load additional gates file and merge with found gates */
+  if ( XLALUserVarWasSet(&uvar.additionalGateFile) ) {
+    XLAL_CHECK( loadAndMergeAdditionalGatesFile(&uvar, &gtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+//    gtParams = loadAndMergeAdditionalGatesFile(&uvar, &gtParams);
+    printf("AfterM %d gates (cross check %d %d %d)\n", gtParams.gateAmount, gtParams.gateStart->length, gtParams.gateEnd->length, gtParams.gateDuration->length);
+    fflush(stdout);
+  }
+
+  /* Gate data */
+  XLAL_CHECK( gateData(&uvar, cfg.originalStrain, &gtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+  /* Write used gates (in the end) into file */
+  FILE *fplog = fopen(cfg.logFileName, "a");
+  if( fplog == NULL) {
+    printf("Error opening file: %s", cfg.logFileName);
+    return EXIT_FAILURE;
+  }
+  fprintf(fplog, "\n\nAfterall Gate(s) found:   %d\n", gtParams.gateAmount);
+  for(UINT2 index = 0; index < gtParams.gateAmount; index++) {
+    fprintf(fplog, "# Start End Dur:   %.16f  %.16f  %.16f\n", gtParams.gateStart->data[index], gtParams.gateEnd->data[index], gtParams.gateDuration->data[index]);
+  }
+  fclose(fplog);
+
+  char newGateFileName[100];
+  snprintf(newGateFileName, 100, "%s%s%s%s", uvar.outDir, "/Gates", *cfg.identifier->data, ".txt");
+  FILE *fpNG = fopen(newGateFileName, "w");
+  if( fpNG == NULL) {
+    printf("Error opening file: %s", newGateFileName);
+    return EXIT_FAILURE;
+  }
+//  fprintf(fp, "Gate(s) found:   %d\n", gtParams->gateAmount);
+  for(UINT2 index = 0; index < gtParams.gateAmount; index++) {
+    fprintf(fpNG, "%.16f %.16f %.16f\n", gtParams.gateStart->data[index], gtParams.gateEnd->data[index], gtParams.gateDuration->data[index]);
+  }
+  fclose(fpNG);
+
+  if (uvar.outputHighpassedStrain)  {
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_B4SecHighpassStrain", *cfg.identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8TimeSeries2fp(fp, cfg.originalStrain);
+    fclose(fp);
+  }
+
+  /* Highpass again */
+  XLAL_CHECK(HighPass(&cfg, cfg.originalStrain, uvar.Highpass) == XLAL_SUCCESS, XLAL_EFUNC);
+
+/*  if (uvar.outputHighpassedStrain)  {
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_AfterSecHighpassStrain", *cfg.identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8TimeSeries2fp(fp, cfg.originalStrain);
+    fclose(fp);
+  }
+*/
+  /* Remove Padding */
+  XLAL_CHECK( (cfg.originalStrain = XLALResizeREAL8TimeSeries(cfg.originalStrain,
+               uvar.padData / cfg.originalStrain->deltaT, (uvar.duration - 2*uvar.padData) / cfg.originalStrain->deltaT) ) != NULL, XLAL_ENOMEM);
+
+//#if (defined DEBUGWRITEOUT || defined DEBUGGATEDSTRAIN)
+//  snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar.outDir, "/C_GatedStrain", *cfg.identifier->data, ".txt");
+//    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+//  XLALWriteREAL8TimeSeries2fp(fp, cfg.originalStrain);
+//  fclose(fp);
+//#endif
+
+
+  //Output timeseries into *.gwf
+  if (uvar.outputGWF)  {
+    XLAL_CHECK ( outputTimeSeriesToFile(&uvar, &cfg, cfg.originalStrain) == XLAL_SUCCESS, XLAL_EFUNC );
+  }
+
+  /* Make the gated SFT */
+  SFTtype *sft = NULL;
+  char description[32];
+  snprintf(description, 32, "GATED_%s", cfg.SFTTukeyWindowNaming);
+  XLAL_CHECK( callMakeSFT(&uvar, &cfg, uvar.SFTFreqStart, uvar.SFTFreqBand, cfg.originalStrain, &sft, 1, description, uvar.tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+  XLALDestroyCOMPLEX8FrequencySeries(sft);
+
+  FILE *fpend = fopen(cfg.logFileName, "a");
+  if( fpend == NULL) {
+    printf("Error opening file: %s", cfg.logFileName);
+    return EXIT_FAILURE;
+  }
+  fprintf(fpend, "\nSuccessfully leaving gateStrain program... ");
+  fclose(fpend);
+
+  XLALFreeMem (&uvar, &cfg, &gtParams );
+  LALCheckMemoryLeaks();
+  printf("\n------------------------------------------------\n");
+#if TRACKMEMUSE
+  printf("Memory use before program termination is:\n"); printmemuse();
+#endif
+
+  double time_spent = (double) (clock()-begin) / CLOCKS_PER_SEC;
+  printf("\n#################################################\n");
+  printf("Successfully leaving gateStrain program in %.3f ... ", time_spent);
+  printf("\n#################################################\n");
+  return 0;
+} /* Main */
+
+/**
+  * Make SFT of non-gated time series.
+  */
+int produceUngatedSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries)  {
+  REAL8TimeSeries *strainCopy = NULL;
+  SFTtype *sft = NULL;
+  char description[32];
+  snprintf(description, 32, "UNGATED_%s", cfg->SFTTukeyWindowNaming);
+
+  XLAL_CHECK( ( strainCopy = XLALCutREAL8TimeSeries(Tseries, 0, uvar->duration / Tseries->deltaT) ) != NULL, XLAL_ENOMEM);
+
+  /* Highpass again */
+  XLAL_CHECK(HighPass(cfg, strainCopy, uvar->Highpass) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Remove Padding */
+  XLAL_CHECK( (strainCopy = XLALResizeREAL8TimeSeries(strainCopy,
+               uvar->padData / strainCopy->deltaT, (uvar->duration - 2*uvar->padData) / strainCopy->deltaT) ) != NULL, XLAL_ENOMEM);
+
+  XLAL_CHECK( callMakeSFT(uvar, cfg, freqStart, freqBand, strainCopy, &sft, uvar->outputUngatedSFT, description, uvar->tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8TimeSeries(strainCopy);
+  XLALDestroyCOMPLEX8FrequencySeries(sft);
+  return XLAL_SUCCESS;
+}
+
+/**
+  * Make SFT with pyCBC gating methode.
+  */
+int producepyCBCGatedSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries, REAL8TimeSeries *magnitude)  {
+  GateParams_t XLAL_INIT_DECL(pyCBCgtParams);
+  REAL8TimeSeries *strainCopy = NULL;
+  REAL8TimeSeries *workCopyMag = NULL;
+  SFTtype *sft = NULL;
+  char description[32];
+
+  XLAL_CHECK( ( strainCopy = XLALCutREAL8TimeSeries(Tseries, 0, uvar->duration / Tseries->deltaT) ) != NULL, XLAL_ENOMEM);
+
+  XLAL_CHECK( (workCopyMag = XLALCutREAL8TimeSeries(magnitude, 0, \
+      magnitude->data->length) ) != NULL, XLAL_ENOMEM);
+
+  for(UINT4 indexx = 0; indexx < workCopyMag->data->length; indexx++) {
+    workCopyMag->data->data[indexx] = fabs(workCopyMag->data->data[indexx]);
+  }
+
+  XLAL_CHECK ( pycbcGateDataMethod(uvar, cfg, workCopyMag, &pyCBCgtParams)
+        == XLAL_SUCCESS, XLAL_EFUNC );
+  if(pyCBCgtParams.gateAmount != 0 )  {
+    XLAL_CHECK( gateData(uvar, strainCopy, &pyCBCgtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+
+/*    FILE* fpold;
+    char bufferold[100];
+    snprintf(bufferold, sizeof bufferold, "%s%s%s%s", uvar.outDir, "/C_strainCopy", *cfg->identifier->data, ".txt");
+    fpold = fopen(bufferold,"w");
+    XLALWriteREAL8TimeSeries2fp(fpold, strainCopy);
+    fclose(fpold);
+    snprintf(bufferold, sizeof bufferold, "%s%s%s%s", uvar.outDir, "/C_MagnitudeStrain", *cfg->identifier->data, ".txt");
+    fpold = fopen(bufferold,"w");
+    XLALWriteREAL8TimeSeries2fp(fpold, workCopyMag);
+    fclose(fpold);*/
+
+  } else {
+    printf("No (old) gate found");
+  }
+
+  /* Highpass again */
+  XLAL_CHECK(HighPass(cfg, strainCopy, uvar->Highpass) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Remove Padding */
+  XLAL_CHECK( (strainCopy = XLALResizeREAL8TimeSeries(strainCopy,
+               uvar->padData / strainCopy->deltaT, (uvar->duration - 2*uvar->padData) / strainCopy->deltaT) ) != NULL, XLAL_ENOMEM);
+
+  snprintf(description, 32, "pyCBCGATED_%s", cfg->SFTTukeyWindowNaming);
+  XLAL_CHECK( callMakeSFT(uvar, cfg, freqStart, freqBand, strainCopy, &sft, uvar->outputpyCBCSFT, description, uvar->tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyCOMPLEX8FrequencySeries(sft);
+  XLALDestroyREAL8TimeSeries(workCopyMag);
+  XLALDestroyREAL8TimeSeries(strainCopy);
+  XLALDestroyREAL8Vector(pyCBCgtParams.gateStart);
+  XLALDestroyREAL8Vector(pyCBCgtParams.gateEnd);
+  XLALDestroyREAL8Vector(pyCBCgtParams.gateDuration);
+
+  return XLAL_SUCCESS;
+}
+
+/**
+ * Register all "user-variables", and initialized them from command-line and config-files
+ */
+int XLALInitUserVars ( UserVariables_t *uvar, int argc, char *argv[] ) {
+  XLAL_CHECK ( uvar != NULL, XLAL_EINVAL, "Invalid NULL input 'uvar'\n");
+  XLAL_CHECK ( argv != NULL, XLAL_EINVAL, "Invalid NULL input 'argv'\n");
+
+#define MISC_DEFAULT "gating"
+  XLAL_CHECK ( (uvar->outLabel = XLALStringDuplicate ( MISC_DEFAULT ))  != NULL, XLAL_EFUNC );
+
+  /* ---------- set a few defaults ---------- */
+  uvar->Tsft = 1800;
+  uvar->Highpass = 10.0;
+  uvar->psdDuration = 4.0;
+  uvar->psdStride = 2.0;
+  uvar->refFreqStart = 33.0;
+  uvar->refFreqBand = 5.0;
+  uvar->refPSDRatio = 1.05;
+  uvar->lowFreqCutoff = 15;
+  uvar->upThreshold = 50;
+  uvar->sigmaFactor = 6;
+  uvar->secondsDeadTime = 3.0;
+  uvar->padData = 8.0;
+  uvar->autogatingTaper = 0.25;
+  uvar->tukeyWindowRadius = 0.001;
+  uvar->SFTFreqStart = 15.0;
+  uvar->SFTFreqBand = 1990.0;
+
+  uvar->maxIterations = 3;
+  uvar->iterReduceHighThresh = 10.0;
+  uvar->iterReduceLowThreshFactor = 0.01;
+  uvar->iterIncreaseDeadtime = 0.1;
+  // uvar->fmin = 0; /* no heterodyning by default */
+  //uvar->Band = 8192;  /* 1/2 LIGO sampling rate by default */
+  uvar->pyCBCFixedDurationGate = 16.0;
+
+  /* start + duration of timeseries */
+  XLALRegisterUvarMember( startTime,            EPOCH, 'G', REQUIRED, "Start-time of requested signal in detector-frame (format ''xx.yy[GPS|MJD]')");
+  XLALRegisterUvarMember( duration,              INT4, 0,  REQUIRED, "Duration of requested signal in seconds");
+
+  /* frame input/output options */
+#ifdef HAVE_LIBLALFRAME
+  XLALRegisterUvarMember ( outDir,   STRING,      'F', REQUIRED,  "Output Dir: directory for output timeseries frame files and short Fourier transforms");
+  XLALRegisterUvarMember ( inFrames,    STRINGVector,'C', REQUIRED,  "CSV list (one per IFO) of input frame cache files");
+  XLALRegisterUvarMember ( inFrChannels,  STRINGVector,'N', REQUIRED,  "CSV list (one per IFO) of frame channels to read timeseries from");
+  XLALRegisterUvarMember ( outFrChannels, STRINGVector, 0,  REQUIRED, "CSV list (one per IFO) of output frame channel names [default: <inFrChannels>-<outLabel> or <IFO>:<outLabel>]");
+#else
+  XLALRegisterUvarMember ( outDir,  STRING,       'F', DEFUNCT, "Need to compile with lalframe support for this option to work");
+  XLALRegisterUvarMember ( inFrames,     STRINGVector, 'C', DEFUNCT, "Need to compile with lalframe support for this option to work");
+  XLALRegisterUvarMember ( inFrChannels, STRINGVector, 'N', DEFUNCT, "Need to compile with lalframe support for this option to work");
+  XLALRegisterUvarMember ( outFrChannels, STRINGVector, 0,  DEFUNCT, "Need to compile with lalframe support for this option to work");
+#endif
+
+  XLALRegisterUvarMember ( tukeyWindowRadius, REAL8, 0, OPTIONAL, "Tukey window radius for (only) the output SFT. Default 0.001");
+  XLALRegisterUvarMember ( SFTFreqStart, REAL8, 0, OPTIONAL, "Start frequency of output SFT");
+  XLALRegisterUvarMember ( SFTFreqBand, REAL8, 0, OPTIONAL, "Frequency band of output SFT");
+  XLALRegisterUvarMember ( Highpass, REAL8, 0, OPTIONAL, "High pass filtering frequency in Hz.");
+
+  /* Gating options */
+  XLALRegisterUvarMember ( psdDuration, REAL8, 0, OPTIONAL, "Duration of the segments for PSD estimation in seconds");
+  XLALRegisterUvarMember ( psdStride, REAL8, 0, OPTIONAL, "Separation between PSD estimation segments in seconds");
+  XLALRegisterUvarMember ( refFreqStart, REAL8, 0, OPTIONAL, "Frequency start for internally calculated reference PSD. Default 33.0 (Hz)");
+  XLALRegisterUvarMember ( refFreqBand, REAL8, 0, OPTIONAL, "Frequency band for internally calculated reference PSD. Default 5.0 (Hz)");
+  XLALRegisterUvarMember ( refPSDRatio, REAL8, 0, OPTIONAL, "Ratio of reference PSD versus intermediate PSD in each frequency bin. Default 1.05");
+  XLALRegisterUvarMember ( lowFreqCutoff, REAL8, 0, OPTIONAL, "Minimum frequency to include in the whitened strain");
+  XLALRegisterUvarMember ( highFreqCutoff, REAL8, 0, OPTIONAL, "Maximum frequency to include in the whitened strain");
+  XLALRegisterUvarMember ( upThreshold, REAL8, 0, OPTIONAL, "Minimum magnitude of whitened strain for considering a transient to be present");
+  XLALRegisterUvarMember ( sigmaFactor, REAL8, 0, OPTIONAL, "Points are considered to belong to the transient if they exceed this factor times calculated sigma");
+  XLALRegisterUvarMember ( secondsDeadTime, REAL8, 0, OPTIONAL, "Time in seconds outliers must be apart to be considered two discrete gates");
+  XLALRegisterUvarMember ( padData, REAL8, 0, OPTIONAL, "Amount of time padded at the beginning and end of the input time series. Default 8.0");
+  XLALRegisterUvarMember ( autogatingTaper, REAL8, 0, OPTIONAL, "Taper for the tukey window to gate data with. Default 0.25");
+  XLALRegisterUvarMember ( outputGWF, BOOLEAN, 0, OPTIONAL, "Write gated time series to *.gwf file if value is not zero. Default is zero");
+  XLALRegisterUvarMember ( PSDReferenceFile, STRING, 0, OPTIONAL, "Input reference PSD which is used to compare the SFT 'quality' after gating. File consists of freq psdvalue pairs. Overwrites refFreqStart & refFreqBand option.");
+
+  XLALRegisterUvarMember ( maxIterations, UINT4, 0, OPTIONAL, "Maximum number of iterations comparing intermediate PSD to best-guess PSD. Default 3");
+  XLALRegisterUvarMember ( iterReduceHighThresh, REAL8, 0, OPTIONAL, "Reduce the high threshold by this amount each iteration");
+  XLALRegisterUvarMember ( iterReduceLowThreshFactor, REAL8, 0, OPTIONAL, "Reduce the lower threshold factor by this amount each iteration");
+  XLALRegisterUvarMember ( iterIncreaseDeadtime, REAL8, 0, OPTIONAL, "Increase the dead time by this amount each iteration");
+
+  XLALRegisterUvarMember ( outputPSD, BOOLEAN, 0, DEVELOPER, "Output PSD of SFT");
+  XLALRegisterUvarMember ( outputMagnitude, BOOLEAN, 0, DEVELOPER, "Output magnitude time series");
+  XLALRegisterUvarMember ( outputHighpassedStrain, BOOLEAN, 0, DEVELOPER, "Output highpassed input time series");
+  XLALRegisterUvarMember ( outputWelchPSD, BOOLEAN, 0, DEVELOPER, "Output Welch PSD estimate");
+  XLALRegisterUvarMember ( outputUngatedSFT, BOOLEAN, 0, DEVELOPER, "Output ungated SFT");
+  XLALRegisterUvarMember ( outputpyCBCSFT, BOOLEAN, 0, DEVELOPER, "Output SFT gated with pyCBC gating");
+  XLALRegisterUvarMember ( pyCBCFixedDurationGate, REAL8, 0, DEVELOPER, "Fixed gate duration when using pyCBC gating");
+  XLALRegisterUvarMember ( outputIntermediateSFT, BOOLEAN, 0, DEVELOPER, "Output intermediate SFTs");
+
+  XLALRegisterUvarMember ( externalGateFile, STRING, 0, OPTIONAL, "Use this file of externally provided gates instead of finding gates. Format: t_start t_end. t_start and t_end are allowed to lie outside given time window.");
+  XLALRegisterUvarMember ( additionalGateFile, STRING, 0, OPTIONAL, "Additionally provide times of gates which are used together with found gates. Format: t_start t_end. t_start and t_end are allowed to lie outside given time window.");
+
+  /* read cmdline & cfgfile  */
+  BOOLEAN should_exit = 0;
+  XLAL_CHECK( XLALUserVarReadAllInput( &should_exit, argc, argv, lalAppsVCSInfoList ) == XLAL_SUCCESS, XLAL_EFUNC );
+  if ( should_exit ) {
+    exit (1);
+  }
+
+  /* Test if output directory is valid */
+  XLAL_CHECK( is_directory(uvar->outDir), XLAL_EFUNC, "Error: %s is not a valid existing directory", uvar->outDir);
+
+  return XLAL_SUCCESS;
+} /* XLALInitUserVars() */
+
+
+/**
+ * Copied from makefakedata_v5, edited: https://lscsoft.docs.ligo.org/lalsuite/lalapps/makefakedata__v5_8c_source.html
+ * Handle user-input and set up shop accordingly, and do all
+ * consistency-checks on user-input.
+ */
+int
+XLALInitgateStrain ( ConfigVars_t *cfg, UserVariables_t *uvar ){
+  XLAL_CHECK ( cfg != NULL, XLAL_EINVAL, "Invalid NULL input 'cfg'\n" );
+  XLAL_CHECK ( uvar != NULL, XLAL_EINVAL, "Invalid NULL input 'uvar'\n");
+
+  cfg->VCSInfoString = XLALVCSInfoString(lalAppsVCSInfoList, 0, "%% "); 
+  XLAL_CHECK ( cfg->VCSInfoString != NULL, XLAL_EFUNC, "XLALVCSInfoString failed.\n" );
+  // ---------- check user-input consistency ----------
+
+  // ----- check if frames + frame channels given
+  BOOLEAN have_frames  = (uvar->inFrames != NULL);
+  BOOLEAN have_channels= (uvar->inFrChannels != NULL);
+  XLAL_CHECK ( have_frames && have_channels, XLAL_EINVAL, "Need both --inFrames and --inFrChannels\n");
+
+  // ----- Time: From --startTime+duration
+  BOOLEAN have_startTime = XLALUserVarWasSet ( &uvar->startTime );
+  BOOLEAN have_duration = XLALUserVarWasSet ( &uvar->duration );
+  uvar->Tsft = 1800;
+  uvar->SFToverlap = 0;
+  // need BOTH startTime+duration
+  XLAL_CHECK ( have_duration && have_startTime, XLAL_EINVAL, "Need BOTH {--startTime,--duration} \n");
+
+  /* High freq cutoff has to be a power of 2 */
+  if ( XLALUserVarWasSet ( &uvar->highFreqCutoff ) ) {
+    XLAL_CHECK ( ((UINT2) uvar->highFreqCutoff & ( (UINT2) uvar->highFreqCutoff - 1)) == 0, XLAL_EINVAL, "--highFreqCutoff has to be a power of 2\n");
+  }
+  /* Handle reference PSD options */
+  if ( XLALUserVarWasSet ( &uvar->PSDReferenceFile ) ) {
+    cfg->have_PSDRefFile = (uvar->PSDReferenceFile != NULL);
+  } else  {
+    cfg->have_PSDRefFile = (uvar->PSDReferenceFile != NULL);
+  }
+  XLAL_CHECK(( XLALUserVarWasSet ( &uvar->refFreqStart ) == XLALUserVarWasSet( &uvar->refFreqBand )), XLAL_EINVAL, "Need BOTH or NONE (--refFreqStart, --refFreqBand)\n");
+
+  /* Handle iteration parameters */
+  XLAL_CHECK(( cfg->threshHigh - uvar->maxIterations * uvar->iterReduceHighThresh < 0.0 ), XLAL_EINVAL, "Combination of high threshold, maximum iterations and threshold reduction leads to negative values. \n");
+  XLAL_CHECK(( cfg->threshHigh - uvar->maxIterations * uvar->iterReduceHighThresh < uvar->sigmaFactor ), XLAL_EINVAL, "Combination of high threshold, maximum iterations, threshold reduction and lower threshold factor likely leads to high threshold values smaller than the lower threshold factor at max iterations. \n");
+
+  char descWin[16];
+  snprintf(descWin, 16, "WIN%g", uvar->tukeyWindowRadius);
+  memmove(descWin+3, descWin+3+2, strlen(descWin)-3);
+//  cfg->SFTTukeyWindowNaming = malloc(strlen(descWin) + 1);
+  cfg->SFTTukeyWindowNaming = strdup(descWin);
+  printf("SFT tukey window naming: %s\n", cfg->SFTTukeyWindowNaming);
+
+#ifdef HAVE_LIBLALFRAME
+  UINT4 numDetectors = uvar->inFrChannels->length;
+  XLAL_CHECK ( uvar->inFrames->length == numDetectors, XLAL_EINVAL, "Need equal number of channel names (%d) as frame specifications (%d)\n", uvar->inFrChannels->length, numDetectors );
+
+  //XLAL_CHECK ( (cfg->inputMultiTS = XLALCalloc ( 1, sizeof(*cfg->inputMultiTS))) != NULL, XLAL_ENOMEM );
+ /// cfg->inputMultiTS->length = numDetectors;
+ // XLAL_CHECK ( (cfg->inputMultiTS->data = XLALCalloc ( numDetectors, sizeof(cfg->inputMultiTS->data[0]) )) != NULL, XLAL_ENOMEM );
+  //if ( cfg->multiTimestamps == NULL ){
+  //  XLAL_CHECK ( (cfg->multiTimestamps = XLALCalloc ( 1, sizeof(*cfg->multiTimestamps) )) != NULL, XLAL_ENOMEM );
+  //   XLAL_CHECK ( (cfg->multiTimestamps->data = XLALCalloc ( numDetectors, sizeof(cfg->multiTimestamps->data[0]))) != NULL, XLAL_ENOMEM );
+  //  cfg->multiTimestamps->length = numDetectors;
+  //}
+  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
+    LALCache *cache;
+    XLAL_CHECK ( (cache = XLALCacheImport ( uvar->inFrames->data[X] )) != NULL, XLAL_EFUNC, "Failed to import cache file '%s'\n", uvar->inFrames->data[X] );
+    // ----- open frame stream ----------
+    LALFrStream *stream;
+    XLAL_CHECK ( (stream = XLALFrStreamCacheOpen ( cache )) != NULL, XLAL_EFUNC, "Failed to open stream from cache file '%s'\n", uvar->inFrames->data[X] );
+    XLALDestroyCache ( cache );
+
+    // Create identifier for file saving identifcation
+    LALStringVector* ParsedString;
+    XLAL_CHECK( ( ParsedString = XLALParseStringVector(uvar->inFrames->data[X], "/")) != NULL, XLAL_EFUNC);
+    XLAL_CHECK( ( cfg->identifier = XLALCreateStringVector(
+      ParsedString->data[ParsedString->length-1], NULL)) != NULL, XLAL_EFUNC);
+    printf("Identifier is: %s\n", *cfg->identifier->data);
+    char buffer[100];
+    snprintf(buffer, 100, "%s%s%s%s", uvar->outDir, "/log_gating", *cfg->identifier->data, ".log");
+    XLAL_CHECK( ( cfg->fileNames = XLALCreateStringVector(buffer, NULL)) != NULL, XLAL_EFUNC);
+    cfg->logFileName = cfg->fileNames->data[0];
+    XLALDestroyStringVector(ParsedString);
+
+    // ----- determine time span of frame data from the stream ----------
+    // determine time spanned by the frames in this cache
+    LIGOTimeGPS frames_startGPS, frames_endGPS;
+    XLAL_CHECK ( XLALFrStreamSeekO ( stream, 0, SEEK_SET ) == 0, XLAL_EFUNC, "Failed to move to start of input frame-stream\n");
+    XLAL_CHECK ( XLALFrStreamTell ( &frames_startGPS, stream ) == XLAL_SUCCESS, XLAL_EFUNC );
+    XLAL_CHECK ( XLALFrStreamSeekO ( stream, 0, SEEK_END ) == 0, XLAL_EFUNC, "Failed to move to end of input frame-stream\n");
+    XLAL_CHECK ( XLALFrStreamTell ( &frames_endGPS, stream ) == XLAL_SUCCESS, XLAL_EFUNC );
+    REAL8 frames_start = XLALGPSGetREAL8 ( &frames_startGPS );
+    REAL8 frames_end   = XLALGPSGetREAL8 ( &frames_endGPS );
+    //    REAL8 frames_span = frames_end - frames_start;
+
+    // Check if given times are correct
+    XLAL_CHECK ( frames_start <= XLALGPSGetREAL8( &uvar->startTime ), XLAL_ETIME, "Frame start is after given time starts\n");
+    XLAL_CHECK ( frames_end >= XLALGPSGetREAL8( &uvar->startTime ) + uvar->duration, XLAL_ETIME, "Start + Duration exceeds frame end\n" );
+    /*
+     LIGOTimeGPS ts_startGPS = uvar->startTime;
+     REAL8 ts_duration = uvar->duration;
+     XLAL_CHECK ( (cfg->multiTimestamps->data[X] = XLALMakeTimestamps ( ts_startGPS, ts_duration, uvar->Tsft, uvar->SFToverlap ) ) != NULL, XLAL_EFUNC );
+     // in this case we can't allow timestamps extending beyond the end of the frame timeseries, so we drop the last timestamp if necessary
+     LIGOTimeGPSVector *timestampsX = cfg->multiTimestamps->data[X];
+     REAL8 tEnd;
+     while ( (tEnd = XLALGPSGetREAL8 ( &timestampsX->data[timestampsX->length-1] ) + timestampsX->deltaT) > frames_end ) {
+     timestampsX->length --;
+     }
+     */
+    const char *channel = uvar->inFrChannels->data[X];
+    size_t limit = 0; // unlimited read
+//    REAL8TimeSeries *ts;
+    //.... Use given time instead of frame time
+    XLAL_CHECK ( (cfg->inputTS = XLALFrStreamInputREAL8TimeSeries ( stream, channel, &uvar->startTime, (REAL8) uvar->duration, limit )) != NULL,
+                XLAL_EFUNC, "Frame reading failed for stream created for '%s': ts_start = {%d,%d}, duration=%.0f\n",
+                uvar->inFrames->data[X], uvar->startTime.gpsSeconds, uvar->startTime.gpsNanoSeconds, (REAL8) uvar->duration );
+
+    XLAL_CHECK ( XLALFrStreamClose ( stream ) == XLAL_SUCCESS, XLAL_EFUNC, "Stream closing failed for cache file '%s'\n", uvar->inFrames->data[X] );
+  } // for X < numDetectors
+#else
+  printf("NEED LIBLALFRAME TO FUNCTION. RECOMPILE");
+#endif
+
+  /* Calculate user-input-dependant variables */
+  uvar->taperLength = (UINT4) (uvar->padData / (cfg->inputTS->deltaT));
+
+  uvar->corruptLength = (UINT4) uvar->padData * 1.0 / (cfg->inputTS->deltaT);
+  return XLAL_SUCCESS;
+} /* XLALInitgateStrain() */
+
+/**
+ * Copied partly from MakeSFTs.c - https://lscsoft.docs.ligo.org/lalsuite/lalapps/_make_s_f_ts_8c_source.html
+ * Highpass a timeseries with a butterworth high pass
+ */
+int HighPass(ConfigVars_t *cfg, REAL8TimeSeries *Tseries, REAL8 frequency) {
+  if (frequency <= 0) {
+    return XLAL_SUCCESS;
+  }
+  PassBandParamStruc filterpar;
+  char tmpname[] = "Butterworth High Pass";
+
+  filterpar.name  = tmpname;
+  filterpar.nMax  = 8;
+  filterpar.f2    = frequency;
+  filterpar.a2    = 0.9;
+  filterpar.f1    = -1.0;
+  filterpar.a1    = -1.0;
+
+  XLAL_CHECK( ( XLALButterworthREAL8TimeSeries(Tseries, &filterpar)) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  #if TRACKMEMUSE
+  printf("Memory use after Highpass:\n"); printmemuse();
+  #endif
+  cfg = cfg;
+  return XLAL_SUCCESS;
+}
+
+/**
+ *  Taper strain at the start and the end
+ */
+int taperStrain(UserVariables_t *uvar, REAL8TimeSeries *Tseries)  {
+  UINT4 endIndex = Tseries->data->length;
+  for(UINT4 index = 0; index < uvar->taperLength; index++)  {
+    Tseries->data->data[index] *= ((REAL8) index) / uvar->taperLength;
+    Tseries->data->data[endIndex - index - 1] *= ((REAL8) index) / uvar->taperLength;
+  }
+  
+#if TRACKMEMUSE
+  printf("Memory use after taperStrain:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* taperStrain() */
+
+/**
+ * Zero-pad strain to a power-of-2 length. As of now, this transforms the multiTimeSeries into the cfg->strain (single) timeseries
+ * TODO: Think about using XLALResize (but this pads zeroes only to the start)
+
+ */
+int zeroPadStrain(ConfigVars_t *cfg, REAL8TimeSeries *inTseries, REAL8TimeSeries **strain)  {
+  REAL8TimeSeries *Tseries;
+  cfg->strainPaddedLength = nextPowerOf2(inTseries->data->length);
+  UINT4 padStart = cfg->strainPaddedLength / 2 - inTseries->data->length / 2;
+  UINT4 padEnd = padStart + inTseries->data->length;
+
+  //Changing the epoch here
+  LIGOTimeGPS XLAL_INIT_DECL(newTime);
+  newTime = *XLALGPSSetREAL8(&newTime, XLALGPSGetREAL8(&inTseries->epoch));
+
+  XLALGPSAdd(&newTime, ( (REAL8) padStart) * inTseries->deltaT * -1.0);
+  XLAL_CHECK ( (Tseries = XLALCreateREAL8TimeSeries(
+                                                    "Zero padded strain",
+                                                    &newTime,
+                                                    0,
+                                                    inTseries->deltaT,
+                                                    &lalStrainUnit,
+                                                    cfg->strainPaddedLength)) != NULL, XLAL_EFUNC);
+
+  /* Calloc has set the array to zero. Skip index 0 to pad start. Same for pad end to end of array.*/
+  /** Set to zero anyway, better to be safe than sorry.  **/
+  for(UINT4 index = 0; index < padStart; index++) {
+    Tseries->data->data[index] = 0;
+    Tseries->data->data[cfg->strainPaddedLength-1-index] = 0;
+  }
+  for(UINT4 index = padStart; index < padEnd ; index++){
+    Tseries->data->data[index] = inTseries->data->data[index-padStart];
+  }
+
+  *strain = Tseries;
+  cfg->padStart = padStart;
+  cfg->padEnd = padEnd;
+
+  XLALDestroyREAL8TimeSeries(inTseries);
+  
+#if TRACKMEMUSE
+  printf("Memory use after zeroPadStrain is:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* zeroPadStrain() */
+
+/**
+ * Estimating the PSD of the timeseries with Welchs Method
+ * See: https://lscsoft.docs.ligo.org/lalsuite/lal/group___time_freq_f_f_t__h.html
+ */
+int estimateWelchPSD(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *unpaddedTseries, REAL8TimeSeries *Tseries, REAL8FrequencySeries **psdFseries){
+  UINT4 halflength = (UINT4) (uvar->psdDuration / Tseries->deltaT / 2 + 1);
+  REAL8Window* hann;
+  REAL8FFTPlan* plan;
+  XLAL_CHECK( (hann = XLALCreateHannREAL8Window((UINT4) uvar->psdDuration / Tseries->deltaT )) != NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (plan = XLALCreateForwardREAL8FFTPlan((UINT4) uvar->psdDuration / Tseries->deltaT, 0)) != NULL, XLAL_ENOMEM);
+
+  REAL8FrequencySeries *psd;
+  XLAL_CHECK( (psd = XLALCreateREAL8FrequencySeries("WELCHPSD",
+                                                    &unpaddedTseries->epoch,
+                                                    0,
+                                                    0,
+                                                    &lalStrainUnit,
+                                                    halflength)) != NULL, XLAL_EFUNC);
+
+  /* For making the PSD, use the unpadded - corruptLength corrected - TimeSeries */
+  XLAL_CHECK( XLALREAL8AverageSpectrumMedian(psd, unpaddedTseries,
+                                            (UINT4) uvar->psdDuration / unpaddedTseries->deltaT,
+                                            (UINT4) uvar->psdStride / unpaddedTseries->deltaT,hann, plan) == XLAL_SUCCESS, XLAL_EFUNC);
+  /* Afterwards use the zero padded Timeseries (for interpolating length etc) */
+  XLALDestroyREAL8Window(hann);
+  XLALDestroyREAL8FFTPlan(plan);
+
+  /* Interpolate PSD */
+  REAL8Sequence *x_in, *y_in, *x_out, *y_out;
+  XLAL_CHECK( (x_in = XLALCreateREAL8Sequence(psd->data->length) ) != NULL, XLAL_ENOMEM);
+  /* Populate x_in-array with frequencies */
+  REAL8 xinf0 = psd->f0;
+  REAL8 xinDeltaF = psd->deltaF;
+  for(UINT4 index = 0; index < psd->data->length; index++)  {
+    x_in->data[index] = xinf0 + index * xinDeltaF;
+  }
+  /* y_in are the psd_values */
+  UINT4 new_length = (psd->data->length-1) * psd->deltaF * Tseries->data->length * Tseries->deltaT + 1;
+  y_in = psd->data;
+  XLAL_CHECK( (x_out = XLALCreateREAL8Sequence(new_length) ) != NULL, XLAL_ENOMEM);
+  /* Populate new x_array with new frequencies ...*/
+  REAL8 xoutf0 = psd->f0;
+  REAL8 xoutDeltaF = 1.0 / (Tseries->data->length * Tseries->deltaT);
+  //  printf("Xoutf0 %f and xoutDeltaF %f\n", xoutf0, xoutDeltaF);
+
+  for(UINT4 index = 0; index < new_length; index++)  {
+    x_out->data[index] = xoutf0 + index * xoutDeltaF;
+  }
+
+  XLAL_CHECK( (y_out = XLALCreateREAL8Sequence(new_length) ) != NULL, XLAL_ENOMEM);
+  /* Do Interpolation.*/
+  const gsl_interp_type* gsl_interp_p = gsl_interp_linear;
+  XLAL_CHECK( XLALREAL8Interpolation(x_in, y_in, x_out, y_out, psd->data->length , gsl_interp_p) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8Sequence(y_in);
+  XLALDestroyREAL8Sequence(x_in);
+  XLALDestroyREAL8Sequence(x_out);
+  psd->data = y_out;
+
+  /* New delta f is 0.5xSampleRate/(LengthOfStrain/2+1) */
+  psd->data->length = new_length;
+  psd->deltaF = xoutDeltaF;
+
+  /* Spectrum Invert Truncate to smear out the peaks */
+  REAL8FFTPlan* fwdplan;
+  REAL8FFTPlan* revplan;
+  XLAL_CHECK( (fwdplan = XLALCreateForwardREAL8FFTPlan((UINT4) cfg->strainPaddedLength, 0)) != NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (revplan = XLALCreateReverseREAL8FFTPlan((UINT4) cfg->strainPaddedLength, 0)) != NULL, XLAL_ENOMEM);
+
+  XLAL_CHECK( ( SpectrumInvertTruncate(psd, uvar->lowFreqCutoff,
+                                       (UINT4) cfg->strainPaddedLength,
+                                       (UINT4) uvar->psdDuration / Tseries->deltaT,
+                                       fwdplan,
+                                       revplan )) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Invert back again */
+  for(UINT4 index = 0; index < psd->data->length; index++) {
+    psd->data->data[index] = 1.0 / psd->data->data[index];
+  }
+  /* Low Frequency Cutoff */
+  UINT4 kmin = uvar->lowFreqCutoff / psd->deltaF;
+  for(UINT4 index = 0; index < kmin; index++) {
+    psd->data->data[index] = INFINITY;
+  }
+  /* High Frequency Cutoff */
+  if(XLALUserVarWasSet(&uvar->highFreqCutoff)) {
+    UINT4 kmax = uvar->highFreqCutoff / psd->deltaF;
+    for(UINT4 index = kmax; index < psd->data->length; index++) {
+      psd->data->data[index] = INFINITY;
+    }
+  }
+
+  XLALDestroyREAL8FFTPlan(fwdplan);
+  XLALDestroyREAL8FFTPlan(revplan);
+  *psdFseries = psd;
+
+#if TRACKMEMUSE
+  printf("Memory use after estimateWelchPSD:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+}/* estimateWelchPSD() */
+
+/**
+**
+**/
+int copyReferencePSDFromWelchsPSD(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8FrequencySeries **referencePSD ) {
+  REAL8 refEnd_freq = uvar->refFreqStart + uvar->refFreqBand;
+  UINT4 welchStart_index = (UINT4) ((uvar->refFreqStart - cfg->welchPSD->f0) / cfg->welchPSD->deltaF);
+  UINT4 welchEnd_index = (UINT4) ((refEnd_freq - cfg->welchPSD->f0) / cfg->welchPSD->deltaF);
+  UINT4 welchLength = welchEnd_index - welchStart_index;
+
+  //Chosen frequencies may not be actual sampling frequencies. Calculate correct frequencies.
+  uvar->refFreqStart = ((REAL8) welchStart_index) * cfg->welchPSD->deltaF + cfg->welchPSD->f0;
+  refEnd_freq = ((REAL8) welchEnd_index) * cfg->welchPSD->deltaF + cfg->welchPSD->f0;
+
+  REAL8 refDeltaF = 1.0 / (uvar->duration - 2 * uvar->padData); // Later used frequency sampling
+  UINT4 refLength = welchLength * cfg->welchPSD->deltaF / refDeltaF; // Length of refPSD with different sampling
+
+  REAL8FrequencySeries *refPSD = NULL;
+  XLAL_CHECK(( refPSD = XLALCreateREAL8FrequencySeries(
+                                 "Harmonic Mean PSD of whole obs run",
+                                 &cfg->strainPadded->epoch,
+                                 uvar->refFreqStart,
+                                 refDeltaF,
+                                 &lalDimensionlessUnit,
+                                 refLength            )) != NULL, XLAL_ENOMEM);
+  /* Interpolate PSD */
+  REAL8Sequence *x_in, *y_in, *x_out, *y_out;
+
+  /* Populate x_in-array with frequencies freq-start to freq-end*/
+  XLAL_CHECK( (x_in = XLALCreateREAL8Sequence(welchLength) ) != NULL, XLAL_ENOMEM);
+  for(UINT4 index = 0; index < welchLength; index++)  {
+    x_in->data[index] = uvar->refFreqStart + index * cfg->welchPSD->deltaF;
+  }
+
+  /* Populate y_in array with values for given frequencies */
+  XLAL_CHECK( (y_in = XLALCreateREAL8Sequence(welchLength) ) != NULL, XLAL_ENOMEM);
+  for(UINT4 index = 0; index < welchLength; index++)  {
+    y_in->data[index] = cfg->welchPSD->data->data[index + welchStart_index];
+  }
+
+  /* Populate x_out with new frequencies ...*/
+  XLAL_CHECK( (x_out = XLALCreateREAL8Sequence(refLength) ) != NULL, XLAL_ENOMEM);
+  for(UINT4 index = 0; index < refLength; index++)  {
+    x_out->data[index] = uvar->refFreqStart + index * refDeltaF;
+  }
+
+  y_out = refPSD->data;
+  /* Do Interpolation.*/
+  const gsl_interp_type* gsl_interp_p = gsl_interp_linear;
+  XLAL_CHECK( XLALREAL8Interpolation(x_in, y_in, x_out, y_out, welchLength , gsl_interp_p) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8Sequence(x_in);
+  XLALDestroyREAL8Sequence(y_in);
+  XLALDestroyREAL8Sequence(x_out);
+
+  *referencePSD = refPSD;
+
+  return XLAL_SUCCESS;
+} /* copyReferencePSDFromWelchsPSD() */
+
+/**
+ * Copied from, changed to a different norm: https://lscsoft.docs.ligo.org/lalsuite/lal/_average_spectrum_8c_source.html
+ */
+COMPLEX16FrequencySeries*
+WhitenCOMPLEX16FrequencySeries(UserVariables_t *uvar, REAL8 strainSampleRate, COMPLEX16FrequencySeries *fseries, const REAL8FrequencySeries *psd)
+{
+  COMPLEX16 *fdata = fseries->data->data;
+  REAL8 *pdata = psd->data->data;
+  double norm;
+  if(XLALUserVarWasSet ( &uvar->highFreqCutoff ))  {
+    norm = uvar->highFreqCutoff - uvar->lowFreqCutoff;
+  } else  {
+    norm = strainSampleRate/2 - uvar->lowFreqCutoff;
+  }
+  LALUnit unit; /* scratch space */
+  unsigned i; /* fseries index */
+  unsigned j; /* psd index */
+
+  if((psd->deltaF != fseries->deltaF) ||
+     (fseries->f0 < psd->f0)) {
+  /* resolution mismatch, or PSD does not span fseries at low end */
+    printf("psd->deltaF: %.16f vs fseries->deltaF: %.16f \n psd->f0: %.16f vs fseries->f0: %.16f \n",
+          psd->deltaF, fseries->deltaF, fseries->f0, psd->f0);
+    XLAL_ERROR_NULL(XLAL_EINVAL);
+  }
+  j = (fseries->f0 - psd->f0) / psd->deltaF;
+  if(j * psd->deltaF + psd->f0 != fseries->f0)
+  /* fseries does not start on an integer PSD sample */
+  XLAL_ERROR_NULL(XLAL_EINVAL);
+  if(j + fseries->data->length > psd->data->length)
+  /* PSD does not span fseries at high end */
+  XLAL_ERROR_NULL(XLAL_EINVAL);
+
+  for(i = 0; i < fseries->data->length; i++, j++)
+  {
+    if(pdata[j])
+    fdata[i] *= 1 / sqrt(norm * pdata[j]);
+    else
+    /* PSD has a 0 in it, treat as a zero in the filter */
+    fdata[i] = 0.0;
+  }
+
+  /* zero the DC and Nyquist components for safety */
+  if(fseries->data->length)
+  {
+    if(fseries->f0 == 0)
+    fdata[0] = 0.0;
+    fdata[fseries->data->length - 1] = 0.0;
+  }
+
+  /* update the units of fseries.  norm has units of Hz */
+  XLALUnitDivide(&unit, &psd->sampleUnits, &lalHertzUnit);
+  XLALUnitSqrt(&unit, &unit);
+  XLALUnitDivide(&fseries->sampleUnits, &fseries->sampleUnits, &unit);
+
+  return fseries;
+} /* WhitenComplex16FrequencySeries() */
+
+/**
+ * Strain --FFT--> Strain Tilde --Whitening--> Whitened Strain Tilde
+ */
+int fftAndWhitenStrain(UserVariables_t *uvar, REAL8TimeSeries *Tseries, COMPLEX16FrequencySeries **CFseries, REAL8FrequencySeries *psdFseries) {
+  XLAL_CHECK( ( (*CFseries) = XLALCreateCOMPLEX16FrequencySeries("StrainTilde",
+                              &Tseries->epoch, 0, (REAL8) 1.0 / (Tseries->data->length * Tseries->deltaT),
+                              &lalStrainUnit, (UINT4) (Tseries->data->length / 2 + 1)  ) ) != NULL, XLAL_ENOMEM);
+  REAL8FFTPlan* plan;
+  XLAL_CHECK( (plan = XLALCreateForwardREAL8FFTPlan(Tseries->data->length, 0)) != NULL, XLAL_ENOMEM);
+  XLAL_CHECK( XLALREAL8ForwardFFT((*CFseries)->data, Tseries->data, plan) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8FFTPlan(plan);
+
+  //Norm with 1/sample rate
+  for(UINT4 indexx = 0; indexx < (*CFseries)->data->length; indexx++) {
+    (*CFseries)->data->data[indexx] *= Tseries->deltaT;
+  }
+
+  //Whitening: XLAL Whitening function is using the wrong norm, take this whitening...
+  XLAL_CHECK( ((*CFseries) = WhitenCOMPLEX16FrequencySeries(uvar, 1.0 / Tseries->deltaT,
+    (*CFseries), psdFseries)) != NULL, XLAL_EFUNC);
+
+  XLALDestroyREAL8FrequencySeries(psdFseries);
+
+#if TRACKMEMUSE
+  printf("Memory use after fftAndWhiten is:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* fftAndWhitenStrain() */
+
+/**
+ * Inverse Fourier Transform and take the absolute: |Ifft(StrainTilde)|=Magnitude
+ */
+int ifft(REAL8TimeSeries **Tseries, COMPLEX16FrequencySeries *CFseries)  {
+  REAL8FFTPlan *plan;
+  XLAL_CHECK( (plan = XLALCreateReverseREAL8FFTPlan((*Tseries)->data->length, 0)) != NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (XLALREAL8FreqTimeFFT((*Tseries), CFseries, plan)) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8FFTPlan(plan);
+  XLALDestroyCOMPLEX16FrequencySeries(CFseries);
+
+#if TRACKMEMUSE
+  printf("Memory use after iffAndAbs is:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* ifft() */
+
+/**
+ * Given |IFFT(Whitened Strain Tilde)|, calculate the corresponding gate parameters
+ */
+int findGlitchesAndDuration(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *magnitude, REAL8TimeSeries *Tseries, GateParams_t *gtParams) {
+  printf("\n__Func: findGlitchesAndDuration: \n");
+
+  /* Prepare: Harmonic Mean and standard deviation of magnitude, then abs magnitude */
+  REAL8 mean = -1.1;
+  REAL8 std = -1.1;
+  REAL8 max = -1.1;
+  XLAL_CHECK( compMagnitudeStatistics(cfg, magnitude, &mean, &std, &max, 128) == XLAL_SUCCESS, XLAL_EFUNC);
+  for(UINT4 indexx = 0; indexx < magnitude->data->length; indexx++) {
+    magnitude->data->data[indexx] = fabs(magnitude->data->data[indexx]);
+  }
+  mean = 0;
+
+  /* Make a copy of the TimeSeries  */
+  REAL8TimeSeries *workingCopy = NULL;
+  SFTtype *sft = NULL;
+  REAL8FrequencySeries *sftPSD = NULL;
+
+  char description[10];
+  strcpy(description, "Reference");
+
+  /* Iterate until SFT ASD is deemed good enough */
+  REAL8 threshFactor = -1;
+  REAL8 secDead = -1;
+  REAL8 sftRatio = DBL_MAX;
+  for(UINT2 iteration = 0; iteration <= uvar->maxIterations; iteration++)  {
+    /* Destroy and make a new copy (Destroying NULL is allowed for [T/F]-Series') */
+    XLALDestroyREAL8TimeSeries(workingCopy);
+    /* Working copy: Remove zero padding but leave additional padding 2048s -> 1816s e.g.
+       Start after zeropad and add. padd, length is then duration - 2x add padd */
+    XLAL_CHECK( (workingCopy = XLALCutREAL8TimeSeries(Tseries,
+                            cfg->padStart + uvar->padData / Tseries->deltaT,
+                            uvar->duration / Tseries->deltaT - 2 * uvar->padData / Tseries->deltaT ) ) != NULL, XLAL_ENOMEM);
+    /* Set up gating constants for this iteration */
+    printf("    Iteration %d:\n", iteration);
+    cfg->threshHigh = uvar->upThreshold - uvar->iterReduceHighThresh * iteration;
+    threshFactor = uvar->sigmaFactor - uvar->iterReduceLowThreshFactor * iteration;
+    cfg->threshLow = mean + threshFactor * std;
+    secDead = uvar->secondsDeadTime + uvar->iterIncreaseDeadtime * iteration;
+    cfg->nDead = secDead / magnitude->deltaT;
+
+    /* Save Paramters to log */
+    printf("    New Parameters: High: %f Low: %f Dead: %f MaxMagnitude: %f\n", cfg->threshHigh, cfg->threshLow, secDead, max);
+    FILE *fp = fopen(cfg->logFileName, "a");
+    XLAL_CHECK( (fp = fopen(cfg->logFileName,"a")) != NULL, XLAL_EFUNC, "Could not open file %s", cfg->logFileName);
+    fprintf(fp, "\nIteration %d\nNew Parameters: HighThreshold: %f \nLowThreshold: %f \nSecondsDead: %f\n", iteration, cfg->threshHigh, cfg->threshLow, secDead);
+
+    if (cfg->threshHigh < cfg->threshLow) {
+      printf("Lower threshold is higher than higher threshold. Segment is not well behaving (and should not be used)? Setting lower threshold = high threshold!\n");
+      cfg->threshLow = cfg->threshHigh;
+    }
+    /* There are 4 cases:
+      1. - sftRatio is good:
+        a. - maximum is below highThreshold: Assume result is good, no/good gates are found. Stop iteration.
+        b. - maximum is above highThreshold: As above, but note that the maximum still exceeds the higher threshold. (If this is triggered often, the uvar->refPSDRatio may be too high.
+      2. - sftRatio is bad:
+        a. - maximum is below highThreshold: Omit iteration. Go into next iteration with lower threshold(s).
+        b. - maximum is above highThreshold: GetGlitches, gateData, calculate sftRatio.
+    */
+
+    if( sftRatio < uvar->refPSDRatio ) {
+      printf("Break at iteration %d: Maximum is %f and HighThreshold is %f while sftRatio@%f < %f\n", iteration, max, cfg->threshHigh, sftRatio, uvar->refPSDRatio);
+      if( max < cfg->threshHigh ) {
+        fprintf(fp, "Break at iteration %d: Maximum@%f is lower than HighThreshold@%f while sftRatio@%f < %f\n", iteration, max, cfg->threshHigh, sftRatio, uvar->refPSDRatio);
+      } else  {
+        fprintf(fp, "Break at iteration %d: Maximum@%f is HIGHER than HighThreshold@%f while sftRatio@%f < %f\n", iteration, max, cfg->threshHigh, sftRatio, uvar->refPSDRatio);
+      }
+      fclose(fp);
+      break;
+    } else {
+      if ( iteration == 0 || max > cfg->threshHigh) {
+        fprintf(fp, "Iteration %d: Maximum %f (HighThreshold %f) & sftRatio %f >= %f\n", iteration, max, cfg->threshHigh, (sftRatio == DBL_MAX) ? -0.0: sftRatio, uvar->refPSDRatio);
+        fclose(fp);
+        XLAL_CHECK( getGlitchDuration(cfg, magnitude, gtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+        REAL8 refStart_freq = cfg->referencePSD->f0;
+        REAL8 refEnd_freq = ((REAL8) cfg->referencePSD->data->length) * cfg->referencePSD->deltaF + cfg->referencePSD->f0;
+        XLAL_CHECK(( sftPSD = XLALCreateREAL8FrequencySeries("PSD of SFT", &workingCopy->epoch, refStart_freq,
+                          1.0 / (workingCopy->data->length * workingCopy->deltaT), &lalDimensionlessUnit, cfg->referencePSD->data->length )) != NULL, XLAL_ENOMEM);
+
+        XLAL_CHECK( gateData(uvar, workingCopy, gtParams) == XLAL_SUCCESS, XLAL_EFUNC);
+        XLAL_CHECK( callMakeSFT(uvar, cfg, refStart_freq, refEnd_freq - refStart_freq, workingCopy, &sft, 0, description, uvar->tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+        XLAL_CHECK( callComputePSD(refStart_freq, refEnd_freq - refStart_freq, 101, sft, &sftPSD) == XLAL_SUCCESS, XLAL_EFUNC);
+        XLALDestroyCOMPLEX8FrequencySeries(sft);
+
+        if (uvar->outputIntermediateSFT && iteration < 10)  {
+          SFTtype *intermediatesft = NULL;
+          REAL8FrequencySeries *intermediatesftPSD = NULL;
+          char descrIntermediate[100];
+          snprintf(descrIntermediate, sizeof descrIntermediate, "%s%d", "Iteration", iteration);
+
+          XLAL_CHECK(( intermediatesftPSD = XLALCreateREAL8FrequencySeries("PSD of intermediate SFT", &workingCopy->epoch, uvar->SFTFreqStart,
+                            1.0 / (workingCopy->data->length * workingCopy->deltaT), &lalDimensionlessUnit, uvar->SFTFreqBand * workingCopy->data->length * workingCopy->deltaT )) != NULL, XLAL_ENOMEM);
+
+          XLAL_CHECK( callMakeSFT(uvar, cfg, uvar->SFTFreqStart, uvar->SFTFreqBand, workingCopy, &intermediatesft, 1, descrIntermediate, uvar->tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+          XLAL_CHECK( callComputePSD(uvar->SFTFreqStart, uvar->SFTFreqBand, 0, intermediatesft, &intermediatesftPSD) == XLAL_SUCCESS, XLAL_EFUNC);
+
+          snprintf(descrIntermediate, sizeof descrIntermediate, "%s%s%s%d%s", uvar->outDir, "/C_Intermediate_SFT_PSD", *cfg->identifier->data, iteration, ".txt");
+          fp = fopen(descrIntermediate,"wb");
+          XLAL_CHECK( (fp = fopen(descrIntermediate,"wb")) != NULL, XLAL_EFUNC, "Could not open file %s", descrIntermediate);
+          XLALWriteREAL8FrequencySeries2fp(fp, intermediatesftPSD);
+          fclose(fp);
+          XLALDestroyREAL8FrequencySeries(intermediatesftPSD);
+        }
+        XLAL_CHECK( compareHMeanToThis(cfg, sftPSD, &sftRatio) == XLAL_SUCCESS, XLAL_EFUNC);
+        XLALDestroyREAL8FrequencySeries(sftPSD);
+      } else  {
+        printf("Omitting iteration %d: Maximum@%f is lower than HighThreshold@%f while sftRatio@%f is >= %f\n", iteration, max, cfg->threshHigh, sftRatio, uvar->refPSDRatio);
+        fprintf(fp, "Omitting iteration %d: Maximum@%f is lower than HighThreshold@%f while sftRatio@%f is >= %f\n", iteration, max, cfg->threshHigh, sftRatio, uvar->refPSDRatio);
+        fclose(fp);
+      }
+    }
+    char logsftRatio[100];
+    snprintf(logsftRatio, sizeof logsftRatio, "%s%s%s%s", uvar->outDir, "/sftRatio.txt", *cfg->identifier->data, ".txt");
+
+    XLAL_CHECK( (fp = fopen(logsftRatio,"a")) != NULL, XLAL_EFUNC, "Could not open file %s", logsftRatio);
+    fprintf(fp, "%1.16f\n", sftRatio);
+    fclose(fp);
+  }
+  //These functions free all memory associated with a LAL time series. It is safe to pass NULL to these functions.
+  XLALDestroyREAL8TimeSeries(workingCopy);
+  XLALDestroyREAL8TimeSeries( cfg->magnitude);
+  XLALDestroyREAL8FrequencySeries( cfg->referencePSD);
+//  XLALDestroyREAL8FrequencySeries(sftPSD);
+#if TRACKMEMUSE
+  printf("Memory use after findGlitchesAndDuration is:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* findGlitchesAndDuration() */
+
+/**
+ * Calculate harmonic mean of mean and harmonic mean of standard deviation over x segments of Timeseries
+ */
+int compMagnitudeStatistics(ConfigVars_t *cfg, REAL8TimeSeries *Tseries, REAL8 *mean, REAL8 *std, REAL8 *max, UINT2 segments)  {
+  *mean = 0.0;
+  *std = 0.0;
+  *max = -1.0;
+  REAL8 x;
+  // Check that (not-padded) timeseries is divideable by segments.
+  UINT4 TsLength = Tseries->data->length;
+  XLAL_CHECK( TsLength % segments == 0, XLAL_ESIZE );
+  UINT4 segLength = TsLength / segments;
+
+  REAL8Vector *means;
+  REAL8Vector *stds;
+  XLAL_CHECK( ( means = XLALCreateREAL8Vector(segments)) != NULL, XLAL_ENOMEM);
+  XLAL_CHECK( ( stds = XLALCreateREAL8Vector(segments)) != NULL, XLAL_ENOMEM);
+  //Calculate mean and std for each segment
+  for(UINT4 segIndex = 0; segIndex < segments; segIndex++)  {
+    means->data[segIndex] = 0;
+    stds->data[segIndex] = 0;
+    for(UINT4 i = 0; i < segLength; i++)  {
+      x = Tseries->data->data[segIndex * segLength + i];
+      means->data[segIndex] += x;
+      if(fabs(x) > *max)  { *max = fabs(x); }   //Adjust maximum if neccessary
+    }
+    means->data[segIndex] /= (REAL8) segLength;
+
+    for(UINT4 i = 0; i < segLength; i++)  {
+      x = Tseries->data->data[segIndex * segLength + i] - means->data[segIndex];
+      stds->data[segIndex] += x*x;
+    }
+    stds->data[segIndex] /= (REAL8) segLength;
+    stds->data[segIndex] = sqrt(stds->data[segIndex]);
+  }
+
+  //Calculate the harmonic mean of the mean and std
+  for(UINT4 segIndex = 0; segIndex < segments; segIndex++)  {
+    *mean += 1.0 / means->data[segIndex];
+    *std += 1.0 / stds->data[segIndex];
+  }
+  *mean = segments / *mean;
+  *std = segments / *std;
+
+  /* Log */
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(cfg->logFileName,"a")) != NULL, XLAL_EFUNC, "Could not open file %s", cfg->logFileName);
+  printf("__Mean: %.6f Std: %.6f Max: %.6f\n", *mean, *std, *max);
+  fprintf(fp, "Mean: %.6f Std: %.6f Max: %.6f\n", *mean, *std, *max);
+  fclose(fp);
+
+  XLALDestroyREAL8Vector(means);
+  XLALDestroyREAL8Vector(stds);
+
+  return XLAL_SUCCESS;
+} /* calculateHarmonicMeanOfMeanAndStd() */
+
+/**
+ * Load the harmonic mean PSD computed from multiple other time segments
+ */
+int loadHMeanPSD(UserVariables_t *uvar, ConfigVars_t *cfg)  {
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(uvar->PSDReferenceFile,"r")) != NULL, XLAL_EFUNC, "Could not open file %s", uvar->PSDReferenceFile);
+  //Get length of Reference, as well as start and end frequency
+  REAL8 throwaway, maxFrequency, minFrequency=0;
+  UINT4 PSDLength = 0;
+  while(EOF != fscanf(fp, "%lf %lf\n", &maxFrequency, &throwaway))  {
+    if(PSDLength==0)  {
+      minFrequency = maxFrequency;
+    }
+    PSDLength++;
+  }
+  XLAL_CHECK(( cfg->referencePSD = XLALCreateREAL8FrequencySeries(
+                                   "Harmonic Mean PSD of whole obs run",
+                                   &cfg->strainPadded->epoch,
+                                   minFrequency,
+                                   1.0 / (uvar->duration - 2 * uvar->padData),
+                                   &lalStrainUnit,
+                                   PSDLength
+            )) != NULL, XLAL_ENOMEM);
+  PSDLength=0;
+  rewind(fp); //Reset filepointer to start of file
+  while(EOF != fscanf(fp, "%lf %lf\n", &throwaway, &cfg->referencePSD->data->data[PSDLength++]))  {
+//Do not delete // printf("%lf\n", cfg->referencePSD->data->data[counter-1]);
+  }
+  fclose(fp);
+  return XLAL_SUCCESS;
+} /* loadHMeanPSD() */
+
+/**
+ * Load file with start and end of chosen gates
+ */
+int loadAndMergeAdditionalGatesFile(UserVariables_t *uvar, GateParams_t *gtParams)  {
+  printf("Found %d gates\n", gtParams->gateAmount);
+
+  GateParams_t XLAL_INIT_DECL(addGates);
+  addGates.gateAmount = 0;
+  XLAL_CHECK( (addGates.gateStart = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (addGates.gateEnd = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (addGates.gateDuration = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(uvar->additionalGateFile,"r")) != NULL, XLAL_EFUNC, "Could not open file %s", uvar->additionalGateFile);
+
+  REAL8 gtStart, gtEnd, gtPrevEnd = 0;
+  while(EOF != fscanf(fp, "%lf %lf\n", &gtStart, &gtEnd))  {
+    /* Gate end or start within this time */
+    if ( gtEnd > XLALGPSGetREAL8(&uvar->startTime) && gtStart < XLALGPSGetREAL8(&uvar->startTime) + uvar->duration )  {
+      XLAL_CHECK( gtEnd - gtStart >= 0.0 , XLAL_EINVAL, "Provided end before start, format for additional gates file is 'gateStart gateEnd', given: %lf %lf", gtStart, gtEnd );
+      XLAL_CHECK( TRUE || gtPrevEnd < gtStart, XLAL_EINVAL, "Last gates end ends after next gates start, they may not overlap and must be sorted in ascending order, given:\nX %lf\n%lf %lf", gtPrevEnd, gtStart, gtEnd);
+      gtPrevEnd = gtEnd;
+
+      XLAL_CHECK( (addGates.gateStart = XLALResizeREAL8Vector(addGates.gateStart, addGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      XLAL_CHECK( (addGates.gateEnd = XLALResizeREAL8Vector(addGates.gateEnd, addGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      XLAL_CHECK( (addGates.gateDuration = XLALResizeREAL8Vector(addGates.gateDuration, addGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      addGates.gateStart->data[addGates.gateAmount] = gtStart;
+      addGates.gateEnd->data[addGates.gateAmount] = gtEnd;
+      addGates.gateDuration->data[addGates.gateAmount] = gtEnd - gtStart;
+      addGates.gateAmount += 1;
+    }
+  }
+  printf("Additional %d gates\n", addGates.gateAmount);
+
+  fclose(fp);
+
+  /* Merge both lists, otherwise we may apply an unwanted double-taper */
+  /* There are no additional gates, nothing to do but return, gtParams still valid: */
+  if (addGates.gateAmount == 0) {
+    XLALDestroyREAL8Vector(addGates.gateStart);
+    XLALDestroyREAL8Vector(addGates.gateEnd);
+    XLALDestroyREAL8Vector(addGates.gateDuration);
+    return XLAL_SUCCESS;
+  } else if(gtParams->gateAmount == 0) {
+    //Gatestrain found no gates, just copy additional into gtParams
+    XLAL_CHECK( (gtParams->gateStart = XLALResizeREAL8Vector(gtParams->gateStart, addGates.gateAmount ) ) !=  NULL, XLAL_ENOMEM);
+    XLAL_CHECK( (gtParams->gateEnd = XLALResizeREAL8Vector(gtParams->gateEnd, addGates.gateAmount ) ) !=  NULL, XLAL_ENOMEM);
+    XLAL_CHECK( (gtParams->gateDuration = XLALResizeREAL8Vector(gtParams->gateDuration, addGates.gateAmount) ) !=  NULL, XLAL_ENOMEM);
+    memcpy(gtParams->gateStart->data, addGates.gateStart->data, sizeof(addGates.gateStart->data[0]) * addGates.gateAmount);
+    memcpy(gtParams->gateEnd->data, addGates.gateEnd->data, sizeof(addGates.gateEnd->data[0]) * addGates.gateAmount);
+    memcpy(gtParams->gateDuration->data, addGates.gateDuration->data, sizeof(addGates.gateDuration->data[0]) * addGates.gateAmount);
+    gtParams->gateAmount = addGates.gateAmount;
+    XLALDestroyREAL8Vector(addGates.gateStart);
+    XLALDestroyREAL8Vector(addGates.gateEnd);
+    XLALDestroyREAL8Vector(addGates.gateDuration);
+    return XLAL_SUCCESS;
+  } else  {
+    /* There are at least 1 gates in each */
+
+    /* Create boolean vector over time with 1/time-baseline spacing.
+     * Iterate over gates and set 1 everywhere a gate is.
+     * Afterwards iterate over vector and open gate everywhere 0->1 and close when 1->0
+     * Bonus? Taper overlap?
+     */
+    REAL8 tStart = XLALGPSGetREAL8(&uvar->startTime);
+    REAL8 tEnd = XLALGPSGetREAL8(&uvar->startTime) + uvar->duration;
+    REAL8 dt = 1.0 / uvar->Tsft;
+    UINT4 NSamples = (tEnd - tStart) / dt;
+    UINT4 NTaper = uvar->autogatingTaper / dt;
+    BOOLEAN * timeZeroedOut = XLALCalloc( NSamples, sizeof(BOOLEAN));
+
+    UINT4 NStart, NEnd;
+
+    for (UINT4 i = 0; i < addGates.gateAmount; i++)  {
+      //Get Start and End in units of samples
+      NStart = fmax(0,        floor(( addGates.gateStart->data[i] - tStart) / dt));
+      NEnd   = fmin(NSamples, ceil(( addGates.gateEnd->data[i] - tStart)/ dt));
+      for (UINT4 j = NStart; j < NEnd; j++) {
+        timeZeroedOut[j] = TRUE;
+      }
+    }
+    for (UINT4 i = 0; i < gtParams->gateAmount; i++)  {
+      //Get Start and End in units of samples
+      NStart = fmax(0,        floor(( gtParams->gateStart->data[i] - tStart) / dt));
+      NEnd   = fmin(NSamples, ceil(( gtParams->gateEnd->data[i] - tStart)/ dt));
+      for (UINT4 j = NStart; j < NEnd; j++) {
+        timeZeroedOut[j] = TRUE;
+      }
+    }
+
+    //Empty gtParams - set to zero is enough, gets resized next
+    gtParams->gateAmount = 0;
+    BOOLEAN previous = FALSE;
+    BOOLEAN next;
+    for (UINT4 j = 0; j < NSamples; j++) {
+      next = timeZeroedOut[j];
+      if (previous == next) {
+        //empty
+      } else if(previous == FALSE && next == TRUE)  {
+        //Open gate
+        XLAL_CHECK( (gtParams->gateStart = XLALResizeREAL8Vector(gtParams->gateStart, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+        XLAL_CHECK( (gtParams->gateEnd = XLALResizeREAL8Vector(gtParams->gateEnd, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+        XLAL_CHECK( (gtParams->gateDuration = XLALResizeREAL8Vector(gtParams->gateDuration, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+        gtParams->gateStart->data[gtParams->gateAmount] = j * dt + tStart;
+
+      } else if (previous == TRUE && next == FALSE) {
+        BOOLEAN breakflag = FALSE;
+        UINT4 i = j;                            //Save current index
+        for (UINT4 k = 0; k < NTaper; k++)  {   //Spool forward and see if there is a next-true value inside the taper distance
+          if(i+k+1 >= NSamples) {break;} //Don't exceed bounds
+          if (timeZeroedOut[i+k+1] == TRUE) {   //Check next value(s) for true within taper
+            j=i+k;                              //Advance j to 1 step before it's true again.
+            breakflag = TRUE;                   //Set breakflag, we don't want to close the gate
+          }
+        }
+        if (breakflag == FALSE) {
+          //Close gate
+          gtParams->gateEnd->data[gtParams->gateAmount] = j * dt + tStart;
+          gtParams->gateDuration->data[gtParams->gateAmount] = gtParams->gateEnd->data[gtParams->gateAmount] - gtParams->gateStart->data[gtParams->gateAmount];
+          gtParams->gateAmount+=1;
+        } else {
+          continue; //Continue, i.e. don't hit previous = next since next is FALSE now but we still have the gate open. Next j is true again.
+        }
+      }
+      previous = next;
+    }
+    //It may be that the last sample should be zeroed out, so we have to close the last gate manually.
+    if (previous == TRUE) {
+      gtParams->gateEnd->data[gtParams->gateAmount] = tEnd;
+      gtParams->gateDuration->data[gtParams->gateAmount] = gtParams->gateEnd->data[gtParams->gateAmount] - gtParams->gateStart->data[gtParams->gateAmount];
+      gtParams->gateAmount+=1;
+    }
+
+    XLALFree(timeZeroedOut);
+    XLALDestroyREAL8Vector(addGates.gateStart);
+    XLALDestroyREAL8Vector(addGates.gateEnd);
+    XLALDestroyREAL8Vector(addGates.gateDuration);
+    REAL8 totalDuration = 0;
+    for (UINT4 i = 0; i < gtParams->gateAmount; i++)  {
+      totalDuration += gtParams->gateDuration->data[i];
+    }
+    printf("Merged %d gates with total duration %.2f\n", gtParams->gateAmount, totalDuration);
+    return XLAL_SUCCESS;
+  }
+} /* loadAndMergeAdditionalGatesFile */
+
+/**
+ * Load file with start and end of chosen gates
+ */
+int gateWithExternalGatesFile(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *Tseries)  {
+  /* Reset gtParams */
+  GateParams_t XLAL_INIT_DECL(externalGates);
+  externalGates.gateAmount = 0;
+  XLALDestroyREAL8Vector(externalGates.gateStart);
+  XLALDestroyREAL8Vector(externalGates.gateEnd);
+  XLALDestroyREAL8Vector(externalGates.gateDuration);
+  XLAL_CHECK( (externalGates.gateStart = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (externalGates.gateEnd = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (externalGates.gateDuration = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(uvar->externalGateFile,"r")) != NULL, XLAL_EFUNC, "Could not open file %s", uvar->externalGateFile);
+
+  REAL8 gtStart, gtEnd;
+  while(EOF != fscanf(fp, "%lf %lf\n", &gtStart, &gtEnd))  {
+    /* Gate end or start within this time */
+    if ( gtEnd > XLALGPSGetREAL8(&uvar->startTime) && gtStart < XLALGPSGetREAL8(&uvar->startTime) + uvar->duration )  {
+      XLAL_CHECK( gtEnd - gtStart >= 0.0 , XLAL_EINVAL);
+
+      XLAL_CHECK( (externalGates.gateStart = XLALResizeREAL8Vector(externalGates.gateStart, externalGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      XLAL_CHECK( (externalGates.gateEnd = XLALResizeREAL8Vector(externalGates.gateEnd, externalGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      XLAL_CHECK( (externalGates.gateDuration = XLALResizeREAL8Vector(externalGates.gateDuration, externalGates.gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      externalGates.gateStart->data[externalGates.gateAmount] = gtStart;
+      externalGates.gateEnd->data[externalGates.gateAmount] = gtEnd;
+      externalGates.gateDuration->data[externalGates.gateAmount] = gtEnd - gtStart;
+      externalGates.gateAmount += 1;
+    }
+  }
+  fclose(fp);
+
+  REAL8TimeSeries *strainCopy = NULL;
+
+  //Make a copy of the input strain
+  XLAL_CHECK( ( strainCopy = XLALCutREAL8TimeSeries(Tseries, 0, uvar->duration / Tseries->deltaT )) != NULL, XLAL_ENOMEM);
+
+  /* Gate data */
+  XLAL_CHECK( gateData(uvar, strainCopy, &externalGates) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  if (uvar->outputHighpassedStrain)  {
+    char buffer[100];
+    snprintf(buffer, sizeof buffer, "%s%s%s%s", uvar->outDir, "/C_B4SecHighpassExternalStrain", *cfg->identifier->data, ".txt");
+    XLAL_CHECK( (fp = fopen(buffer,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", buffer);
+    XLALWriteREAL8TimeSeries2fp(fp, strainCopy);
+    fclose(fp);
+  }
+
+  /* Highpass again */
+  XLAL_CHECK(HighPass(cfg, strainCopy, uvar->Highpass) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  /* Remove Padding */
+  XLAL_CHECK( (strainCopy = XLALResizeREAL8TimeSeries(strainCopy,
+               uvar->padData / strainCopy->deltaT, (uvar->duration - 2*uvar->padData) / strainCopy->deltaT) ) != NULL, XLAL_ENOMEM);
+
+  SFTtype *sft = NULL;
+  char description[32];
+  snprintf(description, 32, "ExternalGateFile_%s", cfg->SFTTukeyWindowNaming);
+
+  /* Make the SFT */
+  XLAL_CHECK( callMakeSFT(uvar, cfg, uvar->SFTFreqStart, uvar->SFTFreqBand, strainCopy, &sft, 1, description, uvar->tukeyWindowRadius) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  XLALDestroyREAL8TimeSeries(strainCopy);
+  XLALDestroyCOMPLEX8FrequencySeries(sft);
+  XLALDestroyREAL8Vector(externalGates.gateStart);
+  XLALDestroyREAL8Vector(externalGates.gateEnd);
+  XLALDestroyREAL8Vector(externalGates.gateDuration);
+
+  return XLAL_SUCCESS;
+} /* gateWithExternalGatesFile() */
+
+
+/**
+ * Given a magnitude and thresholds, find values exceeding the high threshold and adjacent values
+ * exceeding the lower values to get a duration for a glitch.
+ * Gating constants are inside the ConfigVars_t *cfg variable
+ */
+int getGlitchDuration(ConfigVars_t *cfg, REAL8TimeSeries *magnitude, GateParams_t *gtParams) {
+  UINT4 leftCounter = 0;
+  UINT4 rightCounter = 0;
+  UINT4 curIndex = -1;
+  REAL8 timeStart = XLALGPSGetREAL8(&magnitude->epoch);
+
+  /* Reset gtParams */
+  gtParams->gateAmount = 0;
+  XLALDestroyREAL8Vector(gtParams->gateStart);
+  XLALDestroyREAL8Vector(gtParams->gateEnd);
+  XLALDestroyREAL8Vector(gtParams->gateDuration);
+  XLAL_CHECK( (gtParams->gateStart = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (gtParams->gateEnd = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (gtParams->gateDuration = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+
+  //Iterate from 'left' to 'right' through the magnitude
+  for(UINT4 gtIndex = 0; gtIndex < magnitude->data->length; gtIndex++)  {
+    if(magnitude->data->data[gtIndex] > cfg->threshHigh)  {
+      leftCounter=1;
+      rightCounter=1;
+      curIndex = gtIndex;
+      while(leftCounter < cfg->nDead) {
+        if(curIndex < leftCounter)  { //Same as curIndex - leftCounter < 0, but no unsigned error
+          break;
+        } else if(magnitude->data->data[curIndex - leftCounter] > cfg->threshLow) {
+          /* Going left, a value exceeding ThreshLow was detected. */
+          curIndex = curIndex - leftCounter;
+          leftCounter = 1;
+        } else {
+          /* If no value exceeding ThreshLow was detected, progress until leftCounter > nDead */
+          leftCounter++;
+        }
+      }
+      XLAL_CHECK( (gtParams->gateStart = XLALResizeREAL8Vector(gtParams->gateStart, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      gtParams->gateStart->data[gtParams->gateAmount] = timeStart + curIndex * magnitude->deltaT;
+      printf("    Gate Start (GPS Time): %f\n", gtParams->gateStart->data[gtParams->gateAmount]);
+
+      curIndex = gtIndex;
+      while(rightCounter < cfg->nDead)  {
+        if(curIndex + rightCounter >= magnitude->data->length)  {
+          break;
+        } else if(magnitude->data->data[curIndex + rightCounter] > cfg->threshLow)  {
+          curIndex = curIndex + rightCounter;
+          rightCounter = 1;
+        } else  {
+          rightCounter++;
+        }
+      }
+      XLAL_CHECK( (gtParams->gateEnd = XLALResizeREAL8Vector(gtParams->gateEnd, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      gtParams->gateEnd->data[gtParams->gateAmount] = timeStart + curIndex * magnitude->deltaT;
+      printf("    Gate End   (GPS Time): %f\n", gtParams->gateEnd->data[gtParams->gateAmount]);
+
+      XLAL_CHECK( (gtParams->gateDuration = XLALResizeREAL8Vector(gtParams->gateDuration, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+      gtParams->gateDuration->data[gtParams->gateAmount] = gtParams->gateEnd->data[gtParams->gateAmount] - gtParams->gateStart->data[gtParams->gateAmount];
+      printf("    Gate duration: %f seconds\n\n", (gtParams->gateDuration->data[gtParams->gateAmount]));
+
+      gtParams->gateAmount += 1;
+      gtIndex = curIndex;
+    }
+  }
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(cfg->logFileName,"a")) != NULL, XLAL_EFUNC, "Could not open file %s", cfg->logFileName);
+  fprintf(fp, "Gate(s) found:   %d\n", gtParams->gateAmount);
+  REAL8 gtDur=0;
+  for(UINT2 index = 0; index < gtParams->gateAmount; index++) {
+    fprintf(fp, "Start End Dur:   %.16f  %.16f  %.16f\n", gtParams->gateStart->data[index], gtParams->gateEnd->data[index], gtParams->gateDuration->data[index]);
+    gtDur+=gtParams->gateDuration->data[index];
+  }
+  fclose(fp);
+  printf("Gate(s) found with duration:   %d %.4fs\n", gtParams->gateAmount, gtDur);
+  return XLAL_SUCCESS;
+} /* getGlitchDuration() */
+
+/**
+ * Take a timeseries and gate with gateParams
+ */
+int gateData(UserVariables_t *uvar, REAL8TimeSeries *Tseries, GateParams_t *gtParams) {
+  REAL8Window *tukey;
+  REAL8 gateStartIndex = -1;
+  REAL8 gateDuration = 1;
+  REAL8 tukeyShapeParameter = -1;
+  UINT4 tseriesLength = Tseries->data->length;
+  /* The shape parameter e[0,1] sets what fraction of the window is spanned by the tapers.
+ β=0 yields the rectangle window, β=1 yields the Hann window.
+  We want padding only in taper, gate overall 0. If the tapered gate duration is t+d, the fraction which is
+  only taper is t/(t+d).For big d, the shape limits to 0, for small d the shape goes to 1.
+  */
+  for(UINT4 gtIndex = 0; gtIndex < gtParams->gateAmount; gtIndex++) {
+    tukey = NULL;
+    /* Duration of gate is initial duration + taper (in seconds) before and after  */
+    gateDuration = (2 * uvar->autogatingTaper + gtParams->gateDuration->data[gtIndex]) / Tseries->deltaT;
+    tukeyShapeParameter = (2 * uvar->autogatingTaper / Tseries->deltaT) / gateDuration;
+
+    XLAL_CHECK( (tukey = XLALCreateTukeyREAL8Window(gateDuration, tukeyShapeParameter)) != NULL, XLAL_ENOMEM);
+    gateStartIndex = (gtParams->gateStart->data[gtIndex] - XLALGPSGetREAL8(&Tseries->epoch) - uvar->autogatingTaper) / Tseries->deltaT;
+
+    XLAL_CHECK(gateStartIndex > 0 || gateStartIndex < Tseries->data->length, XLAL_ERANGE);
+    //Apply (inverted) tukey to Tseries
+    for(UINT4 tukIndex = 0; tukIndex < tukey->data->length; tukIndex++) {
+      //Tukey is gate duration long: Therefore step thru tukey window from start and apply. Catch out of bounds which may happen due to taper.
+      if( (UINT4) gateStartIndex + tukIndex > 0 && (UINT4) gateStartIndex + tukIndex < tseriesLength )  {
+        Tseries->data->data[(UINT4) gateStartIndex + tukIndex] *= (1.0 - tukey->data->data[tukIndex]);
+      }
+    }
+    XLALDestroyREAL8Window(tukey);
+  }
+  
+#if TRACKMEMUSE
+  printf("Memory use after gateData is:\n"); printmemuse();
+#endif
+  return XLAL_SUCCESS;
+} /* gateData() */
+
+/**
+ * Fields copied from MakeSFTs.c - https://lscsoft.docs.ligo.org/lalsuite/lalapps/_make_s_f_ts_8c_source.html
+ * Make SFT of the TimeSeries.
+ */
+int callMakeSFT(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8 freqStart, REAL8 freqBand, REAL8TimeSeries *Tseries, SFTtype **sft, BOOLEAN write2File, char* description, REAL8 tukeyWindowRadius) {
+  SFTConfigVarsTag SFTVars;
+
+  /* Initialize default values */
+  SFTVars.FrCacheFile=NULL;
+  SFTVars.makeGPSDirs=0;
+  SFTVars.sftVersion=2;
+  SFTVars.commentField=NULL;
+  SFTVars.htdata = 0;
+  SFTVars.makeTmpFile = 0;
+//  SFTVars.PSSCleaning = 0;
+//  SFTVars.PSSCleanHPf = 100.0;
+//  SFTVars.PSSCleanExt = 1;
+
+  /* Fill / Override with meaningful values */
+  SFTVars.HPf = uvar->Highpass;
+  SFTVars.T = (int) Tseries->data->length * Tseries->deltaT; //e.g. 1800
+  char stringT[12];
+  sprintf(stringT, "%d",SFTVars.T);
+  SFTVars.stringT = stringT;
+  SFTVars.GPSStart = XLALGPSGetREAL8(&(Tseries->epoch));
+  SFTVars.GPSEnd = XLALGPSGetREAL8(&(Tseries->epoch)) + Tseries->data->length * Tseries->deltaT;
+
+  SFTVars.ChannelName = uvar->inFrChannels->data[0];
+  char ifo[3];
+  strncpy(ifo, uvar->inFrChannels->data[0], 2);
+  ifo[2] = '\0';
+  SFTVars.IFO = ifo;
+  SFTVars.miscDesc = description;
+
+  //PSS Options....
+  SFTVars.windowOption = 1;
+  SFTVars.windowR = tukeyWindowRadius;
+  SFTVars.overlapFraction = 0.0;
+  SFTVars.useSingle = 0;
+  char frameStructType[] = "PROC_REAL8";
+  SFTVars.frameStructType = frameStructType;
+
+  /** Write SFT options */
+  SFTVars.SFTpath = uvar->outDir;
+  SFTVars.writeFile = write2File;
+
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(cfg->logFileName,"a")) != NULL, XLAL_EFUNC, "Could not open file %s", cfg->logFileName);
+  fprintf(fp, "\nRelevant makeSFT Parameters used: HPf %f - T %d - GPSStart %d - GPSEnd %d - sftVersion %d - ChannelName %s - miscDesc %s - IFO %s - freqStart %f - freqBand %f - windowR %f\n", SFTVars.HPf,   SFTVars.T,   SFTVars.GPSStart,   SFTVars.GPSEnd, SFTVars.sftVersion,   SFTVars.ChannelName, SFTVars.miscDesc, SFTVars.IFO, freqStart, freqBand, tukeyWindowRadius);
+  fclose(fp);
+
+  char commentField[4096];
+  snprintf(commentField, 4096, "\nRelevant makeSFT Parameters used: HPf %f - T %d - GPSStart %d - GPSEnd %d - sftVersion %d - ChannelName %s - miscDesc %s - IFO %s - freqStart %f - freqBand %f - windowR %f\n", SFTVars.HPf,   SFTVars.T,   SFTVars.GPSStart,   SFTVars.GPSEnd, SFTVars.sftVersion,   SFTVars.ChannelName, SFTVars.miscDesc, SFTVars.IFO, freqStart, freqBand, tukeyWindowRadius);
+  SFTVars.commentField = commentField;
+
+  XLAL_CHECK( makeSFT(SFTVars, Tseries, freqStart, freqBand, sft) == XLAL_SUCCESS, XLAL_EFUNC);
+  return XLAL_SUCCESS;
+} /* callMakeSFT() */
+
+/**
+  * Fields copied from ComputePSD.c - https://lscsoft.docs.ligo.org/lalsuite/lalapps/_compute_p_s_d_8c_source.html
+  * Compute PSD of the given SFT
+  */
+int callComputePSD(REAL8 freqStart, REAL8 freqBand, UINT2 blocksRngMed, SFTtype *sft, REAL8FrequencySeries **Fseries)  {
+  PSDUserVarsTag PSDVars;
+  /* default: read all SFT bins */
+  PSDVars.outputPSD = NULL;
+  PSDVars.outputNormSFT = FALSE;
+  PSDVars.outFreqBinEnd = FALSE;
+
+  PSDVars.dumpMultiPSDVector = FALSE;
+
+  PSDVars.binSizeHz = 0.0;
+  PSDVars.binSize   = 1;
+
+  PSDVars.binStep   = 0.0;
+  PSDVars.binStep   = 1;
+
+  PSDVars.blocksRngMed = blocksRngMed; //This does smoothing of PSD
+  /* Meaningful options: */
+  PSDVars.fStart = freqStart;
+  PSDVars.fBand = freqBand;
+
+  /* No output */
+  //char outputPSD[] = "./tempPSD.txt";
+  //PSDVars.outputPSD = outputPSD;
+
+  XLAL_CHECK( computePSD( PSDVars, sft, Fseries) == XLAL_SUCCESS, XLAL_EFUNC);
+
+  return XLAL_SUCCESS;
+} /* callComputePSD() */
+
+/**
+  * Compare this SFT PSD to the harmonic mean over multiple segments
+  */
+int compareHMeanToThis(ConfigVars_t *cfg, REAL8FrequencySeries *sftPSD, REAL8 *sftRatio)  {
+  REAL8 mean = 0;
+  UINT4 vecLength = sftPSD->data->length;
+  for(UINT4 index = 0; index < vecLength -1 ; index++) {
+    mean += sftPSD->data->data[index] / cfg->referencePSD->data->data[index] / vecLength;
+  }
+  printf("    Mean Ratio: %f\n", mean);
+  mean = sqrt(mean);
+  printf("    Sqrt Mean Ratio: %f\n", mean);
+  *sftRatio = mean;
+
+  return XLAL_SUCCESS;
+} /* compareHMeanToThis() */
+
+/**
+ * Copied from: https://lscsoft.docs.ligo.org/lalsuite/lalapps/makefakedata__v5_8c_source.html
+ * Output timeseries into a new *.gwf file
+ */
+int outputTimeSeriesToFile(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *strain){
+#ifdef HAVE_LIBLALFRAME
+  size_t len;
+  printf("Writing Timeseries to file\n");
+  if ( uvar->outDir != NULL)  {
+    XLAL_CHECK ( XLALCheckValidDescriptionField ( uvar->outLabel ) == XLAL_SUCCESS, XLAL_EFUNC );
+    len = strlen(uvar->outDir) + strlen(uvar->outLabel) + 100;
+    char *fname;
+
+    char *hist = XLALUserVarGetLog (UVAR_LOGFMT_CMDLINE);
+    /* Not used for single timeseries
+     if ( XLALUserVarWasSet ( &uvar->outFrChannels ) ) {
+     XLAL_CHECK ( uvar->outFrChannels->length == mTseries->length, XLAL_EINVAL, "--outFrChannels: number of channel names (%d) must agree with number of IFOs (%d)\n",
+     uvar->outFrChannels->length, mTseries->length );
+     }
+     */
+    for ( UINT4 X=0; X < 1 /*mTseries->length*/; X ++ ) {
+      //          REAL8TimeSeries *Tseries = mTseries->data[X];
+      REAL8TimeSeries *Tseries = strain;
+
+      /* use standard frame output filename format */
+      char IFO[2] = { Tseries->name[0], Tseries->name[1] };
+      LIGOTimeGPS startTimeGPS = Tseries->epoch;
+      REAL8 duration = Tseries->data->length * Tseries->deltaT;
+      XLAL_CHECK ( (fname = LALCalloc (1, len )) != NULL, XLAL_ENOMEM );
+      size_t written = snprintf ( fname, len, "%s/%c-%c%c_%s-%d-%d.gwf",
+                                 uvar->outDir, IFO[0], IFO[0], IFO[1], uvar->outLabel, startTimeGPS.gpsSeconds, (int)duration );
+      XLAL_CHECK ( written < len, XLAL_ESIZE, "Frame-filename exceeds expected maximal length (%zu): '%s'\n", len, fname );
+
+      /* define the output frame */
+      LALFrameH *outFrame;
+      XLAL_CHECK ( (outFrame = XLALFrameNew ( &startTimeGPS, duration, uvar->outLabel, 1, 0, 0 )) != NULL, XLAL_EFUNC );
+
+      /* add timeseries to the frame - make sure to change the timeseries name since this is used as the channel name */
+      char buffer[LALNameLength];
+      // if output frame channel names given, use those
+      if ( XLALUserVarWasSet ( &uvar->outFrChannels ) ) {
+        written = snprintf ( buffer, sizeof(buffer), "%s", uvar->outFrChannels->data[X] );
+        if ( buffer[2] == ':' ) { // check we got correct IFO association
+          XLAL_CHECK ( (buffer[0] == Tseries->name[0]) && (buffer[1] == Tseries->name[1]), XLAL_EINVAL,
+                      "Possible IFO mismatch: outFrChannel[%d] = '%s', IFO = '%c%c': be careful about --outFrChannel ordering\n", X, buffer, Tseries->name[0], Tseries->name[1] );
+        } // if buffer[2]==':'
+      } else if ( XLALUserVarWasSet ( &uvar->inFrChannels ) ) { // otherwise: if input frame channel names given, use them for output, append "-<outLabel>"
+        written = snprintf ( buffer, sizeof(buffer), "%s-%s", uvar->inFrChannels->data[X], uvar->outLabel );
+      } else { // otherwise: fall back to <IFO>:<outLabel> channel name
+        written = snprintf ( buffer, sizeof(buffer), "%c%c:%s", Tseries->name[0], Tseries->name[1], uvar->outLabel );
+      }
+      XLAL_CHECK ( written < LALNameLength, XLAL_ESIZE, "Output frame name exceeded max length (%d): '%s'\n", LALNameLength, buffer );
+      strcpy ( Tseries->name, buffer );
+
+      XLAL_CHECK ( (XLALFrameAddREAL8TimeSeriesProcData ( outFrame, Tseries ) == XLAL_SUCCESS ) , XLAL_EFUNC );
+
+      /* Here's where we add extra information into the frame - first we add the command line args used to generate it */
+      XLALFrameAddFrHistory ( outFrame, __FILE__, hist );
+
+      /* then we add the version string */
+      XLALFrameAddFrHistory ( outFrame, __FILE__, cfg->VCSInfoString );
+
+      /* output the frame to file - compression level 1 (higher values make no difference) */
+      XLAL_CHECK ( XLALFrameWrite ( outFrame, fname ) == XLAL_SUCCESS , XLAL_EFUNC );
+
+      /* free the frame, frame file name and history memory */
+      XLALFrameFree ( outFrame );
+      XLALFree ( fname );
+
+    } // for X < numDetectors
+    XLALFree ( hist );
+
+  }
+
+#if TRACKMEMUSE
+  printf("Memory use after outputTimeSeriesToFile is:\n"); printmemuse();
+#endif
+
+  return XLAL_SUCCESS;
+#else
+  printf("NEED LIBLALFRAME TO FUNCTION. RECOMPILE\n");
+  (void)(uvar);
+  (void)(cfg);
+  (void)(strain); /* suppress unused var warning/error */
+  return XLAL_SUCCESS;
+#endif
+
+} /* outputTimeSeriesToFile() */
+
+
+/**
+ * This routine frees up all the memory.
+ */
+int
+XLALFreeMem ( UserVariables_t *uvar, ConfigVars_t *cfg, GateParams_t *gtParams )
+{
+  XLAL_CHECK ( cfg != NULL, XLAL_EINVAL );
+  /* Free config-Variables and userInput stuff */
+  XLALFree(uvar->outLabel);
+  XLALDestroyUserVars();
+  XLALDestroyStringVector( cfg->identifier);
+  XLALDestroyStringVector( cfg->fileNames);
+  XLALFree ( cfg->VCSInfoString );
+  XLALDestroyREAL8TimeSeries( cfg->strainPadded);
+  XLALDestroyREAL8TimeSeries( cfg->originalStrain);
+  XLALDestroyREAL8Vector(gtParams->gateStart);
+  XLALDestroyREAL8Vector(gtParams->gateEnd);
+  XLALDestroyREAL8Vector(gtParams->gateDuration);
+
+  return XLAL_SUCCESS;
+} /* XLALFreeMem() */
+
+
+/**
+  * pyCBC gate data Method. Returns gate parameters which can be used in the gate data method. Writes a log file if gtAmount>0.
+  */
+int pycbcGateDataMethod(UserVariables_t *uvar, ConfigVars_t *cfg, REAL8TimeSeries *magnitude, GateParams_t *gtParams)  {
+  /* Reset gtParams */
+  gtParams->gateAmount = 0;
+  XLALDestroyREAL8Vector(gtParams->gateStart);
+  XLALDestroyREAL8Vector(gtParams->gateEnd);
+  XLALDestroyREAL8Vector(gtParams->gateDuration);
+  XLAL_CHECK( (gtParams->gateStart = XLALCreateREAL8Vector(0) ) !=  NULL, XLAL_ENOMEM);
+
+  REAL8 timeStart = XLALGPSGetREAL8(&magnitude->epoch);
+
+  UINT4 curr_index = 0;
+  REAL8 curr_val = 0;
+  REAL8 cluster_window = 0.5 / magnitude->deltaT;
+  for(UINT4 index = 0; index < magnitude->data->length; index++)  {
+    if( magnitude->data->data[index] > uvar->upThreshold)  {
+      if( (index - curr_index) > cluster_window || gtParams->gateAmount == 0)  {
+        XLAL_CHECK( (gtParams->gateStart = XLALResizeREAL8Vector(gtParams->gateStart, gtParams->gateAmount+1) ) !=  NULL, XLAL_ENOMEM);
+        gtParams->gateStart->data[gtParams->gateAmount] = timeStart + index * magnitude->deltaT;
+        printf("Gate Mid (GPS Time): %f\n", gtParams->gateStart->data[gtParams->gateAmount]);
+
+        gtParams->gateAmount += 1;
+
+        curr_index = index;
+        curr_val = magnitude->data->data[index];
+      } else if(magnitude->data->data[index] > curr_val) {
+        gtParams->gateStart->data[gtParams->gateAmount - 1] = timeStart + index * magnitude->deltaT;
+
+        curr_index = index;
+        curr_val = magnitude->data->data[index];
+      }
+    } //else do nothing
+  }
+  char fileName[100];
+  snprintf(fileName, 100, "%s%s%s%s", uvar->outDir, "/pyCBCGates", *cfg->identifier->data, ".txt");
+
+  FILE *fp = NULL;
+  XLAL_CHECK( (fp = fopen(fileName,"w")) != NULL, XLAL_EFUNC, "Could not open file %s", fileName);
+  XLAL_CHECK( (gtParams->gateEnd = XLALCreateREAL8Vector(gtParams->gateAmount) ) !=  NULL, XLAL_ENOMEM);
+  XLAL_CHECK( (gtParams->gateDuration = XLALCreateREAL8Vector(gtParams->gateAmount) ) !=  NULL, XLAL_ENOMEM);
+  for(UINT2 index = 0; index < gtParams->gateAmount; index++) {
+    fprintf(fp, "%.16f\n", gtParams->gateStart->data[index]);
+    gtParams->gateDuration->data[index] = uvar->pyCBCFixedDurationGate;
+    gtParams->gateStart->data[index] = gtParams->gateStart->data[index] - uvar->pyCBCFixedDurationGate / 2.0;
+    gtParams->gateEnd->data[index] = gtParams->gateStart->data[index] + uvar->pyCBCFixedDurationGate;
+  }
+  fclose(fp);
+
+  return XLAL_SUCCESS;
+}
+
+
+/**
+  * Return the smallest integer power of 2 larger than the argument
+  */
+UINT4 nextPowerOf2(UINT4 x) {
+  return (UINT4) pow ( 2, ceil ( log2 ( x ) ) );
+ }
+
+/**
+ * Copied from: https://lscsoft.docs.ligo.org/lalsuite/lalapps/makefakedata__v5_8c_source.html
+ * determine if the given filepath is an existing directory or not
+ */
+BOOLEAN
+is_directory ( const CHAR *fname )
+{
+  struct stat stat_buf;
+  if ( stat (fname, &stat_buf) )
+    return 0;
+  if ( ! S_ISDIR (stat_buf.st_mode) )
+    return 0;
+  else
+    return 1;
+} /* is_directory() */
+
+/**
+ * Copied and converted to REAL8 from: https://lscsoft.docs.ligo.org/lalsuite/lalapps/makefakedata__v5_8c_source.html
+ * Write a REAL8TimeSeries in a 2-column ASCII format (lines of "GPS_i  data_i")
+ * into an open file 'fp'
+ */
+int
+XLALWriteREAL8TimeSeries2fp ( FILE *fp, const REAL8TimeSeries *TS )
+{
+  printf("Writing TimeSeries to file... \nSTART");
+  XLAL_CHECK ( fp != NULL, XLAL_EINVAL );
+  XLAL_CHECK ( TS != NULL, XLAL_EINVAL );
+  XLAL_CHECK ( (TS->data != NULL) && (TS->data->length >0) && (TS->data->data != NULL), XLAL_EINVAL );
+  REAL8 t0 = XLALGPSGetREAL8( &(TS->epoch) );
+  XLAL_CHECK ( xlalErrno == 0, XLAL_EFAULT, "XLALGPSGetREAL8(%d,%d) failed\n", TS->epoch.gpsSeconds, TS->epoch.gpsNanoSeconds );
+  for( UINT4 i = 0; i < TS->data->length; i++)
+  {
+    REAL8 ti = t0 + i * TS->deltaT;
+    XLAL_CHECK ( fprintf( fp, "%16.9f %1.16e\n", ti, TS->data->data[i] ) > 0, XLAL_EIO );
+  }
+  printf(" ... END\n");
+  return XLAL_SUCCESS;
+} /* XLALWriteREAL8TimeSeries2fp() */
+
+/**
+ * Copied and converted to REAL8 from: https://lscsoft.docs.ligo.org/lalsuite/lalapps/makefakedata__v5_8c_source.html
+ * Write a REAL8FrequencySeries in a 2-column ASCII format (lines of "freq_i  data_i")
+ * into an open file 'fp'
+ */
+int
+XLALWriteREAL8FrequencySeries2fp ( FILE* fp, const REAL8FrequencySeries *FS )
+{
+  printf("Writing REAL8FrequencySeries to file... \nSTART");
+  XLAL_CHECK ( fp != NULL, XLAL_EINVAL );
+  XLAL_CHECK ( FS != NULL, XLAL_EINVAL );
+  XLAL_CHECK ( (FS->data != NULL) && (FS->data->length >0) && (FS->data->data != NULL), XLAL_EINVAL );
+  REAL8 f0 = FS->f0;
+  for( UINT4 i = 0; i < FS->data->length; i++)
+  {
+    REAL8 fi = f0 + i * FS->deltaF;
+    XLAL_CHECK ( fprintf( fp, "%16.9f %1.16e\n", fi, FS->data->data[i] ) > 0, XLAL_EIO );
+  }
+  printf(" ... END\n");
+  return XLAL_SUCCESS;
+} /* XLALWriteREAL8TimeSeries2fp() */
+
+/**
+ * Copied and changed to other norm from: https://lscsoft.docs.ligo.org/lalsuite/lal/_average_spectrum_8c_source.html
+ * This version norms by dividing thruough the length of the (padded) timeseries (in seconds) and applying a hann window
+*/
+int SpectrumInvertTruncate(
+    REAL8FrequencySeries        *spectrum,
+    REAL8                        lowfreq,
+    UINT4                        seglen,
+    UINT4                        trunclen,
+    REAL8FFTPlan                *fwdplan,
+    REAL8FFTPlan                *revplan
+    )
+{
+  UINT4 cut;
+  UINT4 k;
+
+  if ( ! spectrum )
+    XLAL_ERROR( XLAL_EFAULT );
+  if ( ! spectrum->data )
+    XLAL_ERROR( XLAL_EINVAL );
+  if ( spectrum->deltaF <= 0.0 )
+    XLAL_ERROR( XLAL_EINVAL );
+  if ( lowfreq < 0 )
+    XLAL_ERROR( XLAL_EINVAL );
+  if ( ! seglen || spectrum->data->length != seglen/2 + 1 )
+    XLAL_ERROR( XLAL_EBADLEN );
+  if ( trunclen && ! revplan )
+    XLAL_ERROR( XLAL_EFAULT );
+
+  cut = lowfreq / spectrum->deltaF;
+  if ( cut < 1 ) /* need to get rid of DC at least */
+    cut = 1;
+
+  if ( trunclen ) /* truncate while inverting */
+  {
+    COMPLEX16Vector *vtilde; /* frequency-domain vector workspace */
+    REAL8Vector    *vector; /* time-domain vector workspace */
+    REAL8           normfac;
+
+    vtilde = XLALCreateCOMPLEX16Vector( seglen / 2 + 1 );
+    vector = XLALCreateREAL8Vector( seglen );
+
+    /* clear the low frequency components */
+    memset( vtilde->data, 0, cut * sizeof( *vtilde->data ) );
+
+    /* stick the root-inv-spectrum into the complex frequency-domain vector */
+    for ( k = cut; k < vtilde->length - 1; ++k )
+    {
+      if ( spectrum->data->data[k] )
+        vtilde->data[k] = 1.0 / sqrt( spectrum->data->data[k] ); /* purely real */
+      else
+        vtilde->data[k] = 0.0;
+    }
+    /* no Nyquist */
+    vtilde->data[vtilde->length - 1] = 0.0;
+
+    /* construct time-domain version of root-inv-spectrum */
+    XLALREAL8ReverseFFT( vector, vtilde, revplan );
+
+    /* now truncate it: zero time from trunclen/2 to length - trunclen/2 */
+    memset( vector->data + trunclen/2, 0,
+        (vector->length - trunclen) * sizeof( *vector->data ) );
+
+    /* Start changes from lalsuite function */
+    /* Norm by the length of the TimeSeries in seconds */
+    REAL8Window* hann;
+    XLAL_CHECK( (hann = XLALCreateHannREAL8Window((UINT4) trunclen) ) != NULL, XLAL_ENOMEM);
+
+    for( UINT4 i = 0; i < (UINT4) trunclen/2; i++) {
+      vector->data[i] *= hann->data->data[(UINT4) trunclen/2 + i];
+      vector->data[vector->length - i - 1] *= hann->data->data[(UINT4) trunclen/2 + i];
+    }
+    XLALDestroyREAL8Window(hann);
+    /* End changes from lalsuite function */
+
+    /* reconstruct spectrum */
+    XLAL_CHECK(XLALREAL8PowerSpectrum(spectrum->data, vector, fwdplan) == XLAL_SUCCESS, XLAL_EFUNC);
+
+    memset( spectrum->data->data, 0, cut * sizeof( *spectrum->data->data ) );
+    spectrum->data->data[spectrum->data->length - 1] = 0.0;
+
+    /* rescale spectrum: 0.5 to undo factor of two from REAL8PowerSpectrum */
+    /* seglen^2 for the reverse fft (squared because power spectrum) */
+    /* Note: cast seglen to real so that seglen*seglen is a real rather */
+    /* than a four-byte integer which might overflow... */
+    normfac = 0.5 / ( ((REAL8)seglen) * ((REAL8)seglen) );
+    for ( k = cut; k < spectrum->data->length - 1; ++k )
+      spectrum->data->data[k] *= normfac;
+
+    /* clear the low frequency components... again, and Nyquist too */
+    /* cleanup workspace */
+    XLALDestroyCOMPLEX16Vector( vtilde );
+    XLALDestroyREAL8Vector( vector );
+  }
+  else /* otherwise just invert the spectrum */
+  {
+    /* clear the low frequency components */
+    memset( spectrum->data->data, 0, cut * sizeof( *spectrum->data->data ) );
+
+    /* invert the high frequency (non-Nyquist) components */
+    for ( k = cut; k < spectrum->data->length - 1; ++k )
+    {
+      if ( spectrum->data->data[k] )
+        spectrum->data->data[k] = 1.0 / spectrum->data->data[k];
+      else
+        spectrum->data->data[k] = 0.0;
+    }
+
+    /* zero Nyquist */
+    spectrum->data->data[spectrum->data->length - 1] = 0.0;
+  }
+
+  /* now correct the units */
+  XLALUnitRaiseINT2( &spectrum->sampleUnits, &spectrum->sampleUnits, -1 );
+
+  return 0;
+}
diff --git a/lalapps/src/pulsar/MakeData/testMakeSFTs.sh b/lalapps/src/pulsar/MakeData/testMakeSFTs.sh
index 516039c38bea33d15b3183cb8d0ab22cfcdc3c2f..b5a4fda1d4220417139852f49c81bc5bfa1dcf91 100644
--- a/lalapps/src/pulsar/MakeData/testMakeSFTs.sh
+++ b/lalapps/src/pulsar/MakeData/testMakeSFTs.sh
@@ -39,10 +39,122 @@ for file in $MSFTsft; do
 done
 
 ## compare SFTs produced by MFDv5 and MakeSFTs, should be very nearly identical
-tol=1e-10
+tol=1.5e-10
 cmdline="lalapps_compareSFTs -V -e $tol -1 $MFDv5sft -2 $MSFTsft"
 echo "Comparing SFTs produced by MFDv5 and MakeSFTs, allowed tolerance=$tol:"
 if ! eval "$cmdline"; then
     echo "ERROR: something failed when running '$cmdline'"
     exit 1
 fi
+
+#Make SFT analogue to gatestrain
+Band3=200
+highpass=0
+echo "Make SFT analogue to gatestrain"
+# high-pass-freq (-f) sft-duration (-t) sft-write-path (-p) frame-cache (-C) gps-start-time (-s) gps-end-time (-e) channel-name (-N)
+# window-type (-w) window-radius (-r) overlap-fraction (-P) frame-struct-type (-u) start-freq (-F) band (-B)
+cmdline="lalapps_MakeSFTs -f ${highpass} -t ${Tsft} -p . -C $framecache -s ${tstart} -e ${tend} -N H1:mfdv5 -v 2 -i H1 -u PROC_REAL8 -w 1 -r 0.001 -F ${highpass} -B ${Band3} -D 4 -X MSFTGate"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+MSFTsft="./H-1_H1_${Tsft}SFT_MSFTGate-1257/H-1_H1_${Tsft}SFT_MSFTGate-${tstart}-${Tsft}.sft"
+
+../../../frametools/lalapps_frread H-H1_mfdv5-1257741529-1800.gwf H1:mfdv5
+mv H1:mfdv5-1257741529.dat Mfd.gwf.dat
+
+## run gatestrain
+echo "Run gateStrain_v1"
+cmdline="lalapps_gateStrain_v1 --startTime ${tstart} --duration ${Tsft} --SFTFreqStart ${highpass} --SFTFreqBand ${Band3} --outDir . --outputGWF 1 --inFrames $framecache --inFrChannel H1:mfdv5 --outFrChannels H1:mfdv5 --padData 0.0 --Highpass ${highpass}"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+GSFTsft="H-1_H1_1800SFT_GATED_WIN001-1257741529-1800.sft"
+
+../../../frametools/lalapps_frread H-H1_gating-1257741529-1800.gwf H1:mfdv5
+mv H1:mfdv5-1257741529.dat Gate.gwf.dat
+
+#Compare gwf:
+echo "Compare gwf produced by MFD and gatestrain"
+cmdline="diff -q Mfd.gwf.dat Gate.gwf.dat"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+
+cmdline="lalapps_compareSFTs -V -e $tol -1 $MSFTsft -2 $GSFTsft"
+echo "Comparing SFTs produced by MFDv5 and gateStrain_v1, allowed tolerance=$tol:"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+
+rm ${GSFTsft}
+
+## run gatestrain in a few different configurations
+gateStart=`echo "${tstart} + ${Tsft} / 3" | bc`
+gateEnd=`echo "${gateStart} + 3" | bc`
+gateFile=gateFile.txt
+echo "${gateStart} ${gateEnd}" > ${gateFile}
+
+echo "Run gateStrain_v1"
+cmdline="lalapps_gateStrain_v1 --startTime ${tstart} --duration ${Tsft} --SFTFreqStart ${highpass} --SFTFreqBand ${Band3} --outDir . --outputGWF 0 --outputUngatedSFT=1 --outputpyCBCSFT=1 --inFrames $framecache --inFrChannel H1:mfdv5 --outFrChannels H1:mfdv5 --padData 0.0 --Highpass ${highpass} --externalGateFile ${gateFile} --additionalGateFile ${gateFile}"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+#Different gatestrain output formats
+GSFTGatsft="H-1_H1_1800SFT_GATED_WIN001-1257741529-1800.sft"
+GSFTUngsft="H-1_H1_1800SFT_UNGATED_WIN001-1257741529-1800.sft"
+GSFTCBCsft="H-1_H1_1800SFT_pyCBCGATED_WIN001-1257741529-1800.sft"
+GSFTExtsft="H-1_H1_1800SFT_ExternalGateFile_WIN001-1257741529-1800.sft"
+
+cmdline="lalapps_compareSFTs -V -e $tol -1 ${GSFTGatsft} -2 ${GSFTExtsft}"
+echo "Comparing gated SFTs produced by additional gates and external gates (same file), allowed tolerance=$tol:"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+
+cmdline="lalapps_compareSFTs -V -e $tol -1 ${GSFTUngsft} -2 ${GSFTCBCsft}"
+echo "Comparing ungated SFT to pyCBC gated SFT (with no gate found), allowed tolerance=$tol:"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+
+#exit 1
+
+#Test with and without padding
+## run gatestrain
+echo "Run gateStrain_v1 with and without padding"
+pad=8
+padStart=`echo "${tstart} + 8" | bc`
+padDur=`echo "${Tsft} - 16" | bc`
+
+cmdline="lalapps_gateStrain_v1 --startTime ${padStart} --duration ${padDur} --SFTFreqStart ${highpass} --SFTFreqBand ${Band3} --outDir . --outputGWF 1 --inFrames $framecache --inFrChannel H1:mfdv5 --outFrChannels H1:mfdv5 --padData 0.0 --Highpass ${highpass}"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+GSFTsft="H-1_H1_1784SFT_GATED_WIN001-1257741537-1784.sft"
+mv ${GSFTsft} ${GSFTsft}_NoPad
+
+## run gatestrain
+echo "Run gateStrain_v1"
+cmdline="lalapps_gateStrain_v1 --startTime ${tstart} --duration ${Tsft} --SFTFreqStart ${highpass} --SFTFreqBand ${Band3} --outDir . --outputGWF 1 --inFrames $framecache --inFrChannel H1:mfdv5 --outFrChannels H1:mfdv5 --padData ${pad} --Highpass ${highpass}"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi
+GSFTsft="H-1_H1_1784SFT_GATED_WIN001-1257741537-1784.sft"
+mv ${GSFTsft} ${GSFTsft}_WithPad
+
+#Compare SFT with and without padding
+cmdline="lalapps_compareSFTs -V -e $tol -1 ${GSFTsft}_NoPad -2 ${GSFTsft}_WithPad"
+echo "Comparing ungated SFT to pyCBC gated SFT (with no gate found), allowed tolerance=$tol:"
+if ! eval "$cmdline"; then
+    echo "ERROR: something failed when running '$cmdline'"
+    exit 1
+fi