Exemple #1
0
/* 
 * Routine that returns selected frame library:
 * if LAL_FRAME_LIBRARY is set, use the value from that environment;
 * otherwise use the default value.
 * Note: this is NOT threadsafe, but I doubt the frame libraries are
 * threadsafe in any case....
 */
static int XLALFrameLibrary(void)
{
    static int lalFrameLibrary = -1;
    if (lalFrameLibrary < 0) {
        const char *env = getenv("LAL_FRAME_LIBRARY");
        if (env) {
            if (strcmp(env, "FrameL") == 0) {
#if defined HAVE_FRAMEL_H && defined HAVE_LIBFRAME
                lalFrameLibrary = LAL_FRAMEU_FRAME_LIBRARY_FRAMEL;
#else
                XLAL_ERROR_VAL(LAL_FRAMEU_FRAME_LIBRARY_UNAVAILABLE, XLAL_ESYS,
                    "LAL_FRAME_LIBRARY=%s: FrameL frame library not available", env);
#endif
            } else if (strcmp(env, "FrameC") == 0) {
#if defined HAVE_FRAMECPPC_FRAMEC_H && defined HAVE_LIBFRAMECPPC
                lalFrameLibrary = LAL_FRAMEU_FRAME_LIBRARY_FRAMEC;
#else
                XLAL_ERROR_VAL(LAL_FRAMEU_FRAME_LIBRARY_UNAVAILABLE, XLAL_ESYS,
                    "LAL_FRAME_LIBRARY=%s: FrameC frame library not available", env);
#endif
            } else {
                XLAL_PRINT_WARNING("LAL_FRAME_LIBRARY=%s: No valid frame library specified [expect: \"FrameL\" or \"FrameC\"]", env);
                lalFrameLibrary = LAL_FRAMEU_FRAME_LIBRARY_DEFAULT;
            }
        } else {
            lalFrameLibrary = LAL_FRAMEU_FRAME_LIBRARY_DEFAULT;
        }
        switch (lalFrameLibrary) {
        case LAL_FRAMEU_FRAME_LIBRARY_FRAMEL:
            XLAL_PRINT_INFO("Using the FrameL frame library");
            break;
        case LAL_FRAMEU_FRAME_LIBRARY_FRAMEC:
            XLAL_PRINT_INFO("Using the FrameC frame library");
            break;
        default:
            XLAL_ERROR_VAL(LAL_FRAMEU_FRAME_LIBRARY_UNAVAILABLE, XLAL_EERR, "No frame library available");
        }
    }
    return lalFrameLibrary;
}
static int read_matrix(const char dir[], const char fname[], gsl_matrix *m) {
  size_t size = strlen(dir) + strlen(fname) + 2;
  char *path = XLALMalloc(size);
  snprintf(path, size, "%s/%s", dir, fname);

  FILE *f = fopen(path, "rb");
  if (!f)
    XLAL_ERROR(XLAL_EIO, "Could not find ROM data file at path `%s'", path);
  int ret = gsl_matrix_fread(f, m);
  if (ret != 0)
     XLAL_ERROR(XLAL_EIO, "Error reading data from `%s'", path);
  fclose(f);

  XLAL_PRINT_INFO("Sucessfully read data file `%s'", path);
  XLALFree(path);
  return(XLAL_SUCCESS);
}
Exemple #3
0
static int IMRPhenomCGenerateFD(
    COMPLEX16FrequencySeries **htilde, /**< FD waveform */
    const REAL8 phi0,                  /**< phase at peak */
    const REAL8 deltaF,                /**< frequency resolution */
    const REAL8 m1,                    /**< mass of companion 1 [solar masses] */
    const REAL8 m2,                    /**< mass of companion 2 [solar masses] */
    //const REAL8 chi,                   /**< mass-weighted aligned-spin parameter */
    const REAL8 f_min,                 /**< start frequency */
    const REAL8 f_max,                 /**< end frequency */
    const REAL8 distance,              /**< distance to source (m) */
    const BBHPhenomCParams *params      /**< from ComputeIMRPhenomCParams */
) {
  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0, 0}

  int errcode = XLAL_SUCCESS;
  /*
   We can't call XLAL_ERROR() directly with OpenMP on.
   Keep track of return codes for each thread and in addition use flush to get out of
   the parallel for loop as soon as possible if something went wrong in any thread.
  */

  const REAL8 M = m1 + m2;
  const REAL8 eta = m1 * m2 / (M * M);

  /* Memory to temporarily store components of amplitude and phase */
  /*
  REAL8 phSPA, phPM, phRD, aPM, aRD;
  REAL8 wPlusf1, wPlusf2, wMinusf1, wMinusf2, wPlusf0, wMinusf0;
  */

  /* compute the amplitude pre-factor */
  REAL8 amp0 = 2. * sqrt(5. / (64.*LAL_PI)) * M * LAL_MRSUN_SI * M * LAL_MTSUN_SI / distance;

  /* allocate htilde */
  size_t n = NextPow2(f_max / deltaF) + 1;
  /* coalesce at t=0 */
  XLALGPSAdd(&ligotimegps_zero, -1. / deltaF); // shift by overall length in time
  *htilde = XLALCreateCOMPLEX16FrequencySeries("htilde: FD waveform", &ligotimegps_zero, 0.0,
      deltaF, &lalStrainUnit, n);
  memset((*htilde)->data->data, 0, n * sizeof(COMPLEX16));
  XLALUnitMultiply(&((*htilde)->sampleUnits), &((*htilde)->sampleUnits), &lalSecondUnit);
  if (!(*htilde)) XLAL_ERROR(XLAL_EFUNC);

  size_t ind_min = (size_t) (f_min / deltaF);
  size_t ind_max = (size_t) (f_max / deltaF);

  /* Set up spline for phase */
  gsl_interp_accel *acc = gsl_interp_accel_alloc();
  size_t L =  ind_max - ind_min;
  gsl_spline *phiI = gsl_spline_alloc(gsl_interp_cspline, L);
  REAL8 *freqs = XLALMalloc(L*sizeof(REAL8));
  REAL8 *phis = XLALMalloc(L*sizeof(REAL8));

  /* now generate the waveform */
  #pragma omp parallel for
  for (size_t i = ind_min; i < ind_max; i++)
  {

    REAL8 phPhenomC = 0.0;
    REAL8 aPhenomC = 0.0;
    REAL8 f = i * deltaF;

    int per_thread_errcode;
    #pragma omp flush(errcode)
    if (errcode != XLAL_SUCCESS)
      goto skip;

    per_thread_errcode = IMRPhenomCGenerateAmpPhase( &aPhenomC, &phPhenomC, f, eta, params );
    if (per_thread_errcode != XLAL_SUCCESS) {
      errcode = per_thread_errcode;
      #pragma omp flush(errcode)
    }

    phPhenomC -= 2.*phi0; // factor of 2 b/c phi0 is orbital phase

    freqs[i-ind_min] = f;
    phis[i-ind_min] = -phPhenomC; // PhenomP uses cexp(-I*phPhenomC); want to use same phase adjustment code, so we will flip the sign of the phase

    /* generate the waveform */
    ((*htilde)->data->data)[i] = amp0 * aPhenomC * cos(phPhenomC);
    ((*htilde)->data->data)[i] += -I * amp0 * aPhenomC * sin(phPhenomC);

  skip: /* this statement intentionally left blank */;

  }

  if( errcode != XLAL_SUCCESS )
    XLAL_ERROR(errcode);

  /* Correct phasing so we coalesce at t=0 (with the definition of the epoch=-1/deltaF above) */
  gsl_spline_init(phiI, freqs, phis, L);

  REAL8 f_final = params->fRingDown;
  XLAL_PRINT_INFO("f_ringdown = %g\n", f_final);

  // Prevent gsl interpolation errors
  if (f_final > freqs[L-1])
    f_final = freqs[L-1];
  if (f_final < freqs[0])
    XLAL_ERROR(XLAL_EDOM, "f_ringdown <= f_min\n");

  /* Time correction is t(f_final) = 1/(2pi) dphi/df (f_final) */
  REAL8 t_corr = gsl_spline_eval_deriv(phiI, f_final, acc) / (2*LAL_PI);
  XLAL_PRINT_INFO("t_corr = %g\n", t_corr);
  /* Now correct phase */
  for (size_t i = ind_min; i < ind_max; i++) {
    REAL8 f = i * deltaF;
    ((*htilde)->data->data)[i] *= cexp(-2*LAL_PI * I * f * t_corr);
  }

  gsl_spline_free(phiI);
  gsl_interp_accel_free(acc);
  XLALFree(freqs);
  XLALFree(phis);

  return XLAL_SUCCESS;
}
/* Everything needs to be declared as unused in case HDF is not enabled. */
int XLALSimInspiralNRWaveformGetHplusHcross(
        UNUSED REAL8TimeSeries **hplus,        /**< Output h_+ vector */
        UNUSED REAL8TimeSeries **hcross,       /**< Output h_x vector */
        UNUSED REAL8 phiRef,                   /**< orbital phase at reference pt. */
        UNUSED REAL8 inclination,              /**< inclination angle */
        UNUSED REAL8 deltaT,                   /**< sampling interval (s) */
        UNUSED REAL8 m1,                       /**< mass of companion 1 (kg) */
        UNUSED REAL8 m2,                       /**< mass of companion 2 (kg) */
        UNUSED REAL8 r,                        /**< distance of source (m) */
        UNUSED REAL8 fStart,                   /**< start GW frequency (Hz) */
        UNUSED REAL8 fRef,                     /**< reference GW frequency (Hz) */
        UNUSED REAL8 s1x,                      /**< initial value of S1x */
        UNUSED REAL8 s1y,                      /**< initial value of S1y */
        UNUSED REAL8 s1z,                      /**< initial value of S1z */
        UNUSED REAL8 s2x,                      /**< initial value of S2x */
        UNUSED REAL8 s2y,                      /**< initial value of S2y */
        UNUSED REAL8 s2z,                      /**< initial value of S2z */
        UNUSED const char *NRDataFile,         /**< Location of NR HDF file */
        UNUSED LALValue* ModeArray             /**< Container for the ell and m modes to generate. To generate all available modes pass NULL */
        )
{
  #ifndef LAL_HDF5_ENABLED
  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not enabled");
  #else
  /* Declarations */
  UINT4 curr_idx, nr_file_format;
  INT4 model, modem;
  size_t array_length;
  REAL8 nrEta;
  REAL8 S1x, S1y, S1z, S2x, S2y, S2z;
  REAL8 Mflower, time_start_M, time_start_s, time_end_M, time_end_s;
  REAL8 est_start_time, curr_h_real, curr_h_imag;
  REAL8 theta, psi, calpha, salpha;
  REAL8 distance_scale_fac;
  COMPLEX16 curr_ylm;
  REAL8TimeSeries *hplus_corr;
  REAL8TimeSeries *hcross_corr;

  /* These keys follow a strict formulation and cannot be longer than 11
   * characters */
  char amp_key[20];
  char phase_key[20];
  gsl_vector *tmpVector=NULL;
  LALH5File *file, *group;
  LIGOTimeGPS tmpEpoch = LIGOTIMEGPSZERO;
  REAL8Vector *curr_amp, *curr_phase;

  /* Use solar masses for units. NR files will use
   * solar masses as well, so easier for that conversion
   */
  m1 = m1 / LAL_MSUN_SI;
  m2 = m2 / LAL_MSUN_SI;

  file = XLALH5FileOpen(NRDataFile, "r");
  if (file == NULL)
  {
     XLAL_ERROR(XLAL_EIO, "NR SIMULATION DATA FILE %s NOT FOUND.\n", NRDataFile);
  }

  /* Sanity checks on physical parameters passed to waveform
   * generator to guarantee consistency with NR data file.
   */
  XLALH5FileQueryScalarAttributeValue(&nrEta, file, "eta");
  if (fabs((m1 * m2) / pow((m1 + m2),2.0) - nrEta) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "MASSES (%e and %e) ARE INCONSISTENT WITH THE MASS RATIO OF THE NR SIMULATION (eta=%e).\n", m1, m2, nrEta);
  }

  /* Read spin metadata, L_hat, n_hat from HDF5 metadata and make sure
   * the ChooseTDWaveform() input values are consistent with the data
   * recorded in the metadata of the HDF5 file.
   * PS: This assumes that the input spins are in the LAL frame!
   */
  XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
  if (nr_file_format < 2)
  {
    XLALPrintInfo("This NR file is format %d. Only formats 2 and above support the use of reference frequency. For formats < 2 the reference frequency always corresponds to the start of the waveform.", nr_file_format);
    fRef = -1;
  }
  XLALSimInspiralNRWaveformGetSpinsFromHDF5FilePointer(&S1x, &S1y, &S1z,
                                                       &S2x, &S2y, &S2z,
                                                       fRef, m1+m2, file);

  if (fabs(S1x - s1x) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN1X IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }

  if (fabs(S1y - s1y) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN1Y IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }

  if (fabs(S1z - s1z) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN1Z IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }

  if (fabs(S2x - s2x) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN2X IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }

  if (fabs(S2y - s2y) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN2Y IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }

  if (fabs(S2z - s2z) > 1E-3)
  {
     XLAL_ERROR(XLAL_EDOM, "SPIN2Z IS INCONSISTENT WITH THE NR SIMULATION.\n");
  }


  /* First estimate the length of time series that is needed.
   * Demand that 22 mode that is present and use that to figure this out
   */

  XLALH5FileQueryScalarAttributeValue(&Mflower, file, "f_lower_at_1MSUN");
  /* Figure out start time of data */
  group = XLALH5GroupOpen(file, "amp_l2_m2");
  ReadHDF5RealVectorDataset(group, "X", &tmpVector);
  time_start_M = (REAL8)(gsl_vector_get(tmpVector, 0));
  time_end_M = (REAL8)(gsl_vector_get(tmpVector, tmpVector->size - 1));
  gsl_vector_free(tmpVector);
  time_start_s = time_start_M * (m1 + m2) * LAL_MTSUN_SI;
  time_end_s = time_end_M * (m1 + m2) * LAL_MTSUN_SI;

  /* We don't want to return the *entire* waveform if it will be much longer
   * than the specified f_lower. Therefore guess waveform length using
   * the SEOBNR_ROM function and add 10% for safety.
   * FIXME: Is this correct for precessing waveforms?
   */

  if (fStart < Mflower / (m1 + m2) )
  {
    XLAL_ERROR(XLAL_EDOM, "WAVEFORM IS NOT LONG ENOUGH TO REACH f_low. %e %e %e",
                fStart, Mflower, Mflower / (m1 + m2));
  }

  XLALH5FileQueryScalarAttributeValue(&nr_file_format, file, "Format");
  if (nr_file_format > 1)
  {
    if (XLALSimInspiralNRWaveformCheckFRef(file, fStart * (m1+m2)) > 0)
    {
      /* Can use Omega array to get start time */
      est_start_time = XLALSimInspiralNRWaveformGetRefTimeFromRefFreq(file, fStart * (m1+m2)) * (m1 + m2) * LAL_MTSUN_SI;
    }
    else
    {
      /* This is the potential weird case where Omega-vs-time does not start
       * at precisely the same time as flower_at_1MSUN. This gap should be
       * small, so just use the full waveform here.
       */
      est_start_time = time_start_s;
    }
  }
  else
  {
    /* Fall back on SEOBNR chirp time estimate */
    XLALSimIMRSEOBNRv4ROMTimeOfFrequency(&est_start_time, fStart, m1 * LAL_MSUN_SI, m2 * LAL_MSUN_SI, s1z, s2z);
    est_start_time = (-est_start_time) * 1.1;
  }

  if (est_start_time > time_start_s)
  {
    /* Restrict start time of waveform */
    time_start_s = est_start_time;
    time_start_M = time_start_s / ((m1 + m2) * LAL_MTSUN_SI);
  }

  array_length = (UINT4)(ceil( (time_end_s - time_start_s) / deltaT));

  /* Compute correct angles for hplus and hcross following LAL convention. */

  theta = psi = calpha = salpha = 0.;
  XLALSimInspiralNRWaveformGetRotationAnglesFromH5File(&theta, &psi, &calpha,
                       &salpha, file, inclination, phiRef, fRef*(m1+m2));

  /* Create the return time series, use arbitrary epoch here. We set this
   * properly later. */
  XLALGPSAdd(&tmpEpoch, time_start_s);

  *hplus  = XLALCreateREAL8TimeSeries("H_PLUS", &tmpEpoch, 0.0, deltaT,
                                      &lalStrainUnit, array_length );
  *hcross = XLALCreateREAL8TimeSeries("H_CROSS", &tmpEpoch, 0.0, deltaT,
                                      &lalStrainUnit, array_length );

  hplus_corr = XLALCreateREAL8TimeSeries("H_PLUS", &tmpEpoch, 0.0, deltaT,
                                      &lalStrainUnit, array_length );
  hcross_corr = XLALCreateREAL8TimeSeries("H_CROSS", &tmpEpoch, 0.0, deltaT,
                                      &lalStrainUnit, array_length );
  for (curr_idx = 0; curr_idx < array_length; curr_idx++)
  {
    hplus_corr->data->data[curr_idx] = 0.0;
    hcross_corr->data->data[curr_idx] = 0.0;
  }

  /* Create the distance scale factor */
  distance_scale_fac = (m1 + m2) * LAL_MRSUN_SI / r;

  /* Generate the waveform */
  /* NOTE: We assume that for a given ell mode, all m modes are present */
  INT4 NRLmax;
  XLALH5FileQueryScalarAttributeValue(&NRLmax, file, "Lmax");

  if ( ModeArray == NULL )
  {/* Default behaviour: Generate all modes upto NRLmax */
    ModeArray = XLALSimInspiralCreateModeArray();
    for (int ell=2; ell<=NRLmax; ell++)
    {
        XLALSimInspiralModeArrayActivateAllModesAtL(ModeArray, ell);
    }
  }
  /* else Use the ModeArray given */

  for (model=2; model < (NRLmax + 1) ; model++)
  {
    for (modem=-model; modem < (model+1); modem++)
    {

      /* first check if (l,m) mode is 'activated' in the ModeArray */
      /* if activated then generate the mode, else skip this mode. */
      if (XLALSimInspiralModeArrayIsModeActive(ModeArray, model, modem) != 1)
      {
          XLAL_PRINT_INFO("SKIPPING model = %i modem = %i\n", model, modem);
          continue;
      }
      XLAL_PRINT_INFO("generateing model = %i modem = %i\n", model, modem);


      snprintf(amp_key, sizeof(amp_key), "amp_l%d_m%d", model, modem);
      snprintf(phase_key, sizeof(phase_key), "phase_l%d_m%d", model, modem);

      /* Check that both groups exist */
      if (XLALH5FileCheckGroupExists(file, amp_key) == 0)
      {
        continue;
      }
      if (XLALH5FileCheckGroupExists(file, phase_key) == 0)
      {
        continue;
      }

      /* Get amplitude and phase from file */
      XLALSimInspiralNRWaveformGetDataFromHDF5File(&curr_amp, file, (m1 + m2),
                                  time_start_s, array_length, deltaT, amp_key);
      XLALSimInspiralNRWaveformGetDataFromHDF5File(&curr_phase, file, (m1 + m2),
                                time_start_s, array_length, deltaT, phase_key);

      curr_ylm = XLALSpinWeightedSphericalHarmonic(theta, psi, -2,
                                                   model, modem);

      for (curr_idx = 0; curr_idx < array_length; curr_idx++)
      {
        curr_h_real = curr_amp->data[curr_idx]
                    * cos(curr_phase->data[curr_idx]) * distance_scale_fac;
        curr_h_imag = curr_amp->data[curr_idx]
                    * sin(curr_phase->data[curr_idx]) * distance_scale_fac;

        hplus_corr->data->data[curr_idx] = hplus_corr->data->data[curr_idx]
               + curr_h_real * creal(curr_ylm) - curr_h_imag * cimag(curr_ylm);

        hcross_corr->data->data[curr_idx] = hcross_corr->data->data[curr_idx]
               - curr_h_real * cimag(curr_ylm) - curr_h_imag * creal(curr_ylm);

      }

      XLALDestroyREAL8Vector(curr_amp);
      XLALDestroyREAL8Vector(curr_phase);

    }

  }

 /* Correct for the "alpha" angle as given in T1600045 to translate
  * from the NR wave frame to LAL wave-frame
  * Helper time series needed.
  */

  for (curr_idx = 0; curr_idx < array_length; curr_idx++)
  {
    (*hplus)->data->data[curr_idx] =
          (calpha*calpha - salpha*salpha) * hplus_corr->data->data[curr_idx]
          - 2.0*calpha*salpha * hcross_corr->data->data[curr_idx];

    (*hcross)->data->data[curr_idx] =
          + 2.0*calpha*salpha * hplus_corr->data->data[curr_idx]
        + (calpha*calpha - salpha*salpha) * hcross_corr->data->data[curr_idx];
  }

  XLALDestroyREAL8TimeSeries(hplus_corr);
  XLALDestroyREAL8TimeSeries(hcross_corr);
  XLALH5FileClose(file);
  XLALDestroyValue(ModeArray);

  return XLAL_SUCCESS;
  #endif
}
/**
 * @brief Creates a 4-parameter piecewise-polytrope Equation of State.
 * @details A 4-piece piecewise polytrope as described in
 * Physical Review D 79, 124032 (2009) in which the low-density part is
 * fit to the SLY4 EOS.  The remaining pieces are described by adiabatic
 * indices gamma1, gamma2, and gamma3, where gamma1 is the adiabatic index
 * for densities < 10^17.7 kg/m^3, gamma2 is the adiabatic index for densities
 * in the range 10^17.7 kg/m^3 to 10^18 kg/m^3, and gamma3 is the adiabatic
 * index for densities > 10^18 kg/m^3.  The base-10 logarithm of the pressure in
 * Pa at a density of 10^17.7 kg/m^3 is specified by logp1_si.
 * @param logp1_si Base 10 logarithm of the pressure in Pa at the reference
 * density of 10^17.7 kg/m^3.
 * @param gamma1 Adiabatic index for densities below 10^17.7 kg/m^3.
 * @param gamma2 Adiabatic index for densities from 10^17.7 kg/m^3
 * to 10^18 kg/m^3.
 * @param gamma3 Adiabatic index for densities above 10^18 kg/m^3.
 * @return A pointer to a newly created EOS structure.
 */
LALSimNeutronStarEOS *XLALSimNeutronStarEOS4ParameterPiecewisePolytrope(double
    logp1_si, double gamma1, double gamma2, double gamma3)
{
    LALSimNeutronStarEOS *eos;
    LALSimNeutronStarEOSDataPiecewisePolytrope *data;

    /* Data for the 4-piece piecewise polytrope fit to the low-density part of
     * the SLY4 EOS.  Pressure is defined in Pa (N/m^2), and rest-mass density
     * is in kg/m^3.  In the paper PRD 79, 124032 (2009) which used cgs, the
     * k_i values in Table II should be multiplied by c^2. */
    double rhoLow[] = { 0, 2.44033979e10, 3.78358138e14, 2.62780487e15 };
    double kLow[] =
        { 1.0801158752700761e7, 1.311359898998385e10, 6.507604807550857e19,
            3.053461077133694e8 };
    double gammaLow[] = { 1.58424999, 1.28732904, 0.62223344, 1.35692395 };

    /*
     * These are the cgs values:
     * double rhoLow[] = {0, 2.44033979e7, 3.78358138e11, 2.62780487e12};
     * double kLow[] = {6.11252036792443e12, 9.54352947022931e14, 4.787640050002652e22, 3.593885515256112e13};
     * double gammaLow[] = {1.58424999, 1.28732904, 0.62223344, 1.35692395};
     */

    double rho0, rho1, rho2;
    double p1;  /* pressure at 10^17.7 kg/m^3 */
    double p1min;       /* Minimum allowed value of p1 s.t. high density EOS has larger pressure than low density EOS */
    double k1, k2, k3;
    double rhoJoin1, rhoJoin2, pJoin1, pJoin2, gammaJoin, kJoin;        /* constants for extra polytrope if it's needed */
    int i;
    double k_i, rho_i, gamma_i, p_i, n_i, a_i, a_im1, n_im1, epsilon_i,
        enthalpy_i, h_i;

    if (gamma1 <= 1.0 || gamma2 <= 1.0 || gamma3 <= 1.0)
        XLAL_ERROR_NULL(XLAL_EINVAL,
            "Adiabitic indices gamma1=%g, gamma2=%g, and gamma3=%g "
            "must all be greater than 1", gamma1, gamma2, gamma3);

    /* Transition densities between the 3 high-density polytropes */
    rho1 = pow(10, 17.7);
    rho2 = pow(10, 18.0);

    /* pressure at rho1 */
    p1 = pow(10, logp1_si);

    /* pressure constants */
    k1 = p1 / pow(rho1, gamma1);
    k2 = p1 / pow(rho1, gamma2);
    k3 = k2 * pow(rho2, gamma2 - gamma3);

    /* Calculate the variable joining density rho0 between the high and low
     * density EOS */
    rho0 = pow(kLow[3] / k1, 1.0 / (gamma1 - gammaLow[3]));

    p1min = kLow[3] * pow(rho1, gammaLow[3]);
    if (logp1_si < log10(p1min) || logp1_si > 34.5)
        XLAL_ERROR_NULL(XLAL_EINVAL,
            "logp1_si=%g should be between %g and 34.5", logp1_si,
            log10(p1min));

    /* allocate memory */
    eos = LALCalloc(1, sizeof(*eos));
    data = LALCalloc(1, sizeof(*data));

    eos->datatype = LALSIM_NEUTRON_STAR_EOS_DATA_TYPE_PIECEWISE_POLYTROPE;
    eos->data.piecewisePolytrope = data;
    if(snprintf(eos->name, sizeof(eos->name), "4-Piece Polytrope (p1=10^%g Pa,"
	"Gamma1=%g,Gamma2=%g,Gamma3=%g)", logp1_si, gamma1, gamma2, gamma3) >= (int) sizeof(eos->name))
        XLAL_ERROR_NULL(XLAL_EINVAL, "eos name overflow");

    /* setup function pointers */
    eos->free = eos_free_piecewise_polytrope;
    eos->e_of_p = eos_e_of_p_piecewise_polytrope;
    eos->h_of_p = eos_h_of_p_piecewise_polytrope;
    eos->e_of_h = eos_e_of_h_piecewise_polytrope;
    eos->rho_of_h = eos_rho_of_h_piecewise_polytrope;
    eos->p_of_h = eos_p_of_h_piecewise_polytrope;
    eos->dedp_of_p = eos_dedp_of_p_piecewise_polytrope;
    eos->v_of_h = eos_v_of_h_piecewise_polytrope;


    /* Add another polytrope if the joining density is below the start of the
     * last low density polytrope or above the end of the first high density
     * polytrope. */
    if ((rho0 > rhoLow[3]) && (rho0 < rho1)) {
        /* No issue. There will be a total of 7 polytropes. */

        eos->data.piecewisePolytrope->kTab[0] = kLow[0];
        eos->data.piecewisePolytrope->kTab[1] = kLow[1];
        eos->data.piecewisePolytrope->kTab[2] = kLow[2];
        eos->data.piecewisePolytrope->kTab[3] = kLow[3];
        eos->data.piecewisePolytrope->kTab[4] = k1;
        eos->data.piecewisePolytrope->kTab[5] = k2;
        eos->data.piecewisePolytrope->kTab[6] = k3;

        eos->data.piecewisePolytrope->gammaTab[0] = gammaLow[0];
        eos->data.piecewisePolytrope->gammaTab[1] = gammaLow[1];
        eos->data.piecewisePolytrope->gammaTab[2] = gammaLow[2];
        eos->data.piecewisePolytrope->gammaTab[3] = gammaLow[3];
        eos->data.piecewisePolytrope->gammaTab[4] = gamma1;
        eos->data.piecewisePolytrope->gammaTab[5] = gamma2;
        eos->data.piecewisePolytrope->gammaTab[6] = gamma3;

        eos->data.piecewisePolytrope->rhoTab[0] = rhoLow[0];
        eos->data.piecewisePolytrope->rhoTab[1] = rhoLow[1];
        eos->data.piecewisePolytrope->rhoTab[2] = rhoLow[2];
        eos->data.piecewisePolytrope->rhoTab[3] = rhoLow[3];
        eos->data.piecewisePolytrope->rhoTab[4] = rho0;
        eos->data.piecewisePolytrope->rhoTab[5] = rho1;
        eos->data.piecewisePolytrope->rhoTab[6] = rho2;

        eos->data.piecewisePolytrope->nPoly = 7;

    } else {
        /* You have to add an 8th polytrope between gammaLow[3] and gamma1. */
        /* It will be between the densities rhoJoin1 and rhoJoin2. */
        rhoJoin1 = 5.0e15;
        rhoJoin2 = 1.0e16;

        /* Calculate the pressure at the start and end densities. */
        pJoin1 = kLow[3] * pow(rhoJoin1, gammaLow[3]);
        pJoin2 = k1 * pow(rhoJoin2, gamma1);

        /* Calculate K and Gamma for the joining polytrope */
        gammaJoin = log(pJoin2 / pJoin1) / log(rhoJoin2 / rhoJoin1);

        kJoin = pJoin1 / pow(rhoJoin1, gammaJoin);

        /* Now join all 8 polytropes. */
        eos->data.piecewisePolytrope->kTab[0] = kLow[0];
        eos->data.piecewisePolytrope->kTab[1] = kLow[1];
        eos->data.piecewisePolytrope->kTab[2] = kLow[2];
        eos->data.piecewisePolytrope->kTab[3] = kLow[3];
        eos->data.piecewisePolytrope->kTab[4] = kJoin;
        eos->data.piecewisePolytrope->kTab[5] = k1;
        eos->data.piecewisePolytrope->kTab[6] = k2;
        eos->data.piecewisePolytrope->kTab[7] = k3;

        eos->data.piecewisePolytrope->gammaTab[0] = gammaLow[0];
        eos->data.piecewisePolytrope->gammaTab[1] = gammaLow[1];
        eos->data.piecewisePolytrope->gammaTab[2] = gammaLow[2];
        eos->data.piecewisePolytrope->gammaTab[3] = gammaLow[3];
        eos->data.piecewisePolytrope->gammaTab[4] = gammaJoin;
        eos->data.piecewisePolytrope->gammaTab[5] = gamma1;
        eos->data.piecewisePolytrope->gammaTab[6] = gamma2;
        eos->data.piecewisePolytrope->gammaTab[7] = gamma3;

        eos->data.piecewisePolytrope->rhoTab[0] = rhoLow[0];
        eos->data.piecewisePolytrope->rhoTab[1] = rhoLow[1];
        eos->data.piecewisePolytrope->rhoTab[2] = rhoLow[2];
        eos->data.piecewisePolytrope->rhoTab[3] = rhoLow[3];
        eos->data.piecewisePolytrope->rhoTab[4] = rhoJoin1;
        eos->data.piecewisePolytrope->rhoTab[5] = rhoJoin2;
        eos->data.piecewisePolytrope->rhoTab[6] = rho1;
        eos->data.piecewisePolytrope->rhoTab[7] = rho2;

        eos->data.piecewisePolytrope->nPoly = 8;

        XLAL_PRINT_INFO("An extra polytrope was used to join the low and high density regions.");
    }

    /* convert to geometric units and place in piecwisePolytrope structure */
    for (i = 0; i < eos->data.piecewisePolytrope->nPoly; i++) {
        eos->data.piecewisePolytrope->rhoTab[i] *= LAL_G_C2_SI;
        gamma_i = eos->data.piecewisePolytrope->gammaTab[i];
        eos->data.piecewisePolytrope->kTab[i] *=
            pow(LAL_G_SI, 1.0 - gamma_i) * pow((double)LAL_C_SI,
            2.0 * gamma_i - 4.0);
    }

    /* calculate remaining quantities (p, n, a, epsilon, h) in data structure */
    for (i = 0; i < eos->data.piecewisePolytrope->nPoly; i++) {
        k_i = eos->data.piecewisePolytrope->kTab[i];
        rho_i = eos->data.piecewisePolytrope->rhoTab[i];
        gamma_i = eos->data.piecewisePolytrope->gammaTab[i];

        p_i = k_i * pow(rho_i, gamma_i);
        n_i = 1.0 / (gamma_i - 1.0);

        if (i == 0) {
            a_i = 0.0;
        } else {
            a_im1 = eos->data.piecewisePolytrope->aTab[i - 1];
            n_im1 = eos->data.piecewisePolytrope->nTab[i - 1];
            a_i = a_im1 + (n_im1 - n_i) * p_i / rho_i;
        }

        epsilon_i = (1.0 + a_i) * rho_i + n_i * p_i;

        if (i == 0) {
            enthalpy_i = 1.0;   /* p/rho -> 0 as rho -> 0, and a_0 = 0 */
        } else {
            enthalpy_i = 1.0 + a_i + (n_i + 1) * p_i / rho_i;
        }
        h_i = log(enthalpy_i);

        eos->data.piecewisePolytrope->pTab[i] = p_i;
        eos->data.piecewisePolytrope->nTab[i] = n_i;
        eos->data.piecewisePolytrope->aTab[i] = a_i;
        eos->data.piecewisePolytrope->epsilonTab[i] = epsilon_i;
        eos->data.piecewisePolytrope->hTab[i] = h_i;
    }

    eos->pmax = 10.0 * LAL_NUCLEAR_DENSITY_GEOM_SI;
    eos->hmax = eos_h_of_p_piecewise_polytrope(eos->pmax, eos);
    eos->hMinAcausal =
        eos_min_acausal_pseudo_enthalpy_piecewise_polytrope(eos->hmax, eos);

#if 0
    print_piecewise_polytrope_data(eos->data.piecewisePolytrope);
    printf("datatype = %d\n", eos->datatype);
    printf("pmax = %e\n", eos->pmax);
    printf("hmax = %e\n", eos->hmax);
    printf("hMinAcausal = %e\n", eos->hMinAcausal);
#endif

    return eos;
}
static int
XLALSimIMRSpinEOBInitialConditionsPrec(
				   REAL8Vector * initConds,	/**<< OUTPUT, Initial dynamical variables */
				   const REAL8 mass1,	/**<< mass 1 */
				   const REAL8 mass2,	/**<< mass 2 */
				   const REAL8 fMin,	/**<< Initial frequency (given) */
				   const REAL8 inc,	/**<< Inclination */
				   const REAL8 spin1[],	/**<< Initial spin vector 1 */
				   const REAL8 spin2[],	/**<< Initial spin vector 2 */
				   SpinEOBParams * params	/**<< Spin EOB parameters */
)
{

#ifndef LAL_NDEBUG
	if (!initConds) {
		XLAL_ERROR(XLAL_EINVAL);
	}
#endif

	int	debugPK = 0; int printPK = 0;
  FILE* UNUSED out = NULL;

	if (printPK) {
		XLAL_PRINT_INFO("Inside the XLALSimIMRSpinEOBInitialConditionsPrec function!\n");
		XLAL_PRINT_INFO(
    "Inputs: m1 = %.16e, m2 = %.16e, fMin = %.16e, inclination = %.16e\n",
      mass1, mass2, (double)fMin, (double)inc);
		XLAL_PRINT_INFO("Inputs: mSpin1 = {%.16e, %.16e, %.16e}\n",
      spin1[0], spin1[1], spin1[2]);
		XLAL_PRINT_INFO("Inputs: mSpin2 = {%.16e, %.16e, %.16e}\n",
      spin2[0], spin2[1], spin2[2]);
		fflush(NULL);
	}
	static const int UNUSED lMax = 8;

	int		i;

	/* Variable to keep track of whether the user requested the tortoise */
	int		tmpTortoise;

	UINT4		SpinAlignedEOBversion;

	REAL8		mTotal;
	REAL8		eta;
	REAL8		omega   , v0;	/* Initial velocity and angular
					 * frequency */

	REAL8		ham;	/* Hamiltonian */

	REAL8		LnHat    [3];	/* Initial orientation of angular
					 * momentum */
	REAL8		rHat     [3];	/* Initial orientation of radial
					 * vector */
	REAL8		vHat     [3];	/* Initial orientation of velocity
					 * vector */
	REAL8		Lhat     [3];	/* Direction of relativistic ang mom */
	REAL8		qHat     [3];
	REAL8		pHat     [3];

	/* q and p vectors in Cartesian and spherical coords */
	REAL8		qCart    [3], pCart[3];
	REAL8		qSph     [3], pSph[3];

	/* We will need to manipulate the spin vectors */
	/* We will use temporary vectors to do this */
	REAL8		tmpS1    [3];
	REAL8		tmpS2    [3];
	REAL8		tmpS1Norm[3];
	REAL8		tmpS2Norm[3];

	REAL8Vector	qCartVec, pCartVec;
	REAL8Vector	s1Vec, s2Vec, s1VecNorm, s2VecNorm;
	REAL8Vector	sKerr, sStar;
	REAL8		sKerrData[3], sStarData[3];
	REAL8		a = 0.;
	//, chiS, chiA;
	//REAL8 chi1, chi2;

	/*
	 * We will need a full values vector for calculating derivs of
	 * Hamiltonian
	 */
	REAL8		sphValues[12];
	REAL8		cartValues[12];

	/* Matrices for rotating to the new basis set. */
	/* It is more convenient to calculate the ICs in a simpler basis */
	gsl_matrix     *rotMatrix = NULL;
	gsl_matrix     *invMatrix = NULL;
	gsl_matrix     *rotMatrix2 = NULL;
	gsl_matrix     *invMatrix2 = NULL;

	/* Root finding stuff for finding the spherical orbit */
	SEOBRootParams	rootParams;
	const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrid;
	gsl_multiroot_fsolver *rootSolver = NULL;

	gsl_multiroot_function rootFunction;
	gsl_vector     *initValues = NULL;
	gsl_vector     *finalValues = NULL;
	INT4 gslStatus;
        INT4 cntGslNoProgress = 0, MAXcntGslNoProgress = 5;
        //INT4 cntGslNoProgress = 0, MAXcntGslNoProgress = 50;
        REAL8 multFacGslNoProgress = 3./5.;
	//const int	maxIter = 2000;
	const int	maxIter = 10000;

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

	mTotal = mass1 + mass2;
	eta = mass1 * mass2 / (mTotal * mTotal);
	memcpy(tmpS1, spin1, sizeof(tmpS1));
	memcpy(tmpS2, spin2, sizeof(tmpS2));
	memcpy(tmpS1Norm, spin1, sizeof(tmpS1Norm));
	memcpy(tmpS2Norm, spin2, sizeof(tmpS2Norm));
	for (i = 0; i < 3; i++) {
		tmpS1Norm[i] /= mTotal * mTotal;
		tmpS2Norm[i] /= mTotal * mTotal;
	}
	SpinAlignedEOBversion = params->seobCoeffs->SpinAlignedEOBversion;
	/* We compute the ICs for the non-tortoise p, and convert at the end */
	tmpTortoise = params->tortoise;
	params->tortoise = 0;

	EOBNonQCCoeffs *nqcCoeffs = NULL;
	nqcCoeffs = params->nqcCoeffs;

	/*
	 * STEP 1) Rotate to LNhat0 along z-axis and N0 along x-axis frame,
	 * where LNhat0 and N0 are initial normal to orbital plane and
	 * initial orbital separation;
	 */

	/* Set the initial orbital ang mom direction. Taken from STPN code */
	LnHat[0] = sin(inc);
	LnHat[1] = 0.;
	LnHat[2] = cos(inc);

	/*
	 * Set the radial direction - need to take care to avoid singularity
	 * if L is along z axis
	 */
	if (LnHat[2] > 0.9999) {
		rHat[0] = 1.;
		rHat[1] = rHat[2] = 0.;
	} else {
		REAL8		theta0 = atan(-LnHat[2] / LnHat[0]);	/* theta0 is between 0
									 * and Pi */
		rHat[0] = sin(theta0);
		rHat[1] = 0;
		rHat[2] = cos(theta0);
	}

	/* Now we can complete the triad */
	vHat[0] = CalculateCrossProductPrec(0, LnHat, rHat);
	vHat[1] = CalculateCrossProductPrec(1, LnHat, rHat);
	vHat[2] = CalculateCrossProductPrec(2, LnHat, rHat);

	NormalizeVectorPrec(vHat);

	/* Vectors BEFORE rotation */
	if (printPK) {
		for (i = 0; i < 3; i++)
			XLAL_PRINT_INFO(" LnHat[%d] = %.16e, rHat[%d] = %.16e, vHat[%d] = %.16e\n",
        i, LnHat[i], i, rHat[i], i, vHat[i]);

		XLAL_PRINT_INFO("\n\n");
		for (i = 0; i < 3; i++)
			XLAL_PRINT_INFO(" s1[%d] = %.16e, s2[%d] = %.16e\n", i, tmpS1[i], i, tmpS2[i]);
    fflush(NULL);
	}

	/* Allocate and compute the rotation matrices */
	XLAL_CALLGSL(rotMatrix = gsl_matrix_alloc(3, 3));
	XLAL_CALLGSL(invMatrix = gsl_matrix_alloc(3, 3));
	if (!rotMatrix || !invMatrix) {
		if (rotMatrix)
			gsl_matrix_free(rotMatrix);
		if (invMatrix)
			gsl_matrix_free(invMatrix);
		XLAL_ERROR(XLAL_ENOMEM);
	}
	if (CalculateRotationMatrixPrec(rotMatrix, invMatrix, rHat, vHat, LnHat) == XLAL_FAILURE) {
		gsl_matrix_free(rotMatrix);
		gsl_matrix_free(invMatrix);
		XLAL_ERROR(XLAL_ENOMEM);
	}
	/* Rotate the orbital vectors and spins */
	ApplyRotationMatrixPrec(rotMatrix, rHat);
	ApplyRotationMatrixPrec(rotMatrix, vHat);
	ApplyRotationMatrixPrec(rotMatrix, LnHat);
	ApplyRotationMatrixPrec(rotMatrix, tmpS1);
	ApplyRotationMatrixPrec(rotMatrix, tmpS2);
	ApplyRotationMatrixPrec(rotMatrix, tmpS1Norm);
	ApplyRotationMatrixPrec(rotMatrix, tmpS2Norm);

	/* See if Vectors have been rotated fine */
	if (printPK) {
		XLAL_PRINT_INFO("\nAfter applying rotation matrix:\n\n");
		for (i = 0; i < 3; i++)
			XLAL_PRINT_INFO(" LnHat[%d] = %.16e, rHat[%d] = %.16e, vHat[%d] = %.16e\n",
                i, LnHat[i], i, rHat[i], i, vHat[i]);

		XLAL_PRINT_INFO("\n");
		for (i = 0; i < 3; i++)
			XLAL_PRINT_INFO(" s1[%d] = %.16e, s2[%d] = %.16e\n", i, tmpS1[i], i, tmpS2[i]);

    fflush(NULL);
	}
	/*
	 * STEP 2) After rotation in STEP 1, in spherical coordinates, phi0
	 * and theta0 are given directly in Eq. (4.7), r0, pr0, ptheta0 and
	 * pphi0 are obtained by solving Eqs. (4.8) and (4.9) (using
	 * gsl_multiroot_fsolver). At this step, we find initial conditions
	 * for a spherical orbit without radiation reaction.
	 */

  /* Initialise the gsl stuff */
	XLAL_CALLGSL(rootSolver = gsl_multiroot_fsolver_alloc(T, 3));
	if (!rootSolver) {
		gsl_matrix_free(rotMatrix);
		gsl_matrix_free(invMatrix);
		XLAL_ERROR(XLAL_ENOMEM);
	}
	XLAL_CALLGSL(initValues = gsl_vector_calloc(3));
	if (!initValues) {
		gsl_multiroot_fsolver_free(rootSolver);
		gsl_matrix_free(rotMatrix);
		gsl_matrix_free(invMatrix);
		XLAL_ERROR(XLAL_ENOMEM);
	}

	rootFunction.f = XLALFindSphericalOrbitPrec;
	rootFunction.n = 3;
	rootFunction.params = &rootParams;

	/* Calculate the initial velocity from the given initial frequency */
	omega = LAL_PI * mTotal * LAL_MTSUN_SI * fMin;
	v0 = cbrt(omega);

	/* Given this, we can start to calculate the initial conditions */
	/* for spherical coords in the new basis */
	rootParams.omega = omega;
	rootParams.params = params;

	/* To start with, we will just assign Newtonian-ish ICs to the system */
	rootParams.values[0] = scale1 * 1. / (v0 * v0);	/* Initial r */
	rootParams.values[4] = scale2 * v0;	            /* Initial p */
	rootParams.values[5] = scale3 * 1e-3;
	//PK
  memcpy(rootParams.values + 6, tmpS1, sizeof(tmpS1));
	memcpy(rootParams.values + 9, tmpS2, sizeof(tmpS2));

	if (printPK) {
    XLAL_PRINT_INFO("ICs guess: x = %.16e, py = %.16e, pz = %.16e\n",
      rootParams.values[0]/scale1, rootParams.values[4]/scale2,
      rootParams.values[5]/scale3);
    fflush(NULL);
  }

	gsl_vector_set(initValues, 0, rootParams.values[0]);
	gsl_vector_set(initValues, 1, rootParams.values[4]);
  gsl_vector_set(initValues, 2, rootParams.values[5]);

	gsl_multiroot_fsolver_set(rootSolver, &rootFunction, initValues);

	/* We are now ready to iterate to find the solution */
	i = 0;

  if(debugPK){ out = fopen("ICIterations.dat", "w"); }
	do {
		XLAL_CALLGSL(gslStatus = gsl_multiroot_fsolver_iterate(rootSolver));
		if (debugPK) {
      fprintf( out, "%d\t", i );

      /* Write to file */
      fprintf( out, "%.16e\t%.16e\t%.16e\t",
        rootParams.values[0]/scale1, rootParams.values[4]/scale2,
        rootParams.values[5]/scale3 );

      /* Residual Function values whose roots we are trying to find */
      finalValues = gsl_multiroot_fsolver_f(rootSolver);

      /* Write to file */
      fprintf( out, "%.16e\t%.16e\t%.16e\t",
        gsl_vector_get(finalValues, 0),
        gsl_vector_get(finalValues, 1),
        gsl_vector_get(finalValues, 2) );

      /* Step sizes in each of function variables */
      finalValues = gsl_multiroot_fsolver_dx(rootSolver);

      /* Write to file */
      fprintf( out, "%.16e\t%.16e\t%.16e\t%d\n",
        gsl_vector_get(finalValues, 0)/scale1,
        gsl_vector_get(finalValues, 1)/scale2,
        gsl_vector_get(finalValues, 2)/scale3,
        gslStatus );
		}

    if (gslStatus == GSL_ENOPROG || gslStatus == GSL_ENOPROGJ) {
      XLAL_PRINT_INFO(
        "\n NO PROGRESS being made by Spherical orbit root solver\n");

      /* Print Residual Function values whose roots we are trying to find */
      finalValues = gsl_multiroot_fsolver_f(rootSolver);
      XLAL_PRINT_INFO("Function value here given by the following:\n");
      XLAL_PRINT_INFO(" F1 = %.16e, F2 = %.16e, F3 = %.16e\n",
          gsl_vector_get(finalValues, 0),
		       gsl_vector_get(finalValues, 1), gsl_vector_get(finalValues, 2));

      /* Print Step sizes in each of function variables */
      finalValues = gsl_multiroot_fsolver_dx(rootSolver);
//      XLAL_PRINT_INFO("Stepsizes in each dimension:\n");
//      XLAL_PRINT_INFO(" x = %.16e, py = %.16e, pz = %.16e\n",
//          gsl_vector_get(finalValues, 0)/scale1,
//	       gsl_vector_get(finalValues, 1)/scale2,
//          gsl_vector_get(finalValues, 2)/scale3);

      /* Only allow this flag to be caught MAXcntGslNoProgress no. of times */
      cntGslNoProgress += 1;
      if (cntGslNoProgress >= MAXcntGslNoProgress) {
        cntGslNoProgress = 0;

        if(multFacGslNoProgress < 1.){ multFacGslNoProgress *= 1.02; }
        else{ multFacGslNoProgress /= 1.01; }

      } 
      /* Now that no progress is being made, we need to reset the initial guess
       * for the (r,pPhi, pTheta) and reset the integrator */
      rootParams.values[0] = scale1 * 1. / (v0 * v0);	/* Initial r */
      rootParams.values[4] = scale2 * v0;	            /* Initial p */
      if( cntGslNoProgress % 2 )
        rootParams.values[5] = scale3 * 1e-3 / multFacGslNoProgress;
      else
        rootParams.values[5] = scale3 * 1e-3 * multFacGslNoProgress;
      //PK
      memcpy(rootParams.values + 6, tmpS1, sizeof(tmpS1));
      memcpy(rootParams.values + 9, tmpS2, sizeof(tmpS2));

      if (printPK) {
        XLAL_PRINT_INFO("New ICs guess: x = %.16e, py = %.16e, pz = %.16e\n",
                rootParams.values[0]/scale1, rootParams.values[4]/scale2,
                rootParams.values[5]/scale3);
        fflush(NULL);
      }

      gsl_vector_set(initValues, 0, rootParams.values[0]);
      gsl_vector_set(initValues, 1, rootParams.values[4]);
      gsl_vector_set(initValues, 2, rootParams.values[5]);
      gsl_multiroot_fsolver_set(rootSolver, &rootFunction, initValues);
    }
    else if (gslStatus == GSL_EBADFUNC) {
      XLALPrintError(
      "Inf or Nan encountered in evaluluation of spherical orbit Eqn\n");
			gsl_multiroot_fsolver_free(rootSolver);
			gsl_vector_free(initValues);
			gsl_matrix_free(rotMatrix);
			gsl_matrix_free(invMatrix);
			XLAL_ERROR(XLAL_EDOM);
    }
		else if (gslStatus != GSL_SUCCESS) {
			XLALPrintError("Error in GSL iteration function!\n");
			gsl_multiroot_fsolver_free(rootSolver);
			gsl_vector_free(initValues);
			gsl_matrix_free(rotMatrix);
			gsl_matrix_free(invMatrix);
			XLAL_ERROR(XLAL_EDOM);
		}

    /* different ways to test convergence of the method */
		XLAL_CALLGSL(gslStatus = gsl_multiroot_test_residual(rootSolver->f, 1.0e-8));
    /*XLAL_CALLGSL(gslStatus= gsl_multiroot_test_delta(
          gsl_multiroot_fsolver_dx(rootSolver),
          gsl_multiroot_fsolver_root(rootSolver),
          1.e-8, 1.e-5));*/
		i++;
	}
	while (gslStatus == GSL_CONTINUE && i <= maxIter);

  if(debugPK) { fflush(NULL); fclose(out); }

	if (i > maxIter && gslStatus != GSL_SUCCESS) {
		gsl_multiroot_fsolver_free(rootSolver);
		gsl_vector_free(initValues);
		gsl_matrix_free(rotMatrix);
		gsl_matrix_free(invMatrix);
		//XLAL_ERROR(XLAL_EMAXITER);
		XLAL_ERROR(XLAL_EDOM);
	}
	finalValues = gsl_multiroot_fsolver_root(rootSolver);

	if (printPK) {
		XLAL_PRINT_INFO("Spherical orbit conditions here given by the following:\n");
		XLAL_PRINT_INFO(" x = %.16e, py = %.16e, pz = %.16e\n",
           gsl_vector_get(finalValues, 0)/scale1,
		       gsl_vector_get(finalValues, 1)/scale2,
           gsl_vector_get(finalValues, 2)/scale3);
	}
	memset(qCart, 0, sizeof(qCart));
	memset(pCart, 0, sizeof(pCart));

	qCart[0] = gsl_vector_get(finalValues, 0)/scale1;
	pCart[1] = gsl_vector_get(finalValues, 1)/scale2;
	pCart[2] = gsl_vector_get(finalValues, 2)/scale3;


	/* Free the GSL root finder, since we're done with it */
	gsl_multiroot_fsolver_free(rootSolver);
	gsl_vector_free(initValues);


	/*
	 * STEP 3) Rotate to L0 along z-axis and N0 along x-axis frame, where
	 * L0 is the initial orbital angular momentum and L0 is calculated
	 * using initial position and linear momentum obtained in STEP 2.
	 */

	/* Now we can calculate the relativistic L and rotate to a new basis */
	memcpy(qHat, qCart, sizeof(qCart));
	memcpy(pHat, pCart, sizeof(pCart));

	NormalizeVectorPrec(qHat);
	NormalizeVectorPrec(pHat);

	Lhat[0] = CalculateCrossProductPrec(0, qHat, pHat);
	Lhat[1] = CalculateCrossProductPrec(1, qHat, pHat);
	Lhat[2] = CalculateCrossProductPrec(2, qHat, pHat);

	NormalizeVectorPrec(Lhat);

	XLAL_CALLGSL(rotMatrix2 = gsl_matrix_alloc(3, 3));
	XLAL_CALLGSL(invMatrix2 = gsl_matrix_alloc(3, 3));

	if (CalculateRotationMatrixPrec(rotMatrix2, invMatrix2, qHat, pHat, Lhat) == XLAL_FAILURE) {
		gsl_matrix_free(rotMatrix);
		gsl_matrix_free(invMatrix);
		XLAL_ERROR(XLAL_ENOMEM);
	}
	ApplyRotationMatrixPrec(rotMatrix2, rHat);
	ApplyRotationMatrixPrec(rotMatrix2, vHat);
	ApplyRotationMatrixPrec(rotMatrix2, LnHat);
	ApplyRotationMatrixPrec(rotMatrix2, tmpS1);
	ApplyRotationMatrixPrec(rotMatrix2, tmpS2);
	ApplyRotationMatrixPrec(rotMatrix2, tmpS1Norm);
	ApplyRotationMatrixPrec(rotMatrix2, tmpS2Norm);
	ApplyRotationMatrixPrec(rotMatrix2, qCart);
	ApplyRotationMatrixPrec(rotMatrix2, pCart);

        gsl_matrix_free(rotMatrix);
        gsl_matrix_free(rotMatrix2);

        if (printPK) {
		XLAL_PRINT_INFO("qCart after rotation2 %3.10f %3.10f %3.10f\n", qCart[0], qCart[1], qCart[2]);
		XLAL_PRINT_INFO("pCart after rotation2 %3.10f %3.10f %3.10f\n", pCart[0], pCart[1], pCart[2]);
		XLAL_PRINT_INFO("S1 after rotation2 %3.10f %3.10f %3.10f\n", tmpS1Norm[0], tmpS1Norm[1], tmpS1Norm[2]);
		XLAL_PRINT_INFO("S2 after rotation2 %3.10f %3.10f %3.10f\n", tmpS2Norm[0], tmpS2Norm[1], tmpS2Norm[2]);
	}
	/*
	 * STEP 4) In the L0-N0 frame, we calculate (dE/dr)|sph using Eq.
	 * (4.14), then initial dr/dt using Eq. (4.10), and finally pr0 using
	 * Eq. (4.15).
	 */

	/* Now we can calculate the flux. Change to spherical co-ords */
	CartesianToSphericalPrec(qSph, pSph, qCart, pCart);
	memcpy(sphValues, qSph, sizeof(qSph));
	memcpy(sphValues + 3, pSph, sizeof(pSph));
	memcpy(sphValues + 6, tmpS1, sizeof(tmpS1));
	memcpy(sphValues + 9, tmpS2, sizeof(tmpS2));

	memcpy(cartValues, qCart, sizeof(qCart));
	memcpy(cartValues + 3, pCart, sizeof(pCart));
	memcpy(cartValues + 6, tmpS1, sizeof(tmpS1));
	memcpy(cartValues + 9, tmpS2, sizeof(tmpS2));

	REAL8		dHdpphi , d2Hdr2, d2Hdrdpphi;
	REAL8		rDot    , dHdpr, flux, dEdr;

	d2Hdr2 = XLALCalculateSphHamiltonianDeriv2Prec(0, 0, sphValues, params);
	d2Hdrdpphi = XLALCalculateSphHamiltonianDeriv2Prec(0, 5, sphValues, params);

	if (printPK)
		XLAL_PRINT_INFO("d2Hdr2 = %.16e, d2Hdrdpphi = %.16e\n", d2Hdr2, d2Hdrdpphi);

	/* New code to compute derivatives w.r.t. cartesian variables */

	REAL8		tmpDValues[14];
	int UNUSED	status;
	for (i = 0; i < 3; i++) {
		cartValues[i + 6] /= mTotal * mTotal;
		cartValues[i + 9] /= mTotal * mTotal;
	}
    UINT4 oldignoreflux = params->ignoreflux;
    params->ignoreflux = 1;
	status = XLALSpinPrecHcapNumericalDerivative(0, cartValues, tmpDValues, params);
    params->ignoreflux = oldignoreflux;
	for (i = 0; i < 3; i++) {
		cartValues[i + 6] *= mTotal * mTotal;
		cartValues[i + 9] *= mTotal * mTotal;
	}

	dHdpphi = tmpDValues[1] / sqrt(cartValues[0] * cartValues[0] + cartValues[1] * cartValues[1] + cartValues[2] * cartValues[2]);
	//XLALSpinPrecHcapNumDerivWRTParam(4, cartValues, params) / sphValues[0];

	dEdr = -dHdpphi * d2Hdr2 / d2Hdrdpphi;

	if (printPK)
		XLAL_PRINT_INFO("d2Hdr2 = %.16e d2Hdrdpphi = %.16e dHdpphi = %.16e\n",
            d2Hdr2, d2Hdrdpphi, dHdpphi);

	if (d2Hdr2 != 0.0) {
		/* We will need to calculate the Hamiltonian to get the flux */
		s1Vec.length = s2Vec.length = s1VecNorm.length = s2VecNorm.length = sKerr.length = sStar.length = 3;
		s1Vec.data = tmpS1;
		s2Vec.data = tmpS2;
		s1VecNorm.data = tmpS1Norm;
		s2VecNorm.data = tmpS2Norm;
		sKerr.data = sKerrData;
		sStar.data = sStarData;

		qCartVec.length = pCartVec.length = 3;
		qCartVec.data = qCart;
		pCartVec.data = pCart;

		//chi1 = tmpS1[0] * LnHat[0] + tmpS1[1] * LnHat[1] + tmpS1[2] * LnHat[2];
		//chi2 = tmpS2[0] * LnHat[0] + tmpS2[1] * LnHat[1] + tmpS2[2] * LnHat[2];

		//if (debugPK)
			//XLAL_PRINT_INFO("magS1 = %.16e, magS2 = %.16e\n", chi1, chi2);

		//chiS = 0.5 * (chi1 / (mass1 * mass1) + chi2 / (mass2 * mass2));
		//chiA = 0.5 * (chi1 / (mass1 * mass1) - chi2 / (mass2 * mass2));

		XLALSimIMRSpinEOBCalculateSigmaKerr(&sKerr, mass1, mass2, &s1Vec, &s2Vec);
		XLALSimIMRSpinEOBCalculateSigmaStar(&sStar, mass1, mass2, &s1Vec, &s2Vec);

		/*
		 * The a in the flux has been set to zero, but not in the
		 * Hamiltonian
		 */
		a = sqrt(sKerr.data[0] * sKerr.data[0] + sKerr.data[1] * sKerr.data[1] + sKerr.data[2] * sKerr.data[2]);
		//XLALSimIMREOBCalcSpinPrecFacWaveformCoefficients(params->eobParams->hCoeffs, mass1, mass2, eta, /* a */ 0.0, chiS, chiA);
		//XLALSimIMRCalculateSpinPrecEOBHCoeffs(params->seobCoeffs, eta, a);
		ham = XLALSimIMRSpinPrecEOBHamiltonian(eta, &qCartVec, &pCartVec, &s1VecNorm, &s2VecNorm, &sKerr, &sStar, params->tortoise, params->seobCoeffs);

		if (printPK)
			XLAL_PRINT_INFO("Stas: hamiltonian in ICs at this point is %.16e\n", ham);

		/* And now, finally, the flux */
		REAL8Vector	polarDynamics, cartDynamics;
		REAL8		polarData[4], cartData[12];

		polarDynamics.length = 4;
		polarDynamics.data = polarData;

		polarData[0] = qSph[0];
		polarData[1] = 0.;
		polarData[2] = pSph[0];
		polarData[3] = pSph[2];

		cartDynamics.length = 12;
		cartDynamics.data = cartData;

		memcpy(cartData, qCart, 3 * sizeof(REAL8));
		memcpy(cartData + 3, pCart, 3 * sizeof(REAL8));
		memcpy(cartData + 6, tmpS1Norm, 3 * sizeof(REAL8));
		memcpy(cartData + 9, tmpS2Norm, 3 * sizeof(REAL8));

		//XLAL_PRINT_INFO("Stas: starting FLux calculations\n");

		flux = XLALInspiralPrecSpinFactorizedFlux(&polarDynamics, &cartDynamics, nqcCoeffs, omega, params, ham, lMax, SpinAlignedEOBversion);
		/*
		 * flux  = XLALInspiralSpinFactorizedFlux( &polarDynamics,
		 * nqcCoeffs, omega, params, ham, lMax, SpinAlignedEOBversion
		 * );
		 */
		//XLAL_PRINT_INFO("Stas flux = %.16e \n", flux);
		//exit(0);
		flux = flux / eta;

		rDot = -flux / dEdr;
		if (debugPK) {
			XLAL_PRINT_INFO("Stas here I am 2  \n");
		}
		/*
		 * We now need dHdpr - we take it that it is safely linear up
		 * to a pr of 1.0e-3 PK: Ideally, the pr should be of the
		 * order of other momenta, in order for its contribution to
		 * the Hamiltonian to not get buried in the numerical noise
		 * in the numerically larger momenta components
		 */
		cartValues[3] = 1.0e-3;
		for (i = 0; i < 3; i++) {
			cartValues[i + 6] /= mTotal * mTotal;
			cartValues[i + 9] /= mTotal * mTotal;
		}
        oldignoreflux = params->ignoreflux;
        params->ignoreflux = 1;
        params->seobCoeffs->updateHCoeffs = 1;
		status = XLALSpinPrecHcapNumericalDerivative(0, cartValues, tmpDValues, params);
        params->ignoreflux = oldignoreflux;
		for (i = 0; i < 3; i++) {
			cartValues[i + 6] *= mTotal * mTotal;
			cartValues[i + 9] *= mTotal * mTotal;
		}
        REAL8		csi = sqrt(XLALSimIMRSpinPrecEOBHamiltonianDeltaT(params->seobCoeffs, qSph[0], eta, a)*XLALSimIMRSpinPrecEOBHamiltonianDeltaR(params->seobCoeffs, qSph[0], eta, a)) / (qSph[0] * qSph[0] + a * a);

		dHdpr = csi*tmpDValues[0];
		//XLALSpinPrecHcapNumDerivWRTParam(3, cartValues, params);

		if (debugPK) {
			XLAL_PRINT_INFO("Ingredients going into prDot:\n");
			XLAL_PRINT_INFO("flux = %.16e, dEdr = %.16e, dHdpr = %.16e, dHdpr/pr = %.16e\n", flux, dEdr, dHdpr, dHdpr / cartValues[3]);
		}
		/*
		 * We can now calculate what pr should be taking into account
		 * the flux
		 */
		pSph[0] = rDot / (dHdpr / cartValues[3]);
	} else {
		/*
		 * Since d2Hdr2 has evaluated to zero, we cannot do the
		 * above. Just set pr to zero
		 */
		//XLAL_PRINT_INFO("d2Hdr2 is zero!\n");
		pSph[0] = 0;
	}

	/* Now we are done - convert back to cartesian coordinates ) */
	SphericalToCartesianPrec(qCart, pCart, qSph, pSph);

	/*
	 * STEP 5) Rotate back to the original inertial frame by inverting
	 * the rotation of STEP 3 and then  inverting the rotation of STEP 1.
	 */

	/* Undo rotations to get back to the original basis */
	/* Second rotation */
	ApplyRotationMatrixPrec(invMatrix2, rHat);
	ApplyRotationMatrixPrec(invMatrix2, vHat);
	ApplyRotationMatrixPrec(invMatrix2, LnHat);
	ApplyRotationMatrixPrec(invMatrix2, tmpS1);
	ApplyRotationMatrixPrec(invMatrix2, tmpS2);
	ApplyRotationMatrixPrec(invMatrix2, tmpS1Norm);
	ApplyRotationMatrixPrec(invMatrix2, tmpS2Norm);
	ApplyRotationMatrixPrec(invMatrix2, qCart);
	ApplyRotationMatrixPrec(invMatrix2, pCart);

	/* First rotation */
	ApplyRotationMatrixPrec(invMatrix, rHat);
	ApplyRotationMatrixPrec(invMatrix, vHat);
	ApplyRotationMatrixPrec(invMatrix, LnHat);
	ApplyRotationMatrixPrec(invMatrix, tmpS1);
	ApplyRotationMatrixPrec(invMatrix, tmpS2);
	ApplyRotationMatrixPrec(invMatrix, tmpS1Norm);
	ApplyRotationMatrixPrec(invMatrix, tmpS2Norm);
	ApplyRotationMatrixPrec(invMatrix, qCart);
	ApplyRotationMatrixPrec(invMatrix, pCart);

        gsl_matrix_free(invMatrix);
        gsl_matrix_free(invMatrix2);

        /* If required, apply the tortoise transform */
	if (tmpTortoise) {
		REAL8		r = sqrt(qCart[0] * qCart[0] + qCart[1] * qCart[1] + qCart[2] * qCart[2]);
		REAL8		deltaR = XLALSimIMRSpinPrecEOBHamiltonianDeltaR(params->seobCoeffs, r, eta, a);
		REAL8		deltaT = XLALSimIMRSpinPrecEOBHamiltonianDeltaT(params->seobCoeffs, r, eta, a);
		REAL8		csi = sqrt(deltaT * deltaR) / (r * r + a * a);

		REAL8		pr = (qCart[0] * pCart[0] + qCart[1] * pCart[1] + qCart[2] * pCart[2]) / r;

		params->tortoise = tmpTortoise;

		if (debugPK) {
			XLAL_PRINT_INFO("Applying the tortoise to p (csi = %.26e)\n", csi);
			XLAL_PRINT_INFO("pCart = %3.10f %3.10f %3.10f\n", pCart[0], pCart[1], pCart[2]);
		}
		for (i = 0; i < 3; i++) {
			pCart[i] = pCart[i] + qCart[i] * pr * (csi - 1.) / r;
		}
	}


    /* Now copy the initial conditions back to the return vector */
	memcpy(initConds->data, qCart, sizeof(qCart));
	memcpy(initConds->data + 3, pCart, sizeof(pCart));
	memcpy(initConds->data + 6, tmpS1Norm, sizeof(tmpS1Norm));
	memcpy(initConds->data + 9, tmpS2Norm, sizeof(tmpS2Norm));

    for (i=0; i<12; i++) {
        if (fabs(initConds->data[i]) <=1.0e-15) {
            initConds->data[i] = 0.;
        }
    }

	if (debugPK) {
		XLAL_PRINT_INFO("THE FINAL INITIAL CONDITIONS:\n");
		XLAL_PRINT_INFO(" %.16e %.16e %.16e\n%.16e %.16e %.16e\n%.16e %.16e %.16e\n%.16e %.16e %.16e\n", initConds->data[0], initConds->data[1], initConds->data[2],
		       initConds->data[3], initConds->data[4], initConds->data[5], initConds->data[6], initConds->data[7], initConds->data[8],
		       initConds->data[9], initConds->data[10], initConds->data[11]);
	}
	return XLAL_SUCCESS;
}
/**
 * Wrapper for calculating specific derivative of the Hamiltonian in spherical co-ordinates,
 * dH/dr, dH/dptheta and dH/dpphi.
 * It only works for the specific co-ord system we use here
 */
static double
GSLSpinHamiltonianDerivWrapperPrec(double x,	/**<< Derivative at x */
			       void *params /**<< Function parameters */ )
{
	int		debugPK = 0;
	HcapSphDeriv2Params *dParams = (HcapSphDeriv2Params *) params;
	REAL8		mTotal = dParams->params->eobParams->m1 + dParams->params->eobParams->m2;

	REAL8		sphValues[12];
	REAL8		cartValues[12];

	REAL8		dHdr    , dHdx, dHdpy, dHdpz;
	REAL8		r       , ptheta, pphi;

	memcpy(sphValues, dParams->sphValues, sizeof(sphValues));
	sphValues[dParams->varyParam1] = x;

	SphericalToCartesianPrec(cartValues, cartValues + 3, sphValues, sphValues + 3);
	memcpy(cartValues + 6, sphValues + 6, 6 * sizeof(REAL8));

	r = sphValues[0];
	ptheta = sphValues[4];
	pphi = sphValues[5];

	/* New code to compute derivatives w.r.t. cartesian variables */
	REAL8		tmpDValues[14];
	int UNUSED	status;
	for (int i = 0; i < 3; i++) {
		cartValues[i + 6] /= mTotal * mTotal;
		cartValues[i + 9] /= mTotal * mTotal;
	}
    UINT4 oldignoreflux = dParams->params->ignoreflux;
    dParams->params->ignoreflux = 1;
	status = XLALSpinPrecHcapNumericalDerivative(0, cartValues, tmpDValues, dParams->params);
    dParams->params->ignoreflux = oldignoreflux;
	for (int i = 0; i < 3; i++) {
		cartValues[i + 6] *= mTotal * mTotal;
		cartValues[i + 9] *= mTotal * mTotal;
	}

	double		rvec    [3] = {cartValues[0], cartValues[1], cartValues[2]};
	double		pvec    [3] = {cartValues[3], cartValues[4], cartValues[5]};
	double		chi1vec [3] = {cartValues[6], cartValues[7], cartValues[8]};
	double		chi2vec [3] = {cartValues[9], cartValues[10], cartValues[11]};
	double		Lvec    [3] = {CalculateCrossProductPrec(0, rvec, pvec), CalculateCrossProductPrec(1, rvec, pvec), CalculateCrossProductPrec(2, rvec, pvec)};
	double		theta1 = acos(CalculateDotProductPrec(chi1vec, Lvec) / sqrt(CalculateDotProductPrec(chi1vec, chi1vec)) / sqrt(CalculateDotProductPrec(Lvec, Lvec)));
	double		theta2 = acos(CalculateDotProductPrec(chi2vec, Lvec) / sqrt(CalculateDotProductPrec(chi2vec, chi2vec)) / sqrt(CalculateDotProductPrec(Lvec, Lvec)));
	if (debugPK) {
		XLAL_PRINT_INFO("In GSLSpinHamiltonianDerivWrapperPrec");
		XLAL_PRINT_INFO("rvec = %.16e %.16e %.16e\n", rvec[0], rvec[1], rvec[2]);
		XLAL_PRINT_INFO("pvec = %.16e %.16e %.16e\n", pvec[0], pvec[1], pvec[2]);
		XLAL_PRINT_INFO("theta1 = %.16e\n", theta1);
		XLAL_PRINT_INFO("theta2 = %.16e\n", theta2);
	}
	if (theta1 > 1.0e-6 && theta2 >= 1.0e-6) {
		switch (dParams->varyParam2) {
		case 0:
			/* dHdr */
			dHdx = -tmpDValues[3];
			//XLALSpinPrecHcapNumDerivWRTParam(0, cartValues, dParams->params);
			dHdpy = tmpDValues[1];
			//XLALSpinPrecHcapNumDerivWRTParam(4, cartValues, dParams->params);
			dHdpz = tmpDValues[2];
			//XLALSpinPrecHcapNumDerivWRTParam(5, cartValues, dParams->params);

			dHdr = dHdx - dHdpy * pphi / (r * r) + dHdpz * ptheta / (r * r);
			//XLAL_PRINT_INFO("dHdr = %.16e\n", dHdr);
			return dHdr;

			break;
		case 4:
			/* dHdptheta */
			dHdpz = tmpDValues[2];
			//XLALSpinPrecHcapNumDerivWRTParam(5, cartValues, dParams->params);
			return -dHdpz / r;
			break;
		case 5:
			/* dHdpphi */
			dHdpy = tmpDValues[1];
			//XLALSpinPrecHcapNumDerivWRTParam(4, cartValues, dParams->params);
			return dHdpy / r;
			break;
		default:
			XLALPrintError("This option is not supported in the second derivative function!\n");
			XLAL_ERROR_REAL8(XLAL_EINVAL);
			break;
		}
	} else {
		switch (dParams->varyParam2) {
		case 0:
			/* dHdr */
			dHdx = XLALSpinPrecHcapNumDerivWRTParam(0, cartValues, dParams->params);
			dHdpy = XLALSpinPrecHcapNumDerivWRTParam(4, cartValues, dParams->params);
			dHdpz = XLALSpinPrecHcapNumDerivWRTParam(5, cartValues, dParams->params);

			dHdr = dHdx - dHdpy * pphi / (r * r) + dHdpz * ptheta / (r * r);
			//XLAL_PRINT_INFO("dHdr = %.16e\n", dHdr);
			return dHdr;

			break;
		case 4:
			/* dHdptheta */
			dHdpz = XLALSpinPrecHcapNumDerivWRTParam(5, cartValues, dParams->params);
			return -dHdpz / r;
			break;
		case 5:
			/* dHdpphi */
			dHdpy = XLALSpinPrecHcapNumDerivWRTParam(4, cartValues, dParams->params);
			return dHdpy / r;
			break;
		default:
			XLALPrintError("This option is not supported in the second derivative function!\n");
			XLAL_ERROR_REAL8(XLAL_EINVAL);
			break;
		}
	}
}
/**
 * Root function for gsl root finders.
 * The gsl root finder will look for gsl_vector *x position in parameter space
 * where the returned values in gsl_vector *f are zero.
 * The functions on which we search for roots are:
 * dH/dr, dH/dptheta and dH/dpphi-omega,
 * namely, Eqs. 4.8 and 4.9 of Buonanno et al. PRD 74, 104005 (2006).
 */
static int
XLALFindSphericalOrbitPrec(
          const gsl_vector * x,	/**<< Parameters requested by gsl root finder */
		      void *params,	        /**<< Spin EOB parameters */
		      gsl_vector * f	      /**<< Function values for the given parameters*/
)
{
	int		debugPK = 0;
	SEOBRootParams *rootParams = (SEOBRootParams *) params;
	REAL8		mTotal = rootParams->params->eobParams->m1 + rootParams->params->eobParams->m2;
	if (debugPK)
		XLAL_PRINT_INFO("\n\nmtotal in XLALFindSphericalOrbitPrec = %f\n", (float)mTotal);

	REAL8		py      , pz, r, ptheta, pphi;

	/* Numerical derivative of Hamiltonian wrt given value */
	REAL8		dHdx    , dHdpy, dHdpz;
	REAL8		dHdr    , dHdptheta, dHdpphi;

	/* Populate the appropriate values */
	/* In the special theta=pi/2 phi=0 case, r is x */
	rootParams->values[0] = r =  gsl_vector_get(x, 0)/scale1;
	rootParams->values[4] = py = gsl_vector_get(x, 1)/scale2;
	rootParams->values[5] = pz = gsl_vector_get(x, 2)/scale3;

    if(isnan(rootParams->values[0])) {
        rootParams->values[0] = 100.;
    }
    if(isnan(rootParams->values[4])) {
        rootParams->values[4] = 0.1;
    }
    if(isnan(rootParams->values[5])) {
        rootParams->values[5] = 0.01;
    }
	if (debugPK) {
    XLAL_PRINT_INFO("%3.10f %3.10f %3.10f %3.10f %3.10f %3.10f\n",
      rootParams->values[0], rootParams->values[1], rootParams->values[2],
      rootParams->values[3], rootParams->values[4], rootParams->values[5]);
    XLAL_PRINT_INFO("Values r = %.16e, py = %.16e, pz = %.16e\n", r, py, pz);
    fflush(NULL);
  }

	ptheta = -r * pz;
	pphi = r * py;

	if (debugPK)
		XLAL_PRINT_INFO("Input Values r = %.16e, py = %.16e, pz = %.16e\n pthetha = %.16e pphi = %.16e\n", r, py, pz, ptheta, pphi);

	/* dH by dR and dP */
	REAL8		tmpDValues[14];
	int UNUSED	status;
	for (int i = 0; i < 3; i++) {
		rootParams->values[i + 6] /= mTotal * mTotal;
		rootParams->values[i + 9] /= mTotal * mTotal;
	}
    UINT4 oldignoreflux = rootParams->params->ignoreflux;
    rootParams->params->ignoreflux = 1;
	status = XLALSpinPrecHcapNumericalDerivative(0, rootParams->values, tmpDValues, rootParams->params);
    rootParams->params->ignoreflux = oldignoreflux;
	for (int i = 0; i < 3; i++) {
		rootParams->values[i + 6] *= mTotal * mTotal;
		rootParams->values[i + 9] *= mTotal * mTotal;
	}
	REAL8	rvec[3] =
        {rootParams->values[0], rootParams->values[1], rootParams->values[2]};
	REAL8	pvec[3] =
        {rootParams->values[3], rootParams->values[4], rootParams->values[5]};
	REAL8	chi1vec[3] =
        {rootParams->values[6], rootParams->values[7], rootParams->values[8]};
	REAL8	chi2vec[3] =
        {rootParams->values[9], rootParams->values[10], rootParams->values[11]};
	REAL8	Lvec[3] = {CalculateCrossProductPrec(0, rvec, pvec),
    CalculateCrossProductPrec(1, rvec, pvec), CalculateCrossProductPrec(2, rvec, pvec)};
	REAL8	theta1 = acos(CalculateDotProductPrec(chi1vec, Lvec)
                / sqrt(CalculateDotProductPrec(chi1vec, chi1vec))
                / sqrt(CalculateDotProductPrec(Lvec, Lvec)));
	REAL8	theta2 = acos(CalculateDotProductPrec(chi2vec, Lvec)
                / sqrt(CalculateDotProductPrec(chi2vec, chi2vec))
                / sqrt(CalculateDotProductPrec(Lvec, Lvec)));

  if (debugPK) {
		XLAL_PRINT_INFO("rvec = %.16e %.16e %.16e\n", rvec[0], rvec[1], rvec[2]);
		XLAL_PRINT_INFO("pvec = %.16e %.16e %.16e\n", pvec[0], pvec[1], pvec[2]);
		XLAL_PRINT_INFO("theta1 = %.16e\n", theta1);
		XLAL_PRINT_INFO("theta2 = %.16e\n", theta2);
	}

  if (theta1 > 1.0e-6 && theta2 >= 1.0e-6) {
		dHdx = -tmpDValues[3];
		dHdpy = tmpDValues[1];
		dHdpz = tmpDValues[2];
	} else {
		//rootParams->values[5] = 0.;
		//rootParams->values[6] = 0.;
		//rootParams->values[7] = 0.;
		//rootParams->values[8] = sqrt(CalculateDotProductPrec(chi1vec, chi1vec));
    //rootParams->values[9] = 0.;
		//rootParams->values[10]= 0.;
		//rootParams->values[11]= sqrt(CalculateDotProductPrec(chi2vec, chi2vec));

		dHdx = XLALSpinPrecHcapNumDerivWRTParam(0,
                  rootParams->values, rootParams->params);
		dHdpy = XLALSpinPrecHcapNumDerivWRTParam(4,
                  rootParams->values, rootParams->params);
		dHdpz = XLALSpinPrecHcapNumDerivWRTParam(5,
                  rootParams->values, rootParams->params);
	}

	if (XLAL_IS_REAL8_FAIL_NAN(dHdx)) { XLAL_ERROR(XLAL_EDOM); }
	if (XLAL_IS_REAL8_FAIL_NAN(dHdpy)) { XLAL_ERROR(XLAL_EDOM); }
	if (XLAL_IS_REAL8_FAIL_NAN(dHdpz)) { XLAL_ERROR(XLAL_EDOM); }
	if (debugPK)
		XLAL_PRINT_INFO("dHdx = %.16e, dHdpy = %.16e, dHdpz = %.16e\n", dHdx, dHdpy, dHdpz);

	/* Now convert to spherical polars */
	dHdr      = dHdx - dHdpy * pphi / (r * r) + dHdpz * ptheta / (r * r);
	dHdptheta = -dHdpz / r;
	dHdpphi   = dHdpy / r;

	if (debugPK)
		XLAL_PRINT_INFO("dHdr = %.16e dHdptheta = %.16e dHdpphi = %.16e\n",
            dHdr, dHdptheta, dHdpphi);
	/* populate the function vector */
	gsl_vector_set(f, 0, dHdr);
	gsl_vector_set(f, 1, dHdptheta);
	gsl_vector_set(f, 2, dHdpphi - rootParams->omega);

	if (debugPK)
		XLAL_PRINT_INFO("Current funcvals = %.16e %.16e %.16e\n",
        gsl_vector_get(f, 0), gsl_vector_get(f, 1), gsl_vector_get(f, 2) );

  /* Rescale back */
  rootParams->values[0] *= scale1;
  rootParams->values[4] *= scale2;
  rootParams->values[5] *= scale3;

	return XLAL_SUCCESS;
}
/**
 * @brief Advance a LALFrStream stream to the beginning of the next frame
 * @details
 * The position of a LALFrStream is advanced so that the next read will
 * be at the next frame.  If the stream is at the end, the #LAL_FR_STREAM_END
 * bit of the LALFrStreamState state is set, and the routine returns the
 * return code 1.  If there is a gap in the data before the next frame,
 * the #LAL_FR_STREAM_GAP bit of the LALFrStreamState state is set, and the
 * routine returns the return code 2.  If, however, the
 * #LAL_FR_STREAM_IGNOREGAP_MODE bit is not set in the LALFrStreamMode mode
 * then the routine produces an error if a gap is encountered.
 * @param stream Pointer to a #LALFrStream structure.
 * @retval 2 Gap in the data is encountered.
 * @retval 1 End of stream encountered.
 * @retval 0 Normal success.
 * @retval <0 Failure.
 */
int XLALFrStreamNext(LALFrStream * stream)
{
    /* timing accuracy: tenth of a sample interval for a 16kHz fast channel */
    const INT8 tacc = (INT8) floor(0.1 * 1e9 / 16384.0);
    const char *url1;
    const char *url2;
    int pos1;
    int pos2;
    INT8 texp = 0;
    INT8 tact;

    if (stream->state & LAL_FR_STREAM_END)
        return 1;       /* end code */

    /* turn off gap bit */
    stream->state &= ~LAL_FR_STREAM_GAP;

    url2 = url1 = stream->cache->list[stream->fnum].url;
    pos2 = pos1 = stream->pos;

    /* open a new file if necessary */
    if (!stream->file) {
        if (stream->fnum >= stream->cache->length) {
            stream->state |= LAL_FR_STREAM_END;
            return 1;
        }
        if (XLALFrStreamFileOpen(stream, stream->fnum) < 0)
            XLAL_ERROR(XLAL_EFUNC);
    }
    if (stream->file) {
        INT4 nFrame = XLALFrFileQueryNFrame(stream->file);
        if (stream->pos < nFrame) {
            LIGOTimeGPS gpstime;
            XLALGPSToINT8NS(XLALFrFileQueryGTime(&gpstime, stream->file,
                  stream->pos));
            texp =
                XLALGPSToINT8NS(XLALGPSAdd(&gpstime,
                    XLALFrFileQueryDt(stream->file, stream->pos)));
            ++stream->pos;
        }
        if (stream->pos >= nFrame) {
            XLALFrStreamFileClose(stream);
            ++stream->fnum;
        }
        pos2 = stream->pos;
    }
    /* open a new file if necessary */
    if (!stream->file) {
        if (stream->fnum >= stream->cache->length) {
            stream->state |= LAL_FR_STREAM_END;
            return 1;
        }
        if (XLALFrStreamFileOpen(stream, stream->fnum) < 0)
            XLAL_ERROR(XLAL_EFUNC);
        url2 = stream->cache->list[stream->fnum].url;
        pos2 = stream->pos;
    }
    /* compute actual start time of this new frame */
    tact =
        XLALGPSToINT8NS(XLALFrFileQueryGTime(&stream->epoch, stream->file,
            stream->pos));

    /* INT8 is platform dependent, cast to long long for llabs() call */
    if (llabs((long long)(texp - tact)) > tacc) { /* there is a gap */
        stream->state |= LAL_FR_STREAM_GAP;
        if (stream->mode & LAL_FR_STREAM_GAPINFO_MODE) {
            XLAL_PRINT_INFO("Gap in frame data between times %.6f and %.6f",
                1e-9 * texp, 1e-9 * tact);
        }
        if (!(stream->mode & LAL_FR_STREAM_IGNOREGAP_MODE)) {
            XLAL_PRINT_ERROR("Gap in frame data");
            XLAL_PRINT_ERROR("Time %.6f is end of frame %d of file %s",
                1e-9 * texp, pos1, url1);
            XLAL_PRINT_ERROR("Time %.6f is start of frame %d of file %s",
                1e-9 * tact, pos2, url2);
            XLAL_ERROR(XLAL_ETIME);
        }
        return 2;       /* gap code */
    }
    return 0;
}
double  XLALSimLocateOmegaTime(
    REAL8Array *dynamicsHi,
    unsigned int numdynvars,
    unsigned int retLenHi,
    SpinEOBParams   seobParams,
    SpinEOBHCoeffs  seobCoeffs,
    REAL8 m1,
    REAL8 m2,
    REAL8Vector *radiusVec,
    int *found,
    REAL8* tMaxOmega,
    INT4 use_optimized
    )
{
    *tMaxOmega = 0; //Zach E: Fixes Heisenbug with ICC 16 and 17 compilers (5181); removing this line will result in segfaults with both compilers.
    /*
    * Locate merger point (max omega),
    * WaveStep 1.1: locate merger point */
    int debugPK = 0;
    int debugRD = 0;
    FILE *out = NULL;
    gsl_spline    *spline = NULL;
    gsl_interp_accel *acc = NULL;

    if (debugPK) {debugRD = 0;}

    unsigned int peakIdx, i, j;
    REAL8Vector *values = NULL;
    REAL8Vector *dvalues = NULL;
    REAL8Vector *omegaHi = NULL;


    if ( !(values = XLALCreateREAL8Vector( numdynvars )) )
    {
        XLAL_ERROR(  XLAL_ENOMEM );
    }
    if ( !(dvalues = XLALCreateREAL8Vector( numdynvars )) )
    {
        XLAL_ERROR(  XLAL_ENOMEM );
    }
    if ( !(omegaHi = XLALCreateREAL8Vector( retLenHi )) )
    {
        XLAL_ERROR(  XLAL_ENOMEM );
    }
    REAL8 rdotvec[3] = {0,0,0};
    REAL8 rvec[3] = {0,0,0};
    REAL8 rcrossrdot[3] = {0,0,0};
    REAL8Vector timeHi;

    timeHi.length = retLenHi;
    timeHi.data = dynamicsHi->data;

    double dt = timeHi.data[1] - timeHi.data[0];
    double ddradiusVec[timeHi.length - 2];
    unsigned int k;
    for (k = 1; k < timeHi.length-1; k++) {
        ddradiusVec[k] = (radiusVec->data[k+1] - 2.*radiusVec->data[k] + radiusVec->data[k-1])/dt/dt;
        //        XLAL_PRINT_INFO("%3.10f %3.10f\n", timeHi->data[k], ddradiusVec[k]);
    }
    //    for (k = timeHi->length-3; k>=1; k--) {
    //        XLAL_PRINT_INFO("%3.10f %3.10f\n", timeHi->data[k], ddradiusVec[k]);
    //        if (ddradiusVec[k] < 0) {
    //            break;
    //        }
    //    }
    for (k = 0; k < timeHi.length-2; k++) {
        //        XLAL_PRINT_INFO("%3.10f %3.10f\n", timeHi->data[k], ddradiusVec[k]);
        if (dt*k > dt*( timeHi.length-2)-20 && ddradiusVec[k] > 0) {
            break;
        }
    }
    double minoff = dt*( timeHi.length-2 - k) > 0.2 ? dt*( timeHi.length-2 - k) : 0.2;
    if (debugPK) {
        XLAL_PRINT_INFO("Change of sign in ddr %3.10f M before the end\n", minoff );
    }
    // First we search for the maximum (extremum) of amplitude
    double maxoff = 20.0;
    unsigned int Nps = timeHi.length;
    // this definesthe search interval for maximum (we might use min0ff= 0.051 instead)
    double tMin  = timeHi.data[Nps-1] - maxoff;
    // FIXME
    // minoff = 0.0;
    double tMax = timeHi.data[Nps-1] - minoff;
    *tMaxOmega = tMax;
    tMin = tMax - 20.;
    if ( debugPK ) {
        XLAL_PRINT_INFO("tMin, tMax = %3.10f %3.10f\n", tMin, tMax);
    }

    double omega  = 0.0;

    double magR;
    double time1, time2, omegaDeriv, omegaDerivMid, tPeakOmega;

    if(debugPK) {
        out = fopen( "omegaHi.dat", "w" );
        XLAL_PRINT_INFO("length of values = %d, retLenHi = %d\n", values->length, retLenHi);
        fflush(NULL);
    }
    if(debugRD) {
        out = fopen( "omegaHi.dat", "w" );
    }

    for ( i = 0; i < retLenHi; i++ )
    {
        for ( j = 0; j < values->length; j++ )
            { values->data[j] = *(dynamicsHi->data+(j+1)*retLenHi+i); }

        /* Calculate dr/dt */
        memset( dvalues->data, 0, numdynvars*sizeof(dvalues->data[0]));
        if(use_optimized){
          if( XLALSpinPrecHcapRvecDerivative_exact( 0, values->data, dvalues->data,
                                              &seobParams) != XLAL_SUCCESS )
          {
                XLAL_PRINT_INFO(
                    " Calculation of dr/dt failed while computing omegaHi time series\n");
                XLAL_ERROR( XLAL_EFUNC );
          }
        } else {
          if( XLALSpinPrecHcapRvecDerivative( 0, values->data, dvalues->data,
                                              &seobParams) != XLAL_SUCCESS )
          {
                XLAL_PRINT_INFO(
                    " Calculation of dr/dt failed while computing omegaHi time series\n");
                XLAL_ERROR( XLAL_EFUNC );
          }
        }

        /* Calculare r x dr/dt */
        for (j=0; j<3; j++){
            rvec[j] = values->data[j];
            rdotvec[j] = dvalues->data[j];
        }

        //memcpy(rdotvec, dvalues->data, 3*sizeof(REAL8));
        //rvec[0] = posVecxHi.data[i]; rvec[1] = posVecyHi.data[i];
        //rvec[2] = posVeczHi.data[i];
        cross_product( rvec, rdotvec, rcrossrdot );

        /* Calculate omega = |r x dr/dt| / r*r */
        magR = sqrt(inner_product(rvec, rvec));
        omegaHi->data[i] = sqrt(inner_product(rcrossrdot, rcrossrdot)) / (magR*magR);
        if(debugPK || debugRD){
            fprintf( out, "%.16e\t%.16e\n", timeHi.data[i], omegaHi->data[i]);
        }
    }


    // Searching for crude omega_max (extremum)
    peakIdx = 0;
    *found = 0;
    for ( i = 1, peakIdx = 0; i < retLenHi-1; i++ ){
        omega = omegaHi->data[i];

        if (omega >= omegaHi->data[i-1] && omega > omegaHi->data[i+1] && tMax>=timeHi.data[i] && timeHi.data[i]>=tMin){
            peakIdx = i;
            *found = 1;
            if (debugPK){
                XLAL_PRINT_INFO("PK: Crude peak of Omega is at idx = %d. t = %f,  OmegaPeak = %.16e\n",
                    peakIdx, timeHi.data[peakIdx], omega);
                fflush(NULL);

            }
        }
    }

    if(debugPK) {
        fclose(out);
        if (peakIdx ==0){
            XLAL_PRINT_INFO("Stas: peak of orbital frequency was not found. peakIdx = %d, retLenHi = %d, i at exit = %d\n", peakIdx, retLenHi, i);
            fflush(NULL);
        }
    }
    if(debugRD) {
        fclose(out);
    }

    // refining the omega_max search (if it is found)
    tPeakOmega = 0.0;
    if(peakIdx != 0){
        spline = gsl_spline_alloc( gsl_interp_cspline, retLenHi );
        acc    = gsl_interp_accel_alloc();
        time1 = timeHi.data[peakIdx-2];
        gsl_spline_init( spline, timeHi.data, omegaHi->data, retLenHi );
        omegaDeriv = gsl_spline_eval_deriv( spline, time1, acc );

        if ( omegaDeriv > 0. ) { time2 = timeHi.data[peakIdx+2]; }
        else{
            time2 = time1;
            peakIdx = peakIdx-2;
	        time1 = timeHi.data[peakIdx-2];
	        omegaDeriv = gsl_spline_eval_deriv( spline, time1, acc );
        }

        do
        {
            tPeakOmega = ( time1 + time2 ) / 2.;
	        omegaDerivMid = gsl_spline_eval_deriv( spline, tPeakOmega, acc );

	        if ( omegaDerivMid * omegaDeriv < 0.0 ) { time2 = tPeakOmega; }
	        else
	        {
		        omegaDeriv = omegaDerivMid;
		        time1 = tPeakOmega;
		    }
            if (debugPK){
                XLAL_PRINT_INFO("Stas: searching for orbital max: %f, %f, %f, %f \n", time1, time2, omegaDeriv, omegaDerivMid);
            }
        } while ( time2 - time1 > 1.0e-5 );
        if(debugPK) {
          XLAL_PRINT_INFO( "Estimation of the orbital peak is now at time %.16e \n", tPeakOmega);
          fflush(NULL);
        }
    }

    if(*found == 0 || debugRD || debugPK){
        if(debugPK){
            XLAL_PRINT_INFO("Stas: We couldn't find the maximum of orbital frequency, search for maximum of A(r)/r^2 \n");
        }
        REAL8 rad, rad2, m1PlusetaKK, bulk, logTerms, deltaU, u, u2, u3, u4, u5;
        REAL8 listAOverr2[retLenHi];
        REAL8 Aoverr2;
        REAL8Vector *sigmaStar = NULL;
        REAL8Vector *sigmaKerr = NULL;
        if ( !(sigmaStar = XLALCreateREAL8Vector( 3 )) )
        {
          XLALDestroyREAL8Vector( sigmaStar );
          XLAL_ERROR( XLAL_ENOMEM );
        }
        if ( !(sigmaKerr = XLALCreateREAL8Vector( 3 )) )
        {
          XLALDestroyREAL8Vector( sigmaStar );
          XLAL_ERROR( XLAL_ENOMEM );
        }
        REAL8Vector s1Vec, s2Vec;
        s1Vec.length = s2Vec.length = 3;
        REAL8 s1Data[3], s2Data[3];
        REAL8 mTotal = m1 + m2;
        REAL8 a;
        REAL8 eta = m1*m2/(mTotal*mTotal);

        if(debugPK || debugRD){
            out = fopen( "OutAofR.dat", "w" );
        }
        for ( i = 0; i < retLenHi; i++ )
        {
            for ( j = 0; j < values->length; j++ )
            {
                values->data[j] = *(dynamicsHi->data+(j+1)*retLenHi+i);
            }
            for( j = 0; j < 3; j++ )
            {
                //s1DataNorm[k] = values->data[k+6];
                //s2DataNorm[k] = values->data[k+9];
                s1Data[j] = values->data[j+6] * mTotal * mTotal;
                s2Data[j] = values->data[j+9] * mTotal * mTotal;
            }
            s1Vec.data = s1Data;
            s2Vec.data = s2Data;
            XLALSimIMRSpinEOBCalculateSigmaStar( sigmaStar, m1, m2, &s1Vec, &s2Vec );
            XLALSimIMRSpinEOBCalculateSigmaKerr( sigmaKerr, m1, m2, &s1Vec, &s2Vec );

            seobParams.a = a = sqrt(inner_product(sigmaKerr->data, sigmaKerr->data));
            m1PlusetaKK = -1. + eta * seobCoeffs.KK;
            rad2 =  values->data[0]*values->data[0] + values->data[1]*values->data[1] + values->data[2]*values->data[2];
            rad = sqrt(rad2);
            u = 1./rad;
            u2 = u*u;
            u3 = u2*u;
            u4 = u2*u2;
            u5 = u4*u;
            bulk = 1./(m1PlusetaKK*m1PlusetaKK) + (2.*u)/m1PlusetaKK + a*a*u2;
            logTerms = 1. + eta*seobCoeffs.k0 + eta*log(1. + seobCoeffs.k1*u + seobCoeffs.k2*u2 + seobCoeffs.k3*u3 + seobCoeffs.k4*u4 + seobCoeffs.k5*u5 + seobCoeffs.k5l*u5*log(u));
            deltaU = bulk*logTerms;
            listAOverr2[i] = deltaU / rad2;
            if(debugPK || debugRD){
                fprintf(out, "%3.10f %3.10f\n", timeHi.data[i], listAOverr2[i]);
            }

        }
        if(debugPK || debugRD ) fclose(out);
        if (*found == 0){
            // searching formaximum of A(r)/r^2
            peakIdx = 0;
            //*found = 0;
            for ( i = 1, peakIdx = 0; i < retLenHi-1; i++ ){
                Aoverr2 = listAOverr2[i];
                if (Aoverr2 >= listAOverr2[i-1] && Aoverr2 > listAOverr2[i+1]){
                    if (timeHi.data[i] > tMin){
                        peakIdx = i;
                        tPeakOmega = timeHi.data[i];
                        *found = 1;
                        if (debugPK){
                            XLAL_PRINT_INFO("PK: Peak of A(r)/r^2 is at idx = %d. t = %f, Peak ampl. = %.16e\n",
                                peakIdx, timeHi.data[peakIdx], Aoverr2);
                            fflush(NULL);
                        }
                        break;
                    }
                }
            }
        }

        if(debugPK) {
            if (peakIdx ==0){
                XLAL_PRINT_INFO("Stas: peak of A(r)/r^2 was not found. \
                    peakIdx = %d, retLenHi = %d, i at exit = %d\n", peakIdx, retLenHi, i);
                fflush(NULL);
            }
        }
        XLALDestroyREAL8Vector(sigmaStar);
        XLALDestroyREAL8Vector(sigmaKerr);
    }
static REAL8
XLALInspiralPrecSpinFactorizedFlux(
				   REAL8Vector * polvalues,	/**< \f$(r,\phi,p_r,p_\phi)\f$ */
				   REAL8Vector * values,	/**< dynamical variables */
				   EOBNonQCCoeffs * nqcCoeffs,	/**< pre-computed NQC coefficients */
				   const REAL8 omega,	/**< orbital frequency */
				   SpinEOBParams * ak,	/**< physical parameters */
				   const REAL8 H,	/**< real Hamiltonian */
				   const INT4 lMax,	/**< upper limit of the summation over l */
				   const UINT4 SpinAlignedEOBversion	/**< 1 for SEOBNRv1, 2 for SEOBNRv2 */
)
{
	int		debugPK = 0;
  int i = 0;
    double radius = sqrt(values->data[0]*values->data[0] + values->data[1] *values->data[1]  + values->data[2] *values->data[2]  );
    if (radius < 1.) {
        return 0.;
    }
  if (1){
    for( i =0; i < 4; i++)
      if( isnan(polvalues->data[i]) ) {
          XLAL_PRINT_INFO("XLALInspiralPrecSpinFactorizedFlux (from input)::polvalues %3.10f %3.10f %3.10f %3.10f\n", polvalues->data[0], polvalues->data[1], polvalues->data[2], polvalues->data[3]);
          XLALPrintError( "XLAL Error - %s: nan polvalues:  %3.10f %3.10f %3.10f %3.10f  \n", __func__, polvalues->data[0], polvalues->data[1], polvalues->data[2], polvalues->data[3] );
          XLAL_ERROR( XLAL_EINVAL );
      }

    for( i =0; i < 12; i++)
      if( isnan(values->data[i]) ) {
        XLAL_PRINT_INFO("XLALInspiralPrecSpinFactorizedFlux (from input)::values %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f\n", values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6], values->data[7], values->data[8], values->data[9], values->data[10], values->data[11]);
          XLALPrintError( "XLAL Error - %s: nan  in input values:  %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f  \n", __func__,  values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6], values->data[7], values->data[8], values->data[9], values->data[10], values->data[11] );
          XLAL_ERROR( XLAL_EINVAL );
      }
  }

	REAL8		flux = 0.0;
	REAL8		v;
	REAL8		omegaSq;
	COMPLEX16	hLM;
	INT4		l        , m;

	//EOBNonQCCoeffs nqcCoeffs;

#ifndef LAL_NDEBUG
	if (!values || !ak) {
		XLAL_ERROR_REAL8(XLAL_EFAULT);
	}
#endif

	if (lMax < 2) {
		XLAL_ERROR_REAL8(XLAL_EINVAL);
	}
	/* Omega is the derivative of phi */
	omegaSq = omega * omega;

	v = cbrt(omega);

	/* Update the factorized multipole coefficients, w.r.t. new spins */
	if (0) {		/* {{{ */
		XLAL_PRINT_INFO("\nValues inside Flux:\n");
		for (i = 0; i < 11; i++)
			XLAL_PRINT_INFO("values[%d] = %.12e\n", i, values->data[i]);
		/*
		 * Assume that initial conditions are available at this
		 * point, to compute the chiS and chiA parameters. Calculate
		 * the values of chiS and chiA, as given in Eq.16 of
		 * Precessing EOB paper Pan et.al. arXiv:1307.6232 (or PRD 89, 084006 (2014)). Assuming \vec{L} to be pointing in
		 * the direction of \vec{r}\times\vec{p}
		 */
		REAL8		rcrossp  [3], rcrosspMag, s1dotL, s2dotL;
		REAL8		chiS    , chiA, tplspin;

		rcrossp[0] = values->data[1] * values->data[5] - values->data[2] * values->data[4];
		rcrossp[1] = values->data[2] * values->data[3] - values->data[0] * values->data[5];
		rcrossp[2] = values->data[0] * values->data[4] - values->data[1] * values->data[3];
		rcrosspMag = sqrt(rcrossp[0] * rcrossp[0] + rcrossp[1] * rcrossp[1] +
				  rcrossp[2] * rcrossp[2]);

		rcrossp[0] /= rcrosspMag;
		rcrossp[1] /= rcrosspMag;
		rcrossp[2] /= rcrosspMag;

		s1dotL = values->data[6] * rcrossp[0] + values->data[7] * rcrossp[1]
			+ values->data[8] * rcrossp[2];
		s2dotL = values->data[9] * rcrossp[0] + values->data[10] * rcrossp[1]
			+ values->data[11] * rcrossp[2];

		chiS = 0.5 * (s1dotL + s2dotL);
		chiA = 0.5 * (s1dotL - s2dotL);

		/*
		 * Compute the test-particle limit spin of the deformed-Kerr
		 * background
		 */
		switch (SpinAlignedEOBversion) {
		case 1:
			tplspin = 0.0;
			break;
		case 2:
			tplspin = (1. - 2. * ak->eobParams->eta) * chiS + (ak->eobParams->m1
									   - ak->eobParams->m2) / (ak->eobParams->m1 + ak->eobParams->m2) * chiA;
			break;
		default:
			XLALPrintError("XLAL Error - %s: Unknown SEOBNR version!\nAt present only v1 and v2 are available.\n", __func__);
			XLAL_ERROR(XLAL_EINVAL);
			break;
		}

		/* ************************************************* */
		/* Re-Populate the Waveform structures               */
		/* ************************************************* */

		/* Re-compute the spinning coefficients for hLM */
		//debugPK
			XLAL_PRINT_INFO("Re-calculating waveform coefficients in the Flux function with chiS, chiA = %e, %e!\n", chiS, chiA);
		chiS = 0.3039435650957116;
		chiA = -0.2959424290852973;
		XLAL_PRINT_INFO("Changed them to the correct values = %e, %e!\n", chiS, chiA);

        if (ak->alignedSpins==1) {
		if (XLALSimIMREOBCalcSpinPrecFacWaveformCoefficients(ak->eobParams->hCoeffs,
		   ak->eobParams->m1, ak->eobParams->m2, ak->eobParams->eta,
								 tplspin, chiS, chiA, SpinAlignedEOBversion) == XLAL_FAILURE) {
			XLALDestroyREAL8Vector(values);
			XLAL_ERROR(XLAL_EFUNC);
		}
        }
        else {
            if (XLALSimIMREOBCalcSpinPrecFacWaveformCoefficients(ak->eobParams->hCoeffs,
                                                             ak->eobParams->m1, ak->eobParams->m2, ak->eobParams->eta,
                                                             tplspin, chiS, chiA, 3) == XLAL_FAILURE) {
                XLALDestroyREAL8Vector(values);
                XLAL_ERROR(XLAL_EFUNC);
            }
        }
	}			/* }}} */
	//XLAL_PRINT_INFO("v = %.16e\n", v);
	COMPLEX16 hLMTab[lMax+1][lMax+1];
	if (XLALSimIMRSpinEOBFluxGetPrecSpinFactorizedWaveform(&hLMTab[0][0], polvalues, values, v, H,
				lMax, ak) == XLAL_FAILURE) {
		XLAL_ERROR_REAL8(XLAL_EFUNC);
	}
	for (l = 2; l <= lMax; l++) {

		for (m = 1; m <= l; m++) {

			if (debugPK)
				XLAL_PRINT_INFO("\nGetting (%d, %d) mode for flux!\n", l, m);
			//XLAL_PRINT_INFO("Stas, computing the waveform l = %d, m =%d\n", l, m);
			hLM = hLMTab[l][m];
			//XLAL_PRINT_INFO("Stas: done\n");
			/*
			 * For the 2,2 mode, we apply NQC correction to the
			 * flux
			 */
			if (l == 2 && m == 2) {
				COMPLEX16	hNQC;
				/*
				 * switch ( SpinAlignedEOBversion ) { case 1:
				 * XLALSimIMRGetEOBCalibratedSpinNQC(
				 * &nqcCoeffs, l, m, ak->eobParams->eta,
				 * ak->a ); break; case 2: //
				 * XLALSimIMRGetEOBCalibratedSpinNQCv2(
				 * &nqcCoeffs, l, m, ak->eobParams->eta,
				 * ak->a );
				 * XLALSimIMRGetEOBCalibratedSpinNQC3D(
				 * &nqcCoeffs, l, m, ak->eobParams->eta,
				 * ak->a, (ak->chi1 - ak->chi2)/2. ); break;
				 * default: XLALPrintError( "XLAL Error - %s:
				 * Unknown SEOBNR version!\nAt present only
				 * v1 and v2 are available.\n", __func__);
				 * XLAL_ERROR( XLAL_EINVAL ); break; }
				 */
				if (debugPK)
					XLAL_PRINT_INFO("\tl = %d, m = %d, NQC: a1 = %.16e, a2 = %.16e, a3 = %.16e, a3S = %.16e, a4 = %.16e, a5 = %.16e\n\tb1 = %.16e, b2 = %.16e, b3 = %.16e, b4 = %.16e\n",
					       2, 2, nqcCoeffs->a1, nqcCoeffs->a2, nqcCoeffs->a3, nqcCoeffs->a3S, nqcCoeffs->a4, nqcCoeffs->a5,
					       nqcCoeffs->b1, nqcCoeffs->b2, nqcCoeffs->b3, nqcCoeffs->b4);
				XLALSimIMREOBNonQCCorrection(&hNQC, polvalues, omega, nqcCoeffs);
				if (debugPK)
					XLAL_PRINT_INFO("\tl = %d, m = %d, hNQC = %.16e + i%.16e, |hNQC| = %.16e\n", l, m,
					       creal(hNQC), cimag(hNQC), sqrt(creal(hNQC) * creal(hNQC) + cimag(hLM) * cimag(hLM)));

      if((m * m) * omegaSq * (creal(hLM) * creal(hLM) + cimag(hLM) * cimag(hLM)) > 5.) {

		XLAL_PRINT_INFO("\tl = %d, m = %d, mag(hLM) = %.17e, mag(hNQC) = %.17e, omega = %.16e\n",
          l, m, sqrt(creal(hLM) * creal(hLM) + cimag(hLM) * cimag(hLM)),
          sqrt(creal(hNQC) * creal(hNQC) + cimag(hNQC) * cimag(hNQC)), omega);

      XLAL_PRINT_INFO("XLALInspiralPrecSpinFactorizedFlux (from input)::values %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f %3.10f\n", values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6], values->data[7], values->data[8], values->data[9], values->data[10], values->data[11]);
    }

				/* Eq. 16 */
				//FIXME
					hLM *= hNQC;
			}
			if (debugPK)
				XLAL_PRINT_INFO("\tl = %d, m = %d, mag(hLM) = %.17e, omega = %.16e\n", l, m, sqrt(creal(hLM) * creal(hLM) + cimag(hLM) * cimag(hLM)), omega);

			/* Eq. 13 */
			flux += (REAL8) (m * m) * omegaSq * (creal(hLM) * creal(hLM) + cimag(hLM) * cimag(hLM));
		}
	}
    if( (omegaSq > 1 || flux > 5) ) {
        if(debugPK) {
            XLAL_PRINT_INFO("In XLALInspiralPrecSpinFactorizedFlux: omegaSq = %3.12f, FLUX = %3.12f, r = %3.12f\n",
                   omegaSq, flux,radius);
        }
        flux = 0.;
    }

	if (debugPK)
		XLAL_PRINT_INFO("\tStas, FLUX = %.16e\n", flux * LAL_1_PI / 8.0);
	return flux * LAL_1_PI / 8.0;
}