REAL8 calculate_ligo_snr_from_strain(  REAL4TimeVectorSeries *strain,
                                       SimInspiralTable      *thisInj,
                                       const CHAR            ifo[3])
{

  REAL8 ret = -1, snrSq, freq, psdValue;
  REAL8 sampleRate = 4096, deltaF;
  REAL4TimeSeries *chan = NULL;
  REAL4FFTPlan *pfwd;
  COMPLEX8FrequencySeries *fftData;
  UINT4 k;

  /* create the time series */
  chan    = XLALCalculateNRStrain( strain, thisInj, ifo, sampleRate );
  deltaF  = chan->deltaT * strain->data->vectorLength;
  fftData = XLALCreateCOMPLEX8FrequencySeries( chan->name,  &(chan->epoch),
                                               0, deltaF, &lalDimensionlessUnit,
                                               chan->data->length/2 + 1 );

  /* perform the fft */
  pfwd = XLALCreateForwardREAL4FFTPlan( chan->data->length, 0 );
  XLALREAL4TimeFreqFFT( fftData, chan, pfwd );

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

      if ( ifo[0] == 'V' )
        {
          if (freq < 35)
            continue;

          LALVIRGOPsd( NULL, &psdValue, freq );
          psdValue /= 9e-46;
        }
      else
        {
          if (freq < 40)
            continue;

          LALLIGOIPsd( NULL, &psdValue, freq );
        }

      fftData->data->data[k] /= 3e-23;
      snrSq += crealf(fftData->data->data[k]) * crealf(fftData->data->data[k]) / psdValue;
      snrSq += cimagf(fftData->data->data[k]) * cimagf(fftData->data->data[k]) / psdValue;
    }

  snrSq *= 4*fftData->deltaF;

  XLALDestroyREAL4FFTPlan( pfwd );
  XLALDestroyCOMPLEX8FrequencySeries( fftData );

  XLALDestroyREAL4Vector ( chan->data);
  LALFree(chan);

  ret = sqrt(snrSq);
  return ret;
}
int
test_XLALSincInterpolateSFT ( void )
{
  REAL8 f0 = 0;		// heterodyning frequency
  REAL8 sigmaN = 0.001;
  REAL8 dt = 0.1;	// sampling frequency = 10Hz
  LIGOTimeGPS epoch = { 100, 0 };
  REAL8 tStart = XLALGPSGetREAL8 ( &epoch );
  UINT4 numSamples = 1000;
  REAL8 Tspan = numSamples * dt;
  REAL8 df = 1.0 / Tspan;

  UINT4 numSamples0padded = 3 * numSamples;
  REAL8 Tspan0padded = numSamples0padded * dt;
  REAL8 df0padded = 1.0 / Tspan0padded;

  UINT4 numBins = NhalfPosDC ( numSamples );
  UINT4 numBins0padded = NhalfPosDC ( numSamples0padded );
  // original timeseries
  REAL4TimeSeries* ts;
  XLAL_CHECK ( (ts = XLALCreateREAL4TimeSeries ( "test TS_in", &epoch, f0, dt, &emptyLALUnit, numSamples )) != NULL, XLAL_EFUNC );
  for ( UINT4 j = 0; j < numSamples; j ++ ) {
    ts->data->data[j] = crealf ( testSignal ( tStart + j * dt, sigmaN ) );
  } // for j < numSamples

  // zero-padded to double length
  REAL4TimeSeries* ts0padded;
  XLAL_CHECK ( (ts0padded = XLALCreateREAL4TimeSeries ( "test TS_padded", &epoch, f0, dt, &emptyLALUnit, numSamples0padded )) != NULL, XLAL_EFUNC );
  memcpy ( ts0padded->data->data, ts->data->data, numSamples * sizeof(ts0padded->data->data[0]) );
  memset ( ts0padded->data->data + numSamples, 0, (numSamples0padded - numSamples) * sizeof(ts0padded->data->data[0]) );

  // compute FFT on ts and ts0padded
  REAL4FFTPlan *plan, *plan0padded;
  XLAL_CHECK ( (plan        = XLALCreateForwardREAL4FFTPlan ( numSamples, 0 )) != NULL, XLAL_EFUNC );
  XLAL_CHECK ( (plan0padded = XLALCreateForwardREAL4FFTPlan ( numSamples0padded, 0 )) != NULL, XLAL_EFUNC );
  COMPLEX8Vector *fft, *fft0padded;
  XLAL_CHECK ( (fft        = XLALCreateCOMPLEX8Vector ( numBins )) != NULL, XLAL_ENOMEM );
  XLAL_CHECK ( (fft0padded = XLALCreateCOMPLEX8Vector ( numBins0padded )) != NULL, XLAL_ENOMEM );

  XLAL_CHECK ( XLALREAL4ForwardFFT ( fft, ts->data, plan ) == XLAL_SUCCESS, XLAL_EFUNC );
  XLAL_CHECK ( XLALREAL4ForwardFFT ( fft0padded, ts0padded->data, plan0padded ) == XLAL_SUCCESS, XLAL_EFUNC );
  XLALDestroyREAL4TimeSeries ( ts );
  XLALDestroyREAL4TimeSeries ( ts0padded );
  XLALDestroyREAL4FFTPlan( plan );
  XLALDestroyREAL4FFTPlan( plan0padded );

  SFTtype XLAL_INIT_DECL(tmp);
  tmp.f0 = f0;
  tmp.deltaF = df;
  tmp.data = fft;

  REAL8 Band = 0.5/dt - f0;
  SFTtype *sft = NULL;
  XLAL_CHECK ( XLALExtractBandFromSFT ( &sft, &tmp, f0, Band ) == XLAL_SUCCESS, XLAL_EFUNC );
  XLALDestroyCOMPLEX8Vector ( fft );


  tmp.f0 = f0;
  tmp.deltaF = df0padded;
  tmp.data = fft0padded;
  SFTtype *sft0padded = NULL;
  XLAL_CHECK ( XLALExtractBandFromSFT ( &sft0padded, &tmp, f0, Band ) == XLAL_SUCCESS, XLAL_EFUNC );
  XLALDestroyCOMPLEX8Vector ( fft0padded );

  // ---------- interpolate input SFT onto frequency bins of padded-ts FFT for comparison
  UINT4 Dterms = 16;
  REAL8 safetyBins = (Dterms + 1.0);	// avoid truncated interpolation to minimize errors, set to 0 for seeing boundary-effects [they're not so bad...]

  REAL8 fMin = f0 + safetyBins * df;
  fMin = round(fMin / df0padded) * df0padded;
  UINT4 numBinsOut = numBins0padded - 3 * safetyBins;
  REAL8 BandOut = (numBinsOut-1) * df0padded;

  SFTtype *sftUpsampled = NULL;
  XLAL_CHECK ( XLALExtractBandFromSFT ( &sftUpsampled, sft0padded, fMin + 0.5*df0padded, BandOut - df0padded ) == XLAL_SUCCESS, XLAL_EFUNC );

  SFTtype *sftInterpolated;
  XLAL_CHECK ( (sftInterpolated = XLALSincInterpolateSFT ( sft, fMin, df0padded, numBinsOut, Dterms )) != NULL, XLAL_EFUNC );

  // ----- out debug info
  if ( lalDebugLevel & LALINFO )
    {
      XLAL_CHECK ( write_SFTdata ( "SFT_in.dat", sft ) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK ( write_SFTdata ( "SFT_in0padded.dat", sft0padded ) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK ( write_SFTdata ( "SFT_upsampled.dat", sftUpsampled ) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK ( write_SFTdata ( "SFT_interpolated.dat", sftInterpolated ) == XLAL_SUCCESS, XLAL_EFUNC );
    } // if LALINFO

  // ---------- check accuracy of interpolation
  VectorComparison XLAL_INIT_DECL(tol);
  tol.relErr_L1 	= 8e-2;
  tol.relErr_L2		= 8e-2;
  tol.angleV		= 8e-2;
  tol.relErr_atMaxAbsx	= 4e-3;
  tol.relErr_atMaxAbsy	= 4e-3;

  XLALPrintInfo ("Comparing Dirichlet SFT interpolation with upsampled SFT:\n");
  XLAL_CHECK ( XLALCompareSFTs ( sftUpsampled, sftInterpolated, &tol ) == XLAL_SUCCESS, XLAL_EFUNC );

  // ---------- free memory
  XLALDestroySFT ( sft );
  XLALDestroySFT ( sft0padded );
  XLALDestroySFT ( sftUpsampled );
  XLALDestroySFT ( sftInterpolated );

  return XLAL_SUCCESS;

} // test_XLALSincInterpolateSFT()
/**
 * Unit-Test for function XLALSFTVectorToLFT().
 * Generates random data (timeseries + corresponding SFTs),
 * then feeds the SFTs into XLALSFTVectorToLFT()
 * and checks correctness of output Fourier transform by
 * comparing to FT of original real-valued timeseries.
 *
 * \note This indirectly also checks XLALSFTVectorToCOMPLEX8TimeSeries()
 * which is used by XLALSFTVectorToLFT().
 *
 * returns XLAL_SUCCESS on success, XLAL-error otherwise
 */
int
test_XLALSFTVectorToLFT ( void )
{
  // ----- generate real-valued random timeseries and corresponding SFTs
  REAL4TimeSeries *tsR4 = NULL;
  SFTVector *sfts0 = NULL;
  XLAL_CHECK ( XLALgenerateRandomData ( &tsR4, &sfts0 ) == XLAL_SUCCESS, XLAL_EFUNC );
  UINT4 numSamplesR4 = tsR4->data->length;
  REAL8 dt_R4 = tsR4->deltaT;
  REAL8 TspanR4 = numSamplesR4 * dt_R4;
  // ----- consider only the frequency band [3Hz, 4Hz]
  REAL8 out_fMin = 3;
  REAL8 out_Band = 1;
  SFTVector *sftsBand;
  XLAL_CHECK ( (sftsBand = XLALExtractBandFromSFTVector ( sfts0, out_fMin, out_Band )) != NULL, XLAL_EFUNC );
  XLALDestroySFTVector ( sfts0 );

  // ----- 1) compute FFT on original REAL4 timeseries -----
  REAL4FFTPlan *planR4;
  XLAL_CHECK ( (planR4 = XLALCreateForwardREAL4FFTPlan ( numSamplesR4, 0 )) != NULL, XLAL_EFUNC );

  SFTtype *lft0;
  XLAL_CHECK ( (lft0 = XLALCreateSFT ( numSamplesR4/2+1 )) != NULL, XLAL_EFUNC );
  XLAL_CHECK ( XLALREAL4ForwardFFT ( lft0->data, tsR4->data, planR4 ) == XLAL_SUCCESS, XLAL_EFUNC );

  strcpy ( lft0->name, tsR4->name );
  lft0->f0 = 0;
  lft0->epoch = tsR4->epoch;
  REAL8 dfLFT = 1.0 / TspanR4;
  lft0->deltaF = dfLFT;

  // ----- extract frequency band of interest
  SFTtype *lftR4 = NULL;
  XLAL_CHECK ( XLALExtractBandFromSFT ( &lftR4, lft0, out_fMin, out_Band ) == XLAL_SUCCESS, XLAL_EFUNC );
  for ( UINT4 k=0; k < lftR4->data->length; k ++ ) {
    lftR4->data->data[k] *= dt_R4;
  }

  // ----- 2) compute LFT directly from SFTs ----------
  SFTtype *lftSFTs0;
  XLAL_CHECK ( (lftSFTs0 = XLALSFTVectorToLFT ( sftsBand, 1 )) != NULL, XLAL_EFUNC );
  XLALDestroySFTVector ( sftsBand );

  // ----- re-extract frequency band of interest
  SFTtype *lftSFTs = NULL;
  XLAL_CHECK ( XLALExtractBandFromSFT ( &lftSFTs, lftSFTs0, out_fMin, out_Band ) == XLAL_SUCCESS, XLAL_EFUNC );

  if ( lalDebugLevel & LALINFO )
  {   // ----- write debug output
    XLAL_CHECK ( XLALdumpREAL4TimeSeries ( "TS_R4.dat", tsR4 ) == XLAL_SUCCESS, XLAL_EFUNC );

    XLAL_CHECK ( write_SFTdata ("LFT_R4T.dat", lftR4 ) == XLAL_SUCCESS, XLAL_EFUNC );
    XLAL_CHECK ( write_SFTdata ("LFT_SFTs.dat", lftSFTs ) == XLAL_SUCCESS, XLAL_EFUNC );

  } // end: debug output

  // ========== compare resulting LFTs ==========
  VectorComparison XLAL_INIT_DECL(tol0);
  XLALPrintInfo ("Comparing LFT with itself: should give 0 for all measures\n");
  XLAL_CHECK ( XLALCompareSFTs ( lftR4, lftR4, &tol0 ) == XLAL_SUCCESS, XLAL_EFUNC );
  XLAL_CHECK ( XLALCompareSFTs ( lftSFTs, lftSFTs, &tol0 ) == XLAL_SUCCESS, XLAL_EFUNC );

  VectorComparison XLAL_INIT_DECL(tol);
  tol.relErr_L1 	= 4e-2;
  tol.relErr_L2		= 5e-2;
  tol.angleV 		= 5e-2;	// rad
  tol.relErr_atMaxAbsx 	= 1.2e-2;
  tol.relErr_atMaxAbsy  = 1.2e-2;

  XLALPrintInfo ("Comparing LFT from REAL4-timeseries, to LFT from heterodyned COMPLEX8-timeseries:\n");
  XLAL_CHECK ( XLALCompareSFTs ( lftR4, lftSFTs, &tol ) == XLAL_SUCCESS, XLAL_EFUNC );

  // ---------- free memory ----------
  XLALDestroyREAL4TimeSeries ( tsR4 );
  XLALDestroyREAL4FFTPlan ( planR4 );

  XLALDestroySFT ( lft0 );
  XLALDestroySFT ( lftR4 );
  XLALDestroySFT ( lftSFTs );
  XLALDestroySFT ( lftSFTs0 );

  return XLAL_SUCCESS;

} // test_XLALSFTVectorToLFT()
REAL4 XLALCandleDistanceTD(
    Approximant approximant,
    REAL4 candleM1,
    REAL4 candleM2,
    REAL4 candlesnr,
    REAL8 chanDeltaT,
    INT4 nPoints,
    REAL8FrequencySeries *spec,
    UINT4 cut)
{

  LALStatus      status   = blank_status;

  InspiralTemplate  tmplt;
  REAL4Vector    *waveform = NULL;
  COMPLEX8Vector *waveFFT  = NULL;
  REAL4FFTPlan   *fwdPlan  = NULL;

  REAL8          sigmaSq;
  REAL8          distance;
  UINT4          i;

  memset( &tmplt, 0, sizeof(tmplt) );

  /* Create storage for TD and FD template */
  waveform = XLALCreateREAL4Vector( nPoints );
  waveFFT  = XLALCreateCOMPLEX8Vector( spec->data->length );
  fwdPlan  = XLALCreateForwardREAL4FFTPlan( nPoints, 0 );

  /* Populate the template parameters */
  tmplt.mass1 = candleM1;
  tmplt.mass2 = candleM2;
  tmplt.ieta  = 1;
  tmplt.approximant = approximant;
  tmplt.tSampling   = 1.0/chanDeltaT;
  tmplt.order       = LAL_PNORDER_PSEUDO_FOUR; /* Hardcode for EOBNR for now */
  tmplt.fLower      = spec->deltaF *cut;
  tmplt.distance    = 1.0e6 * LAL_PC_SI; /* Mpc */
  tmplt.massChoice  = m1Andm2;
  tmplt.fCutoff     = tmplt.tSampling / 2.0 - spec->deltaF;

  /* From this, calculate the other parameters */
  LAL_CALL( LALInspiralParameterCalc( &status, &tmplt ), &status );

  /* Generate the waveform */
  LAL_CALL( LALInspiralWave( &status, waveform, &tmplt ), &status );

  XLALREAL4ForwardFFT( waveFFT, waveform, fwdPlan );

  sigmaSq = 0.0;
  for ( i = cut; i < waveFFT->length; i++ )
  {
    sigmaSq += ( crealf(waveFFT->data[i]) * crealf(waveFFT->data[i])
            + cimagf(waveFFT->data[i]) * cimagf(waveFFT->data[i]) )/ spec->data->data[i];
  }

  sigmaSq *= 4.0 * chanDeltaT / (REAL8)nPoints;

  /* Now calculate the distance */
  distance = sqrt( sigmaSq ) / (REAL8)candlesnr;

  /* Clean up! */
  XLALDestroyREAL4Vector( waveform );
  XLALDestroyCOMPLEX8Vector( waveFFT );
  XLALDestroyREAL4FFTPlan( fwdPlan );

  return (REAL4)distance;
}
Beispiel #5
0
/* Main Program */
INT4 main ( INT4 argc, CHAR *argv[] ) {

  static LALStatus status;
  INT4 c;
  UINT4 i;
  REAL8 dt, totTime;
  REAL8 sampleRate = -1;
  REAL8 totalMass = -1, massRatio = -1;
  REAL8 lowFreq = -1, df, fLow;
  CHAR  *outFile = NULL, *outFileLong = NULL, tail[50];
  size_t optarg_len;
  REAL8 eta;
  REAL8 newtonianChirpTime, PN1ChirpTime, mergTime;
  UINT4 numPts;
  LIGOTimeGPS epoch;
  REAL8 offset;

  PhenomCoeffs coeffs;
  PhenomParams params;

  REAL4FrequencySeries     *Aeff   = NULL, *Phieff  = NULL;
  COMPLEX8Vector           *uFPlus = NULL, *uFCross = NULL;

  COMPLEX8 num;

  REAL4Vector      *hPlus = NULL, *hCross = NULL;
  REAL4TimeSeries  *hP = NULL, *hC = NULL;
  /*  REAL4TimeSeries  *hP = NULL, *hC = NULL;*/
  REAL4FFTPlan     *prevPlus = NULL, *prevCross = NULL;

  /*REAL4Vector      *Freq = NULL;*/

  UINT4 windowLength;
  INT4 hPLength;
  REAL8 linearWindow;

  /* getopt arguments */
  struct option long_options[] =
  {
    {"mass-ratio",              required_argument, 0,                'q'},
    {"low-freq (Hz)",           required_argument, 0,                'f'},
    {"total-mass (M_sun)",      required_argument, 0,                'm'},
    {"sample-rate",             required_argument, 0,                's'},
    {"output-file",             required_argument, 0,                'o'},
    {"help",                    no_argument,       0,                'h'},
    {"version",                 no_argument,       0,                'V'},
    {0, 0, 0, 0}
  };

  /* parse the arguments */
  while ( 1 )
  {
    /* getopt_long stores long option here */
    int option_index = 0;

    /* parse command line arguments */
    c = getopt_long_only( argc, argv, "q:t:d:hV",
        long_options, &option_index );

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

    switch ( c )
    {
      case 0:
        fprintf( stderr, "Error parsing option '%s' with argument '%s'\n",
            long_options[option_index].name, optarg );
        exit( 1 );
        break;

      case 'h':
        /* help message */
        print_usage( argv[0] );
        exit( 0 );
        break;

      case 'V':
        /* print version information and exit */
        fprintf( stdout, "%s - Compute Ajith's Phenomenological Waveforms " \
		 "(arXiv:0710.2335) and output them to a plain text file\n" \
            "CVS Version: %s\nCVS Tag: %s\n", PROGRAM_NAME, CVS_ID_STRING, \
            CVS_NAME_STRING );
        exit( 0 );
        break;

      case 'q':
        /* set mass ratio */
        massRatio = atof( optarg );
        break;

      case 'f':
        /* set low freq */
        lowFreq = atof( optarg );
        break;

      case 'm':
        /* set total mass */
        totalMass = atof( optarg );
        break;

      case 's':
        /* set sample rate */
        sampleRate = atof( optarg );
        break;

      case 'o':
	/* set name of output file */
        optarg_len = strlen(optarg) + 1;
        outFile = (CHAR *)calloc(optarg_len, sizeof(CHAR));
        memcpy(outFile, optarg, optarg_len);
	break;

      case '?':
        print_usage( argv[0] );
        exit( 1 );
        break;

      default:
        fprintf( stderr, "ERROR: Unknown error while parsing options\n" );
        print_usage( argv[0] );
        exit( 1 );
    }
  }

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


  /* * * * * * * * */
  /* Main Program  */
  /* * * * * * * * */

  eta = massRatio / pow(1. + massRatio, 2.);

  /* This freq low is the one used for the FFT */
  /* fLow = 2.E-3/(totalMass*LAL_MTSUN_SI); */
  fLow = lowFreq;       /* Changed by Ajith. 5 May 2008 */

  /* Phenomenological coefficients as in Ajith et. al */
  GetPhenomCoeffsLongJena( &coeffs );

  /* Compute phenomenologial parameters */
  ComputeParamsFromCoeffs( &params, &coeffs, eta, totalMass );


  /* Check validity of arguments */

  /* check we have freqs */
  if ( totalMass < 0 )
    {
      fprintf( stderr, "ERROR: --total-mass must be specified\n" );
      exit( 1 );
    }

  /* check we have mass ratio and delta t*/
  if ( massRatio < 0 )
    {
      fprintf( stderr, "ERROR: --mass-ratio must be specified\n" );
      exit( 1 );
    }
  if ( lowFreq < 0 )
    {
      fprintf( stderr, "ERROR: --low-freq must be specified\n" );
      exit( 1 );
    }
  if ( sampleRate < 0 )
    {
      fprintf( stderr, "ERROR: --sample-rate must be specified\n" );
      exit( 1 );
    }
  if ( lowFreq > params.fCut )
    {
      fprintf( stderr, "\nERROR in --low-freq\n"\
	       "The value chosen for the low frequency is larger "\
	       "than the frequency at the merger.\n"
	       "Frequency at the merger: %4.2f Hz\nPick either a lower value"\
	       " for --low-freq or a lower total mass\n\n", params.fCut);
      exit(1);
    }
  if ( lowFreq < fLow )
    {
      fprintf( stderr, "\nERROR in --low-freq\n"\
	       "The value chosen for the low frequency is lower "\
	       "than the lowest frequency computed\nby the implemented FFT.\n"
	       "Lowest frequency allowed: %4.2f Hz\nPick either a higher value"\
	       " for --low-freq or a higher total mass\n\n", fLow);
      exit(1);
    }
  if ( outFile == NULL )
    {
      fprintf( stderr, "ERROR: --output-file must be specified\n" );
      exit( 1 );
    }

  /* Complete file name with details of the input variables */
  sprintf(tail, "%s-Phenom_M%3.1f_R%2.1f.dat", outFile, totalMass, massRatio);
  optarg_len = strlen(tail) + strlen(outFile) + 1;
  outFileLong = (CHAR *)calloc(optarg_len, sizeof(CHAR));
  strcpy(outFileLong, tail);

  /* check sample rate is enough */
  if (sampleRate > 4.*params.fCut)   /* Changed by Ajith. 5 May 2008 */
    {
      dt = 1./sampleRate;
    }
  else
    {
      sampleRate = 4.*params.fCut;
      dt = 1./sampleRate;
    }

  /* Estimation of the time duration of the binary           */
  /* See Sathya (1994) for the Newtonian and PN1 chirp times */
  /* The merger time is overestimated                        */
  newtonianChirpTime =
    (5./(256.*eta))*pow(totalMass*LAL_MTSUN_SI,-5./3.)*pow(LAL_PI*fLow,-8./3.);
  PN1ChirpTime =
    5.*(743.+924.*eta)/(64512.*eta*totalMass*LAL_MTSUN_SI*pow(LAL_PI*fLow,2.));
  mergTime = 2000.*totalMass*LAL_MTSUN_SI;
  totTime = 1.2 * (newtonianChirpTime + PN1ChirpTime + mergTime);

  numPts = (UINT4) ceil(totTime/dt);
  df = 1/(numPts * dt);

  /* Compute Amplitude and Phase from the paper (Eq. 4.19) */
  Aeff = XLALHybridP1Amplitude(&params, fLow, df, eta, totalMass, numPts/2+1);
  Phieff = XLALHybridP1Phase(&params, fLow, df, eta, totalMass, numPts/2 +1);

  /* Construct u(f) = Aeff*e^(i*Phieff) */
  XLALComputeComplexVector(&uFPlus, &uFCross, Aeff, Phieff);

  /* Scale this to units of M */
  for (i = 0; i < numPts/2 + 1; i++) {
    num = uFPlus->data[i];
    num.re *= 1./(dt*totalMass*LAL_MTSUN_SI);
    num.im *= 1./(dt*totalMass*LAL_MTSUN_SI);
    uFPlus->data[i] = num;
    num = uFCross->data[i];
    num.re *= 1./(dt*totalMass*LAL_MTSUN_SI);
    num.im *= 1./(dt*totalMass*LAL_MTSUN_SI);
    uFCross->data[i] = num;
  }

  /* Inverse Fourier transform */
  LALCreateReverseREAL4FFTPlan( &status, &prevPlus, numPts, 0 );
  LALCreateReverseREAL4FFTPlan( &status, &prevCross, numPts, 0 );
  hPlus = XLALCreateREAL4Vector(numPts);
  hCross = XLALCreateREAL4Vector(numPts);

  LALReverseREAL4FFT( &status, hPlus, uFPlus, prevPlus );
  LALReverseREAL4FFT( &status, hCross, uFCross, prevCross );

  /* The LAL implementation of the FFT omits the factor 1/n */
  for (i = 0; i < numPts; i++) {
    hPlus->data[i] /= numPts;
    hCross->data[i] /= numPts;
  }

  /* Create TimeSeries to store more info about the waveforms */
  /* Note: it could be done easier using LALFreqTimeFFT instead of ReverseFFT */
  epoch.gpsSeconds = 0;
  epoch.gpsNanoSeconds = 0;

  hP =
    XLALCreateREAL4TimeSeries("", &epoch, 0, dt, &lalDimensionlessUnit, numPts);
  hP->data = hPlus;
  hC =
    XLALCreateREAL4TimeSeries("", &epoch, 0, dt, &lalDimensionlessUnit, numPts);
  hC->data = hCross;

  /* Cutting off the part of the waveform with f < fLow */
  /*  Freq = XLALComputeFreq( hP, hC);
      hP = XLALCutAtFreq( hP, Freq, lowFreq);
      hC = XLALCutAtFreq( hC, Freq, lowFreq); */

  /* multiply the last few samples of the time-series by a linearly
   * dropping window function in order to avid edges in the data
   * Added by Ajith 6 May 2008 */

  hPLength = hP->data->length;
  windowLength = (UINT4) (20.*totalMass * LAL_MTSUN_SI/dt);
  for (i=1; i<= windowLength; i++){
    linearWindow =  (i-1.)/windowLength;
    hP->data->data[hPLength-i] *= linearWindow;
    hC->data->data[hPLength-i] *= linearWindow;
  }

  /* Convert t column to units of (1/M) */
  /*  offset *= (1./(totalMass * LAL_MTSUN_SI));
      hP->deltaT *= (1./(totalMass * LAL_MTSUN_SI)); */

  /* Set t = 0 at the merger (defined as the max of the NR wave) */
  XLALFindNRCoalescenceTimeFromhoft( &offset, hP);
  XLALGPSAdd( &(hP->epoch), -offset);
  XLALGPSAdd( &(hC->epoch), -offset);

  /* Print waveforms to file */
  LALPrintHPlusCross( hP, hC, outFileLong );

  /* Free Memory */

  XLALDestroyREAL4FrequencySeries(Aeff);
  XLALDestroyREAL4FrequencySeries(Phieff);

  XLALDestroyREAL4FFTPlan(prevPlus);
  XLALDestroyREAL4FFTPlan(prevCross);

  XLALDestroyCOMPLEX8Vector(uFPlus);
  XLALDestroyCOMPLEX8Vector(uFCross);
  XLALDestroyREAL4TimeSeries(hP);
  XLALDestroyREAL4TimeSeries(hC);
  /*  XLALDestroyREAL4TimeSeries(hP); */
  /*  XLALDestroyREAL4TimeSeries(hC); */

  return(0);

}