diff --git a/lalinference/lib/LALInferenceInitCBC.c b/lalinference/lib/LALInferenceInitCBC.c
index d8429e738cf1e8d9b110bf2d8174c6632aac119b..2b934c1e156ee898872a802ea863092615c8e1cb 100644
--- a/lalinference/lib/LALInferenceInitCBC.c
+++ b/lalinference/lib/LALInferenceInitCBC.c
@@ -756,6 +756,9 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
     (--no-detector-frame)              model will NOT use detector-centred coordinates and instead RA,dec\n\
     (--grtest-parameters dchi0,..,dxi1,..,dalpha1,..) template will assume deformations in the corresponding phase coefficients.\n\
     (--ppe-parameters aPPE1,....     template will assume the presence of an arbitrary number of PPE parameters. They must be paired correctly.\n\
+    (--phenomXHMMband float)     Threshold parameter for the Multibanding of IMRPhenomXHM. By default set to 10^-4. If set to 0 then do not use multibanding.\n\
+    (--modesList string)         List of modes to be used by the model, e.g. modeList=\"2,2, 2,-2, 2,1, 2,-1\". \n\
+                                 To use all the modes available in the mode do not add --modesList. Do not use if you do not know which modes the model returns!\n\
 \n\
     ----------------------------------------------\n\
     --- Starting Parameters ----------------------\n\
@@ -1306,7 +1309,7 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
     Dinitial=atof(ppt->value);
     distanceVary = LALINFERENCE_PARAM_FIXED;
   }
-  
+
   LALInferenceRegisterUniformVariableREAL8(state, model->params, "logdistance", log(Dinitial), log(Dmin), log(Dmax), distanceVary) ;
   if(LALInferenceGetProcParamVal(commandLine,"--margdist")||LALInferenceGetProcParamVal(commandLine,"--margdist-comoving"))
   {
@@ -1321,7 +1324,7 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
           cosmology=1;
       LALInferenceAddINT4Variable(model->params,"MARGDIST_COSMOLOGY",cosmology, LALINFERENCE_PARAM_FIXED);
   }
-  
+
   LALInferenceRegisterUniformVariableREAL8(state, model->params, "polarisation", zero, psiMin, psiMax, LALINFERENCE_PARAM_LINEAR);
   LALInferenceRegisterUniformVariableREAL8(state, model->params, "costheta_jn", zero, costhetaJNmin, costhetaJNmax,LALINFERENCE_PARAM_LINEAR);
 
@@ -1412,7 +1415,7 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
     XLAL_TRY(eos=XLALSimNeutronStarEOSByName(ppt->value), errnum);
     if(errnum!=XLAL_SUCCESS)
         XLAL_ERROR_NULL(errnum,"%s: %s",__func__,XLALErrorString(errnum));
-    
+
     XLAL_TRY(model->eos_fam = XLALCreateSimNeutronStarFamily(eos),errnum);
     if(errnum!=XLAL_SUCCESS)
         XLAL_ERROR_NULL(errnum,"%s: %s",__func__,XLALErrorString(errnum));
@@ -1421,8 +1424,8 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
   } else if((ppt=LALInferenceGetProcParamVal(commandLine,"--BinaryLove"))){
     LALInferenceRegisterUniformVariableREAL8(state, model->params, "lambdaS", zero, lambdaSMin, lambdaSMax, LALINFERENCE_PARAM_LINEAR);
     LALInferenceRegisterUniformVariableREAL8(state, model->params, "BLuni", 0.5, 0.0, 1.0, LALINFERENCE_PARAM_LINEAR);
-  }    
-  
+  }
+
   LALSimInspiralSpinOrder spinO = LAL_SIM_INSPIRAL_SPIN_ORDER_ALL;
   ppt=LALInferenceGetProcParamVal(commandLine, "--spinOrder");
   if(ppt) {
@@ -1451,6 +1454,29 @@ LALInferenceModel *LALInferenceInitCBCModel(LALInferenceRunState *state) {
     fprintf(stdout,"Template will use %s.\n",ppt->value);
   }
 
+  /* Enable PhenomXHM Multibanding */
+  if((ppt=LALInferenceGetProcParamVal(commandLine,"--phenomXHMMband"))) {
+      REAL8 threshold = atof(ppt->value);
+      XLALSimInspiralWaveformParamsInsertPhenomXHMThresholdMband(model->LALpars, threshold);
+      fprintf(stdout,"Template will use phenomXHMMband %s.\n",ppt->value);
+  }
+
+  /* Enable custom mode list to be passed to waveform generator */
+  if((ppt=LALInferenceGetProcParamVal(commandLine,"--modesList")))
+  {
+     char *currnum;
+     int numbers[25], iii = 0;
+     while ((currnum = strtok(iii ? NULL : ppt->value, ",")) != NULL){
+       numbers[iii++] = atoi(currnum);
+     }
+     LALValue *ModeArray = XLALSimInspiralCreateModeArray();
+     for (int ii=0; ii<iii; ii+=2){
+       XLALSimInspiralModeArrayActivateMode(ModeArray, numbers[ii], numbers[ii+1]);
+     }
+     XLALSimInspiralWaveformParamsInsertModeArray(model->LALpars, ModeArray);
+     XLALDestroyValue(ModeArray);
+   }
+
   fprintf(stdout,"\n\n---\t\t ---\n");
   LALInferenceInitSpinVariables(state, model);
   LALInferenceCheckApproximantNeeds(state,approx);
diff --git a/lalsimulation/.AUTHORS b/lalsimulation/.AUTHORS
index ffcb8beb39e8c4bba3feea1f6af6e511ce506100..8306bb7fbe0827b3d56a1e26f764f2c1301919cd 100644
--- a/lalsimulation/.AUTHORS
+++ b/lalsimulation/.AUTHORS
@@ -10,6 +10,7 @@ Badri Krishnan
 Ben Aylott
 Ben Farr
 Ben Lackey
+Cecilio Garcia-Quiros
 Chris Pankow
 Christopher M. Biwer
 Collin Capano
@@ -25,6 +26,7 @@ Enrico Barausse
 Evan Ochsner
 Fan Zhang
 Frank Ohme
+Geraint Pratten
 Henning Fehrmann
 Ian Harry
 J. S. Read
@@ -40,6 +42,7 @@ Lionel London
 Lucia Santamaria
 László Veréb
 Maria Haney
+Marta Colleoni
 Marton Tapai
 Matthew Pitkin
 Michael Puerrer
@@ -47,6 +50,7 @@ Michalis Agathos
 Miriam Cabero
 Nickolas Fotopoulos
 Ofek Birnholtz
+Patricia Schmidt
 Prayush Kumar
 Reinhard Prix
 Riccardo Sturani
@@ -55,6 +59,7 @@ Roland Haas
 Rory Smith
 Salvatore Vitale
 Sarah Caudill
+Sascha Husa
 Scott Coughlin
 Sebastian Khan
 Serena Vinciguerra
diff --git a/lalsimulation/lib/LALSimIMR.h b/lalsimulation/lib/LALSimIMR.h
index f8ed3e9d9309cbb7c08332281506da7c6c864c83..cb9ca96737a72e6858c363deadde8d20e4d77aa5 100644
--- a/lalsimulation/lib/LALSimIMR.h
+++ b/lalsimulation/lib/LALSimIMR.h
@@ -41,6 +41,7 @@ extern "C" {
  *
  * @{
  * @defgroup LALSimIMRPhenom_c                   LALSimIMRPhenom.c
+ * @defgroup LALSimIMRPhenomX_c                  LALSimIMRPhenomX.c
  * @defgroup LALSimIMREOBNRv2_c                  LALSimIMREOBNRv2.c
  * @defgroup LALSimIMRSpinAlignedEOB_c           LALSimIMRSpinAlignedEOB.c
  * @defgroup LALSimIMRSpinPrecEOB_c              LALSimIMRSpinPrecEOB.c
@@ -336,6 +337,174 @@ int XLALSimIMRPhenSpinFinalMassSpin(REAL8 *finalMass, REAL8 *finalSpin, REAL8 m1
 int XLALSimSpinInspiralGenerator(REAL8TimeSeries **hPlus, REAL8TimeSeries **hCross, REAL8 phi_start, REAL8 deltaT, REAL8 m1, REAL8 m2, REAL8 f_min, REAL8 f_ref, REAL8 r, REAL8 iota, REAL8 s1x, REAL8 s1y, REAL8 s1z, REAL8 s2x, REAL8 s2y, REAL8 s2z, int phaseO, int ampO, REAL8 lambda1, REAL8 lambda2, REAL8 quadparam1, REAL8 quadparam2, LALDict *LALparams);
 int XLALSimIMRPhenSpinInspiralRDGenerator(REAL8TimeSeries **hplus, REAL8TimeSeries **hcross, REAL8 phi0, REAL8 deltaT, REAL8 m1, REAL8 m2, REAL8 f_min, REAL8 f_ref, REAL8 r, REAL8 iota, REAL8 s1x, REAL8 s1y, REAL8 s1z, REAL8 s2x, REAL8 s2y, REAL8 s2z, int phaseO, int ampO, REAL8 lambda1, REAL8 lambda2, REAL8 quadparam1, REAL8 quadparam2, LALDict *LALparams);
 
+/* IMRPhenomX/HM Routines */
+/* in module LALSimIMRPhenomX.c */
+int XLALSimIMRPhenomXASGenerateFD(COMPLEX16FrequencySeries **htilde22,
+  REAL8 m1_SI,
+  REAL8 m2_SI,
+  REAL8 chi1L,
+  REAL8 chi2L,
+  REAL8 distance,
+  REAL8 f_min,
+  REAL8 f_max,
+  REAL8 deltaF,
+  REAL8 phiRef,
+  REAL8 fRef_In,
+  LALDict *lalParams
+);
+
+int XLALSimIMRPhenomXASFrequencySequence(
+  COMPLEX16FrequencySeries **htilde22,
+  const REAL8Sequence *freqs,
+  REAL8 m1_SI,
+  REAL8 m2_SI,
+  REAL8 chi1L,
+  REAL8 chi2L,
+  REAL8 distance,
+  REAL8 phiRef,
+  REAL8 fRef_In,
+  LALDict *lalParams
+);
+
+/* in module LALSimIMRPhenomXHM.c */
+int XLALSimIMRPhenomXHMGenerateFDOneMode(
+ COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+ REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+ REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+ REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+ REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+ UINT4 ell,                           /**< l index of the mode */
+ INT4 emm,                            /**< m index of the mode */
+ REAL8 distance,                      /**< Luminosity distance (m) */
+ REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+ REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+ REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+ REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+ REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+ LALDict *lalParams                   /**< lal dictionary parameters */
+);
+
+int XLALSimIMRPhenomXHMFrequencySequenceOneMode(
+    COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+    REAL8Sequence *freqs,                /**< frequency array to evaluate model */
+    REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+    REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+    REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+    REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+    UINT4 ell,                           /**< l index of the mode */
+    INT4 emm,                            /**< m index of the mode */
+    REAL8 distance,                      /**< Luminosity distance (m) */
+    REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+    REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+    LALDict *lalParams                   /**< lal dictionary parameters */
+);
+
+int XLALSimIMRPhenomXHM(
+   COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
+   COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
+   REAL8 m1_SI,                        /**< mass of companion 1 (kg) */
+   REAL8 m2_SI,                        /**< mass of companion 2 (kg) */
+   REAL8 chi1z,                        /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
+   REAL8 chi2z,                        /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
+   REAL8 f_min,                        /**< Starting GW frequency (Hz) */
+   REAL8 f_max,                        /**< End frequency; 0 defaults to Mf = 0.3 */
+   REAL8 deltaF,                       /**< Sampling frequency (Hz) */
+   REAL8 distance,                     /**< distance of source (m) */
+   REAL8 inclination,                  /**< inclination of source (rad) */
+   REAL8 phiRef,                       /**< reference orbital phase (rad) */
+   REAL8 fRef_In,                      /**< Reference frequency */
+   LALDict *lalParams                  /**<linked list containing the extra testing GR parameters */
+);
+
+
+int XLALSimIMRPhenomXHM2(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 inclination,                   /**  Inclination of the source */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< LAL Dictionary */
+);
+
+
+int XLALSimIMRPhenomXHMMultiBandOneMode(
+  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  UINT4 ell,                           /**< l index of the mode */
+  INT4 emm,                            /**< m index of the mode */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< Extra params */
+);
+
+int XLALSimIMRPhenomXHMMultiBandOneModeMixing(
+  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+  COMPLEX16FrequencySeries *htilde22,  /**< [out] FD waveform */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  UINT4 ell,                           /**< l index of the mode */
+  INT4 emm,                            /**< m index of the mode */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< Extra params */
+);
+
+int XLALSimIMRPhenomXHMAmplitude(
+    REAL8FrequencySeries **amplitude, /**< [out] FD amp */
+    REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+    REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+    REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+    REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+    UINT4 ell,                           /**< l index of the mode */
+    INT4 emm,                            /**< m index of the mode */
+    REAL8 distance,                      /**< Luminosity distance (m) */
+    REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+    REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+    REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+    REAL8 phiRef,                        /**< Orbital amp at fRef (rad) */
+    REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+    LALDict *lalParams                   /**< Extra params */
+  );
+
+int XLALSimIMRPhenomXHMPhase(
+    REAL8FrequencySeries **phase,        /**< [out] FD amp */
+    REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+    REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+    REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+    REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+    UINT4 ell,                           /**< l index of the mode */
+    INT4 emm,                            /**< m index of the mode */
+    REAL8 distance,                      /**< Luminosity distance (m) */
+    REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+    REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+    REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+    REAL8 phiRef,                        /**< Orbital amp at fRef (rad) */
+    REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+    LALDict *lalParams                   /**< Extra params */
+  );
+
+
 /* in module LALSimInspiralNRWaveforms.c */
 
 int XLALSimInspiralNRWaveformGetSpinsFromHDF5File(
diff --git a/lalsimulation/lib/LALSimIMRPhenomX.c b/lalsimulation/lib/LALSimIMRPhenomX.c
new file mode 100644
index 0000000000000000000000000000000000000000..028377c28d5487279b6cced059644361c917e5a9
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX.c
@@ -0,0 +1,674 @@
+/*
+ *  Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+/* Standard LAL */
+#include <lal/Sequence.h>
+#include <lal/Date.h>
+#include <lal/Units.h>
+#include <lal/XLALError.h>
+
+/* LAL datatypes and constants */
+#include <lal/LALDatatypes.h>
+#include <lal/LALStdlib.h>
+#include <lal/LALConstants.h>
+
+/* Time series, frequency series and spherical harmonics */
+#include <lal/TimeSeries.h>
+#include <lal/TimeFreqFFT.h>
+#include <lal/SphericalHarmonics.h>
+#include <lal/FrequencySeries.h>
+
+/* LALSimulation */
+#include <lal/LALSimIMR.h>
+#include <lal/LALSimInspiral.h>
+
+/* Standard C */
+#include <math.h>
+#include <complex.h>
+#include <stdbool.h>
+
+/* GSL */
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+
+#ifndef PHENOMXHMDEBUG
+#define DEBUG 0
+#define PHENOMXDEBUG 0
+#else
+#define DEBUG 1 //print debugging info
+#define PHENOMXDEBUG 1
+#endif
+
+/* Link IMRPhenomX routines */
+#include "LALSimIMRPhenomX.h"
+#include "LALSimIMRPhenomX_ringdown.h"
+#include "LALSimIMRPhenomX_intermediate.h"
+#include "LALSimIMRPhenomX_inspiral.h"
+#include "LALSimIMRPhenomX_internals.c"
+//#include "LALSimIMRPhenomX_tidal.c"
+//#include "LALSimIMRPhenomX_precession.c"
+
+/* Note: This is declared in LALSimIMRPhenomX_internals.c and avoids namespace clashes */
+IMRPhenomX_UsefulPowers powers_of_lalpi;
+
+#ifndef _OPENMP
+#define omp ignore
+#endif
+
+/* ******** ALIGNED SPIN IMR PHENOMENOLOGICAL WAVEFORM: IMRPhenomXAS ********* */
+
+/* EXTERNAL ROUTINES */
+
+/**
+ * @addtogroup LALSimIMRPhenomX_c
+ * @brief Routines to produce IMRPhenomX-family of phenomenological
+ * inspiral-merger-ringdown waveforms.
+ *
+ * These are frequency-domain models for compact binaries at comparable and extreme mass ratios,
+ * tuned to numerical-relativity simulations.
+ *  * IMRPhenomXAS model for 22 mode non-precessing binaries. https://arxiv.org/abs/2001.11412 ; DCC link: https://dcc.ligo.org/LIGO-P2000018
+ *  * IMRPhenomXHM model with subdominant modes non-precessing binaries. https://arxiv.org/abs/2001.10914 ; DCC link: https://dcc.ligo.org/P1900393-v1
+ *  * Multibanding for IMRPhenomXHM. https://arxiv.org/abs/2001.10897 ; DCC link: https://dcc.ligo.org/LIGO-P1900391
+ *
+ * @review IMRPhenomXAS & IMRPhenomXHM reviewed by maria.haney, patricia-schmidt, roberto.cotesta, anuradha.samajdar, jonathan.thompson, nv.krishnendu
+ * Review wiki: https://git.ligo.org/waveforms/reviews/imrphenomx/wikis/home
+ *
+ *
+ */
+
+ /**
+  * @addtogroup LALSimIMRPhenomX_c
+  * @{
+  *
+  * @name Routines for IMRPhenomXAS
+  * @{
+  *
+  * @author Geraint Pratten
+  *
+  * @brief C code for IMRPhenomXAS phenomenological waveform model.
+  *
+  * This is an aligned-spin frequency domain model for the 22 mode.
+  * See G.Pratten et al for details. Any studies that use this waveform model should include
+  * a reference to both of this paper.
+  *
+  * @note The model was calibrated to mass-ratios from 1 to 1000.
+  * The calibration points will be given in forthcoming papers.
+  *
+  * @attention The model is usable outside this parameter range,
+  * and in tests to date gives sensible physical results,
+  * but conclusive statements on the physical fidelity of
+  * the model for these parameters await comparisons against further
+  * numerical-relativity simulations. For more information, see the review wiki
+  * under https://git.ligo.org/waveforms/reviews/imrphenomx/wikis/home
+  *
+  *
+  * Waveform flags:
+  * 	InsPhaseVersion: Determines the inspiral phase model.
+  *			- 104 : Canonical TaylorF2 at 3.5PN including cubic-in-spin and quadratic-in-spin corrections. Uses 4 pseudo-PN coefficients. (RECOMMENDED).
+  *			- 105 : Canonical TaylorF2 at 3.5PN including cubic-in-spin and quadratic-in-spin corrections. Uses 5 pseudo-PN coefficients.
+  *			- 114 : Extended TaylorF2. Includes cubic-in-spin, quadratic-in-spin corrections, 4PN and 4.5PN orbital corrections. Uses 4 pseudo-PN coefficients.
+  *			- 115 : Extended TaylorF2. Includes cubic-in-spin, quadratic-in-spin corrections, 4PN and 4.5PN orbital corrections. Uses 5 pseudo-PN coefficients.
+  *
+  *     IntPhaseVersion: Determines the intermediate phase model.
+  *			-	104 : 4th order polynomial ansatz.
+  *			-   105 : 5th order polynomial ansatz. (RECOMMENDED).
+  *
+  *		RDPhaseVersion: Determines the merger-ringdown phase model.
+  *			-	105 : Deformed Lorentzian using 5 coefficients. (RECOMMENDED).
+  *
+  *		InsAmpVersion : Determines inspiral amplitude model.
+  *			-	103 : Canonical PN re-expanded TaylorF2 amplitude with pseudo-PN corrections. (RECOMMENDED).
+  *
+  *		IntAmpVersion : Determines intermediate amplitude model.
+  *			-	104 : Based on a 4th order polynomial ansatz. Less accurate but stable extrapolation. (RECOMMENDED).
+  *			-	105 : Based on 5th order polynomial ansatz. More accurate in calibration domain, more unstable extrapolation.
+  *
+  *		RDAmpVersion : Determines the merger-ringdown amplitude model.
+  *			-	103 : Deformed Lorentzian with 3 free coefficients. Uses 1 calibrated collocation point and 2 calibrated phenomenological coefficients. (RECOMMENDED).
+  */
+
+
+/**
+ *  Driver routine to calculate an IMRPhenomX aligned-spin,
+ *  inspiral-merger-ringdown phenomenological waveform model
+ *  in the frequency domain.
+ *
+ *  arXiv:2001.11412, https://arxiv.org/abs/2001.11412
+ *
+ *  All input parameters should be in SI units. Angles should be in radians.
+ *
+ *  XLALSimIMRPhenomXASGenerateFD() returns the strain of the 2-2 mode as a complex
+ * frequency series with equal spacing deltaF and contains zeros from zero frequency
+ * to the starting frequency and zeros beyond the cutoff frequency in the ringdown.
+ *
+ */
+int XLALSimIMRPhenomXASGenerateFD(
+  COMPLEX16FrequencySeries **htilde22, /**< [out] FD waveform */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 phi0,                          /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< LAL Dictionary */
+)
+{
+  UINT4 status;
+
+  /* Set debug status here */
+  UINT4 debug = PHENOMXDEBUG;
+
+  if(debug)
+  {
+    printf("fRef_In : %e\n",fRef_In);
+    printf("m1_SI   : %e\n",m1_SI);
+    printf("m2_SI   : %e\n",m2_SI);
+    printf("chi1L   : %e\n",chi1L);
+    printf("chi2L   : %e\n\n",chi2L);
+    printf("Performing sanity checks...\n");
+  }
+
+  /* Perform initial sanity checks */
+  if(*htilde22)       { XLAL_CHECK(NULL != htilde22, XLAL_EFAULT);                                   }
+  if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+  if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+  if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+  if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+  if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+  if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+  if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+  /* If no reference frequency is given, set it to the starting gravitational wave frequency */
+  REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
+
+
+  if(debug)
+  {
+    printf("\n\n **** Initializing waveform struct... **** \n\n");
+  }
+
+
+  /* Initialize the useful powers of LAL_PI */
+  status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+  /* Initialize IMR PhenomX Waveform struct and check that it initialized correctly */
+  IMRPhenomXWaveformStruct *pWF;
+  pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phi0, f_min, f_max, distance, 0.0, lalParams, debug);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+  /*
+      Create a REAL8 frequency series.
+      Use fLow, fHigh, deltaF to compute frequency sequence. Only pass the boundaries (fMin, fMax).
+  */
+  REAL8Sequence *freqs = XLALCreateREAL8Sequence(2);
+  freqs->data[0] = pWF->fMin;
+  freqs->data[1] = pWF->f_max_prime;
+
+
+  if(debug)
+  {
+    printf("\n\n **** Calling IMRPhenomXASGenerateFD... **** \n\n");
+  }
+
+  /* We now call the core IMRPhenomXAS waveform generator */
+  status = IMRPhenomXASGenerateFD(htilde22, freqs, pWF, lalParams);
+  XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXASFDCore failed to generate IMRPhenomX waveform.");
+
+  if(debug)
+  {
+    printf("\n\n **** Call to IMRPhenomXASGenerateFD complete. **** \n\n");
+  }
+
+  /*
+      We now resize htilde22 if our waveform was generated to a cut-off frequency below
+      the desired maximum frequency. Simply fill the remaining frequencies with zeros.
+  */
+  if (pWF->f_max_prime < pWF->fMax)
+  {
+    /*
+        As the user has requested an f_max > Mf = fCut,
+        we resize the frequency series to fill with zeros beyond the cutoff frequency.
+    */
+    size_t n = (*htilde22)->data->length;
+
+    /* Enforce length to be a power of 2 + 1 */
+    size_t n_full = NextPow2(pWF->fMax / pWF->deltaF) + 1;
+
+    /* Resize the COMPLEX16 frequency series */
+    *htilde22 = XLALResizeCOMPLEX16FrequencySeries(*htilde22, 0, n_full);
+    XLAL_CHECK (*htilde22, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
+  }
+  LALFree(pWF);
+  XLALDestroyREAL8Sequence(freqs);
+  return XLAL_SUCCESS;
+}
+
+
+/**
+ * Compute waveform in LAL format at specified frequencies for the IMRPhenomX model.
+ *
+ *  All input parameters should be in SI units. Angles should be in radians.
+ *
+ * XLALSimIMRPhenomXASFrequencySequence() returns the strain of the 2-2 mode as a
+ * complex frequency series with entries exactly at the frequencies specified in
+ * the sequence freqs (which can be unequally spaced). No zeros are added. Assumes positive frequencies.
+ */
+ int XLALSimIMRPhenomXASFrequencySequence(
+     COMPLEX16FrequencySeries **htilde22, /**< [out] FD waveform */
+     const REAL8Sequence *freqs,          /**< [out] Frequency series [Hz] */
+     REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+     REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+     REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+     REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+     REAL8 distance,                      /**< Luminosity distance (m) */
+     REAL8 phi0,                          /**< Phase at reference frequency */
+     REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+     LALDict *lalParams                   /**< LAL Dictionary */
+ )
+ {
+   INT4 return_code = 0;
+
+   /* Sanity checks */
+   if(*htilde22)       { XLAL_CHECK(NULL != htilde22, XLAL_EFAULT);                                   }
+   if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+   if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+   if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+   if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+
+   /*
+	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+		- For mass ratios > 1000: throw a hard error that model is not valid.
+		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+   */
+   REAL8 mass_ratio;
+   if(m1_SI > m2_SI)
+   {
+	mass_ratio = m1_SI / m2_SI;
+   }
+   else
+   {
+	mass_ratio = m2_SI / m1_SI;
+   }
+   if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+
+   // Check on the mass-ratio with a 1e-12 tolerance to avoid rounding errors
+   if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); }
+   if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+   // If fRef is not provided, then set fRef to be the starting GW Frequency
+   REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In;
+
+   UINT4 status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+   XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+   /*
+      This routine automatically performs sanity checks on the masses, spins, etc.
+   */
+   REAL8 f_min_In  = freqs->data[0];
+   REAL8 f_max_In  = freqs->data[freqs->length - 1];
+
+   /*
+      Passing deltaF = 0 implies that freqs is a frequency grid with non-uniform spacing.
+      The function waveform then start at lowest given frequency.
+   */
+
+   /* Initialize IMRPhenomX waveform struct and perform sanity check. */
+   IMRPhenomXWaveformStruct *pWF;
+   pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+   return_code = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, 0.0, fRef, phi0, f_min_In, f_max_In, distance, 0.0, lalParams, 0);
+   XLAL_CHECK(XLAL_SUCCESS == return_code, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+   /* Now call the core IMRPhenomX waveform generator */
+   return_code = IMRPhenomXASGenerateFD(
+     htilde22,
+     freqs,
+     pWF,
+     lalParams
+   );
+   XLAL_CHECK(return_code == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXASFDCore failed to generate IMRPhenomX waveform.");
+   LALFree(pWF);
+
+   return XLAL_SUCCESS;
+ }
+
+ /** @} */
+ /** @} */
+
+
+ /* *********************************************************************************
+  *
+  * The following private function generates an IMRPhenomX frequency-domain waveform
+  *   - Only aligned-spin
+  *   - Only the 22-mode
+  *   - Physical parameters are passed via the waveform struct
+  * *********************************************************************************
+  */
+int IMRPhenomXASGenerateFD(
+  COMPLEX16FrequencySeries **htilde22, /**< [out] FD waveform           */
+  const REAL8Sequence *freqs_In,       /**< Input frequency grid        */
+  IMRPhenomXWaveformStruct *pWF,       /**< IMRPhenomX Waveform Struct  */
+  LALDict *lalParams                   /**< LAL Dictionary Structure    */
+)
+{
+  /* Inherits debug flag from waveform struct */
+  UINT4 debug = PHENOMXDEBUG;
+
+  if(debug)
+  {
+    printf("\n **** Now in IMRPhenomXASGenerateFD... **** \n");
+  }
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  /* Initialize useful powers of LAL_PI */
+  int status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+  /* Inherit minimum and maximum frequencies to generate wavefom from input frequency grid */
+  double f_min = freqs_In->data[0];
+  double f_max = freqs_In->data[freqs_In->length - 1];
+
+  /* Size of array */
+  size_t npts     = 0;
+
+  /* Index shift between freqs and the frequency series */
+  UINT4 offset    = 0;
+
+  /* Initialize frequency sequence */
+  REAL8Sequence *freqs = NULL;
+
+  /* If deltaF is non-zero then we need to generate a uniformly sampled frequency grid of spacing deltaF. Start at f = 0. */
+  if(pWF->deltaF > 0)
+  {
+    /* Return the closest power of 2 */
+    npts = NextPow2(f_max / pWF->deltaF) + 1;
+
+    /* Debug information */
+    if(debug)
+    {
+      printf("npts     = %zu\n",npts);
+      printf("fMin     = %.4f\n",f_min);
+      printf("fMax     = %.4f\n",f_max);
+      printf("dF       = %.4f\n",pWF->deltaF);
+    }
+
+    XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF ), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", pWF->deltaF);
+
+    /* Initialize the htilde frequency series */
+    *htilde22 = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,npts);
+
+    /* Check that frequency series generated okay */
+    XLAL_CHECK(*htilde22,XLAL_ENOMEM,"Failed to allocate COMPLEX16FrequencySeries of length %zu for f_max = %f, deltaF = %g.\n",npts,f_max,pWF->deltaF);
+
+    /* Frequencies will be set using only the lower and upper bounds that we passed */
+    size_t iStart = (size_t) (f_min / pWF->deltaF);
+    size_t iStop  = (size_t) (f_max / pWF->deltaF) + 1;
+
+    XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+          "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+    /* Allocate memory for frequency array and terminate if this fails */
+    freqs = XLALCreateREAL8Sequence(iStop - iStart);
+    if (!freqs)
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+
+    /* Populate frequency array */
+    for (UINT4 i = iStart; i < iStop; i++)
+    {
+      freqs->data[i-iStart] = i * pWF->deltaF;
+    }
+    offset = iStart;
+  }
+  else
+  {
+    /* freqs is a frequency grid with non-uniform spacing, so we start at the lowest given frequency */
+    npts      = freqs_In->length;
+    *htilde22 = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform, 22 mode", &ligotimegps_zero, f_min, pWF->deltaF, &lalStrainUnit, npts);
+
+    XLAL_CHECK (*htilde22, XLAL_ENOMEM, "Failed to allocated waveform COMPLEX16FrequencySeries of length %zu from sequence.", npts);
+
+    offset = 0;
+    freqs  = XLALCreateREAL8Sequence(freqs_In->length);
+
+    /* Allocate memory for frequency array and terminate if this fails */
+    if (!freqs)
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+
+    /* Populate frequency array */
+    for (UINT4 i = 0; i < freqs_In->length; i++)
+    {
+      freqs->data[i] = freqs_In->data[i];
+    }
+  }
+
+  memset((*htilde22)->data->data, 0, npts * sizeof(COMPLEX16));
+  XLALUnitMultiply(&((*htilde22)->sampleUnits), &((*htilde22)->sampleUnits), &lalSecondUnit);
+
+  /* Check if LAL dictionary exists. If not, create a LAL dictionary. */
+  if(lalParams == NULL)
+  {
+    lalParams = XLALCreateDict();
+  }
+
+  if(debug)
+  {
+    printf("\n\n **** Initializing amplitude struct... **** \n\n");
+  }
+
+  /* Allocate and initialize the PhenomX 22 amplitude coefficients struct */
+  IMRPhenomXAmpCoefficients *pAmp22;
+  pAmp22 = XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+  status = IMRPhenomXGetAmplitudeCoefficients(pWF,pAmp22);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXGetAmplitudeCoefficients failed.\n");
+
+  if(debug)
+  {
+    printf("\n\n **** Amplitude struct initialized. **** \n\n");
+    printf("\n\n **** Initializing phase struct... **** \n\n");
+  }
+
+  /* Allocate and initialize the PhenomX 22 phase coefficients struct */
+  IMRPhenomXPhaseCoefficients *pPhase22;
+  pPhase22 = XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+  status   = IMRPhenomXGetPhaseCoefficients(pWF,pPhase22);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXGetPhaseCoefficients failed.\n");
+
+  if(debug)
+  {
+    printf("\n\n **** Phase struct initialized. **** \n\n");
+  }
+
+  /*
+      Apply time shifts so peak amplitude is near t ~ 0.
+  */
+
+  /* Initialize a struct containing useful powers of Mf at fRef */
+  IMRPhenomX_UsefulPowers powers_of_MfRef;
+  status = IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "IMRPhenomX_Initialize_Powers failed for MfRef.\n");
+
+  /* Linear time and phase shifts so that model peaks near t ~ 0 */
+  REAL8 lina = 0;
+
+  /* Get phase connection coefficients */
+  IMRPhenomX_Phase_22_ConnectionCoefficients(pWF,pPhase22);
+  double linb=IMRPhenomX_TimeShift_22(pPhase22, pWF);
+
+  /* 1/eta is used to re-scale phase */
+  REAL8 inveta    = (1.0 / pWF->eta);
+
+  /* Calculate phase at reference frequency: phifRef = 2.0*phi0 + LAL_PI_4 + PhenomXPhase(fRef) */
+  pWF->phifRef = -(inveta * IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF) + linb*pWF->MfRef + lina) + 2.0*pWF->phi0 + LAL_PI_4;
+
+  /*
+      Here we declare explicit REAL8 variables for main loop in order to avoid numerous
+      pointer calls.
+  */
+  //REAL8 MfRef     = pWF->MfRef;
+  REAL8 Msec      = pWF->M_sec;
+
+  REAL8 C1IM      = pPhase22->C1Int;
+  REAL8 C2IM      = pPhase22->C2Int;
+  REAL8 C1RD      = pPhase22->C1MRD;
+  REAL8 C2RD      = pPhase22->C2MRD;
+
+  REAL8 fPhaseIN  = pPhase22->fPhaseMatchIN;
+  REAL8 fPhaseIM  = pPhase22->fPhaseMatchIM;
+  REAL8 fAmpIN    = pAmp22->fAmpMatchIN;
+  REAL8 fAmpIM    = pAmp22->fAmpRDMin;
+
+  if(debug)
+  {
+    printf("\n\n **** Phase struct initialized. **** \n\n");
+    printf("C1IM     = %.4f\n",C1IM);
+    printf("C2IM     = %.4f\n",C2IM);
+    printf("C1RD     = %.4f\n",C1RD);
+    printf("C2RD     = %.4f\n",C2RD);
+    printf("fIN      = %.4f\n",fPhaseIN);
+    printf("fIM      = %.4f\n",fPhaseIM);
+  }
+
+  REAL8 Amp0      = pWF->amp0 * pWF->ampNorm;
+
+  /* initial_status used to track  */
+  UINT4 initial_status = XLAL_SUCCESS;
+
+  /* Now loop over main driver to generate waveform:  h(f) = A(f) * Exp[I phi(f)] */
+  #pragma omp parallel for
+  for (UINT4 idx = 0; idx < freqs->length; idx++)
+  {
+    double Mf    = Msec * freqs->data[idx];   // Mf is declared locally inside the loop
+    UINT4 jdx    = idx  + offset;             // jdx is declared locally inside the loop
+
+    /* Initialize a struct containing useful powers of Mf */
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+    if(initial_status != XLAL_SUCCESS)
+    {
+      status = initial_status;
+      XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+    }
+    else
+    {
+      /* Generate amplitude and phase at MfRef */
+      REAL8 amp = 0.0;
+      REAL8 phi = 0.0;
+
+      /* The functions in this routine are inlined to help performance. */
+      /* Construct phase */
+      if(Mf < fPhaseIN)
+      {
+        phi = IMRPhenomX_Inspiral_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pPhase22);
+      }
+      else if(Mf > fPhaseIM)
+      {
+        phi = IMRPhenomX_Ringdown_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pWF, pPhase22) + C1RD + (C2RD * Mf);
+      }
+      else
+      {
+        phi = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(Mf, &powers_of_Mf, pWF, pPhase22) + C1IM + (C2IM * Mf);
+      }
+
+	  /* Scale phase by 1/eta */
+	  phi  *= inveta;
+      phi  += linb*Mf + lina + pWF->phifRef;
+
+	  /* Construct amplitude */
+	  if(Mf < fAmpIN)
+	  {
+		  amp = IMRPhenomX_Inspiral_Amp_22_Ansatz(Mf, &powers_of_Mf, pWF, pAmp22);
+	  }
+	  else if(Mf > fAmpIM)
+	  {
+		  amp = IMRPhenomX_Ringdown_Amp_22_Ansatz(Mf, pWF, pAmp22);
+	  }
+	  else
+	  {
+        amp = IMRPhenomX_Intermediate_Amp_22_Ansatz(Mf, &powers_of_Mf, pWF, pAmp22);
+      }
+
+	  /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+      ((*htilde22)->data->data)[jdx] = Amp0 * powers_of_Mf.m_seven_sixths * amp * cexp(I * phi);
+    }
+  }
+
+  // Free allocated memory
+  LALFree(pAmp22);
+  LALFree(pPhase22);
+  //LALFree(pWF);
+
+  XLALDestroyREAL8Sequence(freqs);
+
+  return status;
+}
+
+
+/* Useful wrapper to check for uniform frequency grids taken from LALSimIMRPhenomHM.c */
+int IMRPhenomXCheckForUniformFrequencies(
+  REAL8Sequence *frequencies,
+  REAL8 df
+)
+{
+  INT4 IsUniform = 0;
+
+  /* If the frequency series has length of 2 and a df > 0 then it is uniformly sampled */
+  if( (frequencies->length == 2) && (df > 0.) )
+  {
+    IsUniform = 1;
+  }
+
+  return IsUniform;
+};
diff --git a/lalsimulation/lib/LALSimIMRPhenomX.h b/lalsimulation/lib/LALSimIMRPhenomX.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bd846c26d2ddde5da807618aa22dab2b6dd94b8
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX.h
@@ -0,0 +1,57 @@
+#ifndef _LALSIM_IMR_PHENOMX_H
+#define _LALSIM_IMR_PHENOMX_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* CONSTANTS */
+/* Dimensionless frequency (Mf) at which define the end of the waveform */
+#define f_CUT 0.3
+
+#define MAX_ALLOWED_MASS_RATIO 5000
+#define MAX_ALLOWED_ETA 0.0002
+
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+int IMRPhenomXASGenerateFD(
+  COMPLEX16FrequencySeries **htilde22,
+  const REAL8Sequence *freqs,
+  IMRPhenomXWaveformStruct *pWF,
+  LALDict *lalParams
+);
+
+int IMRPhenomXCheckForUniformFrequencies(REAL8Sequence *frequencies,REAL8 df);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LALSIM_IMR_PHENOMX_H */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM.c b/lalsimulation/lib/LALSimIMRPhenomXHM.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba2f55859ebc14174d6e2355e73c65127ec114cd
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM.c
@@ -0,0 +1,2141 @@
+/*
+* Copyright (C) 2019 Marta Colleoni, Cecilio García Quirós
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+//
+//  Created by Marta on 13/02/2019.
+//
+
+#include <lal/LALSimIMR.h>
+#include <lal/SphericalHarmonics.h>
+#include <lal/Sequence.h>
+#include <lal/Date.h>
+#include <lal/Units.h>
+#include <lal/LALConstants.h>
+#include <lal/FrequencySeries.h>
+#include <lal/LALDatatypes.h>
+#include <lal/LALStdlib.h>
+#include <lal/XLALError.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+
+#ifndef _OPENMP
+#define omp ignore
+#endif
+
+#define L_MAX 4
+
+#ifndef PHENOMXHMDEBUG
+#define DEBUG 0
+#else
+#define DEBUG 1 //print debugging info
+#endif
+
+#ifndef PHENOMXHMMBAND
+#define MBAND 0
+#else
+#define MBAND PHENOMXHMMBAND //use multibanding
+#endif
+
+#include "LALSimIMRPhenomXHM_internals.h"
+#include "LALSimIMRPhenomXHM_internals.c"
+
+#include "LALSimIMRPhenomXHM_structs.h"
+#include "LALSimIMRPhenomXHM_qnm.h"
+#include "LALSimIMRPhenomXHM_multiband.c"
+
+#include "LALSimIMRPhenomXHM.h"
+//#include "LALSimIMRPhenomXPHM.c"
+
+/* Note: This is declared in LALSimIMRPhenomX_internals.c and avoids namespace clash */
+IMRPhenomX_UsefulPowers powers_of_lalpiHM;
+
+
+//This is a wrapper function for adding higher modes to the ModeArray
+static LALDict *IMRPhenomXHM_setup_mode_array(LALDict *lalParams);
+
+/*
+* Helper function to multiple hlm with Ylm.
+* Adapted from LALSimIMREOBNRv2HMROMUtilities.c
+*/
+static int IMRPhenomXHMFDAddMode(
+  COMPLEX16FrequencySeries *hptilde,  /**<[out] hp series*/
+  COMPLEX16FrequencySeries *hctilde,  /**<[out] hc series */
+  COMPLEX16FrequencySeries *hlmtilde, /**< hlm mode to add */
+  REAL8 theta,                        /**< Inclination [rad] */
+  REAL8 phi,                          /**< Azimuthal angle [rad]*/
+  INT4 l,                             /**< l index of the lm mode */
+  INT4 m,                             /**< m index of the lm mode */
+  INT4 sym                            /**< Equatorial symmetry */
+);
+
+/* Compute the frequency array and initialize htildelm to the corresponding length. */
+static int SetupWFArrays(
+  REAL8Sequence **freqs,                /**< [out] frequency grid [Hz] */
+  COMPLEX16FrequencySeries **htildelm,  /**< [out] Frequency domain hlm GW strain */
+  REAL8Sequence *freqs_In,              /**< fmin, fmax [Hz] */
+  IMRPhenomXWaveformStruct *pWF,        /**< Waveform structure with parameters */
+  LIGOTimeGPS ligotimegps_zero          /**< = {0,0} */
+);
+
+
+
+/* Return hptilde and hctilde from a sum of modes */
+static int IMRPhenomXHM_MultiMode(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8 m1_SI,                        /**< primary mass [kg] */
+  REAL8 m2_SI,                        /**< secondary mass [kg] */
+  REAL8 chi1z,                        /**< aligned spin of primary */
+  REAL8 chi2z,                        /**< aligned spin of secondary */
+  REAL8 f_min,                        /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                        /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                       /**< Sampling frequency (Hz) */
+  REAL8 distance,                     /**< distance of source (m) */
+  REAL8 inclination,                  /**< inclination of source (rad) */
+  REAL8 phiRef,                       /**< reference orbital phase (rad) */
+  REAL8 fRef_In,                      /**< Reference frequency */
+  LALDict *lalParams                  /**< LALDict struct */
+);
+
+/* Return hptilde and hctilde from a sum of modes */
+static int IMRPhenomXHM_MultiMode2(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8Sequence *freqs_In,            /**< min and max frequency [Hz] */
+  IMRPhenomXWaveformStruct *pWF,      /**< waveform parameters */
+  LALDict *lalParams                  /**< LALDict struct */
+);
+
+
+/* Wrapper function for adding higher modes to the ModeArray */
+static LALDict *IMRPhenomXHM_setup_mode_array(LALDict *lalParams)
+{
+  /* setup ModeArray */
+  if (lalParams == NULL)
+  {
+    lalParams = XLALCreateDict();
+  }
+  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+  /* If the mode array is empty, populate using a default choice of modes */
+  if (ModeArray == NULL)
+  {
+    /* Default behaviour */
+    XLAL_PRINT_INFO("Using default modes for IMRPhenomXHM.\n");
+    ModeArray = XLALSimInspiralCreateModeArray();
+
+    /* Only define +m modes as we get -m modes for free */
+    /* IMRPhenomXHM has the following calibrated modes. 22 mode taken from IMRPhenomXAS */
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 2);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 2, 1);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 3, 3);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 3, 2);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 4, 4);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -2);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 2, -1);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -3);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 3, -2);
+    XLALSimInspiralModeArrayActivateMode(ModeArray, 4, -4);
+
+    XLALSimInspiralWaveformParamsInsertModeArray(lalParams, ModeArray);
+  }
+  else {XLAL_PRINT_INFO("Using custom modes for PhenomXHM.\n"); }
+
+  XLALDestroyValue(ModeArray);
+
+  return lalParams;
+}
+
+
+/* Compute the frequency array and initialize htildelm to the corresponding length. */
+static int SetupWFArrays(
+  REAL8Sequence **freqs,                 /**< [out] frequency grid [Hz */
+  COMPLEX16FrequencySeries **htildelm,  /**< [out] Frequency domain hlm GW strain */
+  REAL8Sequence *freqs_In,              /**< fmin, fmax [Hz] */
+  IMRPhenomXWaveformStruct *pWF,        /**< Waveform structure with parameters */
+  LIGOTimeGPS ligotimegps_zero          /**< = {0,0} */
+){
+
+  /* Inherit minimum and maximum frequencies to generate wavefom from input frequency grid */
+  double f_min = freqs_In->data[0];
+  double f_max = freqs_In->data[freqs_In->length - 1];
+
+  /* Size of array */
+  size_t npts = 0;
+
+  /* Index shift between freqs and the frequency series */
+  UNUSED UINT4 offset = 0;
+
+  /* If deltaF is non-zero then we need to generate a uniformly sampled frequency grid of spacing deltaF. Start at f = 0. */
+  if(pWF->deltaF > 0)
+  {
+    /* Return the closest power of 2 */
+    npts = NextPow2(f_max / pWF->deltaF) + 1;
+
+    /* Debug information */
+    #if DEBUG == 1
+    printf("npts     = %zu\n",npts);
+    printf("fMin     = %.6f\n",f_min);
+    printf("fMax     = %.6f\n",f_max);
+    printf("dF       = %.6f\n",pWF->deltaF);
+    printf("f_max / deltaF = %.6f\n", f_max / pWF->deltaF);
+    #endif
+
+    /* Coalescence time is fixed to t=0, shift by overall length in time. Model is calibrated such that it peaks approx 500M before the end of the waveform, add this time to the epoch. */
+     XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.",pWF->deltaF);
+    /* Initialize the htilde frequency series */
+    *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,npts);
+    /* Check that frequency series generated okay */
+    XLAL_CHECK(*htildelm,XLAL_ENOMEM,"Failed to allocate COMPLEX16FrequencySeries of length %zu for f_max = %f, deltaF = %g.\n",npts,f_max,pWF->deltaF);
+
+    /* Frequencies will be set using only the lower and upper bounds that we passed */
+    size_t iStart = (size_t) (f_min / pWF->deltaF);
+    size_t iStop  = (size_t) (f_max / pWF->deltaF) + 1;
+
+    XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+    "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+    #if DEBUG == 1
+	  printf("f_min asked returned = %.16e %.16e \n",f_min, iStart*pWF->deltaF);
+	  printf("f_max asked returned = %.16e %.16e \n",f_max, iStop*pWF->deltaF);
+    #endif
+
+    /* Allocate memory for frequency array and terminate if this fails */
+    (*freqs) = XLALCreateREAL8Sequence(iStop - iStart);
+    if (!(*freqs))
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+    /* Populate frequency array */
+    for (UINT4 i = iStart; i < iStop; i++)
+    {
+      (*freqs)->data[i-iStart] = i * pWF->deltaF;
+    }
+    offset = iStart;
+  }
+  else
+  {
+    /* freqs is a frequency grid with non-uniform spacing, so we start at the lowest given frequency */
+    npts      = freqs_In->length;
+    *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform, 22 mode", &ligotimegps_zero, f_min, pWF->deltaF, &lalStrainUnit, npts);
+    XLAL_CHECK (*htildelm, XLAL_ENOMEM, "Failed to allocated waveform COMPLEX16FrequencySeries of length %zu from sequence.", npts);
+    offset = 0;
+    (*freqs)  = XLALCreateREAL8Sequence(freqs_In->length);
+
+    /* Allocate memory for frequency array and terminate if this fails */
+    if (!(*freqs))
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+
+    /* Populate frequency array */
+    for (UINT4 i = 0; i < freqs_In->length; i++)
+    {
+      (*freqs)->data[i] = freqs_In->data[i];
+    }
+  }//end loop of freqs
+
+  memset((*htildelm)->data->data, 0, npts * sizeof(COMPLEX16));
+  XLALUnitMultiply(&((*htildelm)->sampleUnits), &((*htildelm)->sampleUnits), &lalSecondUnit);
+
+  return offset;
+}
+
+
+/**
+ * @addtogroup LALSimIMRPhenomX_c
+ * @{
+ *
+ * @name Routines for IMRPhenomXHM
+ * @{
+ *
+ * @author Cecilio García Quirós, Marta Colleoni, Sascha Husa
+ *
+ * @brief C code for IMRPhenomXHM phenomenological waveform model.
+ *
+ * This is an aligned-spin frequency domain model for the 22 mode.
+ * See C.García-Quirós et al for details. Any studies that use this waveform model should include
+ * a reference to this paper.
+ *
+ * @note The model was calibrated to mass-ratios from 1 to 1000.
+ * The calibration points will be given in forthcoming papers.
+ *
+ * @attention The model is usable outside this parameter range,
+ * and in tests to date gives sensible physical results,
+ * but conclusive statements on the physical fidelity of
+ * the model for these parameters await comparisons against further
+ * numerical-relativity simulations. For more information, see the review wiki
+ * under https://git.ligo.org/waveforms/reviews/imrphenomx/wikis/home.
+ * DCC link to the paper and supplementary material: https://dcc.ligo.org/P2000011-v2
+ */
+
+
+
+/********************************/
+/*                              */
+/*        SINGLE MODE           */
+/*                              */
+/********************************/
+
+/* Functions to compute the strain of just one mode htildelm */
+
+/** Returns the Fourier domain strain of just one mode: h_lm. Supports positive and negative m.
+Notice than even when the specified frequencies are positives, the m>0 only lives in the negative frequencies regime.
+With m>0 the mode h_lm is zero for positive frequencies and for the negative frequencies is equal to (-1)^l h*_l-m(-f).
+In the contrary, h_l-m is zero for negative frequencies and only lives for positive frequencies.
+This is a wrapper function that uses XLALSimIMRPhenomXASGenerateFD for the 22 mode and IMRPhenomXHMGenerateFDOneMode for the higher modes.
+ */
+ int XLALSimIMRPhenomXHMGenerateFDOneMode(
+   COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+   REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+   REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+   REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+   REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+   UINT4 ell,                           /**< l index of the mode */
+   INT4 emm,                            /**< m index of the mode */
+   REAL8 distance,                      /**< Luminosity distance (m) */
+   REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+   REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+   REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+   REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+   REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+   LALDict *lalParams                   /**< Extra params */
+ )
+ {
+
+   /* If the 22 is required, call to PhenomX. */
+   if(ell == 2 && abs(emm) == 2){
+     XLALSimIMRPhenomXASGenerateFD(
+       htildelm,
+       m1_SI,
+       m2_SI,
+       chi1L,
+       chi2L,
+       distance,
+       f_min,
+       f_max,
+       deltaF,
+       phiRef,
+       fRef_In,
+       lalParams
+     );
+     if(emm>0){
+       #if DEBUG == 1
+       printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+       #endif
+       for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+         (*htildelm)->data->data[idx] = conj((*htildelm)->data->data[idx]);
+       }
+     }
+     size_t iStart = (size_t) (f_min / deltaF);
+     return iStart;
+   }
+   /***** Higher modes ****/
+   else{
+
+     UINT4 status;
+
+     #if DEBUG == 1
+     printf("\n**********************************************************************\n");
+     printf("\n*                IMRPhenomXHMGenereateFDOneMode        %i%i            *\n", ell, abs(emm));
+     printf("\n**********************************************************************\n");
+     printf("fRef_In : %e\n",fRef_In);
+     printf("m1_SI   : %e\n",m1_SI);
+     printf("m2_SI   : %e\n",m2_SI);
+     printf("chi1L   : %e\n",chi1L);
+     printf("chi2L   : %e\n\n",chi2L);
+     printf("Performing sanity checks...\n");
+     #endif
+
+     /* Sanity checks */
+     if(*htildelm)       { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT);                                   }
+     if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+     if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+     if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+     if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+     if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+     if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+     if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+
+     /*
+     	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+     		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+     		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+     		- For mass ratios > 1000: throw a hard error that model is not valid.
+     		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+     */
+     REAL8 mass_ratio;
+     if(m1_SI > m2_SI)
+     {
+   	  mass_ratio = m1_SI / m2_SI;
+     }
+     else
+     {
+   	  mass_ratio = m2_SI / m1_SI;
+     }
+     if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+     if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+     if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+
+     /* setup ModeArray */
+     if (lalParams == NULL)
+     {
+       lalParams = XLALCreateDict();
+     }
+     lalParams = IMRPhenomXHM_setup_mode_array(lalParams);
+     LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+     /* first check if (l,m) mode is 'activated' in the ModeArray */
+     /* if activated then generate the mode, else skip this mode. */
+     if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1 )
+     { /* skip mode */
+       XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
+       XLAL_ERROR(XLAL_EDOM);
+     } /* else: generate mode */
+
+
+     /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
+     REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
+
+     #if DEBUG == 1
+     printf("\n\n **** Initializing waveform struct... **** \n\n");
+     #endif
+
+     /* Initialize the useful powers of LAL_PI */
+     status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+     status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+     XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+
+     /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
+     IMRPhenomXWaveformStruct *pWF;
+     pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+     status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, 0.0, lalParams, DEBUG);
+     XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+     #if DEBUG == 1
+     printf("\n f_max_prime = %.16f, fMax = %.16f \n",pWF->f_max_prime, pWF->fMax);
+     #endif
+
+
+     /* Return the closest power of 2 */
+     size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+     /* Frequencies will be set using only the lower and upper bounds that we passed */
+     size_t iStart = (size_t) (f_min / deltaF);
+     size_t iStop  = (size_t) (pWF->f_max_prime / deltaF);
+     XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+     "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+     /* Create a REAL8 frequency series only passing the boundaries (fMin, fMax).  */
+     REAL8Sequence *freqs = XLALCreateREAL8Sequence(2);
+     freqs->data[0] = pWF->fMin;
+     freqs->data[1] = pWF->f_max_prime;
+
+
+     #if DEBUG == 1
+     printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[1]);
+     printf("\n\n **** Calling IMRPhenomXHMGenerateFDOneMode... **** \n\n");
+     printf("\n f_max_prime = %.16f, fMax = %.16f \n", pWF->f_max_prime, pWF->fMax);
+     #endif
+
+     /*** Call core single mode waveform generator ***/
+     status = IMRPhenomXHMGenerateFDOneMode(htildelm, freqs, pWF, ell, abs(emm), lalParams);
+     XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHMGenerateFDOneMode failed to generate IMRPhenomXHM waveform.");
+
+     #if DEBUG == 1
+     printf("\n\n **** Call to IMRPhenomXHMGenerateFD complete. **** \n\n");
+     printf("\n f_max_prime = %.16f, fMax = %.16f \n",pWF->f_max_prime, pWF->fMax);
+     #endif
+
+     /* Resize htildelm if needed */
+     if (pWF->f_max_prime < pWF->fMax)
+     {
+       /* The user has requested a higher f_max than Mf = fCut.
+       Resize the frequency series to fill with zeros beyond the cutoff frequency. */
+       size_t n = (*htildelm)->data->length;
+
+       // We want to have the length be a power of 2 + 1
+       size_t n_full = NextPow2(pWF->fMax / pWF->deltaF) + 1;
+
+       /* Resize the COMPLEX16 frequency series */
+       *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
+       XLAL_CHECK (*htildelm, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->f_max_prime, n_full, pWF->fMax );
+     }
+
+     if(emm>0){
+       #if DEBUG == 1
+       printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+       #endif
+       INT4 minus1l = 1;
+       if(ell%2!=0){
+         #if DEBUG == 1
+         printf("\nl odd\n");
+         #endif
+         minus1l = -1;
+       }
+       for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+         (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
+       }
+     }
+
+     /* Free allocated memory */
+     LALFree(pWF);
+     XLALDestroyREAL8Sequence(freqs);
+     XLALDestroyValue(ModeArray);
+
+     #if DEBUG == 1
+     printf("\n Leaving XLALSimIMRPhenomXHMGenerateFDOneMode \n");
+     #endif
+
+     return iStart;
+   }//Higher modes
+ }
+/** @} **
+* @} **/
+
+/* Core function to generate the waveform of one mode: htildelm. */
+int IMRPhenomXHMGenerateFDOneMode(
+  COMPLEX16FrequencySeries **htildelm,  /**< [out] hlm for one mode **/
+  REAL8Sequence *freqs_In,              /**< fmin, fmax [Hz] **/
+  IMRPhenomXWaveformStruct *pWF,        /**< structure of the 22 mode **/
+  UINT4 ell,                            /**< first index of the mode **/
+  UINT4 emm,                            /**< second index of the mode **/
+  LALDict *lalParams                    /**< extra params **/
+)
+{
+
+  #if DEBUG == 1
+  printf("\n\n ***** IMRPhenomXHMGenerateFDOneMode **** \n\n");
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  UINT4 initial_status = XLAL_SUCCESS;
+
+  REAL8Sequence *freqs;
+  UINT4 offset = SetupWFArrays(&freqs, htildelm, freqs_In, pWF, ligotimegps_zero);
+
+  #if DEBUG == 1
+  printf("\nIMRPhenomXHMGenerateFDOneMode: Length@freqs, offset %i %u",freqs->length,offset);
+  printf("\nIMRPhenomXHMGenerateFDOneMode: fstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
+  #endif
+
+  /* Check if LAL dictionary exists. If not, create a LAL dictionary. */
+  if(lalParams == NULL)
+  {
+    lalParams = XLALCreateDict();
+  }
+
+  // allocate qnm struct
+  QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+  IMRPhenomXHM_Initialize_QNMs(qnms);
+
+  // Populate pWFHM
+  IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+  IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams);
+  LALFree(qnms);
+
+  /* Fill only the modes that are not zero. Odd modes for equal mass, equal spins are zero. */
+  /* Since hlmtilde is initialized with zeros, for zero modes we just go to the return line. */
+  if(pWFHM->Ampzero==0){
+
+    /* Allocate coefficients of 22 mode */
+    IMRPhenomXAmpCoefficients *pAmp22=(IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+    IMRPhenomXPhaseCoefficients *pPhase22=(IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+    IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+
+    /* Allocate and initialize the PhenomXHM lm amplitude and phae coefficients struct */
+    IMRPhenomXHMAmpCoefficients *pAmp = (IMRPhenomXHMAmpCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+    IMRPhenomXHMPhaseCoefficients *pPhase = (IMRPhenomXHMPhaseCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+
+    /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
+    IMRPhenomXHM_FillAmpFitsArray(pAmp);
+    IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+
+    /* Get coefficients for Amplitude and phase */
+    if (pWFHM->MixingOn == 1) {
+      // For mode with mixing we need the spheroidal coeffs of the 32 phase and the 22 amplitude coeffs.
+      GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
+      IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+    }
+    IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+    IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
+
+
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    REAL8 Msec = pWF->M_sec;    // Variable to transform Hz to Mf
+    REAL8 Amp0 = pWFHM->Amp0;   // Transform amplitude from NR to physical units
+    REAL8 amp, phi;
+
+    /* Multiply by (-1)^l to get the true h_l-m(f) */
+    if(ell%2 != 0){
+      Amp0 = -Amp0;
+    }
+
+    #if DEBUG == 1
+    //Initialize file to print h_l-m with freqs, amplitude and phase in "Physical" units
+    FILE *file;
+    char fileSpec[40];
+    sprintf(fileSpec, "simulation%i_SM.dat", pWFHM->modeTag);
+    printf("\nOutput file: %s\r\n",fileSpec);
+    file = fopen(fileSpec,"w");
+    fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->chi1L, pWF->chi2L, 22, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
+    fprintf(file,"# Frequency (Hz)    Amplitude    Phase\n");
+    #endif
+
+
+    /* Loop over frequencies to generate waveform */
+    /* Modes with mixing */
+    if(pWFHM->MixingOn==1){
+
+      REAL8 Mf;
+      for (UINT4 idx = 0; idx < freqs->length; idx++)
+      {
+        Mf    = Msec * freqs->data[idx];
+        initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+        if(initial_status != XLAL_SUCCESS)
+        {
+          XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+        }
+        else
+        {
+          amp = IMRPhenomXHM_Amplitude_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+          phi = IMRPhenomXHM_Phase_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+          /* Reconstruct waveform: h_l-m(f) = A(f) * Exp[I phi(f)] */
+          ((*htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
+
+          #if DEBUG == 1
+          fprintf(file, "%.16f  %.16e %.16f\n",  freqs->data[idx], Amp0*amp, phi);
+          #endif
+        }
+      }
+    }  /* Modes without mixing */
+    else{
+      for (UINT4 idx = 0; idx < freqs->length; idx++)
+      {
+        REAL8 Mf    = Msec * freqs->data[idx];
+        initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+        if(initial_status != XLAL_SUCCESS)
+        {
+          XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+        }
+        else
+        {
+          amp = IMRPhenomXHM_Amplitude_noModeMixing(Mf, &powers_of_Mf, pAmp, pWFHM);
+          phi = IMRPhenomXHM_Phase_noModeMixing(Mf, &powers_of_Mf, pPhase, pWFHM, pWF);
+          /* Reconstruct waveform: h_l-m(f) = A(f) * Exp[I phi(f)] */
+          ((*htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
+          #if DEBUG == 1
+          fprintf(file, "%.16f  %.16e %.16f\n",  freqs->data[idx], Amp0*amp, phi);
+          #endif
+        }
+      }
+    }
+    #if DEBUG == 1
+    fclose(file);
+    #endif
+
+
+    // Free allocated memory
+    LALFree(pAmp);
+    LALFree(pPhase);
+    LALFree(pAmp22);
+    LALFree(pPhase22);
+  } // End of non-vanishing modes
+
+  // Free allocated memory
+  LALFree(pWFHM);
+  XLALDestroyREAL8Sequence(freqs);
+
+  #if DEBUG == 1
+  printf("\nIMRPhenomXHMGenerateFDOneMode: Leaving... \n");
+  #endif
+
+
+  return initial_status;
+
+}
+
+
+/** @addtogroup LALSimIMRPhenomX_c
+* @name Routines for IMRPhenomXHM
+* @{
+* @{ **/
+
+/** Get the model evaluated in a prebuilt frequency array */
+int XLALSimIMRPhenomXHMFrequencySequenceOneMode(
+  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+  REAL8Sequence *freqs,                /**< frequency array to evaluate model (positives) */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  UINT4 ell,                           /**< l index of the mode */
+  INT4 emm,                            /**< m index of the mode */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams
+)
+{
+
+  UINT4 debug = 0;
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+  if(ell == 2 && abs(emm) == 2){
+    UINT4 status = XLALSimIMRPhenomXASFrequencySequence(
+      htildelm,
+      freqs,
+      m1_SI,
+      m2_SI,
+      chi1L,
+      chi2L,
+      distance,
+      phiRef,
+      fRef_In,
+      lalParams
+    );
+    if(emm>0){
+      #if DEBUG == 1
+      printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+      #endif
+      for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+        (*htildelm)->data->data[idx] = conj((*htildelm)->data->data[idx]);
+      }
+    }
+    return status;
+  }
+  else{ //Higher modes
+
+    INT4 return_code = 0;
+
+    /* Sanity checks */
+    if(*htildelm)       { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT);                                   }
+    if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+    if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+    if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+    if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+
+    // If fRef is not provided (i.e. set to 0), then take fRef to be the starting GW Frequency
+    REAL8 fRef = (fRef_In == 0.0) ? freqs->data[0] : fRef_In;
+
+    /* Initialize the useful powers of LAL_PI */
+    UINT4 status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+    XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+    status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+    XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+    /*
+    This routine automatically performs sanity checks on the masses, spins, etc.
+    */
+    REAL8 f_min_In  = freqs->data[0];
+    REAL8 f_max_In  = freqs->data[freqs->length - 1];
+
+    /*
+    Passing deltaF = 0 tells us that freqs contains a frequency grid with non-uniform spacing.
+    The function waveform start at lowest given frequency.
+    */
+
+    /* Check if LAL dictionary exists. If not, create a LAL dictionary. */
+    if(lalParams == NULL)
+    {
+      lalParams = XLALCreateDict();
+    }
+
+    /* Initialize IMRPhenomX waveform struct and perform sanity check. */
+    IMRPhenomXWaveformStruct *pWF;
+    pWF = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+    return_code = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, 0.0, fRef, phiRef, f_min_In, f_max_In, distance, 0.0, lalParams, debug);
+    XLAL_CHECK(XLAL_SUCCESS == return_code, XLAL_EFUNC, "Error:  failed.\n");
+
+    // allocate qnm struct
+    QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+    IMRPhenomXHM_Initialize_QNMs(qnms);
+
+    // Populate pWFHM
+    IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+    IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams);
+    LALFree(qnms);
+
+    /* Now call the IMRPhenomXHM waveform generator */
+    return_code = IMRPhenomXHMGenerateFDOneMode(
+      htildelm,
+      freqs,
+      pWF,
+      ell,
+      emm,
+      lalParams
+    );
+    #if DEBUG == 1
+      printf("\nOut of GenerateFDOneMode\n");
+    #endif
+    XLAL_CHECK(return_code == XLAL_SUCCESS, XLAL_EFUNC, "XLALSimIMRPhenomXHMFrequencySequenceOneMode failed to generate IMRPhenomXHM waveform.");
+
+    LALFree(pWF);
+    LALFree(pWFHM);
+
+    #if DEBUG == 1
+    printf("\n\nlength of htildelm = %i \n\n", (*htildelm)->data->length);
+    #endif
+
+    if(emm>0){
+      #if DEBUG == 1
+      printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+      #endif
+      INT4 minus1l = 1;
+      if(ell%2!=0){
+        #if DEBUG == 1
+        printf("\nl odd\n");
+        #endif
+        minus1l = -1;
+      }
+      for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+        (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
+      }
+    }
+
+    return XLAL_SUCCESS;
+
+  }//Higher modes
+}
+
+/*********************************************/
+/*                                           */
+/*          MULTIMODE WAVEFORM               */
+/*                                           */
+/*********************************************/
+
+/** Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
+
+XLALSimIMRPhenomXHM calls the function for a single mode that can be XLALSimIMRPhenomXHMGenerateFDOneMode or XLALSimIMRPhenomXHMMultiBandOneMode,
+depending on if the Multibanding is active or not.
+
+By default XLALSimIMRPhenomXHM is only used when the Multibanding is activated, since each mode has a different coarse frequency array and we can not recycle the array.
+
+This is just a wrapper of the function that actually carry out the calculations: IMRPhenomXHM_MultiMode2.
+
+*/
+
+/* Return hptilde, hctilde */
+int XLALSimIMRPhenomXHM(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency-domain waveform h+ */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency-domain waveform hx */
+  REAL8 m1_SI,                        /**< mass of companion 1 (kg) */
+  REAL8 m2_SI,                        /**< mass of companion 2 (kg) */
+  REAL8 chi1L,                        /**< z-component of the dimensionless spin of object 1 w.r.t. Lhat = (0,0,1) */
+  REAL8 chi2L,                        /**< z-component of the dimensionless spin of object 2 w.r.t. Lhat = (0,0,1) */
+  REAL8 f_min,                        /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                        /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                       /**< Sampling frequency (Hz) */
+  REAL8 distance,                     /**< distance of source (m) */
+  REAL8 inclination,                  /**< inclination of source (rad) */
+  REAL8 phiRef,                       /**< reference orbital phase (rad) */
+  REAL8 fRef_In,                      /**< Reference frequency */
+  LALDict *lalParams                  /**<linked list containing the extra parameters */
+)
+{
+  /* define and init return code for this function */
+  int retcode;
+
+  /* Sanity checks on input parameters: check pointers, etc.
+  More checks are done inside XLALSimIMRPhenomXHMGenerateFDOneMode/XLALSimIMRPhenomXHMMultiBandOneMode */
+  XLAL_CHECK(NULL != hptilde, XLAL_EFAULT);
+  XLAL_CHECK(NULL != hctilde, XLAL_EFAULT);
+  XLAL_CHECK(*hptilde == NULL, XLAL_EFAULT);
+  XLAL_CHECK(*hctilde == NULL, XLAL_EFAULT);
+  XLAL_CHECK(distance > 0, XLAL_EDOM, "distance must be positive.\n");
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+  /* Evaluate the model */
+  retcode = IMRPhenomXHM_MultiMode(
+    hptilde,
+    hctilde,
+    m1_SI,
+    m2_SI,
+    chi1L,
+    chi2L,
+    f_min,
+    f_max,
+    deltaF,
+    distance,
+    inclination,
+    phiRef,
+    fRef_In,
+    lalParams
+  );
+  XLAL_CHECK(retcode == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_MultiMode failed in XLALSimIMRPhenomXHM.");
+
+  #if DEBUG == 1
+  printf("\n******Leaving XLALSimIMRPhenomXHM*****\n");
+  #endif
+
+  return XLAL_SUCCESS;
+}
+
+/** Returns the hptilde and hctilde of the multimode waveform for positive frequencies.
+
+XLALSimIMRPhenomXHM2 builds each mode explicitly in the loop over modes, recycling some common quantities between modes like
+the frequency array, the powers of frequencies, structures, etc so it has less overhead than XLALSimIMRPhenomXHM.
+
+By default XLALSimIMRPhenomXHM2 is only used for the version without Multibanding.
+
+ This is just a wrapper of the function that actually carry out the calculations: IMRPhenomXHM_MultiMode2.
+ */
+int XLALSimIMRPhenomXHM2(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 inclination,                   /**< Inclination of the source */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< LAL Dictionary */
+)
+{
+  UINT4 debug = DEBUG;
+
+  UINT4 status;
+
+  #if DEBUG == 1
+  printf("\n*** IMRPhenomXHM2 ***\n");
+  printf("fRef_In : %e\n",fRef_In);
+  printf("m1_SI   : %e\n",m1_SI);
+  printf("m2_SI   : %e\n",m2_SI);
+  printf("chi1L   : %e\n",chi1L);
+  printf("chi2L   : %e\n",chi2L);
+  printf("f_min   : %.e  \n", f_min);
+  printf("f_min   : %.6f  \n", f_min);
+  printf("Performing sanity checks...\n");
+  #endif
+
+  /* Perform initial sanity checks */
+  if(*hptilde)       { XLAL_CHECK(NULL != hptilde, XLAL_EFAULT);                                   }
+  if(*hctilde)       { XLAL_CHECK(NULL != hctilde, XLAL_EFAULT);                                   }
+  if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+  if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+  if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+  if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+  if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+  if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+  if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+  /* If no reference frequency is given, set it to the starting gravitational wave frequency */
+  REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
+
+
+  #if DEBUG == 1
+  printf("\nInitializing waveform struct...\n");
+  #endif
+
+  /* Initialize the useful powers of LAL_PI */
+  status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+  /* Initialize IMR PhenomX Waveform struct and check that it initialized correctly */
+  IMRPhenomXWaveformStruct *pWF;
+  pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, inclination, lalParams, debug);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error:  failed.\n");
+
+
+  /* Check that the frequency array will be consistent: fmin < fmax_prime */
+  /* Return the closest power of 2 */
+  size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+  /* Frequencies will be set using only the lower and upper bounds that we passed */
+  size_t iStart = (size_t) (f_min / deltaF);
+  size_t iStop  = (size_t) (pWF->f_max_prime / deltaF);
+  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+  /*  Create a REAL8 frequency series.
+  Use fLow, fHigh, deltaF to compute frequency sequence. Only pass the boundaries (fMin, f_max_prime).   */
+  REAL8Sequence *freqs = XLALCreateREAL8Sequence(2);
+  freqs->data[0] = pWF->fMin;
+  freqs->data[1] = pWF->f_max_prime;
+
+
+  /* We now call the core IMRPhenomXHM_Multimode2 waveform generator. */
+  status = IMRPhenomXHM_MultiMode2(hptilde, hctilde, freqs, pWF, lalParams);
+  XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_MultiMode2 failed to generate IMRPhenomXHM waveform.");
+
+  #if DEBUG == 1
+  printf("\n\n **** Call to IMRPhenomXHM_MultiMode2 complete. **** \n\n");
+  #endif
+
+
+  /* Resize hptilde and hctilde if needed */
+  size_t n = (*hptilde)->data->length;
+  REAL8 lastfreq = n * deltaF;
+  #if DEBUG == 1
+      printf("\nlastfreq = %.16e\n", lastfreq);
+  #endif
+  if (lastfreq < f_max)
+  {
+
+    /* The user has requested a higher f_max than Mf = fCut.
+    Resize the frequency series to fill with zeros beyond the cutoff frequency. */
+
+    // We want to have the length be a power of 2 + 1
+    size_t n_full = NextPow2(f_max / deltaF) + 1;
+    #if DEBUG == 1
+        printf("\nlastfreq after resize = %.16e\n", n_full*deltaF);
+    #endif
+    /* Resize the COMPLEX16 frequency series */
+    *hptilde = XLALResizeCOMPLEX16FrequencySeries(*hptilde, 0, n_full);
+    *hctilde = XLALResizeCOMPLEX16FrequencySeries(*hctilde, 0, n_full);
+    XLAL_CHECK (*hptilde, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, lastfreq, n_full, f_max );
+  }
+
+  /* Free memory */
+  LALFree(pWF);
+  XLALDestroyREAL8Sequence(freqs);
+
+  return XLAL_SUCCESS;
+}
+/** @}
+* @} **/
+
+
+/* Core function of XLALSimIMRPhenomXHM, returns hptilde, hctilde corresponding to a sum of modes.
+The default modes are 22, 21, 33, 32 and 44. It returns also the contribution of the corresponding negatives modes. */
+static int IMRPhenomXHM_MultiMode(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8 m1_SI,                        /**< primary mass [kg] */
+  REAL8 m2_SI,                        /**< secondary mass [kg] */
+  REAL8 chi1z,                        /**< aligned spin of primary */
+  REAL8 chi2z,                        /**< aligned spin of secondary */
+  REAL8 f_min,                        /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                        /**< End frequency; 0 defaults to Mf = 0.3 */
+  REAL8 deltaF,                       /**< Sampling frequency (Hz) */
+  REAL8 distance,                     /**< distance of source (m) */
+  REAL8 inclination,                  /**< inclination of source (rad) */
+  REAL8 phiRef,                       /**< reference orbital phase (rad) */
+  REAL8 fRef_In,                      /**< Reference frequency */
+  LALDict *lalParams                  /**< LALDict struct */
+)
+{
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  INT4 sym; /* sym will decide whether to add the -m mode (when equatorial symmetry is present) */
+
+  /* Setup ModeArray reading from lalParams. */
+  if (lalParams == NULL)
+  {
+    lalParams = XLALCreateDict();
+  }
+  lalParams = IMRPhenomXHM_setup_mode_array(lalParams);
+  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+  /* At this point ModeArray should contain the list of modes
+  and therefore if NULL then something is wrong and abort. */
+  if (ModeArray == NULL)
+  {
+    XLAL_ERROR(XLAL_EDOM, "ModeArray is NULL when it shouldn't be. Aborting.\n");
+  }
+
+  INT4 status = 0;
+
+  INT4 init = 0; //Variable to control initialization of hptilde and hctilde
+
+  /* When calling only the 32 mode, we need to call also the 22 for the mixing, but not sum it for hp, hc */
+  INT4 add22 = 1;
+
+
+  COMPLEX16FrequencySeries *htilde22 = NULL;
+  INT4 posMode, negMode;
+  /* Take input/default value for the threshold of the Multibanding. If = 0 then do not use Multibanding. */
+  REAL8 resTest  = XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(lalParams);
+
+  /***** Loop over modes ******/
+  for (UINT4 ell = 2; ell <= L_MAX; ell++)
+  {
+    for (UINT4 emm = 1; emm <= ell; emm++)
+    { /* Loop over only positive m is intentional.
+      The single mode function returns the negative mode h_l-m, and the positive is added automatically in IMRPhenomXHMFDAddMode. */
+      /* First check if (l,m) mode is 'activated' in the ModeArray */
+      /* if activated then generate the mode, else skip this mode. */
+      posMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm);
+      negMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -emm);
+      if ( posMode != 1 && negMode != 1)
+      { /* skip mode */
+        continue;
+      } /* else: generate mode */
+      #if DEBUG == 1
+      printf("\n Mode %i%i\n",ell, emm);
+      #endif
+
+      // Variable to store the strain of only one (negative) mode: h_l-m
+      COMPLEX16FrequencySeries *htildelm = NULL;
+
+
+      if (resTest == 0){  // No multibanding
+        XLALSimIMRPhenomXHMGenerateFDOneMode(&htildelm, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams);
+      }
+      else{               // With multibanding
+        if(ell==3 && emm==2){  // mode with mixing
+          XLALSimIMRPhenomXHMMultiBandOneModeMixing(&htildelm, htilde22, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams);
+        }
+        else{                  // modes without mixing
+          XLALSimIMRPhenomXHMMultiBandOneMode(&htildelm, m1_SI, m2_SI, chi1z, chi2z, ell, -emm, distance, f_min, f_max, deltaF, phiRef, fRef_In, lalParams);
+        }
+        // If the 22 mode is active we will recycle for the mixing of the 32, we save it in another variable: htilde22.
+        if(ell==2 && emm==2){
+          htilde22 = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, htildelm->data->length);
+          for(UINT4 idx = 0; idx < htildelm->data->length; idx++){
+            htilde22->data->data[idx] = htildelm->data->data[idx];
+          }
+        }
+      }
+
+      /**** For debugging ****/
+      #if DEBUG == 1
+      //Save mode l-m in file
+      FILE *file;
+      char fileSpec[40];
+      sprintf(fileSpec, "simulation%i%i_MM.dat", ell,emm);
+      printf("\nOutput file: %s\r\n",fileSpec);
+      file = fopen(fileSpec,"w");
+      REAL8 m2_SI_a, m1_SI_a, chi1z_a, chi2z_a;
+      if(m1_SI < m2_SI){
+        m2_SI_a = m1_SI;
+        m1_SI_a = m2_SI;
+        chi1z_a = chi2z;
+        chi2z_a = chi1z;
+      }
+      else{
+        m1_SI_a = m1_SI;
+        m2_SI_a = m2_SI;
+        chi1z_a = chi1z;
+        chi2z_a = chi2z;
+      }
+      fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i Mtot = %.16f distance = %.16f\n", m1_SI_a/m2_SI_a, chi1z_a, chi2z_a, ell, emm, (m1_SI+m2_SI)/ LAL_MSUN_SI, distance/LAL_PC_SI/pow(10.,6));
+      fprintf(file,"# Frequency (Hz)    Real     Imaginary\n");
+      COMPLEX16 data;
+      for(UINT4 idx = 0; idx < ((htildelm)->data->length); idx++)
+      {
+        data = ((htildelm)->data->data)[idx];
+        fprintf(file, "%.16f  %.16e %.16e\n",  idx*deltaF, creal(data), cimag(data));
+      }
+      fclose(file);
+      #endif
+      /**** End debugging ****/
+
+
+      if (!(htildelm)){ XLAL_ERROR(XLAL_EFUNC);}
+
+      /* We test for hypothetical m=0 modes */
+      if (emm == 0)
+      {
+        sym = 0;
+      }
+      else
+      {
+        sym = 1;
+      }
+      /* Allocate hptilde and hctilde if they were not yet. */
+      /* Taken from IMRPhenomHM */
+      if( init == 0){
+        /* Coalescence time is fixed to t=0, shift by overall length in time. Model is calibrated such that it peaks approx 500M before the end of the waveform, add this time to the epoch. */
+        XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", deltaF);
+        size_t n = (htildelm)->data->length;
+        *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
+        if (!(hptilde)){  XLAL_ERROR(XLAL_EFUNC);}
+        memset((*hptilde)->data->data, 0, n * sizeof(COMPLEX16));
+        XLALUnitDivide(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit);
+        *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform",  &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
+        if (!(hctilde)){ XLAL_ERROR(XLAL_EFUNC);}
+        memset((*hctilde)->data->data, 0, n * sizeof(COMPLEX16));
+        XLALUnitDivide(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
+        init = 1;
+      }
+      /* Skip 22 mode if it was only required for the mixing of the 32 */
+      if(ell == 2 && emm == 2 && add22 == 0){
+        status = XLAL_SUCCESS;
+      }
+      /* Add the hl-m mode to hptilde and hctilde. */
+      else{     // According to LAL documentation the azimuthal angle phi = pi/2 - phiRef. This is not taken into account in PhenomD and that's why there is an dephasing of Pi/2 between PhenomD and SEOBNRv4
+          if(posMode==1 && negMode!=1){
+            status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, emm, 0);  // add only the positive mode
+          }
+          else if(posMode!=1 && negMode==1){
+            status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, -emm, 0);  // add only the negative mode
+          }
+          else{
+            status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, inclination, LAL_PI_2 , ell, emm, sym);    // add both positive and negative modes
+          }
+    }
+    XLALDestroyCOMPLEX16FrequencySeries(htildelm);
+  }//Loop over emm
+}//Loop over ell
+XLAL_CHECK(status == XLAL_SUCCESS, XLAL_EFUNC, "IMRPhenomXHM_Multimode failed to generate IMRPhenomXHM waveform.");
+
+/* Free memory */
+XLALDestroyCOMPLEX16FrequencySeries(htilde22);
+XLALDestroyValue(ModeArray);
+
+#if DEBUG == 1
+printf("\n******Leaving IMRPhenomXHM_MultiMode*****\n");
+#endif
+
+return XLAL_SUCCESS;
+}
+
+
+
+/* Core function of XLALSimIMRPhenomXHM2, returns hptilde, hctilde corresponding to a sum of modes.
+The default modes are 22, 21, 33, 32 and 44 with the respective negatives ones. */
+static int IMRPhenomXHM_MultiMode2(
+  COMPLEX16FrequencySeries **hptilde, /**< [out] Frequency domain h+ GW strain */
+  COMPLEX16FrequencySeries **hctilde, /**< [out] Frequency domain hx GW strain */
+  REAL8Sequence *freqs_In,            /**< min and max frequency [Hz] */
+  IMRPhenomXWaveformStruct *pWF,      /**< waveform parameters */
+  LALDict *lalParams                  /**< LALDict struct */
+)
+{
+  #if DEBUG == 1
+  printf("\n\n**** IMRPhenomXHM_MultiMode2 **** \n\n");
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  /* Initialize useful powers of LAL_PI */
+  int status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+  /* Build the frequency array and initialize htildelm to the length of freqs. */
+  REAL8Sequence *freqs;
+  COMPLEX16FrequencySeries *htildelm;
+  // offset is the number of frequency points between 0 and f_min.
+  UINT4 offset = SetupWFArrays(&freqs, &htildelm, freqs_In, pWF, ligotimegps_zero);
+
+  UINT4 len = freqs->length;
+
+  #if DEBUG == 1
+  printf("\n\nfstart, fend, lenfreqs lenhtildelm = %.16f %.16f %i %i\n\n", freqs->data[0], freqs->data[len-1], len, htildelm->data->length);
+  #endif
+
+  // Allocate qnm struct, it contains ringdown and damping frequencies.
+  QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+  IMRPhenomXHM_Initialize_QNMs(qnms);
+
+  UINT4 initial_status = XLAL_SUCCESS;
+
+  // Variable to transform Hz in adimensional frequencies Mf:  Mf = Msec * Hz.
+  REAL8 Msec  = pWF->M_sec;
+
+  /* Transform the frequency array to adimensional frequencies to evaluate the model.
+  Compute and array of the structure IMRPhenomX_UsefulPowers, with the useful powers of each frequency. */
+  REAL8 *Mf = (REAL8 *)XLALMalloc(len * sizeof(REAL8));
+  IMRPhenomX_UsefulPowers *powers_of_Mf = (IMRPhenomX_UsefulPowers *)XLALMalloc(len * sizeof(IMRPhenomX_UsefulPowers));
+
+  for (UINT4 idx = 0; idx < len; idx++){
+    Mf[idx] = Msec * freqs->data[idx];
+    initial_status     = IMRPhenomX_Initialize_Powers(&(powers_of_Mf[idx]), Mf[idx]);
+    if(initial_status != XLAL_SUCCESS)
+    {
+      status = initial_status;
+      XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+    }
+  }
+
+  INT4 sym = 1; /* sym will decide whether to add the m mode (when equatorial symmetry is present) */
+
+  /* setup ModeArray */
+  if (lalParams == NULL)
+  {
+    lalParams = XLALCreateDict();
+  }
+  lalParams = IMRPhenomXHM_setup_mode_array(lalParams);
+  LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+  /* At this point ModeArray should contain the list of modes
+  and therefore if NULL then something is wrong and abort. */
+  if (ModeArray == NULL)
+  {
+    XLAL_ERROR(XLAL_EDOM, "ModeArray is NULL when it shouldn't be. Aborting.\n");
+  }
+
+  /* Allocate hptilde and hctilde */
+  /* Coalescence time is fixed to t=0, shift by overall length in time. Model is calibrated such that it peaks approx 500M before the end of the waveform, add this time to the epoch. */
+    XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", pWF->deltaF);
+  //XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF + 500*pWF->Mtot*LAL_MTSUN_SI), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df + 500M with df = %g.", pWF->deltaF);
+  size_t n = (htildelm)->data->length;
+  *hptilde = XLALCreateCOMPLEX16FrequencySeries("hptilde: FD waveform", &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
+  if (!(hptilde)){   XLAL_ERROR(XLAL_EFUNC);}
+  memset((*hptilde)->data->data, 0, n * sizeof(COMPLEX16));  // what is this for??
+  XLALUnitDivide(&(*hptilde)->sampleUnits, &(*hptilde)->sampleUnits, &lalSecondUnit); // what does it do?
+
+  *hctilde = XLALCreateCOMPLEX16FrequencySeries("hctilde: FD waveform",  &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
+  if (!(hctilde)){ XLAL_ERROR(XLAL_EFUNC);}
+  memset((*hctilde)->data->data, 0, n * sizeof(COMPLEX16));
+  XLALUnitDivide(&(*hctilde)->sampleUnits, &(*hctilde)->sampleUnits, &lalSecondUnit);
+
+  #if DEBUG == 1
+  printf("\nlength htildelm = %zu\n", n);
+  #endif
+
+  /******* Compute and add 22 Mode if active **********/
+  COMPLEX16FrequencySeries *htilde22 = NULL;
+  INT4 pos22, neg22;
+  pos22 = XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, 2);
+  neg22 = XLALSimInspiralModeArrayIsModeActive(ModeArray, 2, -2);
+  if (pos22 == 1 || neg22 == 1){
+    #if DEBUG == 1
+    printf("\n\nCalling IMRPhenomXASFrequencySequence...\n\n");
+    #endif
+    COMPLEX16FrequencySeries *htilde22tmp = NULL;
+    XLALSimIMRPhenomXASFrequencySequence(&htilde22tmp, freqs, pWF->m1_SI, pWF->m2_SI, pWF->chi1L, pWF->chi2L, pWF->distance, pWF->phiRef_In, pWF->fRef, lalParams);
+    //If htilde22tmp is shorter than hptilde, need to resize
+    htilde22 = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform", &(ligotimegps_zero), 0.0, pWF->deltaF, &lalStrainUnit, n);
+    for(UINT4 idx = 0; idx < offset; idx++)
+    {
+      (htilde22->data->data)[idx] = 0.;
+    }
+    for(UINT4 idx = 0; idx < ((htilde22tmp)->data->length); idx++)
+    {
+      ((htilde22)->data->data)[idx+offset] = ((htilde22tmp)->data->data)[idx];
+    }
+    for(UINT4 idx = ((htilde22tmp)->data->length); idx < ((htildelm)->data->length) - offset; idx++)
+    {
+      (htilde22->data->data)[idx+offset] = 0.;
+    }
+    if(pos22==1 && neg22!=1){
+      status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, 2, 0);  // add only the positive mode
+    }
+    else if(pos22!=1 && neg22==1){
+      status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, -2, 0);  // add only the negative mode
+    }
+    else{
+      status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htilde22, pWF->inclination, LAL_PI_2, 2, 2, sym); // add both positive and negative modes
+    }
+
+    #if DEBUG == 1
+    //Save 22 mode in file
+    printf("phifRef22=%f\n",pWF->phifRef);
+    FILE *file22;
+    char fileSpec22[40];
+
+    sprintf(fileSpec22, "simulation%i_MM2.dat", 22);
+    printf("\nOutput file: %s\r\n",fileSpec22);
+    file22 = fopen(fileSpec22,"w");
+
+    fprintf(file22,"# q = %.16f m1 = %.16f m2 = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->m1, pWF->m2, pWF->chi1L, pWF->chi2L, 22, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
+    fprintf(file22,"# Frequency (Hz)    Real    Imaginary\n");
+
+    COMPLEX16 data22;
+    for(UINT4 idx = 0; idx < ((htilde22)->data->length); idx++)
+    {
+      data22 = ((htilde22)->data->data)[idx];
+      fprintf(file22, "%.16f  %.16e %.16e\n",  idx*pWF->deltaF, creal(data22), cimag(data22));
+    }
+    fclose(file22);
+    printf("\n lenhtilde22 =   %i\n",  htilde22->data->length);
+    #endif
+
+    XLALDestroyCOMPLEX16FrequencySeries(htilde22tmp);
+  } // End of 22 mode
+
+
+  #if DEBUG == 1
+  printf("\n\nlenfreqs lenhtildelm =  %i %i\n\n",  len, htildelm->data->length);
+  #endif
+
+  // Initialize Amplitude and phase coefficients of the 22. pAmp22 will be filled only for the 32. pPhase22 is used for all the modes, that is why is computed outside the loop.
+  IMRPhenomXAmpCoefficients *pAmp22=(IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+  IMRPhenomXPhaseCoefficients *pPhase22=(IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+  IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+
+
+  /****** Loop over higher modes ******/
+  REAL8 amp, phi;  // Amplitude and phase of the hlm mode
+  INT4 minus1l, posMode, negMode;
+  REAL8 Amp0;
+  for (UINT4 ell = 2; ell <= L_MAX; ell++)
+  {
+    /* Multiply by (-1)^l to get the true h_l-m(f) */
+    if(ell%2 != 0){
+      minus1l = -1;
+    }
+    else{
+      minus1l = 1;
+    }
+    Amp0 = minus1l * pWF->ampNorm * pWF->amp0;
+
+    for (INT4 emm = 1; emm < (INT4)ell + 1; emm++){
+      /* Loop over only positive m is intentional. The single mode function returns the negative mode h_l-m, and the positive is added automatically in IMRPhenomXHMFDAddMode. */
+      /* First check if (l,m) mode is 'activated' in the ModeArray */
+      /* if activated then generate the mode, else skip this mode. */
+      posMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm);
+      negMode = XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, -emm);
+      if ((posMode != 1 && negMode != 1) || (ell == 2 && abs(emm) == 2))
+      { /* skip mode */
+        continue;
+      } /* else: generate mode */
+
+      /* We test for hypothetical m=0 modes */
+      if (emm == 0)
+      {
+        sym = 0;
+      }
+      else
+      {
+        sym = 1;
+      }
+
+      /* Now build the corresponding hlm mode */
+
+      // Populate pWFHM with useful parameters of each mode
+      IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+      IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF, qnms, lalParams);
+
+      // If mode is even and black holes are equal we skip this part and return an array of zeros.
+      if(pWFHM->Ampzero==0){
+
+        #if DEBUG == 1
+        printf("\n\nInitializing amplitude struct of %i...\n\n",pWFHM->modeTag);
+        #endif
+
+        /* Allocate and initialize the PhenomXHM lm amplitude and phase coefficients struct */
+        IMRPhenomXHMAmpCoefficients *pAmp;
+        pAmp = XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+        IMRPhenomXHMPhaseCoefficients *pPhase;
+        pPhase = XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+        IMRPhenomXHM_FillAmpFitsArray(pAmp);
+        IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+
+        /* Get coefficients for Amplitude and Phase */
+        if (pWFHM->MixingOn == 1)  {
+          // For the 32 we need the speroidal coefficients for the phase and the amplitude coefficients of the 22.
+          GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
+          IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+        }
+        IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+        IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
+
+        #if DEBUG == 1
+        printf("\n\n **** Amplitude and Phase struct initialized. **** \n\n");
+        #endif
+
+        /* Loop over frequencies to generate waveform */
+        /* With mode mixng */
+        if(pWFHM->MixingOn==1){
+          // If the 22 mode has been already computed we use it for the mixing of the 32.
+          if(pos22 == 1 || neg22 == 1){
+            for (UINT4 idx = 0; idx < len; idx++)
+            {
+              COMPLEX16 wf22 = htilde22->data->data[idx + offset]; //This will be rescaled inside SpheroidalToSphericalRecycle for the rotation
+              amp = IMRPhenomXHM_Amplitude_ModeMixingRecycle(Mf[idx], &powers_of_Mf[idx], wf22, pAmp, pPhase, pWFHM);
+              phi = IMRPhenomXHM_Phase_ModeMixingRecycle(Mf[idx], &powers_of_Mf[idx], wf22, pAmp, pPhase, pWFHM);
+              /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+              ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
+            }
+          }
+          // If the 22 has not been computed, its ringdown part is computed internally using pAmp22 and pPhase22.
+          else{
+            for (UINT4 idx = 0; idx < len; idx++)
+            {
+              amp = IMRPhenomXHM_Amplitude_ModeMixing(Mf[idx], &powers_of_Mf[idx], pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+              phi = IMRPhenomXHM_Phase_ModeMixing(Mf[idx], &powers_of_Mf[idx], pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+              /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+              ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
+            }
+          }
+        }     /* No mode mixing */
+        else{
+          for (UINT4 idx = 0; idx < len; idx++)
+          {
+            amp = IMRPhenomXHM_Amplitude_noModeMixing(Mf[idx], &powers_of_Mf[idx], pAmp, pWFHM);
+            phi = IMRPhenomXHM_Phase_noModeMixing(Mf[idx], &powers_of_Mf[idx], pPhase, pWFHM, pWF);
+            /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+            ((htildelm)->data->data)[idx+offset] = Amp0 * amp * cexp(I * phi);
+          }
+        }/* End of loop over frequencies */
+        /* In GetPhaseCoefficients we call IMRPhenomX_Phase_22_ConnectionCoefficients so the coefficients below are initialized,
+         however every time a new mode is called we need to have these coefficients to be initially zero.*/
+        pPhase22->C1Int = 0;
+        pPhase22->C2Int = 0;
+        pPhase22->C1MRD = 0;
+        pPhase22->C2MRD = 0;
+
+        #if DEBUG == 1
+        ParametersToFile(pWF, pWFHM, pAmp, pPhase);
+        #endif
+        /* Free memory */
+        LALFree(pAmp);
+        LALFree(pPhase);
+      }
+      // Return array of zeros if the mode is zero
+      else{
+        for (UINT4 idx = 0; idx < len; idx++)
+        {
+          ((htildelm)->data->data)[idx+offset] = 0.;
+        }
+      }// end Amp zero
+
+
+      #if DEBUG == 1
+      // Save the hlm mode into a file
+      FILE *file;
+      char fileSpec[40];
+
+      sprintf(fileSpec, "simulation%i_MM2.dat", pWFHM->modeTag);
+      printf("\nOutput file: %s\r\n",fileSpec);
+      file = fopen(fileSpec,"w");
+
+      fprintf(file,"# q = %.16f m1 = %.16f m2 = %.16f chi1 = %.16f chi2 = %.16f lm = %i Mtot = %.16f distance = %.16f\n", pWF->q, pWF->m1, pWF->m2, pWF->chi1L, pWF->chi2L, pWFHM->modeTag, pWF->Mtot, pWF->distance/LAL_PC_SI/pow(10.,6));
+      fprintf(file,"# Frequency (Hz)    Amplitude    Phase\n");
+
+      COMPLEX16 data0;
+      for(UINT4 idx = 0; idx < htildelm->data->length; idx++)
+      {
+        data0 = ((htildelm)->data->data)[idx];
+        fprintf(file, "%.16f  %.16e %.16e\n",  idx*pWF->deltaF, creal(data0), cimag(data0));
+      }
+      fclose(file);
+      #endif
+
+      // Add the recent mode to hptilde and hctilde. beta is the azimuthal angle = pi/2 - phiRef, it is computed in IMRPhenomX_internals.c
+      if(posMode==1 && negMode!=1){
+        status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, emm, 0);  // add only the positive mode
+      }
+      else if(posMode!=1 && negMode==1){
+        status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, -emm, 0);  // add only the negative mode
+      }
+      else{
+        status = IMRPhenomXHMFDAddMode(*hptilde, *hctilde, htildelm, pWF->inclination, LAL_PI_2, ell, emm, sym); // add both positive and negative modes
+      }
+      LALFree(pWFHM);
+    }
+  }// End loop of higher modes
+
+
+  /* Free allocated memory */
+  XLALDestroyCOMPLEX16FrequencySeries(htilde22);
+  XLALDestroyCOMPLEX16FrequencySeries(htildelm);
+  XLALDestroyREAL8Sequence(freqs);
+  XLALDestroyValue(ModeArray);
+  LALFree(powers_of_Mf);
+  LALFree(pAmp22);
+  LALFree(pPhase22);
+  LALFree(qnms);
+  LALFree(Mf);
+
+
+  return status;
+}
+
+
+/* Function to sum one mode (htildelm) to hp/c tilde */
+static int IMRPhenomXHMFDAddMode(
+  COMPLEX16FrequencySeries *hptilde,  /**<[out] hp series*/
+  COMPLEX16FrequencySeries *hctilde,  /**<[out] hc series */
+  COMPLEX16FrequencySeries *htildelm, /**< hlm mode to add */
+  REAL8 theta,                        /**< Inclination [rad] */
+  REAL8 phi,                          /**< Azimuthal angle [rad]*/
+  INT4 l,                             /**< l index of the lm mode */
+  INT4 m,                             /**< m index of the lm mode */
+  INT4 sym                            /**< Equatorial symmetry */
+){
+  COMPLEX16 Ystar, Ym;
+  UINT4 j;
+  COMPLEX16 hlm; /* helper variable that contains a single point of hlmtilde */
+
+  INT4 minus1l; /* (-1)^l */
+  if (l % 2 !=0)
+  {
+    minus1l = -1;
+  }
+  else
+  {
+    minus1l = 1;
+  }
+
+  Ym = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, -m);
+
+  if (sym)
+  {
+	/* Equatorial symmetry: add in -m and m mode */
+    Ystar = conj(XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m));
+    COMPLEX16 factorp = 0.5 * (Ym + minus1l * Ystar);
+    COMPLEX16 factorc = I * 0.5 * ( Ym - minus1l * Ystar);
+
+	#if DEBUG == 1
+    printf("\nfactorp = %.16e", cabs(factorp));
+    printf("\nfactorc = %.16e",cabs(factorc));
+    printf("\nhtildelm length = %i\n", htildelm->data->length);
+    printf("\nhp/hc tilde length = %i %i\n", hptilde->data->length,hptilde->data->length);
+	#endif
+
+    for (j = 0; j < htildelm->data->length; ++j) {
+      hlm = htildelm->data->data[j];
+      hptilde->data->data[j] += (factorp * hlm);
+      hctilde->data->data[j] += (factorc * hlm);
+    }
+  }
+  else  // only positives or negative modes
+  {
+     COMPLEX16 Ylm, factorp, factorc;
+     if (m >0){  // only m>0
+       Ylm = conj(XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m));
+       factorp = 0.5*minus1l*Ylm;
+       factorc = -I*0.5*minus1l*Ylm;
+     }
+     else{   // only m<0
+       Ylm = XLALSpinWeightedSphericalHarmonic(theta, phi, -2, l, m);
+       factorp = 0.5*Ylm;
+       factorc = I*0.5*Ylm;
+     }
+
+    COMPLEX16* datap = hptilde->data->data;
+    COMPLEX16* datac = hctilde->data->data;
+
+    for ( j = 0; j < htildelm->data->length; ++j ) {
+      hlm = (htildelm->data->data[j]);
+      datap[j] += factorp*hlm;
+      datac[j] += factorc*hlm;
+    }
+  }
+  return XLAL_SUCCESS;
+}
+
+/** @addtogroup LALSimIMRPhenomX_c
+* @name Routines for IMRPhenomXHM
+* @{
+* @{ **/
+
+/** Returns amplitude of one single mode */
+int XLALSimIMRPhenomXHMAmplitude(
+    REAL8FrequencySeries **amplitude, /**< [out] FD amp */
+    REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+    REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+    REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+    REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+    UINT4 ell,                           /**< l index of the mode */
+    INT4 emm,                            /**< m index of the mode */
+    REAL8 distance,                      /**< Luminosity distance (m) */
+    REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+    REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+    REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+    REAL8 phiRef,                        /**< Orbital amp at fRef (rad) */
+    REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+    LALDict *lalParams                   /**< Extra params */
+  )
+  {
+    UINT4 status;
+
+    #if DEBUG == 1
+    printf("\nI am in %i %i mode\n",ell,emm);
+    printf("fRef_In : %e\n",fRef_In);
+    printf("m1_SI   : %e\n",m1_SI);
+    printf("m2_SI   : %e\n",m2_SI);
+    printf("chi1L   : %e\n",chi1L);
+    printf("chi2L   : %e\n\n",chi2L);
+    printf("Performing sanity checks...\n");
+    #endif
+
+    /* Sanity checks */
+    if(*amplitude)       { XLAL_CHECK(NULL != amplitude, XLAL_EFAULT);                                   }
+    if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+    if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+    if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+    if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+    if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+    if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+    if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+    /*
+      Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+        - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+        - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+        - For mass ratios > 1000: throw a hard error that model is not valid.
+        - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+    */
+    REAL8 mass_ratio;
+    if(m1_SI > m2_SI)
+    {
+      mass_ratio = m1_SI / m2_SI;
+    }
+    else
+    {
+      mass_ratio = m2_SI / m1_SI;
+    }
+    if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+    if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+    if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+
+      /* Set LIGOTimeGPS */
+      LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+      /* setup ModeArray */
+      if (lalParams == NULL)
+      {
+          lalParams = XLALCreateDict();
+      }
+      lalParams = IMRPhenomXHM_setup_mode_array(lalParams);
+      LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+      /* first check if (l,m) mode is 'activated' in the ModeArray */
+      /* if activated then generate the mode, else skip this mode. */
+      if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1)
+      { /* skip mode */
+        XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
+        XLAL_ERROR(XLAL_EDOM);
+      } /* else: generate mode */
+      XLALDestroyValue(ModeArray);
+
+
+      /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
+      REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
+
+      /* Initialize the useful powers of LAL_PI */
+      status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+      status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+      XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+      /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
+      IMRPhenomXWaveformStruct *pWF;
+      pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+      status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, 0.0, lalParams, DEBUG);
+      XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+
+      /* Check that the frequency array will be consistent: fmin < fmax_prime */
+      /* Return the closest power of 2 */
+      size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+      /* Frequencies will be set using only the lower and upper bounds that we passed */
+      size_t iStart = (size_t) (f_min / deltaF);
+      size_t iStop  = (size_t) (pWF->f_max_prime / deltaF);
+      XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+      "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+
+      /*
+      Create a REAL8 frequency series.
+      Use fLow, fHigh, deltaF to compute frequency sequence. Only pass the boundaries (fMin, fMax).
+      */
+      REAL8Sequence *freqs_In = XLALCreateREAL8Sequence(2);
+      freqs_In->data[0] = pWF->fMin;
+      freqs_In->data[1] = pWF->f_max_prime;
+
+      REAL8Sequence *freqs;
+      UINT4 offset = SetupWFArraysReal(&freqs, amplitude, freqs_In, pWF, ligotimegps_zero);
+
+      // allocate qnm struct
+      QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+      IMRPhenomXHM_Initialize_QNMs(qnms);
+      // Populate pWFHM
+      IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+      IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams);
+      LALFree(qnms);
+
+      //populate coefficients of 22 mode, to rotate to spherical
+      IMRPhenomXAmpCoefficients *pAmp22=(IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+      IMRPhenomXPhaseCoefficients *pPhase22=(IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+
+      /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
+      IMRPhenomXHMAmpCoefficients *pAmp = (IMRPhenomXHMAmpCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+      IMRPhenomXHMPhaseCoefficients *pPhase = (IMRPhenomXHMPhaseCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+
+      /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
+      IMRPhenomXHM_FillAmpFitsArray(pAmp);
+
+
+      /* Get coefficients for Amplitude and phase */
+      if (pWFHM->MixingOn == 1)  {
+        IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+        IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+        GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
+        IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+      }
+      IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+
+      REAL8 Amp0 = pWFHM->Amp0, amp;
+      IMRPhenomX_UsefulPowers powers_of_Mf;
+      /* Loop over frequencies to generate waveform */
+      /* Modes with mixing */
+      if(pWFHM->MixingOn==1){
+
+        REAL8 Mf;
+        for (UINT4 idx = 0; idx < freqs->length; idx++)
+        {
+          Mf    = pWF->M_sec * freqs->data[idx];
+          INT4 initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf, Mf);
+          if(initial_status != XLAL_SUCCESS)
+          {
+            status = initial_status;
+            XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+          }
+          else
+          {
+            amp = IMRPhenomXHM_Amplitude_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+            ((*amplitude)->data->data)[idx+offset] = Amp0 * amp;
+          }
+        }
+      }  /* Modes without mixing */
+      else{
+        for (UINT4 idx = 0; idx < freqs->length; idx++)
+        {
+          REAL8 Mf    = pWF->M_sec * freqs->data[idx];
+          INT4 initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+          if(initial_status != XLAL_SUCCESS)
+          {
+            status = initial_status;
+            XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+          }
+          else
+          {
+            amp = IMRPhenomXHM_Amplitude_noModeMixing(Mf, &powers_of_Mf, pAmp, pWFHM);
+            ((*amplitude)->data->data)[idx+offset] = Amp0 * amp;
+          }
+        }
+      }
+
+      /* Resize amplitude if needed */
+      if (pWF->f_max_prime < pWF->fMax)
+      {
+        /*
+        The user has requested a higher f_max than Mf = fCut.
+        Resize the frequency series to fill with zeros beyond the cutoff frequency.
+        */
+        size_t n = (*amplitude)->data->length;
+
+        // We want to have the length be a power of 2 + 1
+        size_t n_full = NextPow2(pWF->fMax / pWF->deltaF) + 1;
+
+        /* Resize the COMPLEX16 frequency series */
+        *amplitude = XLALResizeREAL8FrequencySeries(*amplitude, 0, n_full);
+        XLAL_CHECK (*amplitude, XLAL_ENOMEM, "Failed to resize waveform REAL8FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
+      }
+
+      LALFree(pWFHM);
+      LALFree(pWF);
+      LALFree(pAmp22);
+      LALFree(pAmp);
+      LALFree(pPhase22);
+      LALFree(pPhase);
+
+      return XLAL_SUCCESS;
+  }
+
+/** Returns phase of one single mode */
+  int XLALSimIMRPhenomXHMPhase(
+      REAL8FrequencySeries **phase,        /**< [out] FD amp */
+      REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+      REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+      REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+      REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+      UINT4 ell,                           /**< l index of the mode */
+      INT4 emm,                            /**< m index of the mode */
+      REAL8 distance,                      /**< Luminosity distance (m) */
+      REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+      REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = 0.3 */
+      REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+      REAL8 phiRef,                        /**< Orbital amp at fRef (rad) */
+      REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+      LALDict *lalParams                   /**< Extra params */
+    )
+    {
+      UINT4 status;
+
+      #if DEBUG == 1
+      printf("\nI am in %i %i mode\n",ell,emm);
+      printf("fRef_In : %e\n",fRef_In);
+      printf("m1_SI   : %e\n",m1_SI);
+      printf("m2_SI   : %e\n",m2_SI);
+      printf("chi1L   : %e\n",chi1L);
+      printf("chi2L   : %e\n\n",chi2L);
+      printf("Performing sanity checks...\n");
+      #endif
+
+      /* Sanity checks */
+      if(*phase)       { XLAL_CHECK(NULL != phase, XLAL_EFAULT);                                   }
+      if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+      if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+      if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+      if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+      if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+      if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+      if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+      /*
+        Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+          - For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+          - For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+          - For mass ratios > 1000: throw a hard error that model is not valid.
+          - For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+      */
+      REAL8 mass_ratio;
+      if(m1_SI > m2_SI)
+      {
+        mass_ratio = m1_SI / m2_SI;
+      }
+      else
+      {
+        mass_ratio = m2_SI / m1_SI;
+      }
+      if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+      if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+      if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+
+        /* Set LIGOTimeGPS */
+        LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+        /* setup ModeArray */
+        if (lalParams == NULL)
+        {
+            lalParams = XLALCreateDict();
+        }
+        lalParams = IMRPhenomXHM_setup_mode_array(lalParams);
+        LALValue *ModeArray = XLALSimInspiralWaveformParamsLookupModeArray(lalParams);
+
+        /* first check if (l,m) mode is 'activated' in the ModeArray */
+        /* if activated then generate the mode, else skip this mode. */
+        if (XLALSimInspiralModeArrayIsModeActive(ModeArray, ell, emm) != 1)
+        { /* skip mode */
+          XLALPrintError("XLAL Error - %i%i mode is not included\n", ell, emm);
+          XLAL_ERROR(XLAL_EDOM);
+        } /* else: generate mode */
+        XLALDestroyValue(ModeArray);
+
+
+        /* If no reference frequency is given, we will set it to the starting gravitational wave frequency */
+        REAL8 fRef = (fRef_In == 0.0) ? f_min : fRef_In;
+
+        /* Initialize the useful powers of LAL_PI */
+        status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+        status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+        XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+
+        /* Initialize IMRPhenomX Waveform struct and check that it generated successfully */
+        IMRPhenomXWaveformStruct *pWF;
+        pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+        status = IMRPhenomXSetWaveformVariables(pWF,m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef, phiRef, f_min, f_max, distance, 0.0, lalParams, DEBUG);
+        XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+
+        /* Check that the frequency array will be consistent: fmin < fmax_prime */
+        /* Return the closest power of 2 */
+        size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+        /* Frequencies will be set using only the lower and upper bounds that we passed */
+        size_t iStart = (size_t) (f_min / deltaF);
+        size_t iStop  = (size_t) (pWF->f_max_prime / deltaF);
+        XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+        "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+
+        /*
+        Create a REAL8 frequency series.
+        Use fLow, fHigh, deltaF to compute frequency sequence. Only pass the boundaries (fMin, fMax).
+        */
+        REAL8Sequence *freqs_In = XLALCreateREAL8Sequence(2);
+        freqs_In->data[0] = pWF->fMin;
+        freqs_In->data[1] = pWF->f_max_prime;
+
+        REAL8Sequence *freqs;
+        UINT4 offset = SetupWFArraysReal(&freqs, phase, freqs_In, pWF, ligotimegps_zero);
+
+        // allocate qnm struct
+        QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+        IMRPhenomXHM_Initialize_QNMs(qnms);
+        // Populate pWFHM
+        IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+        IMRPhenomXHM_SetHMWaveformVariables(ell, abs(emm), pWFHM, pWF, qnms, lalParams);
+        LALFree(qnms);
+
+        //populate coefficients of 22 mode, to rotate to spherical
+        IMRPhenomXAmpCoefficients *pAmp22=(IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+        IMRPhenomXPhaseCoefficients *pPhase22=(IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+        IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+
+        /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
+        IMRPhenomXHMAmpCoefficients *pAmp = (IMRPhenomXHMAmpCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+        IMRPhenomXHMPhaseCoefficients *pPhase = (IMRPhenomXHMPhaseCoefficients*) XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+
+        /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
+        IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+
+
+        /* Get coefficients for Amplitude and phase */
+        if (pWFHM->MixingOn == 1)  {
+          GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
+          IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+          IMRPhenomXHM_FillAmpFitsArray(pAmp);
+          IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+        }
+        IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
+
+        IMRPhenomX_UsefulPowers powers_of_Mf;
+        REAL8 addpi = 0;   // Add pi to the phase if (-1)^l is negative
+
+        /* Multiply by (-1)^l to get the true negative mode */
+        if(ell%2 != 0){
+          addpi = LAL_PI;
+        }
+        /* Loop over frequencies to generate waveform */
+        /* Modes with mixing */
+        if(pWFHM->MixingOn==1){
+
+          REAL8 Mf;
+          for (UINT4 idx = 0; idx < freqs->length; idx++)
+          {
+            Mf    = pWF->M_sec * freqs->data[idx];
+            INT4 initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+            if(initial_status != XLAL_SUCCESS)
+            {
+              status = initial_status;
+              XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+            }
+            else
+            {
+              REAL8 phi = IMRPhenomXHM_Phase_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+              ((*phase)->data->data)[idx+offset] = phi + addpi;
+            }
+          }
+        }  /* Modes without mixing */
+        else{
+          for (UINT4 idx = 0; idx < freqs->length; idx++)
+          {
+            REAL8 Mf    = pWF->M_sec * freqs->data[idx];
+            INT4 initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+            if(initial_status != XLAL_SUCCESS)
+            {
+              status = initial_status;
+              XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d", initial_status);
+            }
+            else
+            {
+              REAL8 phi = IMRPhenomXHM_Phase_noModeMixing(Mf, &powers_of_Mf, pPhase, pWFHM, pWF);
+              ((*phase)->data->data)[idx+offset] = phi + addpi;
+            }
+          }
+        }
+
+        /* If the mode is positive, the wf is (-1)^l*conjugate(wf). For the phase this is translated in adding or not pi and changing the sign. */
+        if(emm > 0){
+            for (UINT4 idx = 0; idx < freqs->length; idx++)
+            {
+                ((*phase)->data->data)[idx+offset] = addpi - ((*phase)->data->data)[idx+offset];
+            }
+        }
+
+        /* Resize htildelm if needed */
+        if (pWF->f_max_prime < pWF->fMax)
+        {
+          /*
+          The user has requested a higher f_max than Mf = fCut.
+          Resize the frequency series to fill with zeros beyond the cutoff frequency.
+          */
+          size_t n = (*phase)->data->length;
+
+          // We want to have the length be a power of 2 + 1
+          size_t n_full = NextPow2(pWF->fMax / pWF->deltaF) + 1;
+
+          /* Resize the COMPLEX16 frequency series */
+          *phase = XLALResizeREAL8FrequencySeries(*phase, 0, n_full);
+          XLAL_CHECK (*phase, XLAL_ENOMEM, "Failed to resize waveform REAL8FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
+        }
+
+        LALFree(pWFHM);
+        LALFree(pWF);
+        LALFree(pAmp22);
+        LALFree(pAmp);
+        LALFree(pPhase22);
+        LALFree(pPhase);
+
+        return XLAL_SUCCESS;
+    }
+/** @}
+* @} **/
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM.h b/lalsimulation/lib/LALSimIMRPhenomXHM.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4d5824d7fdf1aa3bfc789b466505593a7401146
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM.h
@@ -0,0 +1,65 @@
+/*
+* Copyright (C) 2019 Marta Colleoni, Cecilio García Quirós
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*/
+
+#ifndef _LALSIM_IMR_PHENOMXHM_H
+#define _LALSIM_IMR_PHENOMXHM_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+#include <complex.h>
+
+#include <lal/LALStdlib.h>
+#include <lal/LALConstants.h>
+#include <lal/Date.h>
+#include <lal/FrequencySeries.h>
+#include <lal/TimeSeries.h>
+#include <lal/TimeFreqFFT.h>
+#include <lal/Units.h>
+#include <lal/LALSimInspiral.h>
+
+
+/* CONSTANTS */
+#define MAX_ALLOWED_MASS_RATIO 5000
+#define MAX_ALLOWED_ETA 0.0002
+
+// /* Returns the Fourier domain strain of just one negative mode: h_l-m. This quantity is zero for negative frequencies.
+// However the positive mode h_lm is zero for positive frequencies and for the negative frequencies is equal to (-1)^l h*_l-m(-f).
+// This is a wrapper function that use XLALSimIMRPhenomXASGenerateFD for the 22 mode and XLALSimIMRPhenomXHMOneMode for the higher modes. */
+
+
+#include "LALSimIMRPhenomXHM_structs.h"
+
+int IMRPhenomXHMGenerateFDOneMode(
+   COMPLEX16FrequencySeries **htildelm,  /**< [out] hlm for one mode **/
+   REAL8Sequence *freqs_In,              /**< fmin, fmax [Hz] **/
+   IMRPhenomXWaveformStruct *pWF,        /**< structure of the 22 mode **/
+   UINT4 ell,                            /**< first index of the mode **/
+   UINT4 emm,                            /**< second index of the mode **/
+   LALDict *lalParams                    /**< extra params **/
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LALSIM_IMR_PHENOMXHM_H */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.c b/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.c
new file mode 100644
index 0000000000000000000000000000000000000000..815ca43491c86663baf4f7565f86ccd070394192
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+ //
+//  LALSimIMRPhenomXHM_inspiral.c
+//
+//
+//  Created by Marta on 06/02/2019.
+//
+
+#include "LALSimIMRPhenomXHM_inspiral.h"
+
+/*************************************/
+/*                                   */
+/*            AMPLITUDE              */
+/*                                   */
+/*************************************/
+
+/* Fits of the collocation points in the inspiral across parameter space. 3 for each mode: iv1, iv2, iv3
+ [iv1,iv2,iv3]=[0.5*f^Ins_lm,0.75*f^Ins_lm,f^Ins_lm]
+ For more details about the reconstruction procedure, see Sec. IV.A
+ */
+
+ /* These parameter-space fits are documented in the supplementary material of https://dcc.ligo.org/P2000011-v2.
+    There are 2 Mathematica notebooks (one for amplitude and one for phase) that read the fits data and automatically generate the C-code below.
+    For more information read https://git.ligo.org/waveforms/reviews/imrphenomx/blob/master/documentation/ParspaceFits/README and the documentation in the notebooks. */
+
+// Spin parameter S = chi_PN = chi_eff - 38/113 * eta * (chi1 + chi2)
+// chi_eff = (m1*chi1 + m2*chi2)/(m1 + m2)
+
+
+
+static double IMRPhenomXHM_Insp_Amp_21_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, eta2,eta3,eta4,eta5,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 4.*eta)*(0.037868557189995156 + 0.10740090317702103*eta + 1.963812986867654*eta2 - 16.706455229589558*eta3 + 69.75910808095745*eta4 - 98.3062466823662*eta5);
+            double eqSpin = sqrt(1. - 4.*eta)*S*(-0.007963757232702219 + 0.10627108779259965*eta - 0.008044970210401218*S + eta2*(-0.4735861262934258 - 0.5985436493302649*S - 0.08217216660522082*S2));
+            double uneqSpin = -0.257787704938017*(chi1 - 1.*chi2)*eta2*(1. + 8.75928187268504*eta2) - 0.2597503605427412*(chi1 - 1.*chi2)*eta2*S;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_21_iv1: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_21_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 4.*eta)*(0.05511628628738656 - 0.12579599745414977*eta + 2.831411618302815*eta2 - 14.27268643447161*eta3 + 28.3307320191161*eta4);
+            double eqSpin = sqrt(1. - 4.*eta)*S*(-0.008692738851491525 + eta*(0.09512553997347649 + 0.116470975986383*S) - 0.009520793625590234*S + eta2*(-0.3409769288480959 - 0.8321002363767336*S - 0.13099477081654226*S2) - 0.006383232900211555*S2);
+            double uneqSpin = -0.2962753588645467*(chi1 - 1.*chi2)*eta2*(1. + 1.3993978458830476*eta2) - 0.17100612756133535*(chi1 - 1.*chi2)*eta2*S*(1. + 18.974303741922743*eta2*delta);
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_21_iv2: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_21_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 4.*eta)*(0.059110044024271766 - 0.0024538774422098405*eta + 0.2428578654261086*eta2);
+            double eqSpin = sqrt(1. - 4.*eta)*S*(-0.007044339356171243 - 0.006952154764487417*S + eta2*(-0.016643018304732624 - 0.12702579620537421*S + 0.004623467175906347*S2) - 0.007685497720848461*S2);
+            double uneqSpin = -0.3172310538516028*(chi1 - 1.*chi2)*(1. - 2.9155919835488024*eta2)*eta2 - 0.11975485688200693*(chi1 - 1.*chi2)*eta2*S*(1. + 17.27626751837825*eta2*delta);
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_21_iv3: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_33_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, eta2,eta3,eta4,eta5,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = (sqrt(1. - 4.*eta)*(-0.056586690934283326 - 0.14374841547279146*eta + 0.5584776628959615*eta2))/(-0.3996185676368123 + eta);
+            double eqSpin = sqrt(1. - 4.*eta)*S*((0.056042044149691175 + 0.12482426029674777*S)*S + eta*(2.1108074577110343 - 1.7827773156978863*S2) + eta2*(-7.657635515668849 - 0.07646730296478217*S + 5.343277927456605*S2));
+            double uneqSpin = 0.45866449225302536*(chi1 - 1.*chi2)*(1. - 9.603750707244906*eta2)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_33_iv1: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_33_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 4.*eta)*(0.2137734510411439 - 0.7692194209223682*eta + 26.10570221351058*eta2 - 316.0643979123107*eta3 + 2090.9063511488234*eta4 - 6897.3285171507105*eta5 + 8968.893362362503*eta6);
+            double eqSpin = sqrt(1. - 4.*eta)*S*(0.018546836505210842 + 0.05924304311104228*S + eta*(1.6484440612224325 - 0.4683932646001618*S - 2.110311135456494*S2) + 0.10701786057882816*S2 + eta2*(-6.51575737684721 + 1.6692205620001157*S + 8.351789152096782*S2));
+            double uneqSpin = 0.3929315188124088*(chi1 - 1.*chi2)*(1. - 11.289452844364227*eta2)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_33_iv2: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_33_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 4.*eta)*(0.2363760327127446 + 0.2855410252403732*eta - 10.159877125359897*eta2 + 162.65372389693505*eta3 - 1154.7315106095564*eta4 + 3952.61320206691*eta5 - 5207.67472857814*eta6);
+            double eqSpin = sqrt(1. - 4.*eta)*S*(0.04573095188775319 + 0.048249943132325494*S + eta*(0.15922377052827502 - 0.1837289613228469*S - 0.2834348500565196*S2) + 0.052963737236081304*S2);
+            double uneqSpin = 0.25187274502769835*(chi1 - 1.*chi2)*(1. - 12.172961866410864*eta2)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_33_iv3: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_32_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+  UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,eta7,eta8,S2,S3,S4;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            eta8 = pow(eta,8);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = sqrt(1. - 3.*eta)*(0.019069933430190773 - 0.19396651989685837*eta + 11.95224600241255*eta2 - 158.90113442757382*eta3 + 1046.65239329071*eta4 - 3476.940285294999*eta5 + 4707.249209858949*eta6);
+            double eqSpin = sqrt(1. - 3.*eta)*S*(0.0046910348789512895 + 0.40231360805609434*eta - 0.0038263656140933152*S + 0.018963579407636953*S2 + eta2*(-1.955352354930108 + 2.3753413452420133*S - 0.9085620866763245*S3) + 0.02738043801805805*S3 + eta3*(7.977057990568723 - 7.9259853291789515*S + 0.49784942656123987*S2 + 5.2255665027119145*S3));
+            double uneqSpin = 0.058560321425018165*pow(chi1 - 1.*chi2,2)*(1. - 19.936477485971217*eta2)*eta2 + 1635.4240644598524*(chi1 - 1.*chi2)*eta8*delta + 0.2735219358839411*(chi1 - 1.*chi2)*eta2*S*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_32_iv1: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_32_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,eta7,eta8,S2,S3,S4;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            eta8 = pow(eta,8);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = sqrt(1. - 3.*eta)*(0.024621376891809633 - 0.09692699636236377*eta + 2.7200998230836158*eta2 - 16.160563094841066*eta3 + 32.930430889650836*eta4);
+            double eqSpin = sqrt(1. - 3.*eta)*S*(0.008522695567479373 - 1.1104639098529456*eta2 - 0.00362963820787208*S + 0.016978054142418417*S2 + eta*(0.24280554040831698 + 0.15878436411950506*S - 0.1470288177047577*S3) + 0.029465887557447824*S3 + eta3*(4.649438233164449 - 0.7550771176087877*S + 0.3381436950547799*S2 + 2.5663386135613093*S3));
+            double uneqSpin = -0.007061187955941243*pow(chi1 - 1.*chi2,2)*(1. - 2.024701925508361*eta2)*eta2 + 215.06940561269835*(chi1 - 1.*chi2)*eta8*delta + 0.1465612311350642*(chi1 - 1.*chi2)*eta2*S*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_32_iv2: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_32_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,eta7,eta8,eta9,S2,S3,S4;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            eta8 = pow(eta,8);
+            eta9 = pow(eta,9);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = (sqrt(1. - 3.*eta)*(-0.006150151041614737 + 0.017454430190035*eta + 0.02620962593739105*eta2 - 0.019043090896351363*eta3))/(-0.2655505633361449 + eta);
+            double eqSpin = sqrt(1. - 3.*eta)*S*(0.011073381681404716 + 0.00347699923233349*S + eta*S*(0.05592992411391443 - 0.15666140197050316*S2) + 0.012079324401547036*S2 + eta2*(0.5440307361144313 - 0.008730335213434078*S + 0.04615964369925028*S2 + 0.6703688097531089*S3) + 0.016323101357296865*S3);
+            double uneqSpin = -0.020140175824954427*pow(chi1 - 1.*chi2,2)*(1. - 12.675522774051249*eta2)*eta2 - 417.3604094454253*(chi1 - 1.*chi2)*eta8*delta + 0.10464021067936538*(chi1 - 1.*chi2)*eta2*S*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_32_iv3: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_44_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, eta2,eta3,eta4,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(1. - 3.*eta)*(0.06190013067931406 + 0.1928897813606222*eta + 1.9024723168424225*eta2 - 15.988716302668415*eta3 + 35.21461767354364*eta4);
+            double eqSpin = sqrt(1. - 3.*eta)*S*(0.011454874900772544 + 0.044702230915643903*S + eta*(0.6600413908621988 + 0.12149520289658673*S - 0.4482406547006759*S2) + 0.07327810908370004*S2 + eta2*(-2.1705970511116486 - 0.6512813450832168*S + 1.1237234702682313*S2));
+            double uneqSpin = 0.4766851579723911*(chi1 - 1.*chi2)*(1. - 15.950025762198988*eta2)*eta2 + 0.127900699645338*pow(chi1 - 1.*chi2,2)*(1. - 15.79329306044842*eta2)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_44_iv1: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_44_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 0.08406011695496626 - 0.1469952725049322*eta + 0.2997223283799925*eta2 - 1.2910560244510723*eta3;
+            double eqSpin = (0.023924074703897662 + 0.26110236039648027*eta - 1.1536009170220438*eta2)*S + (0.04479727299752669 - 0.1439868858871802*eta + 0.05736387085230215*eta2)*S2 + (0.06028104440131858 - 0.4759412992529712*eta + 1.1090751649419717*eta2)*S3;
+            double uneqSpin = 0.10346324686812074*pow(chi1 - 1.*chi2,2)*(1. - 16.135903382018213*eta2)*eta2 + 0.2648241309154185*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_44_iv2: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Amp_44_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,S2,S3;
+    switch (InspAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 0.08212436946985402 - 0.025332770704783136*eta - 3.2466088293309885*eta2 + 28.404235115663706*eta3 - 111.36325359782991*eta4 + 157.05954559045156*eta5;
+            double eqSpin = S*(0.03488890057062679 + 0.039491331923244756*S + eta*(-0.08968833480313292 - 0.12754920943544915*S - 0.11199012099701576*S2) + 0.034468577523793176*S2);
+            double uneqSpin = 0.2062291124580944*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Insp_Amp_44_iv3: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+
+/***********************************************/
+/*     Pseudo PN Amplitude Coefficients    */
+/***********************************************/
+
+/* The whole inspiral ansatz is given by
+
+    PNAnsatz(f) + pseudo-PN(f),  with pseudo-PN(f) = rho1 *(f/fcutInsp)^(7/3) + rho2(f/fcutInsp)^(8/3) + rho3(f/fcutInsp)^(9/3).
+
+  The coefficients are computed demanding that the pseudo-PN part at the three collocation points frequencies returns the actual collocation points: iv1, iv2, iv3.
+
+*/
+
+/* The input arguments for these rho coefficients are the value of the collocation points: v1, v2, v3, useful powers of the frequencies of these points f1, f2, f3 and the cutting frequency for the
+inspiral fcutInsp. The values v1, v2, v3 are given by the fit of the collocation points minus the value of the PNAnsatz at that frequency. */
+
+/* There are 3 functions, one for each pseudoPN coefficient rho1,2,3.
+Every function contains three possible results, depending on if you reconstruct with 3, 2 or 1 collocation points.
+With 2 colloc points rho3 = 0, and with 1 colloc point rho2=rho3=0 */
+
+/* Get Pseudo PN Amp coefficient rho1 at f^(7/3) */
+static double IMRPhenomXHM_Inspiral_Amp_rho1(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcutInsp, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM){
+  double retVal = 0.;
+  switch(pWFHM->IMRPhenomXHMInspiralAmpVersion){
+    case 3: // 3 inspiral collocation points
+    {
+      // default version
+      retVal = (powers_of_fcutInsp->seven_thirds*(-(powers_of_f1->three*powers_of_f3->eight_thirds*v2) + powers_of_f1->eight_thirds*powers_of_f3->three*v2 + powers_of_f2->three*(powers_of_f3->eight_thirds*v1 - powers_of_f1->eight_thirds*v3) + powers_of_f2->eight_thirds*(-(powers_of_f3->three*v1) + powers_of_f1->three*v3)))/(powers_of_f1->seven_thirds*(powers_of_f1->one_third - powers_of_f2->one_third)*powers_of_f2->seven_thirds*(powers_of_f1->one_third - powers_of_f3->one_third)*(powers_of_f2->one_third - powers_of_f3->one_third)*powers_of_f3->seven_thirds);
+      break;
+    }
+    case 2:  // 2 inspiral collocation points
+    {
+      retVal=(powers_of_fcutInsp->seven_thirds*(-(powers_of_f2->eight_thirds*v1) + powers_of_f1->eight_thirds*v2))/(powers_of_f1->seven_thirds*(powers_of_f1->one_third - powers_of_f2->one_third)*powers_of_f2->seven_thirds);
+      break;
+    }
+    case 1:  // 1 inspiral collocation points
+    {
+      retVal=(powers_of_fcutInsp->seven_thirds*v1)/(powers_of_f1->seven_thirds);
+      break;
+    }
+    case 0:  // No collocation points, reconstruct with PN only
+    {
+      retVal=0;
+      break;
+    }
+    default: {
+      XLALPrintError("Error in IMRPhenomXHM_Inspiral_Amp_rho1: version is not valid. Versions available are 0,1,2,3.\n");
+      XLAL_ERROR(XLAL_EDOM, "IMRPhenomXHM_Inspiral_Amp_rho1 version is not valid.  Aborting. Versions available are 0,1,2,3.\n");
+    }
+  }
+  return retVal;
+
+}
+
+/* Get Pseudo PN Amp coefficient rho2 at f^(8/3) */
+static double IMRPhenomXHM_Inspiral_Amp_rho2(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcutInsp, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM){
+
+  double retVal = 0;
+  switch(pWFHM->IMRPhenomXHMInspiralAmpVersion){
+    case 3:  // 3 inspiral collocation points
+    {
+      // default version
+      retVal=(-(powers_of_fcutInsp->eight_thirds*(-(powers_of_f1->three*powers_of_f3->seven_thirds*v2) + powers_of_f1->seven_thirds*powers_of_f3->three*v2 + powers_of_f2->three*(powers_of_f3->seven_thirds*v1 - powers_of_f1->seven_thirds*v3) + powers_of_f2->seven_thirds*(-(powers_of_f3->three*v1) + powers_of_f1->three*v3))))/(powers_of_f1->seven_thirds*(powers_of_f1->one_third - powers_of_f2->one_third)*powers_of_f2->seven_thirds*(powers_of_f1->one_third - powers_of_f3->one_third)*(powers_of_f2->one_third - powers_of_f3->one_third)*powers_of_f3->seven_thirds);
+      break;
+    }
+    case 2: // 2 inspiral collocation points
+    {
+
+      retVal=(-(powers_of_fcutInsp->eight_thirds*(-(powers_of_f2->seven_thirds*v1) + powers_of_f1->seven_thirds*v2)))/(powers_of_f1->seven_thirds*(powers_of_f1->one_third - powers_of_f2->one_third)*powers_of_f2->seven_thirds);
+      break;
+    }
+    case 1:  // 1 inspiral collocation points
+    {
+      retVal = 0;
+      break;
+    }
+    case 0:  // No collocation points, reconstruct with PN only
+    {
+      retVal=0;
+      break;
+    }
+    default: {XLALPrintError("Error in IMRPhenomXHM_Inspiral_Amp_rho2: version is not valid. Versions avilable are 0,1,2,3.\n");XLAL_ERROR(XLAL_EDOM, "IMRPhenomXHM_Inspiral_Amp_rho2 version is not valid. Aborting. Versions available are 0,1,2,3.\n");}
+  }
+  return retVal;
+
+}
+
+/* Get Pseudo PN Amp coefficient rho3 at f^(9/3) */
+static double IMRPhenomXHM_Inspiral_Amp_rho3(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcutInsp, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM){
+
+  double retVal = 0;
+  switch(pWFHM->IMRPhenomXHMInspiralAmpVersion){
+    case 3:   // 3 inspiral collocation points
+    {
+      // default version
+      retVal=(powers_of_fcutInsp->three*(powers_of_f1->seven_thirds*(-powers_of_f1->one_third + powers_of_f3->one_third)*powers_of_f3->seven_thirds*v2 + powers_of_f2->seven_thirds*(-(powers_of_f3->eight_thirds*v1) + powers_of_f1->eight_thirds*v3) + powers_of_f2->eight_thirds*(powers_of_f3->seven_thirds*v1 - powers_of_f1->seven_thirds*v3)))/(powers_of_f1->seven_thirds*(powers_of_f1->one_third - powers_of_f2->one_third)*powers_of_f2->seven_thirds*(powers_of_f1->one_third - powers_of_f3->one_third)*(powers_of_f2->one_third - powers_of_f3->one_third)*powers_of_f3->seven_thirds);
+      break;
+    }
+    case 2:   // 2 inspiral collocation points
+    {
+      retVal = 0;
+      break;
+    }
+    case 1:   // 1 inspiral collocation point
+    {
+      retVal = 0;
+      break;
+    }
+    case 0:  // No collocation points, reconstruct with PN only
+    {
+      retVal=0;
+      break;
+    }
+      default: {XLALPrintError("Error in IMRPhenomXHM_Inspiral_Amp_rho3: version is not valid.\n");XLAL_ERROR(XLAL_EDOM, "IMRPhenomXHM_Inspiral_Amp_rho3 version is not valid.  Aborting. Versions available: 0,1,2,3.\n");}
+  }
+  return retVal;
+}
+
+
+/************* INSPIRAL AMPLITUDE ANSATZ ******************/
+
+/*
+   The ansatz is built by performing the Stationary Phase Approximation of the Time-Domain Amplitude up to 3PN.
+   The result is rexpanded in power series up to 3PN, except for the 21 mode, which is better behaved without the reexpansion.
+*/
+
+//Return the Fourier Domain Post-Newtonian ansatz up to 3PN without the pseudoPN terms for a particular frequency
+static double IMRPhenomXHM_Inspiral_PNAmp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp){
+
+  // The 21 mode is special, is not a power series
+  if(pWFHM->useFAmpPN==1){
+    return IMRPhenomXHM_Inspiral_PNAmp_21Ansatz(powers_of_Mf, pWFHM, pAmp);
+  }
+
+   //This returns the amplitude strain rescaled with the prefactor of the 22 mode: divided by sqrt(2*eta/3.)/pi^(1/6)
+  double complex CpnAmp;
+  double pnAmp;
+  int InsAmpFlag = pWFHM->IMRPhenomXHMInspiralAmpFitsVersion;
+  switch(InsAmpFlag)
+  {
+    case 122018:
+    {
+      CpnAmp = (pAmp->pnInitial
+        + powers_of_Mf->one_third    * pAmp->pnOneThird
+        + powers_of_Mf->two_thirds   * pAmp->pnTwoThirds
+        + powers_of_Mf->itself       * pAmp->pnThreeThirds
+        + powers_of_Mf->four_thirds  * pAmp->pnFourThirds
+        + powers_of_Mf->five_thirds  * pAmp->pnFiveThirds
+        + powers_of_Mf->two          * pAmp->pnSixThirds
+      );
+      pnAmp = (pAmp->PNglobalfactor)*cabs(CpnAmp);
+      break;
+    }
+    default :
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Inspiral_PNAmp_Ansatz: IMRPhenomXInspiralAmpVersion is not valid. Recommended version is 122018.\n");
+    }
+  }
+
+  return pnAmp;
+}
+
+//Return the 21 mode Fourier Domain Post-Newtonian ansatz up to 3PN without the pseudoPN terms for a particular frequency
+static double IMRPhenomXHM_Inspiral_PNAmp_21Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp){
+
+  double complex CpnAmpTD; //This is not the real strain of the lm mode. It is the strain rescaled with the prefactor of the 22 mode: divided by sqrt(2*eta/3.)/pi^(1/6)
+  double pnAmp, XdotT4, x_to_m_one_four, two_to_m_one_sixths = 0.8908987181403393, three_to_m_one_second = 0.5773502691896257;
+  x_to_m_one_four = two_to_m_one_sixths * powers_of_lalpiHM.m_one_sixth * powers_of_Mf->m_one_sixth;
+  int InsAmpFlag = pWFHM->IMRPhenomXHMInspiralAmpFitsVersion;
+  switch(InsAmpFlag)
+  {
+    case 122018:
+    {
+      // Complex time-domain Post-Newtonina amplitude, power series
+      CpnAmpTD = (
+         powers_of_Mf->one_third    * pAmp->x05
+        + powers_of_Mf->two_thirds  * pAmp->x1
+        + powers_of_Mf->itself      * pAmp->x15
+        + powers_of_Mf->four_thirds * pAmp->x2
+        + powers_of_Mf->five_thirds * pAmp->x25
+        + powers_of_Mf->two         * pAmp->x3
+      );
+      CpnAmpTD = CpnAmpTD*powers_of_Mf->two_thirds*pAmp->PNTDfactor;
+
+      // Value of the the derivative of the PN expansion parameter X given by TaylorT4
+      XdotT4 = powers_of_Mf->five_thirds * powers_of_Mf->five_thirds * pAmp->xdot5
+      + powers_of_Mf->four          * pAmp->xdot6
+      + powers_of_Mf->eight_thirds*powers_of_Mf->five_thirds * pAmp->xdot65
+      + powers_of_Mf->seven_thirds*powers_of_Mf->seven_thirds * pAmp->xdot7
+      + powers_of_Mf->eight_thirds*powers_of_Mf->seven_thirds * pAmp->xdot75
+      + powers_of_Mf->eight_thirds * powers_of_Mf->eight_thirds * pAmp->xdot8
+      + (powers_of_Mf->log*2./3. + pAmp->log2pi_two_thirds )*powers_of_Mf->eight_thirds * powers_of_Mf->eight_thirds * pAmp->xdot8Log
+      + powers_of_Mf->eight_thirds * powers_of_Mf->eight_thirds * powers_of_Mf->one_third  * pAmp->xdot85;
+
+      // Perform the SPA, multiply time-domain by the phasing factor
+      pnAmp = 2. * powers_of_lalpiHM.sqrt  * three_to_m_one_second  * cabs(CpnAmpTD) * x_to_m_one_four / sqrt(XdotT4) /powers_of_Mf->m_seven_sixths/pWFHM->ampNorm;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Inspiral_PNAmp_Ansatz: IMRPhenomXInspiralAmpVersion is not valid. Recommended version is 122018.\n");}
+  }
+  return pnAmp;
+}
+
+
+//This is the complete Inspiral Amplitude Ansatz: PN ansatz + pseudoPN terms
+static double IMRPhenomXHM_Inspiral_Amp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp)
+{
+    double InspAmp; //This is the amplitude strain rescaled with the prefactor of the 22 mode: divided by [sqrt(2*eta/3.)/pi^(1/6) * f^(-7/6)]
+    int InsAmpFlag = pWFHM->IMRPhenomXHMInspiralAmpFitsVersion;
+    switch(InsAmpFlag)
+    {
+        case 122018:
+        {
+            InspAmp = IMRPhenomXHM_Inspiral_PNAmp_Ansatz(powers_of_Mf, pWFHM, pAmp)
+            + powers_of_Mf->seven_thirds / pAmp->fcutInsp_seven_thirds * pAmp->rho1
+            + powers_of_Mf->eight_thirds / pAmp->fcutInsp_eight_thirds * pAmp->rho2
+            + powers_of_Mf->three        / pAmp->fcutInsp_three * pAmp->rho3
+            ;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Inspiral_Amp_Ansatz: IMRPhenomXInspiralAmpVersion is not valid. Recommended version is 2018. \n");}
+    }
+    return InspAmp;
+}
+
+/* Numerical derivative of the inspiral (4th order finite differences)
+   It is used for reconstructing the intermediate region */
+static double IMRPhenomXHM_Inspiral_Amp_NDAnsatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp){
+
+    double df = 10e-10;
+    double Nder;
+    double fun2R, funR, funL, fun2L;
+    double centralfreq = powers_of_Mf->itself;
+
+    IMRPhenomX_UsefulPowers powers_of_Mf2R, powers_of_MfR, powers_of_MfL, powers_of_Mf2L;
+
+    IMRPhenomX_Initialize_Powers(&powers_of_Mf2R, centralfreq + 2*df);
+    IMRPhenomX_Initialize_Powers(&powers_of_MfR, centralfreq + df);
+    IMRPhenomX_Initialize_Powers(&powers_of_MfL, centralfreq  - df);
+    IMRPhenomX_Initialize_Powers(&powers_of_Mf2L, centralfreq - 2*df);
+
+    fun2R = IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_Mf2R, pWFHM, pAmp);
+    funR  = IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_MfR, pWFHM, pAmp);
+    funL  = IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_MfL, pWFHM, pAmp);
+    fun2L = IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_Mf2L, pWFHM, pAmp);
+    Nder = (-fun2R + 8*funR - 8*funL + fun2L )/(12*df);
+
+    return Nder;
+}
+
+/* VETO function:  when extrapolating the model outside the calibration region the collocation points can be bad behaved.
+   With this function we select those that will be used in the reconstruction. */
+void IMRPhenomXHM_Inspiral_Amplitude_Veto(
+  double *iv1, double *iv2, double *iv3,
+  IMRPhenomX_UsefulPowers *powers_of_f1,
+  IMRPhenomX_UsefulPowers *powers_of_f2,
+  IMRPhenomX_UsefulPowers *powers_of_f3,
+  IMRPhenomXHMAmpCoefficients *pAmp,
+  IMRPhenomXHMWaveformStruct *pWFHM
+)
+{
+    double threshold = 0.2/(pWFHM->ampNorm);
+    #if DEBUG == 1
+    printf("\n\nf1, f2, f3 = %.16f %.16f %.16f\n\n",powers_of_f1->itself,powers_of_f2->itself,powers_of_f3->itself);
+    printf("\n\nf1, f2, f3 = %.16f %.16f %.16f\n\n",threshold*powers_of_f1->seven_sixths,threshold*powers_of_f2->seven_sixths,threshold*powers_of_f3->seven_sixths);
+    printf("\nInspiral Veto: AmpVersion = %i",pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    #endif
+    // Remove too low collocation points (heuristic).
+    if(pAmp->CollocationPointsValuesAmplitudeInsp[0] < threshold*powers_of_f1->seven_sixths){
+        *iv1 = 0;
+        pWFHM->IMRPhenomXHMInspiralAmpVersion = 2;
+    }
+    if(pAmp->CollocationPointsValuesAmplitudeInsp[1] < threshold*powers_of_f2->seven_sixths){
+        *iv2 = 0;
+        pWFHM->IMRPhenomXHMInspiralAmpVersion = pWFHM->IMRPhenomXHMInspiralAmpVersion -1;
+    }
+    if(pAmp->CollocationPointsValuesAmplitudeInsp[2] < threshold*powers_of_f3->seven_sixths){
+        *iv3 = 0;
+        pWFHM->IMRPhenomXHMInspiralAmpVersion = pWFHM->IMRPhenomXHMInspiralAmpVersion -1;
+    }
+}
+
+// Check if the three collocation points are wavy
+int WavyPoints(double p1, double p2, double p3){
+    if((p1>p2 && p2<p3) || (p1<p2 && p2>p3)){
+        return 1;
+    }else{
+        return 0;
+    }
+}
+
+
+
+/*************************************/
+/*                                   */
+/*              PHASE                */
+/*                                   */
+/*************************************/
+
+// Spin parameter S = (m1^2*chi1 + m2^2*chi2)/(m1^2 + m2^2)
+
+// Below we give paramater-space fits for the weighted difference between each mode's phase and the 22-phase: phi_lm-m/2 phi_22(2/m f), see Eqs. (4.10-4.12)
+
+static double IMRPhenomXHM_Insp_Phase_21_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag) {
+    UNUSED double total,eta2,eta3,eta4,eta5,S2,S3;
+    switch (InspPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 13.664473636545068 - 170.08866400251395*eta + 3535.657736681598*eta2 - 26847.690494515424*eta3 + 96463.68163125668*eta4 - 133820.89317471132*eta5;
+            double eqSpin = (S*(18.52571430563905 - 41.55066592130464*S + eta3*(83493.24265292779 + 16501.749243703132*S - 149700.4915210766*S2) + eta*(3642.5891077598003 + 1198.4163078715173*S - 6961.484805326852*S2) + 33.8697137964237*S2 + eta2*(-35031.361998480075 - 7233.191207000735*S + 62149.00902591944*S2)))/(6.880288191574696 + 1.*S);
+            double uneqSpin = -134.27742343186577*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_Insp_Phase_21_lambda: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Phase_33_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag) {
+    double total=0,eta2,eta3;
+    double delta=sqrt(1. - 4.*eta);
+    switch (InspPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = eta2*eta;
+            double noSpin = 4.1138398568400705 + 9.772510519809892*eta - 103.92956504520747*eta2 + 242.3428625556764*eta3;
+            double eqSpin = ((-0.13253553909611435 + 26.644159828590055*eta - 105.09339163109497*eta2)*S)/(1. + 0.11322426762297967*S);
+            double uneqSpin = -19.705359163581168*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_Insp_Phase_32_lambda: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Insp_Phase_32_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag) {
+    double total,eta2,eta3,eta4,S2,S3,S4;
+    switch (InspPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = (9.913819875501506 + 18.424900617803107*eta - 574.8672384388947*eta2 + 2671.7813055097877*eta3 - 6244.001932443913*eta4)/(1. - 0.9103118343073325*eta);
+            double eqSpin = (-4.367632806613781 + 245.06757304950986*eta - 2233.9319708029775*eta2 + 5894.355429022858*eta3)*S + (-1.375112297530783 - 1876.760129419146*eta + 17608.172965575013*eta2 - 40928.07304790013*eta3)*S2 + (-1.28324755577382 - 138.36970336658558*eta + 708.1455154504333*eta2 - 273.23750933544176*eta3)*S3 + (1.8403161863444328 + 2009.7361967331492*eta - 18636.271414571278*eta2 + 42379.205045791656*eta3)*S4;
+            double uneqSpin = (chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2*(-105.34550407768225 - 1566.1242344157668*chi1*eta + 1566.1242344157668*chi2*eta + 2155.472229664981*eta*S);
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_Insp_Phase_32_lambda: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Insp_Phase_44_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag) {
+    double total,eta2,eta3,eta4,eta5,S2;
+    switch (InspPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            S2 = pow(S,2);
+            double noSpin = 5.254484747463392 - 21.277760168559862*eta + 160.43721442910618*eta2 - 1162.954360723399*eta3 + 1685.5912722190276*eta4 - 1538.6661348106031*eta5;
+            double eqSpin = (0.007067861615983771 - 10.945895160727437*eta + 246.8787141453734*eta2 - 810.7773268493444*eta3)*S + (0.17447830920234977 + 4.530539154777984*eta - 176.4987316167203*eta2 + 621.6920322846844*eta3)*S2;
+            double uneqSpin = -8.384066369867833*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_Insp_Phase_44_lambda: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+// Returns linear-in-f term coming from the complex part of each mode's amplitude that will be added to the orbital phase, this is an expansion of Eq. (4.9) truncated at linear order
+static double IMRPhenomXHM_Insp_Phase_LambdaPN(double eta, int modeInt){
+
+    double output;
+    const double PI = powers_of_lalpiHM.itself;
+
+    switch(modeInt){
+        case 21:
+        {//2 f \[Pi] (-(1/2) - Log[16]/2)
+            output=(2.*PI*(-0.5-2.*log(2)));
+            break;
+        }
+        case 33:
+        {//2/3 f \[Pi] (-(21/5) + 6 Log[3/2])
+            output=2./3.*PI*(-21./5.+6.*log(1.5));
+            break;
+        }
+        case 32:
+        { //-((2376 f \[Pi] (-5 + 22 \[Eta]))/(-3960 + 11880 \[Eta]))
+            output=-((2376.*PI*(-5.+22.*eta))/(-3960.+11880*eta));
+            break;
+        }
+        case 44:
+        { //(45045 f \[powers_of_lalpiHM.itself] (336 - 1193 \[Eta] +320 (-1 + 3 \[Eta]) Log[2]))/(2 (-1801800 + 5405400 \[Eta]))
+            output=45045.*PI*(336.-1193.*eta+320.*(-1.+3.*eta)*log(2))/(2.*(-1801800. + 5405400.*eta));
+            break;
+        }
+        default: output=0.;
+    }
+
+    return -1.*output;
+}
+
+
+/************* INSPIRAL PHASE ANSATZ *************/
+
+/*
+ The function loads the rescaled phenX coefficients for the phase and correct the result with a linear-in-f term coming from the complex part of the PN amplitude
+
+ The rescaling of the 22-coefficients is explained in App. D
+*/
+static double IMRPhenomXHM_Inspiral_Phase_AnsatzInt(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMPhaseCoefficients *pPhase)
+{
+    //compute the orbital phase by laoding the rescaled phenX coefficients
+    double philm=0.;
+    double freqs[]={powers_of_Mf->m_five_thirds,powers_of_Mf->m_four_thirds,powers_of_Mf->m_one,powers_of_Mf->m_two_thirds,powers_of_Mf->m_one_third,1.,powers_of_Mf->one_third,powers_of_Mf->two_thirds, Mf, powers_of_Mf->four_thirds, powers_of_Mf->five_thirds, powers_of_Mf->two,powers_of_Mf->seven_thirds};
+    double logMf=powers_of_Mf->log;
+    for(int i=0; i<N_MAX_COEFFICIENTS_PHASE_INS; i++)
+        philm+=(pPhase->phi[i]+pPhase->phiL[i]*(logMf))*freqs[i];
+    return philm;
+}
+
+static double IMRPhenomXHM_Inspiral_Phase_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf,IMRPhenomXHMPhaseCoefficients *pPhase)
+{
+    //compute the orbital phase by laoding the rescaled phenX coefficients
+    double dphilm=0.;
+    double coeffs[]={-5./3,-4./3,-1.,-2./3,-1./3,0.,1./3, 2./3, 1., 4./3, 5./3, 2., 7./3};
+    double freqs[]={powers_of_Mf->m_eight_thirds,powers_of_Mf->m_seven_thirds,powers_of_Mf->m_two,powers_of_Mf->m_five_thirds,powers_of_Mf->m_four_thirds,powers_of_Mf->m_one,powers_of_Mf->m_two_thirds,powers_of_Mf->m_one_third,1.,powers_of_Mf->one_third, powers_of_Mf->two_thirds, Mf,powers_of_Mf->four_thirds};
+    double logMf=powers_of_Mf->log;
+
+    for(int i=0; i<N_MAX_COEFFICIENTS_PHASE_INS; i++)
+        dphilm+=((pPhase->phi[i]+pPhase->phiL[i]*(logMf))*coeffs[i]+pPhase->phiL[i])*freqs[i];
+    return dphilm;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.h b/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.h
new file mode 100644
index 0000000000000000000000000000000000000000..5104d958f2dbdaab89b6c5bec7f5a18ad58e5600
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_inspiral.h
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2019 Marta Colleoni, Cecilio García Quirós
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*
+*/
+//
+//  LALSimIMRPhenomXHM_inspiral.h
+//
+//
+//  Created by Marta on 06/02/2019.
+//
+
+#ifndef LALSimIMRPhenomXHM_inspiral_h
+#define LALSimIMRPhenomXHM_inspiral_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+#include "LALSimIMRPhenomX_utilities.h"
+#include "LALSimIMRPhenomXHM_structs.h"
+#include "LALSimIMRPhenomX_internals.h"
+
+
+/********** AMPLITUDE ***************/
+
+//Collocations Points Fits
+static double IMRPhenomXHM_Insp_Amp_21_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_21_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_21_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_33_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_33_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_33_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_32_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_32_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_32_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_44_iv1(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_44_iv2(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+static double IMRPhenomXHM_Insp_Amp_44_iv3(double eta, double S, double chi1, double chi2, int InspAmpFlag);
+
+/******************* Pseudo PN Amplitude coefficients ***************************/
+static double IMRPhenomXHM_Inspiral_Amp_rho1(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcut3, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM);
+static double IMRPhenomXHM_Inspiral_Amp_rho2(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcut3, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM);
+static double IMRPhenomXHM_Inspiral_Amp_rho3(double v1, double v2, double v3, IMRPhenomX_UsefulPowers *powers_of_fcut3, IMRPhenomX_UsefulPowers *powers_of_f1, IMRPhenomX_UsefulPowers *powers_of_f2, IMRPhenomX_UsefulPowers *powers_of_f3, IMRPhenomXHMWaveformStruct *pWFHM);
+
+//Ansatzs for a give frequency
+static double IMRPhenomXHM_Inspiral_PNAmp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp);
+static double IMRPhenomXHM_Inspiral_Amp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp);
+static double IMRPhenomXHM_Inspiral_Amp_NDAnsatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp);
+static double IMRPhenomXHM_Inspiral_PNAmp_21Ansatz(IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp);
+
+//Veto amplitude
+void IMRPhenomXHM_Inspiral_Amplitude_Veto(
+  double *iv1, double *iv2, double *iv3,
+  IMRPhenomX_UsefulPowers *powers_of_f1,
+  IMRPhenomX_UsefulPowers *powers_of_f2,
+  IMRPhenomX_UsefulPowers *powers_of_f3,
+  IMRPhenomXHMAmpCoefficients *pAmp,
+  IMRPhenomXHMWaveformStruct *pWFHM
+);
+static int WavyPoints(double p1, double p2, double p3);
+
+
+/*********** PHASE ***************/
+
+//Fits across parameter space
+static double IMRPhenomXHM_Insp_Phase_21_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag);
+static double IMRPhenomXHM_Insp_Phase_32_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag);
+static double IMRPhenomXHM_Insp_Phase_33_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag);
+static double IMRPhenomXHM_Insp_Phase_44_lambda(double eta, double S, double chi1, double chi2, int InspPhaseFlag);
+static double IMRPhenomXHM_Insp_Phase_LambdaPN(double eta, int modeInt);
+
+//Ansatzs
+static double IMRPhenomXHM_Inspiral_Phase_AnsatzInt(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMPhaseCoefficients *pPhase);
+static double IMRPhenomXHM_Inspiral_Phase_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXHMPhaseCoefficients *pPhase);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* LALSimIMRPhenomXHM_inspiral_h */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.c b/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.c
new file mode 100644
index 0000000000000000000000000000000000000000..92098eef7d863752234dfd20cac2bded6b39fa5b
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.c
@@ -0,0 +1,2865 @@
+/*
+* Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*
+*/
+//
+//  LALSimIMRPhenomXHM_Intermediate.c
+//
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_roots.h>
+#include <gsl/gsl_poly.h>
+
+#include "LALSimIMRPhenomXHM_intermediate.h"
+
+/***********************************************/
+/*                                             */
+/*                  AMPLITUDE                  */
+/*                                             */
+/***********************************************/
+
+
+// Fits of the intermediate collocation points over parameter space.
+
+/* These parameter-space fits are documented in the supplementary material of https://dcc.ligo.org/P2000011-v2.
+   There are 2 Mathematica notebooks (one for amplitude and one for phase) that read the fits data and automatically generate the C-code below.
+   For more information read https://git.ligo.org/waveforms/reviews/imrphenomx/blob/master/documentation/ParspaceFits/README and the documentation in the notebooks. */
+
+// IMRPhenomXHM_Inter_Amp_lm_intX returns the value of the amplitude at the collocation point intX
+// IMRPhenomXHM_Inter_Amp_lm_dintX returns the value of the derivative of the amplitude at the collocation point intX
+// for a definition of the frequencies corresponding to int0/1/2, see Sec V.A.
+
+// The dominant spin parameter is S = (m1^2*chi1 + m2^2*chi2)/(m1^2 + m2^2)
+
+
+static double IMRPhenomXHM_Inter_Amp_21_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,eta4,S2,S3;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      S2 = pow(S,2);
+      S3 = pow(S,3);
+      double noSpin = sqrt(eta - 4.*eta2)*(21.256776327599113 - 25.594352690383847*eta + 30.14761650482866*eta2);
+      double eqSpin = sqrt(eta - 4.*eta2)*S*(-11.262044985632757 - 1.8167045597937677*S + eta*(-1.1798437990445079 + 6.344825546437461*S - 4.881427482271166*S2));
+      double uneqSpin = -3.6366100759176696*pow(chi1 - 1.*chi2,2)*(1. - 4.*eta)*eta - 31.60048733143782*(chi1 - 1.*chi2)*eta2*(1. + 2.1502870640831855*eta2);
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_21_int1: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_21_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, eta2,eta3,eta4,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 4.*eta2)*(19.15445065708005 - 21.13596229438309*eta + 29.742565944285772*eta2);
+      double eqSpin = sqrt(eta - 4.*eta2)*S*(-12.766814596085734 - 2.123816950673979*S + eta*(-2.913184982025043 + 6.006571549661901*S));
+      double uneqSpin = -25.856046423804255*(chi1 - 1.*chi2)*eta2*(1. + 5.7871199275552*eta2);
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_21_int2: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_33_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, eta2,eta3,eta4,eta5,eta6,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      eta6 = pow(eta,6);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 4.*eta2)*(27.927652424857733 - 133.56611389260297*eta + 974.8550901501316*eta2 - 3744.785831952632*eta3 + 5621.897260910284*eta4);
+      double eqSpin = sqrt(eta - 4.*eta2)*S*(7.348313807306079 + eta*(-60.248696675045565 - 37.07212326362276*S) + 5.059236579431119*S + eta2*(159.68630712802727 + 83.33807316873204*S));
+      double uneqSpin = 1412.367880056888*(chi1 - 1.*chi2)*eta6;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_33_int1: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_33_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, eta2,eta3,eta4,eta5,eta6,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      eta6 = pow(eta,6);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 4.*eta2)*(20.162169689041903 - 18.666422946967764*eta + 53.04107631052987*eta2);
+      double eqSpin = sqrt(eta - 4.*eta2)*S*(3.896260108714186 + eta*(-33.707998325000965 - 61.1244771077077*S) + 4.878506403725656*S + eta2*(91.31681057861915 + 196.40535070402336*S));
+      double uneqSpin = 1637.4256048973248*(chi1 - 1.*chi2)*eta6;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_33_int2: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_32_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,eta7,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      eta6 = pow(eta,6);
+      eta7 = pow(eta,7);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 3.*eta2)*(6.523612598187996 - 56.93956111746338*eta + 1021.6414686597869*eta2 - 12107.114370361525*eta3 + 76320.90587515048*eta4 - 244144.92645448362*eta5 + 321790.55131499085*eta6);
+      double eqSpin = sqrt(eta - 3.*eta2)*S*(2.9649243713119895 + eta3*(1790.8363334078751 - 5438.911035114849*S) + eta*(-37.87005271181108 - 126.1263286618178*S) + 4.063724538613828*S + eta2*(48.39743086535961 + 1341.2619677741804*S) + eta4*(-5200.659417644607 + 7369.386205324284*S));
+      double uneqSpin = eta2*(-0.4386152975075188*(pow(chi1,2) - 2.*chi1*chi2 + pow(chi2,2)) + (chi2*(3.6527252109313233 - 7.324266404418883*S) + chi1*(-3.6527252109313233 + 7.324266404418883*S))*delta);
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_32_int1: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_32_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,S2,S3;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      S2 = pow(S,2);
+      S3 = pow(S,3);
+      double noSpin = sqrt(eta - 3.*eta2)*(5.941845842405418 - 31.905244419036794*eta + 271.105632998832*eta2 - 2113.9652334868965*eta3 + 6214.038393898584*eta4);
+      double eqSpin = sqrt(eta - 3.*eta2)*S*(-2.726472456645038 + 2.9454485454761827*S + eta3*(10581.664858726683 - 8474.190197512324*S - 11680.937129551317*S2) + eta*(98.08119212251981 - 119.88112323140916*S - 145.5079981415436*S2) + 3.5684571473795095*S2 + eta2*(-1595.8027347570667 + 1686.7137359336039*S + 2139.8290160628144*S2) + eta4*(-21488.25117198268 + 13866.428366595079*S + 20863.270079587106*S2));
+      double uneqSpin = 0.0038732029045487884*(chi1 - 1.*chi2)*eta2*delta;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_32_int2: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_44_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 3.*eta2)*(10.804555518381166 - 72.3834734399584*eta + 540.0541240482852*eta2 - 2612.999845214264*eta3 + 4779.096001663427*eta4);
+      double eqSpin = sqrt(eta - 3.*eta2)*S*(4.26336253142121 + eta*(-47.94914754514519 - 39.31284390368824*S) + 3.0973959822174297*S + eta2*(119.70401520575753 + 106.91295627237112*S));
+      double uneqSpin = 0.7262636326998003*pow(chi1 - 1.*chi2,2)*(1. - 4.*eta)*eta + 3.001401833124412*(chi1 - 1.*chi2)*eta2*delta;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_44_int1: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_44_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag) {
+  UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 3.*eta2)*(9.020721305469884 - 53.221883492311235*eta + 508.07176447172264*eta2 - 3194.0620894511508*eta3 + 6769.9274392345915*eta4);
+      double eqSpin = sqrt(eta - 3.*eta2)*S*(3.256591670091969 + eta*(-38.38922554651356 - 25.286684856422735*S) + 2.374434219852751*S + eta2*(96.41777041220982 + 64.74544118094362*S));
+      double uneqSpin = 3.2337593375595417*(chi1 - 1.*chi2)*eta2*delta;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_44_int2: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+/*
+Fits for the extra collocation point for EMR cases with 2 intermediate regions
+*/
+static double IMRPhenomXHM_Inter_Amp_21_int0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = 0.872895771366973 + 441.76285124642845*eta - 24617.068739152524*eta2 + 518054.9485981792*eta3;
+      double eqSpin = S*(-0.0720494539485585 + eta*(-173.67847091983123 - 113.29725582509889*S) - 0.2687302438646897*S + eta2*(3571.0393588230045 + 2640.919925429635*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_21_int0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_21_dint0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = -0.8535048463050732 - 93.1876950411214*eta + 13641.071903017495*eta2 - 337621.44851304166*eta3;
+      double eqSpin = S*(-1.2067842398131878 + eta2*(-1972.284151572111 - 8172.057025783849*S) - 0.26539816223182355*S + eta*(77.26350785961219 + 189.63365484152857*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_21_dint0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_33_int0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = 1.5852399637975103 + 549.5183711492834*eta - 34257.76380246282*eta2 + 743142.8286902909*eta3;
+      double eqSpin = S*(0.7436306553052219 + eta*(-89.49451655594787 - 174.5730646548662*S) + 0.4253024979725725*S + eta2*(1185.1654325913717 + 6510.983041407191*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_33_int0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_33_dint0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = -4.691600252198376 + 101.4338937535679*eta + 9262.994550540048*eta2 - 310993.1309846956*eta3;
+      double eqSpin = S*(-4.198232394219111 + eta2*(-28714.904192060643 - 5100.09336069277*S) - 0.40986595512314733*S + eta*(734.7118618746317 + 292.04566260701574*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_33_dint0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_32_int0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2,S3;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      S3 = pow(S,3);
+      double noSpin = 0.24794156582503746 + 115.81823862983131*eta - 6626.167995915723*eta2 + 141004.29332593994*eta3;
+      double eqSpin = (0.21144389781375486 + 35.10041265469983*eta - 1794.2301585086836*eta2)*S + (0.2781735549493081 - 37.038950686633*eta + 1258.628375238807*eta2)*S2 + (0.23428222791962147 - 63.98011009365723*eta + 2118.213562899934*eta2)*S3;
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_32_int0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_32_dint0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = -0.3391808620221253 - 14.604141885467747*eta + 3694.1706648870427*eta2 - 95482.02951271653*eta3;
+      double eqSpin = S*(-1.2844502090793946 + eta2*(-5018.762853306415 - 6332.389157828062*S) - 1.2356159239385598*S + eta*(149.04865679660233 + 188.2052849646003*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_32_dint0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_44_int0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2,S3;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      S3 = pow(S,3);
+      double noSpin = 0.5664660641971224 + 185.58965113823874*eta - 11458.768824989507*eta2 + 249386.7511724409*eta3;
+      double eqSpin = (0.1741768776210781 - 9.365114803167128*eta + 703.2622732011035*eta2)*S + (0.20169229783048184 - 62.13147149352512*eta + 2833.5738711424974*eta2)*S2 + (0.4423803798742513 - 23.60535149579996*eta - 994.9241585715828*eta2)*S3;
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_44_int0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_Inter_Amp_44_dint0(double eta, double S, UNUSED double chi1, UNUSED double chi2, int InterAmpFlag) {
+  UNUSED double total=0,eta2,S2;
+  switch (InterAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      S2 = pow(S,2);
+      double noSpin = -1.796444922382065 + 111.51170611049032*eta - 1728.7493675776548*eta2;
+      double eqSpin = S*(-1.842119860613924 + eta2*(-11235.484645624338 - 2927.019210835522*S) - 0.36655273031432567*S + eta*(312.34531117524097 + 128.64488103364167*S));
+      double uneqSpin = 0.;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Amp_44_dint0: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+
+/* Solves system of equations for 5th order polynomial ansatz */
+
+/* We use a 5th order polynomial to connect the inspiral and ringdown regions.
+This polynomial is built such that it has the same value and derivative at the boundaries of the
+intermediate region than the inspiral and ringdown part (demanding continuity for the function
+and its first derivative) and also crosses through the two intermediate collocation points.
+Sometimes we will not use the 5th order but a lower one to assure a better behaviour.
+
+Now we have the functions to get the coefficients of such a polynomial:
+      delta0 + delta1*f + delta2*f^2 + delta3*f^3 + delta4*f^4 + delta5*f^5
+
+The different cases inside one function correspond to the different ways of building the polynomial,
+and it depend on the number of collocation points and derivatives we are using.
+For example case:105 correspond to the 5th order polynomial we have described before.
+*/
+
+static double IMRPhenomXHM_Intermediate_Amp_delta0(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch (IntAmpFlag)
+  {
+    case 101: //linear, only v1, v2
+    {
+      UNUSED double f1mf4 = f1-f4;
+
+      retVal = (-(f4*v1) + f1*v4)/f1mf4;
+      break;
+    }
+    case 102: //quadratic: v1, v2, d2
+    {
+      UNUSED double f12    = f1*f1;
+      UNUSED double f42    = f4*f4;
+      UNUSED double f1mf4  = f1-f4;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+
+      retVal = (-(d4*f1*f1mf4*f4) + f42*v1 + f12*v4 - 2*f1*f4*v4)/f1mf42;
+      break;
+    }
+    case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+
+      UNUSED double f1mf4  = f1-f4;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f1mf43 = f1mf42*f1mf4;
+
+      retVal = (d4*f12*f4*(-f1 + f4) + d1*f1*(-f1 + f4)*f42 + 3*f1*f42*v1 - f43*v1 + f13*v4 - 3*f12*f4*v4)/f1mf43;
+      break;
+    }
+    case 103:   // 4 freqs, no boundaries derivatives
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      retVal = (f1*f1mf3*f1mf4*f3*f3mf4*f4*v2 + f23*(f1*f1mf4*f4*v3 + f32*(-(f4*v1) + f1*v4) + f3*(f42*v1 - f12*v4)) + f2*(f12*f1mf4*f42*v3 + f33*(-(f42*v1) + f12*v4) + f32*(f43*v1 - f13*v4)) +
+      f22*(f1*f4*(-f12 + f42)*v3 + f33*(f4*v1 - f1*v4) + f3*(-(f43*v1) + f13*v4)))/(f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4);
+      break;
+    }
+    case 1043:  //no left derivative
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+
+      retVal = (-(d4*f1*f1mf2*f1mf3*f1mf4*f2*f2mf3*f2mf4*f3*f3mf4*f4) - f1*f1mf3*f1mf42*f3*f3mf42*f42*v2 +
+      f24*(-(f1*f1mf42*f42*v3) + f33*(f42*v1 + f12*v4 - 2*f1*f4*v4) + f3*f4*(f43*v1 + 2*f13*v4 - 3*f12*f4*v4) - f32*(2*f43*v1 + f13*v4 - 3*f1*f42*v4)) +
+      f2*f4*(f12*f1mf42*f43*v3 - f34*(f43*v1 + 2*f13*v4 - 3*f12*f4*v4) - f32*f4*(f44*v1 + 3*f14*v4 - 4*f13*f4*v4) + 2*f33*(f44*v1 + f14*v4 - 2*f12*f42*v4)) +
+      f22*(-(f1*f1mf42*(2*f1 + f4)*f43*v3) + f3*f42*(f44*v1 + 3*f14*v4 - 4*f13*f4*v4) + f34*(2*f43*v1 + f13*v4 - 3*f1*f42*v4) - f33*(3*f44*v1 + f14*v4 - 4*f1*f43*v4)) +
+      f23*(f1*f1mf42*(f1 + 2*f4)*f42*v3 - f34*(f42*v1 + f12*v4 - 2*f1*f4*v4) + f32*(3*f44*v1 + f14*v4 - 4*f1*f43*v4) - 2*f3*(f45*v1 + f14*f4*v4 - 2*f12*f43*v4)))/(f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+      break;
+    }
+    case 1042:   //4th order poly: v1,d1, v4,d4, v3  // used for the first intermediate region
+    {
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double f1mf43 = f1mf42*f1mf4;
+
+      retVal = (-(d4*f12*f1mf32*f1mf4*f3*f3mf4*f4) + d1*f1*f1mf3*f1mf4*f3*f3mf42*f42 - 4*f12*f33*f42*v1 + 3*f1*f34*f42*v1 + 8*f12*f32*f43*v1 - 4*f1*f33*f43*v1 - f34*f43*v1 - 4*f12*f3*f44*v1 - f1*f32*f44*v1 +
+      2*f33*f44*v1 + 2*f1*f3*f45*v1 - f32*f45*v1 + f15*f42*v3 - 3*f14*f43*v3 + 3*f13*f44*v3 - f12*f45*v3 + f15*f32*v4 - 2*f14*f33*v4 + f13*f34*v4 - 2*f15*f3*f4*v4 + f14*f32*f4*v4 + 4*f13*f33*f4*v4 -
+      3*f12*f34*f4*v4 + 4*f14*f3*f42*v4 - 8*f13*f32*f42*v4 + 4*f12*f33*f42*v4)/(f1mf32*f1mf43*f3mf42);
+
+      break;
+    }
+    case 104:  //Geraint's Version, 4th order poly: v1,d1, v4,d4, v2
+    {
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((-(d4*f12*f1mf22*f1mf4*f2*f2mf4*f4) + d1*f1*f1mf2*f1mf4*f2*f2mf42*f42 + f42*(f2*f2mf42*(-4*f12 + 3*f1*f2 + 2*f1*f4 - f2*f4)*v1 + f12*f1mf43*v2) +
+      f12*f1mf22*f2*(f1*f2 - 2*f1*f4 - 3*f2*f4 + 4*f42)*v4)/(f1mf22*f1mf43*f2mf42));
+      break;
+    }
+    case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf42*f1mf4;
+
+      retVal = (
+        (-(d4*f12*f1mf22*f1mf32*f1mf4*f2*f2mf3*f2mf4*f3*f3mf4*f4) - d1*f1*f1mf2*f1mf3*f1mf4*f2*f2mf3*f2mf42*f3*f3mf42*f42 + 5*f13*f24*f33*f42*v1 - 4*f12*f25*f33*f42*v1 - 5*f13*f23*f34*f42*v1 +
+        3*f1*f25*f34*f42*v1 + 4*f12*f23*f35*f42*v1 - 3*f1*f24*f35*f42*v1 - 10*f13*f24*f32*f43*v1 + 8*f12*f25*f32*f43*v1 + 5*f12*f24*f33*f43*v1 - 4*f1*f25*f33*f43*v1 + 10*f13*f22*f34*f43*v1 -
+        5*f12*f23*f34*f43*v1 - f25*f34*f43*v1 - 8*f12*f22*f35*f43*v1 + 4*f1*f23*f35*f43*v1 + f24*f35*f43*v1 + 5*f13*f24*f3*f44*v1 - 4*f12*f25*f3*f44*v1 + 15*f13*f23*f32*f44*v1 -
+        10*f12*f24*f32*f44*v1 - f1*f25*f32*f44*v1 - 15*f13*f22*f33*f44*v1 + 5*f1*f24*f33*f44*v1 + 2*f25*f33*f44*v1 - 5*f13*f2*f34*f44*v1 + 10*f12*f22*f34*f44*v1 - 5*f1*f23*f34*f44*v1 +
+        4*f12*f2*f35*f44*v1 + f1*f22*f35*f44*v1 - 2*f23*f35*f44*v1 - 10*f13*f23*f3*f45*v1 + 5*f12*f24*f3*f45*v1 + 2*f1*f25*f3*f45*v1 - f12*f23*f32*f45*v1 + 2*f1*f24*f32*f45*v1 - f25*f32*f45*v1 +
+        10*f13*f2*f33*f45*v1 + f12*f22*f33*f45*v1 - 3*f24*f33*f45*v1 - 5*f12*f2*f34*f45*v1 - 2*f1*f22*f34*f45*v1 + 3*f23*f34*f45*v1 - 2*f1*f2*f35*f45*v1 + f22*f35*f45*v1 + 5*f13*f22*f3*f46*v1 +
+        2*f12*f23*f3*f46*v1 - 4*f1*f24*f3*f46*v1 - 5*f13*f2*f32*f46*v1 - f1*f23*f32*f46*v1 + 2*f24*f32*f46*v1 - 2*f12*f2*f33*f46*v1 + f1*f22*f33*f46*v1 + 4*f1*f2*f34*f46*v1 - 2*f22*f34*f46*v1 -
+        3*f12*f22*f3*f47*v1 + 2*f1*f23*f3*f47*v1 + 3*f12*f2*f32*f47*v1 - f23*f32*f47*v1 - 2*f1*f2*f33*f47*v1 + f22*f33*f47*v1 - f17*f33*f42*v2 + 2*f16*f34*f42*v2 - f15*f35*f42*v2 + 2*f17*f32*f43*v2 -
+        f16*f33*f43*v2 - 4*f15*f34*f43*v2 + 3*f14*f35*f43*v2 - f17*f3*f44*v2 - 4*f16*f32*f44*v2 + 8*f15*f33*f44*v2 - 3*f13*f35*f44*v2 + 3*f16*f3*f45*v2 - 8*f14*f33*f45*v2 + 4*f13*f34*f45*v2 +
+        f12*f35*f45*v2 - 3*f15*f3*f46*v2 + 4*f14*f32*f46*v2 + f13*f33*f46*v2 - 2*f12*f34*f46*v2 + f14*f3*f47*v2 - 2*f13*f32*f47*v2 + f12*f33*f47*v2 + f17*f23*f42*v3 - 2*f16*f24*f42*v3 +
+        f15*f25*f42*v3 - 2*f17*f22*f43*v3 + f16*f23*f43*v3 + 4*f15*f24*f43*v3 - 3*f14*f25*f43*v3 + f17*f2*f44*v3 + 4*f16*f22*f44*v3 - 8*f15*f23*f44*v3 + 3*f13*f25*f44*v3 - 3*f16*f2*f45*v3 +
+        8*f14*f23*f45*v3 - 4*f13*f24*f45*v3 - f12*f25*f45*v3 + 3*f15*f2*f46*v3 - 4*f14*f22*f46*v3 - f13*f23*f46*v3 + 2*f12*f24*f46*v3 - f14*f2*f47*v3 + 2*f13*f22*f47*v3 - f12*f23*f47*v3 +
+        f12*f1mf22*f1mf32*f2*f2mf3*f3*(f4*(-3*f2*f3 + 4*(f2 + f3)*f4 - 5*f42) + f1*(f2*f3 - 2*(f2 + f3)*f4 + 3*f42))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta0: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+    }
+  }
+
+  return retVal;
+}
+
+static double IMRPhenomXHM_Intermediate_Amp_delta1(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+  switch ( IntAmpFlag )
+  {
+    case 101: //linear, only v1, v2
+    {
+      UNUSED double f1mf4 = f1-f4;
+
+      retVal = (v1 - v4)/f1mf4;
+      break;
+    }
+    case 102: //quadratic: v1, v2, d2
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f42 = f4*f4;
+      UNUSED double f1mf42 = (f1-f4)*(f1-f4);
+
+      retVal = (d4*(f12 - f42) + 2*f4*(-v1 + v4))/f1mf42;
+      break;
+    }
+    case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f42 = f4*f4;
+
+      UNUSED double f1mf4  = f1-f4;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f1mf43 = f1mf42*f1mf4;
+
+      retVal = (d4*f1*f1mf4*(f1 + 2*f4) - f4*(d1*(-2*f12 + f1*f4 + f42) + 6*f1*(v1 - v4)))/f1mf43;
+      break;
+    }
+    case 103:   // 4 freqs, no boundaries derivatives
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      retVal = (f12*f1mf4*f42*(v2 - v3) + f33*(f42*(v1 - v2) + f12*(v2 - v4)) + f22*(f43*(v1 - v3) + f13*(v3 - v4) + f33*(-v1 + v4)) + f32*(f43*(-v1 + v2) + f13*(-v2 + v4)) +
+      f23*(f42*(-v1 + v3) + f32*(v1 - v4) + f12*(-v3 + v4)))/(f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4);
+      break;
+    }
+    case 1043:  //no left derivative
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double v1mv2 = v1-v2;
+      UNUSED double v2mv3 = v2-v3;
+      UNUSED double v2mv4 = v2-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal =(d4*f1mf4*f2mf4*f3mf4*(f1*f2*f3 + f2*f3*f4 + f1*(f2 + f3)*f4) + (f4*(f12*f1mf42*f43*v2mv3 + f34*(f43*v1mv2 +
+        3*f12*f4*v2mv4 + 2*f13*(-v2 + v4)) + f32*f4*(f44*v1mv2 + 4*f13*f4*v2mv4 + 3*f14*(-v2 + v4)) + 2*f33*(f44*(-v1 + v2)
+        + f14*v2mv4 + 2*f12*f42*(-v2 + v4)) + 2*f23*(f44*v1mv3 + f34*v1mv4 + 2*f12*f42*v3mv4 + 2*f32*f42*(-v1 + v4) + f14*(-v3 + v4))
+        + f24*(3*f32*f4*v1mv4 + f43*(-v1 + v3) + 2*f13*v3mv4 + 2*f33*(-v1 + v4) + 3*f12*f4*(-v3 + v4)) + f22*f4*(4*f33*f4*v1mv4 + f44*(-v1 + v3)
+        + 3*f14*v3mv4 + 3*f34*(-v1 + v4) + 4*f13*f4*(-v3 + v4))))/(f1mf2*f1mf3*f2mf3))/(f1mf42*f2mf42*f3mf42);
+
+      break;
+    }
+    case 1042:   //4th order poly: v1,d1, v4,d4, v3  // used for the first intermediate region
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double f1mf43 = f1mf42*f1mf4;
+
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal = (d4*f15*f32 - 2*d4*f14*f33 + d4*f13*f34 + d4*f14*f32*f4 - 2*d1*f13*f33*f4 - 2*d4*f13*f33*f4 + 2*d1*f12*f34*f4 + d4*f12*f34*f4 - d4*f15*f42 + 3*d1*f13*f32*f42 + d4*f13*f32*f42 - 2*d1*f12*f33*f42 +
+        2*d4*f12*f33*f42 - d1*f1*f34*f42 - 2*d4*f1*f34*f42 + d4*f14*f43 - d1*f12*f32*f43 - 3*d4*f12*f32*f43 + 2*d1*f1*f33*f43 + 2*d4*f1*f33*f43 - d1*f34*f43 - d1*f13*f44 - d1*f1*f32*f44 + 2*d1*f33*f44 +
+        d1*f12*f45 - d1*f32*f45 + 8*f12*f33*f4*v1 - 6*f1*f34*f4*v1 - 12*f12*f32*f42*v1 + 8*f1*f33*f42*v1 + 4*f12*f44*v1 - 2*f1*f45*v1 - 2*f15*f4*v3 + 4*f14*f42*v3 - 4*f12*f44*v3 + 2*f1*f45*v3 +
+        2*f15*f4*v4 - 8*f12*f33*f4*v4 + 6*f1*f34*f4*v4 - 4*f14*f42*v4 + 12*f12*f32*f42*v4 - 8*f1*f33*f42*v4)/(f1mf32*f1mf43*f3mf42);
+
+        #if DEBUG == 1
+        printf("\ndelta1 = %.16f", retVal);
+        printf("\nf1 = %.16f", f1);
+        printf("\nf2 = %.16f", f2);
+        printf("\nf3 = %.16f", f3);
+        printf("\nf4 = %.16f", f4);
+        printf("\nv1 = %.16f", v1);
+        printf("\nv2 = %.16f", v2);
+        printf("\nv3 = %.16f", v3);
+        printf("\nv4 = %.16f", v4);
+        printf("\nd1 = %.16f", d1);
+        printf("\nd4 = %.16f", d4);
+        #endif
+
+        break;
+      }
+      case 104:  //Geraint's Version, 4th order poly: v1,d1, v2,d2, v3
+      {
+
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf22 = f1mf2*f1mf2;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf32 = f2mf3*f2mf3;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+        UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+        retVal = ((d4*f1*f1mf22*f1mf4*f2mf4*(2*f2*f4 + f1*(f2 + f4)) + f4*(-(d1*f1mf2*f1mf4*f2mf42*(2*f1*f2 + (f1 + f2)*f4)) -
+        2*f1*(f44*(v1 - v2) + 3*f24*(v1 - v4) + f14*(v2 - v4) + 4*f23*f4*(-v1 + v4)
+        + 2*f13*f4*(-v2 + v4) + f1*(2*f43*(-v1 + v2) + 6*f22*f4*(v1 - v4) + 4*f23*(-v1 + v4)))))/(f1mf22*f1mf43*f2mf42));
+        break;
+      }
+      case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+      {
+
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+        UNUSED double f15 = f14*f1;
+        UNUSED double f16 = f15*f1;
+        UNUSED double f17 = f16*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+        UNUSED double f25 = f24*f2;
+        UNUSED double f26 = f25*f2;
+        UNUSED double f27 = f26*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+        UNUSED double f35 = f34*f3;
+        UNUSED double f36 = f35*f3;
+        UNUSED double f37 = f36*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+        UNUSED double f46 = f45*f4;
+        UNUSED double f47 = f46*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf22 = f1mf2*f1mf2;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf32 = f2mf3*f2mf3;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+        UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+        retVal = (
+          (d4*f1*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f1*f2*f3 + 2*f2*f3*f4 + f1*(f2 + f3)*f4) +
+          f4*(d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(2*f1*f2*f3 + f2*f3*f4 + f1*(f2 + f3)*f4) +
+          f1*(f16*(f43*(v2 - v3) + 2*f33*(v2 - v4) + 3*f22*f4*(v3 - v4) + 3*f32*f4*(-v2 + v4) + 2*f23*(-v3 + v4)) +
+          f13*f4*(f45*(-v2 + v3) + 5*f34*f4*(v2 - v4) + 4*f25*(v3 - v4) + 4*f35*(-v2 + v4) + 5*f24*f4*(-v3 + v4)) +
+          f14*(3*f45*(v2 - v3) + 2*f35*(v2 - v4) + 5*f34*f4*(v2 - v4) + 10*f23*f42*(v3 - v4) + 10*f33*f42*(-v2 + v4) + 2*f25*(-v3 + v4) + 5*f24*f4*(-v3 + v4)) +
+          f15*(3*f44*(-v2 + v3) + 2*f33*f4*(v2 - v4) + 5*f32*f42*(v2 - v4) + 4*f24*(v3 - v4) + 4*f34*(-v2 + v4) + 2*f23*f4*(-v3 + v4) + 5*f22*f42*(-v3 + v4)) -
+          5*f12*(-(f32*f3mf42*f43*(v1 - v2)) + 2*f23*(f44*(-v1 + v3) + 2*f32*f42*(v1 - v4) + f34*(-v1 + v4)) + f24*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) +
+          f22*f4*(f44*(v1 - v3) + 3*f34*(v1 - v4) + 4*f33*f4*(-v1 + v4))) +
+          f1*(-(f32*f3mf42*(4*f3 + 3*f4)*f43*(v1 - v2)) + 2*f23*(f45*(-v1 + v3) + 5*f34*f4*(v1 - v4) + 4*f35*(-v1 + v4)) + 4*f25*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) -
+          5*f24*f4*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) + 3*f22*f4*(f45*(v1 - v3) + 4*f35*(v1 - v4) + 5*f34*f4*(-v1 + v4))) -
+          2*(-(f33*f3mf42*f44*(v1 - v2)) + f24*(2*f45*(-v1 + v3) + 5*f33*f42*(v1 - v4) + 3*f35*(-v1 + v4)) + f25*(f44*(v1 - v3) + 3*f34*(v1 - v4) + 4*f33*f4*(-v1 + v4)) +
+          f23*f4*(f45*(v1 - v3) + 4*f35*(v1 - v4) + 5*f34*f4*(-v1 + v4))))))/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+        );
+        break;
+      }
+      default:
+      {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta1: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+      }
+    }
+    return retVal;
+  }
+
+static double IMRPhenomXHM_Intermediate_Amp_delta2(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+    double retVal;
+
+    switch ( IntAmpFlag )
+    {
+      case 101: //linear, only v1, v2
+      {
+        retVal = 0.;
+        break;
+      }
+      case 102: //quadratic: v1, v2, d2
+      {
+        UNUSED double f1mf4  = f1-f4;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+
+        retVal = (-(d4*f1mf4) + v1 - v4)/f1mf42;
+        break;
+      }
+      case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f42 = f4*f4;
+
+        UNUSED double f1mf4  = f1-f4;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f1mf43 = f1mf42*f1mf4;
+
+        retVal = (-(d1*(f12 + f1*f4 - 2*f42)) + d4*(-2*f12 + f1*f4 + f42) + 3*(f1 + f4)*(v1 - v4))/f1mf43;
+        break;
+      }
+      case 103:   // 4 freqs, no boundaries derivatives
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        retVal = (-(f1*f4*(f12 - f42)*(v2 - v3)) + f3*(f43*(v1 - v2) + f13*(v2 - v4)) + f23*(f4*(v1 - v3) + f1*(v3 - v4) + f3*(-v1 + v4)) + f33*(f4*(-v1 + v2) + f1*(-v2 + v4)) +
+        f2*(f43*(-v1 + v3) + f33*(v1 - v4) + f13*(-v3 + v4)))/(f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4);
+        break;
+      }
+      case 1043:  //no left derivative: v1, v2, v3, v4, d4
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+        UNUSED double f25 = f24*f2;
+        UNUSED double f26 = f25*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f46 = f44*f42;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+
+        UNUSED double v1mv2 = v1-v2;
+        UNUSED double v2mv3 = v2-v3;
+        UNUSED double v2mv4 = v2-v4;
+        UNUSED double v1mv3 = v1-v3;
+        UNUSED double v1mv4 = v1-v4;
+        UNUSED double v3mv4 = v3-v4;
+
+        retVal = (-(d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4*(f3*f4 + f2*(f3 + f4) + f1*(f2 + f3 + f4))) - 2*f34*f43*v1 + 3*f33*f44*v1 - f3*f46*v1 - f14*f33*v2 + f13*f34*v2 + 3*f14*f3*f42*v2 - 3*f1*f34*f42*v2 -
+        2*f14*f43*v2 - 4*f13*f3*f43*v2 + 4*f1*f33*f43*v2 + 2*f34*f43*v2 + 3*f13*f44*v2 - 3*f33*f44*v2 - f1*f46*v2 + f3*f46*v2 + 2*f14*f43*v3 - 3*f13*f44*v3 + f1*f46*v3 +
+        f2*f42*(f44*v1mv3 + 3*f34*v1mv4 - 4*f33*f4*v1mv4 - 3*f14*v3mv4 + 4*f13*f4*v3mv4) + f24*(2*f43*v1mv3 + f33*v1mv4 - 3*f3*f42*v1mv4 - f13*v3mv4 + 3*f1*f42*v3mv4) +
+        f23*(-3*f44*v1mv3 - f34*v1mv4 + 4*f3*f43*v1mv4 + f14*v3mv4 - 4*f1*f43*v3mv4) + f14*f33*v4 - f13*f34*v4 - 3*f14*f3*f42*v4 + 3*f1*f34*f42*v4 + 4*f13*f3*f43*v4 - 4*f1*f33*f43*v4)/
+        (f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+        break;
+      }
+      case 1042:   //4th order poly: v1,d1, v2,d2, v3   // used for the first intermediate region
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+        UNUSED double f15 = f14*f1;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+
+        UNUSED double f1mf43 = f1mf42*f1mf4;
+
+        retVal = (-(d4*f1mf32*f1mf4*f3mf4*(f12 + f3*f4 + 2*f1*(f3 + f4))) + d1*f1mf3*f1mf4*f3mf42*(f1*f3 + 2*(f1 + f3)*f4 + f42) - 4*f12*f33*v1 + 3*f1*f34*v1 - 4*f1*f33*f4*v1 + 3*f34*f4*v1 + 12*f12*f3*f42*v1 -
+        4*f33*f42*v1 - 8*f12*f43*v1 + f1*f44*v1 + f45*v1 + f15*v3 + f14*f4*v3 - 8*f13*f42*v3 + 8*f12*f43*v3 - f1*f44*v3 - f45*v3 -
+        f1mf32*(f13 + f3*(3*f3 - 4*f4)*f4 + f12*(2*f3 + f4) + f1*(3*f3 - 4*f4)*(f3 + 2*f4))*v4)/(f1mf32*f1mf43*f3mf42);
+        break;
+      }
+      case 104:  //Geraint's Version, 4th order poly: v1,d1, v2,d2, v3
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+        UNUSED double f15 = f14*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf22 = f1mf2*f1mf2;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf32 = f2mf3*f2mf3;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+        UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+        retVal = ((-(d4*f1mf22*f1mf4*f2mf4*(f12 + f2*f4 + 2*f1*(f2 + f4))) + d1*f1mf2*f1mf4*f2mf42*(f1*f2 + 2*(f1 + f2)*f4 + f42)
+        - 4*f12*f23*v1 + 3*f1*f24*v1 - 4*f1*f23*f4*v1 + 3*f24*f4*v1 + 12*f12*f2*f42*v1 -
+        4*f23*f42*v1 - 8*f12*f43*v1 + f1*f44*v1 + f45*v1 + f15*v2 + f14*f4*v2 - 8*f13*f42*v2 + 8*f12*f43*v2 - f1*f44*v2 - f45*v2 -
+        f1mf22*(f13 + f2*(3*f2 - 4*f4)*f4 + f12*(2*f2 + f4) + f1*(3*f2 - 4*f4)*(f2 + 2*f4))*v4)/(f1mf22*f1mf43*f2mf42));
+
+        break;
+      }
+      case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+        UNUSED double f15 = f14*f1;
+        UNUSED double f16 = f15*f1;
+        UNUSED double f17 = f16*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+        UNUSED double f25 = f24*f2;
+        UNUSED double f26 = f25*f2;
+        UNUSED double f27 = f26*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+        UNUSED double f35 = f34*f3;
+        UNUSED double f36 = f35*f3;
+        UNUSED double f37 = f36*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+        UNUSED double f46 = f45*f4;
+        UNUSED double f47 = f46*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf22 = f1mf2*f1mf2;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf32 = f2mf3*f2mf3;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+        UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+        retVal = (
+          (-(d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f2*f3*f4 + f12*(f2 + f3 + f4) + 2*f1*(f2*f3 + (f2 + f3)*f4))) -
+          d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1*f2*f3 + 2*(f2*f3 + f1*(f2 + f3))*f4 + (f1 + f2 + f3)*f42) + 5*f13*f24*f33*v1 - 4*f12*f25*f33*v1 - 5*f13*f23*f34*v1 + 3*f1*f25*f34*v1 +
+          4*f12*f23*f35*v1 - 3*f1*f24*f35*v1 + 5*f12*f24*f33*f4*v1 - 4*f1*f25*f33*f4*v1 - 5*f12*f23*f34*f4*v1 + 3*f25*f34*f4*v1 + 4*f1*f23*f35*f4*v1 - 3*f24*f35*f4*v1 - 15*f13*f24*f3*f42*v1 +
+          12*f12*f25*f3*f42*v1 + 5*f1*f24*f33*f42*v1 - 4*f25*f33*f42*v1 + 15*f13*f2*f34*f42*v1 - 5*f1*f23*f34*f42*v1 - 12*f12*f2*f35*f42*v1 + 4*f23*f35*f42*v1 + 10*f13*f24*f43*v1 - 8*f12*f25*f43*v1 +
+          20*f13*f23*f3*f43*v1 - 15*f12*f24*f3*f43*v1 - 20*f13*f2*f33*f43*v1 + 5*f24*f33*f43*v1 - 10*f13*f34*f43*v1 + 15*f12*f2*f34*f43*v1 - 5*f23*f34*f43*v1 + 8*f12*f35*f43*v1 - 15*f13*f23*f44*v1 +
+          10*f12*f24*f44*v1 + f1*f25*f44*v1 + 15*f13*f33*f44*v1 - 10*f12*f34*f44*v1 - f1*f35*f44*v1 + f12*f23*f45*v1 - 2*f1*f24*f45*v1 + f25*f45*v1 - f12*f33*f45*v1 + 2*f1*f34*f45*v1 - f35*f45*v1 +
+          5*f13*f2*f46*v1 + f1*f23*f46*v1 - 2*f24*f46*v1 - 5*f13*f3*f46*v1 - f1*f33*f46*v1 + 2*f34*f46*v1 - 3*f12*f2*f47*v1 + f23*f47*v1 + 3*f12*f3*f47*v1 - f33*f47*v1 - f17*f33*v2 + 2*f16*f34*v2 -
+          f15*f35*v2 - f16*f33*f4*v2 + 2*f15*f34*f4*v2 - f14*f35*f4*v2 + 3*f17*f3*f42*v2 - f15*f33*f42*v2 - 10*f14*f34*f42*v2 + 8*f13*f35*f42*v2 - 2*f17*f43*v2 - 5*f16*f3*f43*v2 + 15*f14*f33*f43*v2 -
+          8*f12*f35*f43*v2 + 4*f16*f44*v2 - 15*f13*f33*f44*v2 + 10*f12*f34*f44*v2 + f1*f35*f44*v2 + f12*f33*f45*v2 - 2*f1*f34*f45*v2 + f35*f45*v2 - 4*f14*f46*v2 + 5*f13*f3*f46*v2 + f1*f33*f46*v2 -
+          2*f34*f46*v2 + 2*f13*f47*v2 - 3*f12*f3*f47*v2 + f33*f47*v2 + f17*f23*v3 - 2*f16*f24*v3 + f15*f25*v3 + f16*f23*f4*v3 - 2*f15*f24*f4*v3 + f14*f25*f4*v3 - 3*f17*f2*f42*v3 + f15*f23*f42*v3 +
+          10*f14*f24*f42*v3 - 8*f13*f25*f42*v3 + 2*f17*f43*v3 + 5*f16*f2*f43*v3 - 15*f14*f23*f43*v3 + 8*f12*f25*f43*v3 - 4*f16*f44*v3 + 15*f13*f23*f44*v3 - 10*f12*f24*f44*v3 - f1*f25*f44*v3 -
+          f12*f23*f45*v3 + 2*f1*f24*f45*v3 - f25*f45*v3 + 4*f14*f46*v3 - 5*f13*f2*f46*v3 - f1*f23*f46*v3 + 2*f24*f46*v3 - 2*f13*f47*v3 + 3*f12*f2*f47*v3 - f23*f47*v3 -
+          f1mf22*f1mf32*f2mf3*(f13*(f22 + f2*f3 + f32 - 3*f42) + f2*f3*f4*(3*f2*f3 - 4*(f2 + f3)*f4 + 5*f42) + f1*(f2*f3 + 2*(f2 + f3)*f4)*(3*f2*f3 - 4*(f2 + f3)*f4 + 5*f42) +
+          f12*(2*f2*f3*(f2 + f3) + (f22 + f2*f3 + f32)*f4 - 6*(f2 + f3)*f42 + 5*f43))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+        );
+
+        break;
+      }
+      default:
+      {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta2: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+      }
+    }
+
+    return retVal;
+}
+
+static double IMRPhenomXHM_Intermediate_Amp_delta3(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+    double retVal;
+
+    switch ( IntAmpFlag )
+    {
+      case 101: //linear, only v1, v2
+      {
+        retVal = 0.;
+        break;
+      }
+      case 102: //quadratic: v1, v2, d2
+      {
+        retVal = 0.;
+        break;
+      }
+      case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+      {
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f1mf43 = f1mf42*f1mf4;
+
+        retVal = (d1*f1mf4 + d4*f1mf4 - 2*v1 + 2*v4)/f1mf43;
+        break;
+      }
+      case 103:  // 4 freqs, no boundaries derivatives
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        retVal = (f1*f1mf4*f4*(v2 - v3) + f32*(f4*(v1 - v2) + f1*(v2 - v4)) + f2*(f42*(v1 - v3) + f12*(v3 - v4) + f32*(-v1 + v4)) + f3*(f42*(-v1 + v2) + f12*(-v2 + v4)) +
+        f22*(f4*(-v1 + v3) + f3*(v1 - v4) + f1*(-v3 + v4)))/(f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4);
+        break;
+      }
+      case 1043:  //no left derivative: v1, v2, v3, v4, d4
+      {
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+
+        UNUSED double f22 = f2*f2;
+        UNUSED double f23 = f22*f2;
+        UNUSED double f24 = f23*f2;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f34 = f32*f32;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+
+        UNUSED double f1mf2 = f1-f2;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f2mf3 = f2-f3;
+        UNUSED double f2mf4 = f2-f4;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f2mf42 = f2mf4*f2mf4;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+
+        UNUSED double v1mv2 = v1-v2;
+        UNUSED double v2mv3 = v2-v3;
+        UNUSED double v2mv4 = v2-v4;
+        UNUSED double v1mv3 = v1-v3;
+        UNUSED double v1mv4 = v1-v4;
+        UNUSED double v3mv4 = v3-v4;
+
+        retVal = (d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4*(f1 + f2 + f3 + f4) + f34*f42*v1 - 3*f32*f44*v1 + 2*f3*f45*v1 + f14*f32*v2 - f12*f34*v2 - 2*f14*f3*f4*v2 + 2*f1*f34*f4*v2 + f14*f42*v2 - f34*f42*v2 +
+        4*f12*f3*f43*v2 - 4*f1*f32*f43*v2 - 3*f12*f44*v2 + 3*f32*f44*v2 + 2*f1*f45*v2 - 2*f3*f45*v2 - f14*f42*v3 + 3*f12*f44*v3 - 2*f1*f45*v3 +
+        f24*(-(f42*v1mv3) - f32*v1mv4 + 2*f3*f4*v1mv4 + f12*v3mv4 - 2*f1*f4*v3mv4) - 2*f2*f4*(f44*v1mv3 + f34*v1mv4 - 2*f32*f42*v1mv4 - f14*v3mv4 + 2*f12*f42*v3mv4) +
+        f22*(3*f44*v1mv3 + f34*v1mv4 - 4*f3*f43*v1mv4 - f14*v3mv4 + 4*f1*f43*v3mv4) - f14*f32*v4 + f12*f34*v4 + 2*f14*f3*f4*v4 - 2*f1*f34*f4*v4 - 4*f12*f3*f43*v4 + 4*f1*f32*f43*v4)/
+        (f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+        break;
+      }
+      case 1042:   //4th order poly: v1,d1, v2,d2, v3  // used for the first intermediate region
+      {
+
+        UNUSED double f12 = f1*f1;
+        UNUSED double f13 = f12*f1;
+        UNUSED double f14 = f13*f1;
+        UNUSED double f15 = f14*f1;
+
+        UNUSED double f42 = f4*f4;
+        UNUSED double f43 = f42*f4;
+        UNUSED double f44 = f43*f4;
+        UNUSED double f45 = f44*f4;
+
+        UNUSED double f32 = f3*f3;
+        UNUSED double f33 = f32*f3;
+        UNUSED double f34 = f33*f3;
+
+        UNUSED double f1mf4 = f1-f4;
+        UNUSED double f1mf3 = f1-f3;
+        UNUSED double f3mf4 = f3-f4;
+
+        UNUSED double f1mf42 = f1mf4*f1mf4;
+        UNUSED double f1mf32 = f1mf3*f1mf3;
+        UNUSED double f3mf42 = f3mf4*f3mf4;
+
+        UNUSED double f1mf43 = f1mf42*f1mf4;
+
+        UNUSED double v1mv4 = v1-v4;
+        UNUSED double v1mv3 = v1-v3;
+        UNUSED double v3mv4 = v3-v4;
+
+        retVal = (2*d4*f14*f3 - d1*f13*f32 - 3*d4*f13*f32 + d1*f1*f34 + d4*f1*f34 - 2*d4*f14*f4 + 2*d1*f13*f3*f4 + 2*d4*f13*f3*f4 - d1*f12*f32*f4 + d4*f12*f32*f4 - d1*f34*f4 - d4*f34*f4 - d1*f13*f42 + d4*f13*f42 +
+          2*d1*f12*f3*f42 - 2*d4*f12*f3*f42 - d1*f1*f32*f42 + d4*f1*f32*f42 - d1*f12*f43 + d4*f12*f43 - 2*d1*f1*f3*f43 - 2*d4*f1*f3*f43 + 3*d1*f32*f43 + d4*f32*f43 + 2*d1*f1*f44 - 2*d1*f3*f44 +
+          4*f12*f32*v1 - 2*f34*v1 - 8*f12*f3*f4*v1 + 4*f1*f32*f4*v1 + 4*f12*f42*v1 - 8*f1*f3*f42*v1 + 4*f32*f42*v1 + 4*f1*f43*v1 - 2*f44*v1 - 2*f14*v3 + 4*f13*f4*v3 - 4*f1*f43*v3 + 2*f44*v3 + 2*f14*v4 -
+          4*f12*f32*v4 + 2*f34*v4 - 4*f13*f4*v4 + 8*f12*f3*f4*v4 - 4*f1*f32*f4*v4 - 4*f12*f42*v4 + 8*f1*f3*f42*v4 - 4*f32*f42*v4)/(f1mf32*f1mf43*f3mf42);
+          break;
+        }
+        case 104:  //Geraint's Version, 4th order poly: v1,d1, v2,d2, v3
+        {
+
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf22 = f1mf2*f1mf2;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf32 = f2mf3*f2mf3;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+          UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+          retVal = ((d4*f1mf22*f1mf4*f2mf4*(2*f1 + f2 + f4) - d1*f1mf2*f1mf4*f2mf42*(f1 + f2 + 2*f4)
+          + 2*(f44*(-v1 + v2) + 2*f12*f2mf42*(v1 - v4) + 2*f22*f42*(v1 - v4)
+          + 2*f13*f4*(v2 - v4) + f24*(-v1 + v4) + f14*(-v2 + v4) + 2*f1*f4*(f42*(v1 - v2) + f22*(v1 - v4) + 2*f2*f4*(-v1 + v4)))) / (f1mf22*f1mf43*f2mf42));
+
+
+          break;
+        }
+        case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+          UNUSED double f15 = f14*f1;
+          UNUSED double f16 = f15*f1;
+          UNUSED double f17 = f16*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+          UNUSED double f25 = f24*f2;
+          UNUSED double f26 = f25*f2;
+          UNUSED double f27 = f26*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+          UNUSED double f35 = f34*f3;
+          UNUSED double f36 = f35*f3;
+          UNUSED double f37 = f36*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+          UNUSED double f45 = f44*f4;
+          UNUSED double f46 = f45*f4;
+          UNUSED double f47 = f46*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf22 = f1mf2*f1mf2;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf32 = f2mf3*f2mf3;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+          UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+          retVal = (
+            (d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f12 + f2*f3 + (f2 + f3)*f4 + 2*f1*(f2 + f3 + f4)) + d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1*f2 + f1*f3 + f2*f3 + 2*(f1 + f2 + f3)*f4 + f42) -
+            5*f13*f24*f32*v1 + 4*f12*f25*f32*v1 + 5*f13*f22*f34*v1 - 2*f25*f34*v1 - 4*f12*f22*f35*v1 + 2*f24*f35*v1 + 10*f13*f24*f3*f4*v1 - 8*f12*f25*f3*f4*v1 - 5*f12*f24*f32*f4*v1 + 4*f1*f25*f32*f4*v1 -
+            10*f13*f2*f34*f4*v1 + 5*f12*f22*f34*f4*v1 + 8*f12*f2*f35*f4*v1 - 4*f1*f22*f35*f4*v1 - 5*f13*f24*f42*v1 + 4*f12*f25*f42*v1 + 10*f12*f24*f3*f42*v1 - 8*f1*f25*f3*f42*v1 - 5*f1*f24*f32*f42*v1 +
+            4*f25*f32*f42*v1 + 5*f13*f34*f42*v1 - 10*f12*f2*f34*f42*v1 + 5*f1*f22*f34*f42*v1 - 4*f12*f35*f42*v1 + 8*f1*f2*f35*f42*v1 - 4*f22*f35*f42*v1 - 5*f12*f24*f43*v1 + 4*f1*f25*f43*v1 -
+            20*f13*f22*f3*f43*v1 + 10*f1*f24*f3*f43*v1 + 20*f13*f2*f32*f43*v1 - 5*f24*f32*f43*v1 + 5*f12*f34*f43*v1 - 10*f1*f2*f34*f43*v1 + 5*f22*f34*f43*v1 - 4*f1*f35*f43*v1 + 15*f13*f22*f44*v1 -
+            5*f1*f24*f44*v1 - 2*f25*f44*v1 - 15*f13*f32*f44*v1 + 5*f1*f34*f44*v1 + 2*f35*f44*v1 - 10*f13*f2*f45*v1 - f12*f22*f45*v1 + 3*f24*f45*v1 + 10*f13*f3*f45*v1 + f12*f32*f45*v1 - 3*f34*f45*v1 +
+            2*f12*f2*f46*v1 - f1*f22*f46*v1 - 2*f12*f3*f46*v1 + f1*f32*f46*v1 + 2*f1*f2*f47*v1 - f22*f47*v1 - 2*f1*f3*f47*v1 + f32*f47*v1 + f17*f32*v2 - 3*f15*f34*v2 + 2*f14*f35*v2 - 2*f17*f3*f4*v2 +
+            f16*f32*f4*v2 + 5*f14*f34*f4*v2 - 4*f13*f35*f4*v2 + f17*f42*v2 - 2*f16*f3*f42*v2 + f15*f32*f42*v2 + f16*f43*v2 + 10*f15*f3*f43*v2 - 15*f14*f32*f43*v2 + 4*f1*f35*f43*v2 - 8*f15*f44*v2 +
+            15*f13*f32*f44*v2 - 5*f1*f34*f44*v2 - 2*f35*f44*v2 + 8*f14*f45*v2 - 10*f13*f3*f45*v2 - f12*f32*f45*v2 + 3*f34*f45*v2 - f13*f46*v2 + 2*f12*f3*f46*v2 - f1*f32*f46*v2 - f12*f47*v2 +
+            2*f1*f3*f47*v2 - f32*f47*v2 - f17*f22*v3 + 3*f15*f24*v3 - 2*f14*f25*v3 + 2*f17*f2*f4*v3 - f16*f22*f4*v3 - 5*f14*f24*f4*v3 + 4*f13*f25*f4*v3 - f17*f42*v3 + 2*f16*f2*f42*v3 - f15*f22*f42*v3 -
+            f16*f43*v3 - 10*f15*f2*f43*v3 + 15*f14*f22*f43*v3 - 4*f1*f25*f43*v3 + 8*f15*f44*v3 - 15*f13*f22*f44*v3 + 5*f1*f24*f44*v3 + 2*f25*f44*v3 - 8*f14*f45*v3 + 10*f13*f2*f45*v3 + f12*f22*f45*v3 -
+            3*f24*f45*v3 + f13*f46*v3 - 2*f12*f2*f46*v3 + f1*f22*f46*v3 + f12*f47*v3 - 2*f1*f2*f47*v3 + f22*f47*v3 +
+            f1mf22*f1mf32*f2mf3*(2*f22*f32 + f13*(f2 + f3 - 2*f4) + f12*(f2 + f3 - 2*f4)*(2*(f2 + f3) + f4) - 4*(f22 + f2*f3 + f32)*f42 + 5*(f2 + f3)*f43 +
+            f1*(4*f2*f3*(f2 + f3) - 4*(f22 + f2*f3 + f32)*f4 - 3*(f2 + f3)*f42 + 10*f43))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+          );
+
+          break;
+        }
+        default:
+        {
+          XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta3: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+        }
+      }
+
+      return retVal;
+}
+
+static double IMRPhenomXHM_Intermediate_Amp_delta4(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+      double retVal;
+
+      switch ( IntAmpFlag )
+      {
+        case 101: //linear, only v1, v2
+        {
+          retVal = 0.;
+          break;
+        }
+        case 102: //quadratic: v1, v2, d2
+        {
+          retVal = 0.;
+          break;
+        }
+        case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+        {
+          retVal = 0.;
+          break;
+        }
+        case 103:   // 4 freqs, no boundaries derivatives
+        {
+          retVal = 0.;
+          break;
+        }
+        case 1043:  //no left derivative: v1, v2, v3, v4, d4
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+
+          UNUSED double v1mv2 = v1-v2;
+          UNUSED double v2mv3 = v2-v3;
+          UNUSED double v2mv4 = v2-v4;
+          UNUSED double v1mv3 = v1-v3;
+          UNUSED double v1mv4 = v1-v4;
+          UNUSED double v3mv4 = v3-v4;
+
+          retVal = (-(d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4) - f33*f42*v1 + 2*f32*f43*v1 - f3*f44*v1 - f13*f32*v2 + f12*f33*v2 + 2*f13*f3*f4*v2 - 2*f1*f33*f4*v2 - f13*f42*v2 - 3*f12*f3*f42*v2 + 3*f1*f32*f42*v2 +
+          f33*f42*v2 + 2*f12*f43*v2 - 2*f32*f43*v2 - f1*f44*v2 + f3*f44*v2 + f13*f42*v3 - 2*f12*f43*v3 + f1*f44*v3 + f23*(f42*v1mv3 + f32*v1mv4 - 2*f3*f4*v1mv4 - f12*v3mv4 + 2*f1*f4*v3mv4) +
+          f2*f4*(f43*v1mv3 + 2*f33*v1mv4 - 3*f32*f4*v1mv4 - 2*f13*v3mv4 + 3*f12*f4*v3mv4) + f22*(-2*f43*v1mv3 - f33*v1mv4 + 3*f3*f42*v1mv4 + f13*v3mv4 - 3*f1*f42*v3mv4) + f13*f32*v4 - f12*f33*v4 -
+          2*f13*f3*f4*v4 + 2*f1*f33*f4*v4 + 3*f12*f3*f42*v4 - 3*f1*f32*f42*v4)/(f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+          break;
+        }
+        case 1042:   //4th order poly: v1,d1, v2,d2, v3   // used for the first intermediate region
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+          UNUSED double f15 = f14*f1;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+          UNUSED double f45 = f44*f4;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+
+          UNUSED double f1mf43 = f1mf42*f1mf4;
+
+          retVal = (-(d4*f1mf32*f1mf4*f3mf4) + d1*f1mf3*f1mf4*f3mf42 - 3*f1*f32*v1 + 2*f33*v1 + 6*f1*f3*f4*v1 - 3*f32*f4*v1 - 3*f1*f42*v1 + f43*v1 + f13*v3 - 3*f12*f4*v3 + 3*f1*f42*v3 - f43*v3 -
+          f1mf32*(f1 + 2*f3 - 3*f4)*v4)/(f1mf32*f1mf43*f3mf42);
+          break;
+        }
+        case 104:  //Geraint's Version, 4th order poly: v1,d1, v2, v4,d4
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf22 = f1mf2*f1mf2;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf32 = f2mf3*f2mf3;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+          UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+          retVal = ((-(d4*f1mf22*f1mf4*f2mf4) + d1*f1mf2*f1mf4*f2mf42 - 3*f1*f22*v1 + 2*f23*v1 + 6*f1*f2*f4*v1 - 3*f22*f4*v1
+          - 3*f1*f42*v1 + f43*v1 + f13*v2 - 3*f12*f4*v2 + 3*f1*f42*v2 - f43*v2 - f1mf22*(f1 + 2*f2 - 3*f4)*v4)/(f1mf22*f1mf43*f2mf42));
+
+          break;
+        }
+        case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+          UNUSED double f15 = f14*f1;
+          UNUSED double f16 = f15*f1;
+          UNUSED double f17 = f16*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+          UNUSED double f25 = f24*f2;
+          UNUSED double f26 = f25*f2;
+          UNUSED double f27 = f26*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+          UNUSED double f35 = f34*f3;
+          UNUSED double f36 = f35*f3;
+          UNUSED double f37 = f36*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+          UNUSED double f45 = f44*f4;
+          UNUSED double f46 = f45*f4;
+          UNUSED double f47 = f46*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf22 = f1mf2*f1mf2;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf32 = f2mf3*f2mf3;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+          UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+          retVal = (
+            (-(d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(2*f1 + f2 + f3 + f4)) - d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1 + f2 + f3 + 2*f4) + 5*f13*f23*f32*v1 - 3*f1*f25*f32*v1 - 5*f13*f22*f33*v1 +
+            2*f25*f33*v1 + 3*f1*f22*f35*v1 - 2*f23*f35*v1 - 10*f13*f23*f3*f4*v1 + 6*f1*f25*f3*f4*v1 + 5*f12*f23*f32*f4*v1 - 3*f25*f32*f4*v1 + 10*f13*f2*f33*f4*v1 - 5*f12*f22*f33*f4*v1 -
+            6*f1*f2*f35*f4*v1 + 3*f22*f35*f4*v1 + 5*f13*f23*f42*v1 - 3*f1*f25*f42*v1 + 15*f13*f22*f3*f42*v1 - 10*f12*f23*f3*f42*v1 - 15*f13*f2*f32*f42*v1 + 5*f1*f23*f32*f42*v1 - 5*f13*f33*f42*v1 +
+            10*f12*f2*f33*f42*v1 - 5*f1*f22*f33*f42*v1 + 3*f1*f35*f42*v1 - 10*f13*f22*f43*v1 + 5*f12*f23*f43*v1 + f25*f43*v1 + 15*f12*f22*f3*f43*v1 - 10*f1*f23*f3*f43*v1 + 10*f13*f32*f43*v1 -
+            15*f12*f2*f32*f43*v1 + 5*f23*f32*f43*v1 - 5*f12*f33*f43*v1 + 10*f1*f2*f33*f43*v1 - 5*f22*f33*f43*v1 - f35*f43*v1 + 5*f13*f2*f44*v1 - 10*f12*f22*f44*v1 + 5*f1*f23*f44*v1 - 5*f13*f3*f44*v1 +
+            10*f12*f32*f44*v1 - 5*f1*f33*f44*v1 + 5*f12*f2*f45*v1 + 2*f1*f22*f45*v1 - 3*f23*f45*v1 - 5*f12*f3*f45*v1 - 2*f1*f32*f45*v1 + 3*f33*f45*v1 - 4*f1*f2*f46*v1 + 2*f22*f46*v1 + 4*f1*f3*f46*v1 -
+            2*f32*f46*v1 - 2*f16*f32*v2 + 3*f15*f33*v2 - f13*f35*v2 + 4*f16*f3*f4*v2 - 2*f15*f32*f4*v2 - 5*f14*f33*f4*v2 + 3*f12*f35*f4*v2 - 2*f16*f42*v2 - 5*f15*f3*f42*v2 + 10*f14*f32*f42*v2 -
+            3*f1*f35*f42*v2 + 4*f15*f43*v2 - 5*f14*f3*f43*v2 + f35*f43*v2 + 5*f13*f3*f44*v2 - 10*f12*f32*f44*v2 + 5*f1*f33*f44*v2 - 4*f13*f45*v2 + 5*f12*f3*f45*v2 + 2*f1*f32*f45*v2 - 3*f33*f45*v2 +
+            2*f12*f46*v2 - 4*f1*f3*f46*v2 + 2*f32*f46*v2 + 2*f16*f22*v3 - 3*f15*f23*v3 + f13*f25*v3 - 4*f16*f2*f4*v3 + 2*f15*f22*f4*v3 + 5*f14*f23*f4*v3 - 3*f12*f25*f4*v3 + 2*f16*f42*v3 +
+            5*f15*f2*f42*v3 - 10*f14*f22*f42*v3 + 3*f1*f25*f42*v3 - 4*f15*f43*v3 + 5*f14*f2*f43*v3 - f25*f43*v3 - 5*f13*f2*f44*v3 + 10*f12*f22*f44*v3 - 5*f1*f23*f44*v3 + 4*f13*f45*v3 - 5*f12*f2*f45*v3 -
+            2*f1*f22*f45*v3 + 3*f23*f45*v3 - 2*f12*f46*v3 + 4*f1*f2*f46*v3 - 2*f22*f46*v3 -
+            f1mf22*f1mf32*f2mf3*(2*f2*f3*(f2 + f3) + 2*f12*(f2 + f3 - 2*f4) - 3*(f22 + f2*f3 + f32)*f4 + f1*(f22 + 5*f2*f3 + f32 - 6*(f2 + f3)*f4 + 5*f42) + 5*f43)*v4)/
+            (f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+          );
+
+          break;
+        }
+        default:
+        {
+          XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta4: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+        }
+      }
+
+      return retVal;
+}
+
+static double IMRPhenomXHM_Intermediate_Amp_delta5(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+      double retVal;
+
+      switch ( IntAmpFlag )
+      {
+        case 101:
+        {
+          retVal = 0.;
+          break;
+        }
+        case 102: //quadratic: v1, v2, d2
+        {
+          retVal = 0.;
+          break;
+        }
+        case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+        {
+          //printf("\nIMRPhenomXHM_Intermediate_Amp_delta5 = 0 \r\n");
+          retVal = 0.;
+          break;
+        }
+        case 103:   // 4 freqs, no boundaries derivatives
+        {
+          retVal = 0.;
+          break;
+        }
+        case 1043:  //no left derivative: v1, v2, v3, v4, d4
+        {
+          retVal = 0.;
+          break;
+        }
+        case 1042:   //4th order poly: v1,d1, v2,d2, v3   // used for the first intermediate region
+        {
+          retVal = 0.0;
+          break;
+        }
+        case 104:  //Geraint's Version, 4th order poly: v1,d1, v2,d2, v3
+        {
+          retVal = 0.0;
+          break;
+        }
+        case 105: // Geraint, standard way: v1, v2, v3, v4, d1, d4
+        {
+          UNUSED double f12 = f1*f1;
+          UNUSED double f13 = f12*f1;
+          UNUSED double f14 = f13*f1;
+          UNUSED double f15 = f14*f1;
+          UNUSED double f16 = f15*f1;
+          UNUSED double f17 = f16*f1;
+
+          UNUSED double f22 = f2*f2;
+          UNUSED double f23 = f22*f2;
+          UNUSED double f24 = f23*f2;
+          UNUSED double f25 = f24*f2;
+          UNUSED double f26 = f25*f2;
+          UNUSED double f27 = f26*f2;
+
+          UNUSED double f32 = f3*f3;
+          UNUSED double f33 = f32*f3;
+          UNUSED double f34 = f33*f3;
+          UNUSED double f35 = f34*f3;
+          UNUSED double f36 = f35*f3;
+          UNUSED double f37 = f36*f3;
+
+          UNUSED double f42 = f4*f4;
+          UNUSED double f43 = f42*f4;
+          UNUSED double f44 = f43*f4;
+          UNUSED double f45 = f44*f4;
+          UNUSED double f46 = f45*f4;
+          UNUSED double f47 = f46*f4;
+
+          UNUSED double f1mf2 = f1-f2;
+          UNUSED double f1mf3 = f1-f3;
+          UNUSED double f1mf4 = f1-f4;
+          UNUSED double f2mf3 = f2-f3;
+          UNUSED double f2mf4 = f2-f4;
+          UNUSED double f3mf4 = f3-f4;
+
+          UNUSED double f1mf22 = f1mf2*f1mf2;
+          UNUSED double f1mf32 = f1mf3*f1mf3;
+          UNUSED double f1mf42 = f1mf4*f1mf4;
+          UNUSED double f2mf32 = f2mf3*f2mf3;
+          UNUSED double f2mf42 = f2mf4*f2mf4;
+          UNUSED double f3mf42 = f3mf4*f3mf4;
+          UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+          retVal = (
+            (d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4 + d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42 - 4*f12*f23*f32*v1 + 3*f1*f24*f32*v1 + 4*f12*f22*f33*v1 - 2*f24*f33*v1 - 3*f1*f22*f34*v1 + 2*f23*f34*v1 +
+              8*f12*f23*f3*f4*v1 - 6*f1*f24*f3*f4*v1 - 4*f1*f23*f32*f4*v1 + 3*f24*f32*f4*v1 - 8*f12*f2*f33*f4*v1 + 4*f1*f22*f33*f4*v1 + 6*f1*f2*f34*f4*v1 - 3*f22*f34*f4*v1 - 4*f12*f23*f42*v1 +
+              3*f1*f24*f42*v1 - 12*f12*f22*f3*f42*v1 + 8*f1*f23*f3*f42*v1 + 12*f12*f2*f32*f42*v1 - 4*f23*f32*f42*v1 + 4*f12*f33*f42*v1 - 8*f1*f2*f33*f42*v1 + 4*f22*f33*f42*v1 - 3*f1*f34*f42*v1 +
+              8*f12*f22*f43*v1 - 4*f1*f23*f43*v1 - f24*f43*v1 - 8*f12*f32*f43*v1 + 4*f1*f33*f43*v1 + f34*f43*v1 - 4*f12*f2*f44*v1 - f1*f22*f44*v1 + 2*f23*f44*v1 + 4*f12*f3*f44*v1 + f1*f32*f44*v1 -
+              2*f33*f44*v1 + 2*f1*f2*f45*v1 - f22*f45*v1 - 2*f1*f3*f45*v1 + f32*f45*v1 + f15*f32*v2 - 2*f14*f33*v2 + f13*f34*v2 - 2*f15*f3*f4*v2 + f14*f32*f4*v2 + 4*f13*f33*f4*v2 - 3*f12*f34*f4*v2 +
+              f15*f42*v2 + 4*f14*f3*f42*v2 - 8*f13*f32*f42*v2 + 3*f1*f34*f42*v2 - 3*f14*f43*v2 + 8*f12*f32*f43*v2 - 4*f1*f33*f43*v2 - f34*f43*v2 + 3*f13*f44*v2 - 4*f12*f3*f44*v2 - f1*f32*f44*v2 +
+              2*f33*f44*v2 - f12*f45*v2 + 2*f1*f3*f45*v2 - f32*f45*v2 - f15*f22*v3 + 2*f14*f23*v3 - f13*f24*v3 + 2*f15*f2*f4*v3 - f14*f22*f4*v3 - 4*f13*f23*f4*v3 + 3*f12*f24*f4*v3 - f15*f42*v3 -
+              4*f14*f2*f42*v3 + 8*f13*f22*f42*v3 - 3*f1*f24*f42*v3 + 3*f14*f43*v3 - 8*f12*f22*f43*v3 + 4*f1*f23*f43*v3 + f24*f43*v3 - 3*f13*f44*v3 + 4*f12*f2*f44*v3 + f1*f22*f44*v3 - 2*f23*f44*v3 +
+              f12*f45*v3 - 2*f1*f2*f45*v3 + f22*f45*v3 + f1mf22*f1mf32*f2mf3*(2*f2*f3 + f1*(f2 + f3 - 2*f4) - 3*(f2 + f3)*f4 + 4*f42)*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+            );
+            break ;
+          }
+          default:
+          {
+            XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_delta5: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+          }
+        }
+        return retVal;
+}
+
+
+/*********************************************/
+/*         INTERMEDIATE AMPLITUDE ANSATZ     */
+/*********************************************/
+
+// Build the polynomial with the coefficients given and return the inverse of the polynomial (this is the ansatz)
+static double IMRPhenomXHM_Intermediate_Amp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp)
+{
+        double a0 = pAmp->delta0;
+        double a1 = pAmp->delta1;
+        double a2 = pAmp->delta2;
+        double a3 = pAmp->delta3;
+        double a4 = pAmp->delta4;
+        double a5 = pAmp->delta5;
+        double polynomial;
+        int InterAmpPolOrder = pAmp->InterAmpPolOrder;
+
+        switch ( InterAmpPolOrder )
+        {
+          case 101:   // linear order
+          {
+            double ff = powers_of_f->itself;
+            polynomial = a0 + a1*ff ;
+            break;
+          }
+          case 102:   // quadratic order
+          {
+            double ff = powers_of_f->itself;
+            double ff2 = powers_of_f->two;
+            polynomial = a0 + a1*ff + a2*ff2;
+            break;
+          }
+          case 103:   //cubic order
+          {
+            double ff  = powers_of_f->itself;
+            double ff2 = powers_of_f->two;
+            double ff3 = powers_of_f->three;
+            polynomial = a0 + a1*ff + a2*ff2 + a3*ff3;
+            break;
+          }
+          case 1042:    // 4th order, used for the first intermediate region
+          {
+            double ff  = powers_of_f->itself;
+            double ff2 = powers_of_f->two;
+            double ff3 = powers_of_f->three;
+            double ff4 = powers_of_f->four;
+            a0         = pAmp->alpha0;
+            a1         = pAmp->alpha1;
+            a2         = pAmp->alpha2;
+            a3         = pAmp->alpha3;
+            a4         = pAmp->alpha4;
+            polynomial = a0 + a1*ff + a2*ff2 + a3*ff3 + a4*ff4;
+            break;
+          }
+          case 104:     // 4th order
+          {
+            double ff = powers_of_f->itself;
+            double ff2 = powers_of_f->two;
+            double ff3 = powers_of_f->three;
+            double ff4 = powers_of_f->four;
+            polynomial = a0 + a1*ff + a2*ff2 + a3*ff3 + a4*ff4;
+            break;
+          }
+          case 105:     // 5th order
+          {
+            double ff  = powers_of_f->itself;
+            double ff2 = powers_of_f->two;
+            double ff3 = powers_of_f->three;
+            double ff4 = powers_of_f->four;
+            double ff5 = powers_of_f->five;
+            polynomial = a0 + a1*ff + a2*ff2 + a3*ff3 + a4*ff4 + a5*ff5;
+            break;
+          }
+          default:
+          {
+            XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomXHM_Intermediate_Amp_Ansatz: InterAmpPolOrder is not valid.\n");
+          }
+        }
+        return 1. / polynomial;
+}
+
+
+/**** VETO functions ****/
+
+// Utility functions used to decide how many collocation points and which kind of reconstruction we do in the intermediate
+
+
+// Remove too low collocation points (heuristic)
+void IMRPhenomXHM_Intermediate_Amplitude_Veto(double *int1, double *int2, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+  double threshold = 0.2/(pWF22->ampNorm);
+  if( 1./(*int1) < threshold )
+  {
+    *int1 = 1.;
+    pWFHM->IMRPhenomXHMIntermediateAmpVersion = 1042;
+    if( 1./(*int2) < threshold ){
+      *int2 = 1.;
+      pWFHM->IMRPhenomXHMIntermediateAmpVersion = 1032;
+    }
+  }else if( 1./(*int2) < threshold )
+  {
+    *int2 = 1.;
+    pWFHM->IMRPhenomXHMIntermediateAmpVersion = 1042;
+  }
+}
+
+// Check if a particular frequency belong to an interval
+int InsideInterval(double ftest, double fmin, double fmax){
+
+  if(ftest >= fmin && ftest <= fmax){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+
+// Check if the 2nd order polynomial crosses zero
+int CrossZeroP2(double a0, double a1, double a2, double fstart, double fend){
+
+  double complex f1, f2;
+  double discriminant = -4*a0*a2 + a1*a1;
+
+  f1 = creall((-a1 - sqrt(discriminant))/(2.*a2));
+  f2 = creall((-a1 + sqrt(discriminant))/(2.*a2));
+
+  if( discriminant >= 0 && (InsideInterval(f1, fstart, fend) || InsideInterval(f2, fstart, fend) )){
+    return 1;
+  }else{
+    return 0;
+  }
+}
+
+// Check if the 3th order polynomial crosses zero
+int CrossZeroP3(double a0, double a1, double a2, double a3, double fstart, double fend)
+{
+
+  double q1 = -a2/(3.*a3);
+  double q2 = -a2*a2 + 3*a1*a3;
+  double q3 = -2*a2*a2*a2 + 9*a1*a2*a3-27*a0*a3*a3;
+  double discri = 4*q2*q2*q2 + q3*q3;
+  double complex onethirdpower = cpow( q3 + csqrt(discri) , 1/3.);
+  double complex f1, f2, f3;
+  double twothird = pow(2,1/3.);
+  double complex z1 = (1. + I*sqrt(3.)), z2 = (1. - I*sqrt(3.));
+  int i1=0, i2=0, i3=0;
+
+  // These are the points where the polynomial is zero
+  f1 = q1 - q2*twothird/(3*a3*onethirdpower) + onethirdpower/(3.*a3*twothird);
+  f2 = q1 + q2*z1/(3*twothird*twothird*a3*onethirdpower) - onethirdpower*z2/(6*twothird*a3);
+  f3 = q1 + q2*z2/(3*twothird*twothird*a3*onethirdpower) - onethirdpower*z1/(6*twothird*a3);
+
+  // If the solution is real and lay inside the interval then we return true.
+  // Sometimes due to finite precission the imaginary part can be not exactly zero and we set the threshold 10^-15 as limiting value.
+  double threshold = pow(10.,-15);
+  if (fabs(cimag(f1)) < threshold ){
+    i1 = InsideInterval(creall(f1), fstart, fend);
+  }
+  if (fabs(cimag(f2)) < threshold ){
+    i2 = InsideInterval(creall(f2), fstart, fend);
+  }
+  if (fabs(cimag(f3)) < threshold ){
+    i3 = InsideInterval(creall(f3), fstart, fend);
+  }
+  #if DEBUG == 1
+  printf("\nCrossZeroP3: Coefficients = %.16f %.16f %.16f %.16f",a0, a1, a2, a3);
+  printf("\nCrossZeroP3: discri = %.16f ", discri);
+  printf("\nCrossZeroP3: Imag f1, f2, f3 = %.16e %.16e %.16e ", fabs(cimag(f1)), fabs(cimag(f2)), fabs(cimag(f3)));
+  printf("\nCrossZeroP3: a3 = %.16f %.16f", creal(a3), cimag(a3));
+  printf("\nCrossZeroP3: onethirdpower = %.16f %.16f", creal(onethirdpower), cimag(onethirdpower));
+  printf("\nCrossZeroP3: f1 = %.16e %.16e", creal(f1), cimag(f1));
+  printf("\nCrossZeroP3: f2 = %.16e %.16e", creal(f2), cimag(f2));
+  printf("\nCrossZeroP3: f3 = %.16e %.16e", creal(f3), cimag(f3));
+  printf("\nCrossZeroP3: i1, i2, i3 = %i %i %i", i1, i2, i3);
+  #endif
+  if (i1 == 0 && i2 == 0 && i3 == 0 ){
+    return 0;
+  }else{
+    return 1;
+  }
+}
+
+// Check if the 4th order polynomial crosses zero
+int CrossZeroP4(double a0, double a1, double a2, double a3, double a4, double fstart, double fend){
+
+  double q0 = -a3/(4*a4);
+  double q1 = a3*a3/(4*a4*a4) -2*a2/(3*a4);
+  double q1b = 2*q1;
+  double q2 = a2*a2 - 3*a1*a3 + 12*a0*a4;
+  double q3 = 2*a2*a2*a2 - 9*a1*a2*a3 + 27*a0*a3*a3 + 27*a1*a1*a4 - 72*a0*a2*a4;
+  double complex squareroot = csqrt(-4*q2*q2*q2 + q3*q3);
+  double complex onethird = cpow(q3 + squareroot , 1/3.);
+  double twothird = pow(2,1/3.);
+  double complex frac1 = twothird*q2/(3*a4*onethird);
+  double complex frac2 = onethird/(3*twothird*a4);
+  double complex bigdenom = 4*sqrt(q1 + frac1 + frac2);
+  double bignum = -a3*a3*a3/(a4*a4*a4) + 4*a2*a3/(a4*a4) - 8*a1/a4;
+  double threshold = pow(10.,-15);
+
+  complex double f1, f2, f3, f4;
+
+  // These are the solutions
+  f1 = q0 - 0.5*csqrt(q1 + frac1 + frac2) - 0.5*csqrt(q1b - frac1 - frac2 - bignum/bigdenom);
+  f2 = q0 - 0.5*csqrt(q1 + frac1 + frac2) + 0.5*csqrt(q1b - frac1 - frac2 - bignum/bigdenom);
+  f3 = q0 + 0.5*csqrt(q1 + frac1 + frac2) - 0.5*csqrt(q1b - frac1 - frac2 + bignum/bigdenom);
+  f4 = q0 + 0.5*csqrt(q1 + frac1 + frac2) + 0.5*csqrt(q1b - frac1 - frac2 + bignum/bigdenom);
+
+  #if DEBUG == 1
+  printf("\n***** CrossZeroP4 *********\n");
+  printf("q0, q1, q1b, q2, q3 %.16f %.16f %.16f %.16f %.16f\n", q0, q1, q1b, q2, q3);
+  printf("bigdenom bignum %.16f %.16f %.16f %.16f\n", creal(bigdenom), cimag(bigdenom), creal(bignum), cimag(bignum));
+  printf("squareroot %.16f  %.16f \n", creal(squareroot), cimag(squareroot));
+  printf("frac1 frac2 %.16f %.16f %.16f %.16f \n", creal(frac1), cimag(frac1), creal(frac2), cimag(frac2));
+  printf("twothird onethird %.16f %.16f %.16f %.16f", creal(twothird), cimag(twothird), creal(onethird), cimag(onethird));
+  printf("\nfstart, fend = %.16f %.16f\n", fstart, fend);
+  printf("\nf1 = %.16f %.16f", creal(f1), cimag(f1));
+  printf("\nf2 = %.16f %.16f", creal(f2), cimag(f2));
+  printf("\nf3 = %.16f %.16f", creal(f3), cimag(f3));
+  printf("\nf4 = %.16f %.16f", creal(f4), cimag(f4));
+  #endif
+
+  int i1=0, i2=0, i3=0, i4=0;
+
+  // Check if the soultions are real and lay in the interval
+  if (fabs(cimag(f1)) < threshold ){
+    i1 = InsideInterval(creall(f1), fstart, fend);
+  }
+  if (fabs(cimag(f2)) < threshold){
+    i2 = InsideInterval(creall(f2), fstart, fend);
+  }
+  if (fabs(cimag(f3)) < threshold ){
+    i3 = InsideInterval(creall(f3), fstart, fend);
+  }
+  if (fabs(cimag(f4)) < threshold ){
+    i4 = InsideInterval(creall(f4), fstart, fend);
+  }
+
+  if (i1 == 0 && i2 == 0 && i3 == 0 && i4 == 0 ){
+    return 0;
+  }else{
+    return 1;
+  }
+}
+
+
+// Check if the 5th order polynomial crosses zero.
+// In this case there is no analytical solution and we have to check numerically
+int CrossZeroP5(double a0, double a1, double a2, double a3, double a4, double a5, double fstart, double fend)
+{//https://www.gnu.org/software/gsl/doc/html/poly.html
+  double threshold = pow(10.,-15);
+  /* coefficients of P(x) =  -1 + x^5  */
+  double a[6] = { a0, a1, a2, a3, a4, a5 };
+  double z[10];
+
+  gsl_poly_complex_workspace * w
+      = gsl_poly_complex_workspace_alloc (6);
+
+  gsl_poly_complex_solve (a, 6, w, z);
+
+  gsl_poly_complex_workspace_free (w);
+
+  #if DEBUG == 1
+  for (int i = 0; i < 5; i++)
+    {
+
+      printf ("z%d = %+.18f %+.18f\n",
+              i, z[2*i], z[2*i+1]);
+    }
+    #endif
+
+    int i1=0, i2=0, i3=0, i4=0, i5=0;
+
+    // Check if the soultions are real and lay in the interval
+    if (fabs(z[1]) < threshold ){
+      i1 = InsideInterval(z[0], fstart, fend);
+    }
+    if (fabs(z[3]) < threshold){
+      i2 = InsideInterval(z[2], fstart, fend);
+    }
+    if (fabs(z[4]) < threshold ){
+      i3 = InsideInterval(z[4], fstart, fend);
+    }
+    if (fabs(z[5]) < threshold ){
+      i4 = InsideInterval(z[6], fstart, fend);
+    }
+    if (fabs(z[7]) < threshold ){
+      i5 = InsideInterval(z[8], fstart, fend);
+    }
+
+    if (i1 == 0 && i2 == 0 && i3 == 0 && i4 == 0 && i5 == 0 ){
+      return 0;
+    }else{
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+// Get the coefficients of the polynomial for a particular reconstruction indicated with IntAmpFlag
+void Update_Intermediate_Amplitude_Coefficients(IMRPhenomXHMAmpCoefficients *pAmp, int IntAmpFlag)
+{
+    double d1 = pAmp->d1;
+    double d4 = pAmp->d4;
+    double v1 = pAmp->v1;
+    double v2 = pAmp->v2;
+    double v3 = pAmp->v3;
+    double v4 = pAmp->v4;
+    double f1 = pAmp->f1;
+    double f2 = pAmp->f2;
+    double f3 = pAmp->f3;
+    double f4 = pAmp->f4;
+    #if DEBUG == 1
+    printf("\n UpdateCoeff IMRPhenomXHMIntermediateAmpVersion = %i", IntAmpFlag);
+    #endif
+    pAmp->delta0 = IMRPhenomXHM_Intermediate_Amp_delta0(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+    pAmp->delta1 = IMRPhenomXHM_Intermediate_Amp_delta1(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+    pAmp->delta2 = IMRPhenomXHM_Intermediate_Amp_delta2(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+    pAmp->delta3 = IMRPhenomXHM_Intermediate_Amp_delta3(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+    pAmp->delta4 = IMRPhenomXHM_Intermediate_Amp_delta4(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+    pAmp->delta5 = IMRPhenomXHM_Intermediate_Amp_delta5(d1,d4,v1,v2,v3,v4,f1,f2,f3,f4,IntAmpFlag);
+}
+
+// Check if the polynomial crosses zero wrapper.
+// If it crosses zero, then remove one collocation point and lower the order of the polynomial.
+// The order can be as low as linear order, when it is certain that it does not cross zero.
+void ChoosePolOrder(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp){
+  switch(pWFHM->IMRPhenomXHMIntermediateAmpVersion)
+  {
+    case 105:  // v1, v2, v3, v4, d1, d4
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 105\n");
+      #endif
+      // struct pol5_params params;
+      // params.a0 = pAmp->delta0;
+      // params.a1 = pAmp->delta1;
+      // params.a2 = pAmp->delta2;
+      // params.a3 = pAmp->delta3;
+      // params.a4 = pAmp->delta4;
+      // params.a5 = pAmp->delta5;
+
+      double fstart, fend;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+      #if DEBUG == 1
+      printf("\n In ChoosePolOrder\n");
+      #endif
+      if(CrossZeroP5(pAmp->delta0, pAmp->delta1, pAmp->delta2, pAmp->delta3, pAmp->delta4, pAmp->delta5, fstart, fend)==1){
+      //if (RootPol5_finder_gsl(params, fstart, fend) == 1){
+        #if DEBUG == 1
+        printf("\n Pol5 crosses zero \n");
+        #endif
+        //int dummy = RootPol5_finder_gsl(params, fstart, fend);
+        //update Coefficients and intermediate version
+        Update_Intermediate_Amplitude_Coefficients(pAmp, 1042);
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion=104;
+        //check if the lower order cross zero
+        ChoosePolOrder(pWFHM, pAmp);
+      }else{
+        pAmp->InterAmpPolOrder = 105;
+      }
+      break;
+    }
+    case 1043:  //no left derivative: v1, v2, v3, v4, d4
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 1043\n");
+      #endif
+      double a0, a1, a2, a3, a4, fstart, fend;
+      a0 = pAmp->delta0;
+      a1 = pAmp->delta1;
+      a2 = pAmp->delta2;
+      a3 = pAmp->delta3;
+      a4 = pAmp->delta4;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+
+      if(CrossZeroP4(a0, a1, a2, a3, a4, fstart, fend) == 1){
+        //update Coefficients and intermediate version
+        Update_Intermediate_Amplitude_Coefficients(pAmp, 1032);
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion=1032;
+        //check if the lower order cross zero
+        ChoosePolOrder(pWFHM, pAmp);
+      }else{
+        pAmp->InterAmpPolOrder = 104;
+      }
+      break;
+    }
+    case 1042:  //Remove one inter collocation point: v1, d1, v3, v4, d4.
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 1042\n");
+      #endif
+      double a0, a1, a2, a3, a4, fstart, fend;
+      a0 = pAmp->delta0;
+      a1 = pAmp->delta1;
+      a2 = pAmp->delta2;
+      a3 = pAmp->delta3;
+      a4 = pAmp->delta4;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+
+      if(CrossZeroP4(a0, a1, a2, a3, a4, fstart, fend) == 1){
+        //update Coefficients and intermediate version
+        Update_Intermediate_Amplitude_Coefficients(pAmp, 1032);
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion=1032;
+        //check if the lower order cross zero
+        ChoosePolOrder(pWFHM, pAmp);
+      }else{
+        pAmp->InterAmpPolOrder = 104;
+      }
+      break;
+    }
+    case 104:    //Remove one inter collocation point: v1, d1, v2, v4,d4,
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 104\n");
+      #endif
+      double a0, a1, a2, a3, a4, fstart, fend;
+      a0 = pAmp->delta0;
+      a1 = pAmp->delta1;
+      a2 = pAmp->delta2;
+      a3 = pAmp->delta3;
+      a4 = pAmp->delta4;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+
+      if(CrossZeroP4(a0, a1, a2, a3, a4, fstart, fend) == 1){
+        //update Coefficients and intermediate version
+        Update_Intermediate_Amplitude_Coefficients(pAmp, 1032);
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion=1032;
+        //check if the lower order cross zero
+        ChoosePolOrder(pWFHM, pAmp);
+      }else{
+        pAmp->InterAmpPolOrder = 104;
+      }
+      break;
+    }
+    case 1032:  // 2 freqs, points and derivatives: v1, v4, d1, d4
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 1032\n");
+      #endif
+      double a0, a1, a2, a3, fstart, fend;
+      a0 = pAmp->delta0;
+      a1 = pAmp->delta1;
+      a2 = pAmp->delta2;
+      a3 = pAmp->delta3;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+
+      if(CrossZeroP3(a0, a1, a2, a3, fstart, fend) == 1){
+        //update Coefficients and intermediate version
+        #if DEBUG == 1
+        printf("\nCrossZeroP3 True\n");
+        #endif
+        Update_Intermediate_Amplitude_Coefficients(pAmp, 102);
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion = 102;
+        //check if the lower order cross zero
+        ChoosePolOrder(pWFHM, pAmp);
+      }else{
+        #if DEBUG == 1
+        printf("\nCrossZeroP3 False\n");
+        #endif
+        pAmp->InterAmpPolOrder = 103;
+      }
+      break;
+    }
+    case 103:   // 4 freqs, no boundaries derivatives
+    {
+      #if DEBUG == 1
+      printf("\nChoosePolOrder 103\n");
+      #endif
+      double a0, a1, a2, a3, fstart, fend;
+      a0 = pAmp->delta0;
+      a1 = pAmp->delta1;
+      a2 = pAmp->delta2;
+      a3 = pAmp->delta3;
+      fstart = pAmp->fAmpMatchIN;
+      fend = pAmp->fAmpMatchIM;
+
+      if(
+        CrossZeroP3(a0, a1, a2, a3, fstart, fend) == 1){
+          //update Coefficients and intermediate version
+          Update_Intermediate_Amplitude_Coefficients(pAmp, 102);
+          pWFHM->IMRPhenomXHMIntermediateAmpVersion=102;
+          //check if the lower order cross zero
+          ChoosePolOrder(pWFHM, pAmp);
+        }else{
+          pAmp->InterAmpPolOrder = 103;
+        }
+        break;
+      }
+      case 102: //quadratic: v1, v2, d2
+      {
+        #if DEBUG == 1
+        printf("\nChoosePolOrder 102\n");
+        #endif
+        double a0, a1, a2, fstart, fend;
+        a0 = pAmp->delta0;
+        a1 = pAmp->delta1;
+        a2 = pAmp->delta2;
+        fstart = pAmp->fAmpMatchIN;
+        fend = pAmp->fAmpMatchIM;
+
+        if(CrossZeroP2(a0, a1, a2, fstart, fend) == 1){
+          //update Coefficients and intermediate version
+          Update_Intermediate_Amplitude_Coefficients(pAmp, 101);
+          pWFHM->IMRPhenomXHMIntermediateAmpVersion=101;
+          //check if the lower order cross zero
+          ChoosePolOrder(pWFHM, pAmp);
+        }else{
+          pAmp->InterAmpPolOrder = 102;
+        }
+        break;
+      }
+      case 101: //linear, only v1, v2
+      {
+        #if DEBUG == 1
+        printf("\nChoosePolOrder 101\n");
+        #endif
+        //The linear reconstruction is not going to cross zero, since both boundaries to connect are positive
+        pAmp->InterAmpPolOrder = 101;
+        break;
+      }
+    }
+}
+
+
+/***********************************************/
+/*                                             */
+/*                   PHASE                     */
+/*                                             */
+/***********************************************/
+
+// Fits of phase derivatives at collocation points for each mode
+
+static double IMRPhenomXHM_Inter_Phase_21_p1(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    //double delta=sqrt(1-4.*eta);
+    switch (InterPhaseFlag){
+        case 122019:{
+
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 4045.84 + 7.63226/eta - 1956.93*eta - 23428.1*eta2 + 369153.*eta3 - 2.28832e6*eta4 + 6.82533e6*eta5 - 7.86254e6*eta6;
+            double eqSpin = - 347.273*S + 83.5428*S2 - 355.67*S3 + (4.44457*S + 16.5548*S2 + 13.6971*S3)/eta + eta*( - 79.761*S - 355.299*S2 + 1114.51*S3 - 1077.75*S4) + 92.6654*S4 + eta2*(- 619.837*S - 722.787*S2 + 2392.73*S3 + 2689.18*S4);
+            double uneqSpin =  ( 918.976*chi1*sqrt(1. - 4.*eta) - 918.976*chi2*sqrt(1. - 4.*eta))*eta + ( 91.7679*chi1*sqrt(1. - 4.*eta) - 91.7679*chi2*sqrt(1. - 4.*eta))*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p1: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p1(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            double noSpin = 4360.19 + 4.27128/eta - 8727.4*eta + 18485.9*eta2 + 371303.00000000006*eta3 - 3.22792e6*eta4 + 1.01799e7*eta5 - 1.15659e7*eta6;
+            double eqSpin = ((11.6635 - 251.579*eta - 3255.6400000000003*eta2 + 19614.6*eta3 - 34860.2*eta4)*S + (14.8017 + 204.025*eta - 5421.92*eta2 + 36587.3*eta3 - 74299.5*eta4)*S2)/(eta);
+            double uneqSpin = eta*(223.65100000000004*chi1*sqrt(1. - 4.*eta)*(3.9201300240106223 + 1.*eta) - 223.65100000000004*chi2*sqrt(1. - 4.*eta)*(3.9201300240106223 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p1: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p1(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 4414.11 + 4.21564/eta - 10687.8*eta + 58234.6*eta2 - 64068.40000000001*eta3 - 704442.*eta4 + 2.86393e6*eta5 - 3.26362e6*eta6;
+            double eqSpin = ((6.39833 - 610.267*eta + 2095.72*eta2 - 3970.89*eta3)*S + (22.956700000000005 - 99.1551*eta + 331.593*eta2 - 794.79*eta3)*S2 + (10.4333 + 43.8812*eta - 541.261*eta2 + 294.289*eta3)*S3 + eta*(106.047 - 1569.0299999999997*eta + 4810.61*eta2)*S4)/(eta);
+            double uneqSpin = 132.244*sqrt(1. - 4.*eta)*eta*(chi1*(6.227738120444028 - 1.*eta) + chi2*(-6.227738120444028 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p1: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p1(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6, eta7,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 4349.66 + 4.34125/eta - 8202.33*eta + 5534.1*eta2 + 536500.*eta3 - 4.33197e6*eta4 + 1.37792e7*eta5 - 1.60802e7*eta6;
+            double eqSpin = ((12.0704 - 528.098*eta + 1822.9100000000003*eta2 - 9349.73*eta3 + 17900.9*eta4)*S + (10.4092 + 253.334*eta - 5452.04*eta2 + 35416.6*eta3 - 71523.*eta4)*S2 + eta*(492.60300000000007 - 9508.5*eta + 57303.4*eta2 - 109418.*eta3)*S3)/(eta);
+            double uneqSpin = -262.143*sqrt(1. - 4.*eta)*eta*(chi1*(-3.0782778864970646 - 1.*eta) + chi2*(3.0782778864970646 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p1: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Inter_Phase_21_p2(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = eta2*eta;
+            eta4 = eta3*eta;
+            eta5 = eta3*eta2;
+            eta6 = eta4*eta2;
+            eta7 = eta4*eta3;
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4= S3*S;
+            double noSpin = 3509.09 + 0.91868/eta + 194.72*eta - 27556.2*eta2 + 369153.*eta3 - 2.28832e6*eta4 + 6.82533e6*eta5 - 7.86254e6*eta6;
+            double eqSpin = ((0.7083999999999999 - 60.1611*eta + 131.815*eta2 - 619.837*eta3)*S + (6.104720000000001 - 59.2068*eta + 278.588*eta2 - 722.787*eta3)*S2 + (5.7791 + 117.913*eta - 1180.4*eta2 + 2392.73*eta3)*S3 + eta*(92.6654 - 1077.75*eta + 2689.18*eta2)*S4)/(eta);
+            double uneqSpin = -91.7679*sqrt(1. - 4.*eta)*eta*(chi1*(-1.6012352903357276 - 1.*eta) + chi2*(1.6012352903357276 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p2: version is not valid.Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p2(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            double noSpin = 3797.06 + 0.786684/eta - 2397.09*eta - 25514.*eta2 + 518314.99999999994*eta3 - 3.41708e6*eta4 + 1.01799e7*eta5 - 1.15659e7*eta6;
+            double eqSpin = ((6.7812399999999995 + 39.4668*eta - 3520.37*eta2 + 19614.6*eta3 - 34860.2*eta4)*S + (4.80384 + 293.215*eta - 5914.61*eta2 + 36587.3*eta3 - 74299.5*eta4)*S2)/(eta);
+            double uneqSpin = -223.65100000000004*sqrt(1. - 4.*eta)*eta*(chi1*(-1.3095134830606614 - 1.*eta) + chi2*(1.3095134830606614 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p2: version is not valid.Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p2(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3980.7 + 0.956703/eta - 6202.38*eta + 29218.1*eta2 + 24484.2*eta3 - 807629.*eta4 + 2.86393e6*eta5 - 3.26362e6*eta6;
+            double eqSpin = ((1.92692 - 226.825*eta + 75.246*eta2 + 1291.56*eta3)*S + (15.328700000000001 - 99.1551*eta + 608.328*eta2 - 2402.94*eta3)*S2 + (10.4333 + 43.8812*eta - 541.261*eta2 + 294.289*eta3)*S3 + eta*(106.047 - 1569.0299999999997*eta + 4810.61*eta2)*S4)/(eta);
+            double uneqSpin = 132.244*sqrt(1. - 4.*eta)*eta*(chi1*(2.5769789177580837 - 1.*eta) + chi2*(-2.5769789177580837 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p2: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p2(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3804.19 + 0.66144/eta - 2421.77*eta - 33475.8*eta2 + 665951.*eta3 - 4.50145e6*eta4 + 1.37792e7*eta5 - 1.60802e7*eta6;
+            double eqSpin = ((5.83038 - 172.047*eta + 926.576*eta2 - 7676.87*eta3 + 17900.9*eta4)*S + (6.17601 + 253.334*eta - 5672.02*eta2 + 35722.1*eta3 - 71523.*eta4)*S2 + eta*(492.60300000000007 - 9508.5*eta + 57303.4*eta2 - 109418.*eta3)*S3)/(eta);
+            double uneqSpin = -262.143*sqrt(1. - 4.*eta)*eta*(chi1*(-1.0543062374352932 - 1.*eta) + chi2*(1.0543062374352932 + 1.*eta));
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p2: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Inter_Phase_21_p3(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    double delta=sqrt(1.-4*eta);
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = eta2*eta;
+            eta4 = eta2*eta2;
+            eta5 = eta2*eta3;
+            eta6 = eta3*eta3;
+            eta7 = eta3*eta4;
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3241.68 + 890.016*eta - 28651.9*eta2 + 369153.*eta3 - 2.28832e6*eta4 + 6.82533e6*eta5 - 7.86254e6*eta6;
+            double eqSpin = (-2.2484 + 187.641*eta - 619.837*eta2)*S + (3.22603 + 166.323*eta - 722.787*eta2)*S2 + (117.913 - 1094.59*eta + 2392.73*eta2)*S3 + (92.6654 - 1077.75*eta + 2689.18*eta2)*S4;
+            double uneqSpin = 91.7679*(chi1 - 1.*chi2)*delta*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p3: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p3(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            double noSpin = 3321.83 + 1796.03*eta - 52406.1*eta2 + 605028.*eta3 - 3.52532e6*eta4 + 1.01799e7*eta5 - 1.15659e7*eta6;
+            double eqSpin = (223.601 - 3714.77*eta + 19614.6*eta2 - 34860.2*eta3)*S + (314.317 - 5906.46*eta + 36587.3*eta2 - 74299.5*eta3)*S2;
+            double uneqSpin = 223.651*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p3: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p3(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3416.57 + 2308.63*eta - 84042.9*eta2 + 1.01936e6*eta3 - 6.0644e6*eta4 + 1.76399e7*eta5 - 2.0065e7*eta6;
+            double eqSpin = (24.6295 - 282.354*eta - 2582.55*eta2 + 12750.*eta3)*S + (433.675 - 8775.86*eta + 56407.8*eta2 - 114798.*eta3)*S2 + (559.705 - 10627.4*eta + 61581.*eta2 - 114029.*eta3)*S3 + (106.047 - 1569.03*eta + 4810.61*eta2)*S4;
+            double uneqSpin = 63.9466*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p3: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p3(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4, eta5, eta6, S2, S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3308.97 + 2353.58*eta - 66340.1*eta2 + 777272.*eta3 - 4.64438e6*eta4 + 1.37792e7*eta5 - 1.60802e7*eta6;
+            double eqSpin = (-21.5697 + 926.576*eta - 7989.26*eta2 + 17900.9*eta3)*S + (353.539 - 6403.24*eta + 37599.5*eta2 - 71523.*eta3)*S2 + (492.603 - 9508.5*eta + 57303.4*eta2 - 109418.*eta3)*S3;
+            double uneqSpin = 262.143*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p3: version is not valid.Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Inter_Phase_21_p4(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,S3,S4;
+    //double delta=sqrt(1.-4.*eta);
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3160.88 + 974.355*eta - 28932.5*eta2 + 369780.*eta3 - 2.28832e6*eta4 + 6.82533e6*eta5 - 7.86254e6*eta6;
+            double eqSpin = (26.3355 - 196.851*eta + 438.401*eta2)*S + (45.9957 - 256.248*eta + 117.563*eta2)*S2 + (-20.0261 + 467.057*eta - 1613.*eta2)*S3 + (-61.7446 + 577.057*eta - 1096.81*eta2)*S4;
+            double uneqSpin = 65.3326*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p4: version is not valid.Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p4(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5, eta6,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3239.44 - 661.15*eta + 5139.79*eta2 + 3456.2*eta3 - 248477.*eta4 + 1.17255e6*eta5 - 1.70363e6*eta6;
+            double eqSpin = (225.859 - 4150.09*eta + 24364.*eta2 - 46537.3*eta3)*S + (35.2439 - 994.971*eta + 8953.98*eta2 - 23603.5*eta3)*S2 + (-310.489 + 5946.15*eta - 35337.1*eta2 + 67102.4*eta3)*S3;
+            double uneqSpin = 30.484*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p4: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p4(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3307.49 - 476.909*eta - 5980.37*eta2 + 127610.*eta3 - 919108.*eta4 + 2.86393e6*eta5 - 3.26362e6*eta6;
+            double eqSpin = (-5.02553 - 282.354*eta + 1291.56*eta2)*S + (-43.8823 + 740.123*eta - 2402.94*eta2)*S2 + (43.8812 - 370.362*eta + 294.289*eta2)*S3 + (106.047 - 1569.03*eta + 4810.61*eta2)*S4;
+            double uneqSpin = -132.244*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p4: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p4(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3245.63 - 928.56*eta + 8463.89*eta2 - 17422.6*eta3 - 165169.*eta4 + 908279.*eta5 - 1.31138e6*eta6;
+            double eqSpin = (32.506 - 590.293*eta + 3536.61*eta2 - 6758.52*eta3)*S + (-25.7716 + 738.141*eta - 4867.87*eta2 + 9129.45*eta3)*S2 + (-15.7439 + 620.695*eta - 4679.24*eta2 + 9582.58*eta3)*S3;
+            double uneqSpin = 87.0832*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p4: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Inter_Phase_21_p5(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0, delta=sqrt(1.- 4.*eta),eta2,eta3,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3102.36 + 315.911*eta - 1688.26*eta2 + 3635.76*eta3;
+            double eqSpin = (-23.0959 + 320.93*eta - 1029.76*eta2)*S + (-49.5435 + 826.816*eta - 3079.39*eta2)*S2 + (40.7054 - 365.842*eta + 1094.11*eta2)*S3 + (81.8379 - 1243.26*eta + 4689.22*eta2)*S4;
+            double uneqSpin = 119.014*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p5: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p5(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3114.3 + 2143.06*eta - 49428.3*eta2 + 563997.*eta3 - 3.35991e6*eta4 + 9.99745e6*eta5 - 1.17123e7*eta6;
+            double eqSpin = (190.051 - 3705.08*eta + 23046.2*eta2 - 46537.3*eta3)*S + (63.6615 - 1414.2*eta + 10166.1*eta2 - 23603.5*eta3)*S2 + (-257.524 + 5179.97*eta - 33001.4*eta2 + 67102.4*eta3)*S3;
+            double uneqSpin = 54.9833*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p5: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p5(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3259.03 - 3967.58*eta + 111203.*eta2 - 1.81883e6*eta3 + 1.73811e7*eta4 - 9.56988e7*eta5 + 2.75056e8*eta6 - 3.15866e8*eta7;
+            double eqSpin = (19.7509 - 1104.53*eta + 3810.18*eta2)*S + (-230.07 + 2314.51*eta - 5944.49*eta2)*S2 + (-201.633 + 2183.43*eta - 6233.99*eta2)*S3 + (106.047 - 1569.03*eta + 4810.61*eta2)*S4;
+            double uneqSpin = 112.714*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p5: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p5(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3108.38 + 3722.46*eta - 119588.*eta2 + 1.92148e6*eta3 - 1.69796e7*eta4 + 8.39194e7*eta5 - 2.17143e8*eta6 + 2.2829700000000003e8*eta7;
+            double eqSpin = (118.319 - 529.854*eta)*eta*S + (21.0314 - 240.648*eta + 516.333*eta2)*S2 + (20.3384 - 356.241*eta + 999.417*eta2)*S3;
+            double uneqSpin = 97.1364*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p5: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+static double IMRPhenomXHM_Inter_Phase_21_p6(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3089.18 + 4.89194*eta + 190.008*eta2 - 255.245*eta3;
+            double eqSpin = (2.96997 + 57.1612*eta - 432.223*eta2)*S + (-18.8929 + 630.516*eta - 2804.66*eta2)*S2 + (-24.6193 + 549.085*eta2)*S3 + (-12.8798 - 722.674*eta + 3967.43*eta2)*S4;
+            double uneqSpin = 74.0984*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_21_p6: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_33_p6(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3, eta4, eta5, eta6,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3111.46 + 384.121*eta - 13003.6*eta2 + 179537.*eta3 - 1.19313e6*eta4 + 3.79886e6*eta5 - 4.64858e6*eta6;
+            double eqSpin = (182.864 - 3834.22*eta + 24532.9*eta2 - 50165.9*eta3)*S + (21.0158 - 746.957*eta + 6701.33*eta2 - 17842.3*eta3)*S2 + (-292.855 + 5886.62*eta - 37382.4*eta2 + 75501.8*eta3)*S3;
+            double uneqSpin = 75.5162*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_33_p6: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_32_p6(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            S4 = pow(S,4);
+            double noSpin = 3259.03 - 3967.58*eta + 111203.*eta2 - 1.81883e6*eta3 + 1.73811e7*eta4 - 9.56988e7*eta5 + 2.75056e8*eta6 - 3.15866e8*eta7;
+            double eqSpin = (19.7509 - 1104.53*eta + 3810.18*eta2)*S + (-230.07 + 2314.51*eta - 5944.49*eta2)*S2 + (-201.633 + 2183.43*eta - 6233.99*eta2)*S3 + (106.047 - 1569.03*eta + 4810.61*eta2)*S4;
+            double uneqSpin = 112.714*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_32_p6: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_Inter_Phase_44_p6(double eta, double S, double chi1, double chi2, int InterPhaseFlag) {
+    UNUSED double total=0.,eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (InterPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = 3096.03 + 986.752*eta - 20371.1*eta2 + 220332.*eta3 - 1.31523e6*eta4 + 4.29193e6*eta5 - 6.01179e6*eta6;
+            double eqSpin = (-9.96292 - 118.526*eta + 2255.76*eta2 - 6758.52*eta3)*S + (-14.4869 + 370.039*eta - 3605.8*eta2 + 9129.45*eta3)*S2 + (17.0209 + 70.1931*eta - 3070.08*eta2 + 9582.58*eta3)*S3;
+            double uneqSpin = 23.0759*(1.*chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_Inter_Phase_44_p6: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+
+
+/************* PHASE ANSATZ ****************/
+
+static double IMRPhenomXHM_Inter_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase){
+
+  int modeTag = pWFHM->modeTag;
+  double invf  = powers_of_f->m_one;
+  double invf2 = powers_of_f->m_two;
+  double invf3 = powers_of_f->m_three;
+  double logfv=powers_of_f->log;
+  double phaseIR;
+  double fda=pWFHM->fDAMP;
+  double frd=pWFHM->fRING;
+
+  if(modeTag!=32)
+  /*  5 coefficients */
+
+  phaseIR = pPhase->c0 *ff + (pPhase->c1)*logfv - (pPhase->c2)*invf -1./3.* (pPhase->c4)*invf3 + (pPhase->cL)* atan((ff - frd)/fda);
+  else {          /*  6 coefficients */
+
+    invf3 = powers_of_f->m_three;
+    /*(c0 + c1 /f + c2 /(f)^2 + c4 /(f)^4 + c3 /f^3 +
+    cL fdamp/((fdamp)^2 + (f - fRD )^2))*/
+    phaseIR = pPhase->c0 *ff + (pPhase->c1)*logfv - (pPhase->c2)*invf -1./3.* (pPhase->c4)*invf3 -0.5*pPhase->c3*invf2+ (pPhase->cL)* atan((ff - frd)/fda);
+  }
+
+  return phaseIR;
+
+}
+
+static double IMRPhenomXHM_Inter_Phase_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase){
+
+  int modeTag = pWFHM->modeTag;
+  double invf  = powers_of_f->m_one;
+  double invf2 = powers_of_f->m_two;
+  double invf4 = powers_of_f->m_four;
+  double dphaseIR;
+  double fda=pWFHM->fDAMP;
+  double frd=pWFHM->fRING;
+
+  if(modeTag!=32)
+  /*  5 coefficients */
+
+  /*(c0 + c1 /f + c2 /(f)^2 + c4 /(f)^4 +
+  cL fdamp/((fdamp)^2 + (f - fRD )^2))*/
+  dphaseIR = ( pPhase->c0 + (pPhase->c1)*invf + (pPhase->c2)*invf2 + (pPhase->c4)*invf4 + ( (pPhase->cL)* fda/(fda*fda +(ff - frd)*(ff - frd)) ) );
+  else {          /*  6 coefficients */
+
+    double invf3 = powers_of_f->m_three;
+    /*(c0 + c1 /f + c2 /(f)^2 + c4 /(f)^4 + c3 /f^3 +
+    cL fdamp/((fdamp)^2 + (f - fRD )^2))*/
+    dphaseIR = ( pPhase->c0 + (pPhase->c1)*invf + (pPhase->c2)*invf2 + (pPhase->c4)*invf4 +
+    (pPhase->c3)*invf3 + ( (pPhase->cL)* fda/(fda*fda +(ff - frd)*(ff - frd)) ) );
+  }
+
+  return dphaseIR;
+
+}
+
+static double IMRPhenomXHM_Inter_Phase_dAnsatz(double ff,  IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase){
+
+  int modeTag = pWFHM->modeTag;
+  double invf2 = powers_of_f->m_two;
+  double invf3 = powers_of_f->m_three;
+  double invf5 = powers_of_f->m_five;
+  double d2phaseIR;
+  double fda=pWFHM->fDAMP;
+  double frd=pWFHM->fRING;
+
+  if(modeTag!=32)
+  /*  5 coefficients */
+
+  /*(-((4 c4)/f^5) - (2 c2)/f^3 - c1/f^2 - (
+  2 cL fdamp (f - fRD))/(fdamp^2 + (f - fRD)^2)^2)*/
+  d2phaseIR =  -(pPhase->c1)*invf2 -2. *(pPhase->c2)*invf3 -4. *(pPhase->c4)*invf5 -2.* (pPhase->cL)* (ff - frd)*fda/pow((fda*fda +(ff - frd)*(ff - frd)),2);
+  else {          /*  6 coefficients */
+
+    double invf4 = powers_of_f->m_four;
+    /*(-((4 c4)/f^5) - (2 c2)/f^3 - c1/f^2 -3 c3/ f^4- (
+    2 cL fdamp (f - fRD))/(fdamp^2 + (f - fRD)^2)^2)*/
+    d2phaseIR =-(pPhase->c1)*invf2 -3.*pPhase->c3*invf4-2. *(pPhase->c2)*invf3 -4. *(pPhase->c4)*invf5 -2.* (pPhase->cL)* (ff - frd)*fda/pow((fda*fda +(ff - frd)*(ff - frd)),2);
+  }
+
+  return d2phaseIR;
+
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.h b/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.h
new file mode 100644
index 0000000000000000000000000000000000000000..27c297360fddb3230b72bfe17657ef911845e4b6
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_intermediate.h
@@ -0,0 +1,149 @@
+/*
+* Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with with program; see the file COPYING. If not, write to the
+*  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+*  MA  02111-1307  USA
+*
+*/
+//
+//  LALSimIMRPhenomXHM_Intermediate.h
+//
+//
+//  Created by Marta on 06/02/2019.
+//
+
+#ifndef LALSimIMRPhenomXHM_intermediate_h
+#define LALSimIMRPhenomXHM_intermediate_h
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+#include "LALSimIMRPhenomXHM_structs.h"
+
+
+
+/*********** AMPLITUDE *****************/
+
+//Fits int1, int2. 2 collocation points
+static double IMRPhenomXHM_Inter_Amp_21_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_21_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_33_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_33_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_32_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_32_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_44_int1(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_44_int2(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+
+//Fits int0, dint0. Extra collocation point for EMR cases
+static double IMRPhenomXHM_Inter_Amp_21_int0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_21_dint0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_33_int0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_33_dint0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_32_int0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_32_dint0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_44_int0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+static double IMRPhenomXHM_Inter_Amp_44_dint0(double eta, double S, double chi1, double chi2, int InterAmpFlag);
+
+//Coefficients of polynomial. They are feed with the some collocation points.
+static double IMRPhenomXHM_Intermediate_Amp_delta0(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomXHM_Intermediate_Amp_delta1(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomXHM_Intermediate_Amp_delta2(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomXHM_Intermediate_Amp_delta3(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomXHM_Intermediate_Amp_delta4(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomXHM_Intermediate_Amp_delta5(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+
+//Ansatz. Inverse of a polynomial
+static double IMRPhenomXHM_Intermediate_Amp_Ansatz(IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp);
+
+//Veto Functions
+static void IMRPhenomXHM_Intermediate_Amplitude_Veto(double *int1, double *int2, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+static int InsideInterval(double ftest, double fmin, double fmax);
+static int CrossZeroP2(double a0, double a1, double a2, double fstart, double fend);
+static int CrossZeroP3(double a0, double a1, double a2, double a3, double fstart, double fend);
+static int CrossZeroP4(double a0, double a1, double a2, double a3, double a4, double fstart, double fend);
+static int CrossZeroP5(double a0, double a1, double a2, double a3, double a4, double a5, double fstart, double fend);
+
+//Functions and struct need by gsl for finding the root of a 5th order polynomial
+// static double pol5 (double x, void *params);
+// static double pol5_deriv(double x, void *params);
+// static void pol5_fdf(double x, void *params, double *y, double *dy);
+// typedef struct pol5_params
+// {
+//     REAL8 a0, a1, a2, a3, a4, a5;
+// } pol5_params;
+// static int RootPol5_finder_gsl(struct pol5_params params, double x_lo, double x_hi);
+
+//Get the coefficients of the polynomial for a particular reconstruction indicated with IntAmpFlag
+static void Update_Intermediate_Amplitude_Coefficients(IMRPhenomXHMAmpCoefficients *pAmp, int IntAmpFlag);
+
+//Check if the polynomials cross zero and lower the order if needed in an iterative way
+static void ChoosePolOrder(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMAmpCoefficients *pAmp);
+
+
+/************** PHASE ******************/
+
+//Fits of the collocation points across paramter space
+static double IMRPhenomXHM_Inter_Phase_21_p1(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_21_p2(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_21_p3(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_21_p4(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_21_p5(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_21_p6(double eta, double S, double chi1, double chi2, int);
+
+
+static double IMRPhenomXHM_Inter_Phase_33_p1(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_33_p2(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_33_p3(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_33_p4(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_33_p5(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_33_p6(double eta, double S, double chi1, double chi2, int);
+
+static double IMRPhenomXHM_Inter_Phase_32_p1(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_32_p2(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_32_p3(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_32_p4(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_32_p5(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_32_p6(double eta, double S, double chi1, double chi2, int);
+
+
+static double IMRPhenomXHM_Inter_Phase_44_p1(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_44_p2(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_44_p3(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_44_p4(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_44_p5(double eta, double S, double chi1, double chi2, int);
+static double IMRPhenomXHM_Inter_Phase_44_p6(double eta, double S, double chi1, double chi2, int);
+
+//Ansatz
+static double IMRPhenomXHM_Inter_Phase_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase);
+static inline double IMRPhenomXHM_Inter_Phase_dAnsatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase);
+static double IMRPhenomXHM_Inter_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXHMPhaseCoefficients *pPhase);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* LALSimIMPhenomXHM_Intermediate_h */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_internals.c b/lalsimulation/lib/LALSimIMRPhenomXHM_internals.c
new file mode 100644
index 0000000000000000000000000000000000000000..92dea48101eb895c4cfc919b01271c3473754401
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_internals.c
@@ -0,0 +1,2310 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+//
+//  LALSimIMRPhenomXHM_internals.c
+//
+//  Created by Marta on 06/02/2019.
+//
+
+#include "LALSimIMRPhenomXHM_structs.h"
+
+#include "LALSimIMRPhenomXHM_qnm.h"
+#include "LALSimIMRPhenomXHM_qnm.c"
+
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+#include "LALSimIMRPhenomXHM_ringdown.c"
+#include "LALSimIMRPhenomXHM_intermediate.c"
+#include "LALSimIMRPhenomXHM_inspiral.c"
+
+
+/*Equations referenced in this file come from arXiv:2001.10914 [gr-qc], see also dcc:LIGO-P2000011 */
+
+/* Intialize Quasi Normal Modes' ringdown and damping frequencies */
+void IMRPhenomXHM_Initialize_QNMs(QNMFits *qnms){
+
+  // pointers to fring fits
+  qnms->fring_lm[0]=evaluate_QNMfit_fring21;
+  qnms->fring_lm[1]=evaluate_QNMfit_fring33;
+  qnms->fring_lm[2]=evaluate_QNMfit_fring32;
+  qnms->fring_lm[3]=evaluate_QNMfit_fring44;
+
+  //pointers to fdamp fits
+  qnms->fdamp_lm[0]=evaluate_QNMfit_fdamp21;
+  qnms->fdamp_lm[1]=evaluate_QNMfit_fdamp33;
+  qnms->fdamp_lm[2]=evaluate_QNMfit_fdamp32;
+  qnms->fdamp_lm[3]=evaluate_QNMfit_fdamp44;
+}
+
+/* Initialize Mixing Coefficients (complex). We assume mixing with just one mode. Only 32 mode has mixing. */
+void IMRPhenomXHM_Initialize_MixingCoeffs(IMRPhenomXHMWaveformStruct *wf, IMRPhenomXWaveformStruct *wf22)
+{
+  wf->mixingCoeffs[0]=evaluate_QNMfit_re_l2m2lp2(wf22->afinal)+I*evaluate_QNMfit_im_l2m2lp2(wf22->afinal);
+  wf->mixingCoeffs[1]=evaluate_QNMfit_re_l2m2lp3(wf22->afinal)+I*evaluate_QNMfit_im_l2m2lp3(wf22->afinal);
+  wf->mixingCoeffs[2]=evaluate_QNMfit_re_l3m2lp2(wf22->afinal)+I*evaluate_QNMfit_im_l3m2lp2(wf22->afinal);
+  wf->mixingCoeffs[3]=evaluate_QNMfit_re_l3m2lp3(wf22->afinal)+I*evaluate_QNMfit_im_l3m2lp3(wf22->afinal);
+
+  // Adjust conventions so that they match the ones used for the hybrids
+  wf->mixingCoeffs[2]=-1.* wf->mixingCoeffs[2];
+  wf->mixingCoeffs[3]=-1.* wf->mixingCoeffs[3];
+
+  #if DEBUG == 1
+  printf("\nMixing coefficients:\n");
+  printf("re(a222)=%f,im(a222)=%f \n",evaluate_QNMfit_re_l2m2lp2(wf22->afinal),evaluate_QNMfit_im_l2m2lp2(wf22->afinal));
+  printf("re(a223)=%f,im(a223)=%f \n",evaluate_QNMfit_re_l2m2lp3(wf22->afinal),evaluate_QNMfit_im_l2m2lp3(wf22->afinal));
+  printf("re(a322)=%f,im(a322)=%f \n",evaluate_QNMfit_re_l3m2lp2(wf22->afinal),evaluate_QNMfit_im_l3m2lp2(wf22->afinal));
+  printf("re(a323)=%f,im(a323)=%f \n",evaluate_QNMfit_re_l3m2lp3(wf22->afinal),evaluate_QNMfit_im_l3m2lp3(wf22->afinal));
+  #endif
+}
+
+/* Store useful parameters specific of higher modes (thus not in IMRPhenomXWaveformStruct) in IMRPhenomXHMWaveformStruct */
+/* E.g.: MECO, ringdown and damping frequencies, the version of the fits, etc. */
+void IMRPhenomXHM_SetHMWaveformVariables(
+  int ell,
+  int emm,
+  IMRPhenomXHMWaveformStruct *wf,
+  IMRPhenomXWaveformStruct *wf22,
+  QNMFits *qnms,
+  LALDict *LALParams
+)
+{
+
+  // read in which mode is being generated
+  wf->ell=ell;
+  wf->emm=emm;
+  wf->modeTag=ell*10+emm;      //21, 33, 32, 44
+  wf->ampNorm = wf22->ampNorm;
+  wf->fMECOlm = wf22->fMECO*emm*0.5;
+  wf->Ampzero = 0;                       // Ampzero = 1 (true) for odd modes and equal black holes
+  wf->Amp0 = wf22->ampNorm * wf22->amp0;
+  wf->useFAmpPN = 0;                     // Only true for the 21, this mode has a different inspiral ansatz
+  if(wf22->eta < 0.013886133703630232 && wf22->chi1L<=0.9){ // For q>70 and chi1<0.9 use two intermediate regions.
+    wf->AmpEMR = 1;                                         // These cases have a more pronounced drop off in the amplitude at the end of the inspiral and need two intermediate regions to model it.
+  }
+  else{
+    wf->AmpEMR = 0;
+  }
+  switch(wf->modeTag){
+    case 21:{
+      wf->modeInt=0;
+      wf->MixingOn=0;
+      if(wf22->q < 8.){
+        wf->InspiralAmpVeto=1;
+        wf->IntermediateAmpVeto=1;
+      }else{
+        wf->InspiralAmpVeto=0;
+        wf->IntermediateAmpVeto=0;
+      }
+      wf->RingdownAmpVeto=1;
+      if(wf22->q == 1. && wf22->chi1L == wf22->chi2L){  // Odd mode for equal mass, equal spin is zero
+        wf->Ampzero = 1;
+      }
+      if(wf22->eta >= 0.0237954){ //for EMR (q>40.)
+        wf->useFAmpPN = 1;
+      }
+      break;
+    }
+    case 33:{
+      wf->modeInt=1;
+      wf->MixingOn=0;
+      wf->InspiralAmpVeto=0;
+      wf->IntermediateAmpVeto=0;
+      wf->RingdownAmpVeto=0;
+      if(wf22->q == 1. && wf22->chi1L == wf22->chi2L){  // Odd mode for equal mass, equal spin is zero
+        wf->Ampzero = 1;
+      }
+      break;
+    }
+    case 32:{            //Mode with Mixing
+      wf->modeInt=2;
+      wf->MixingOn=1;
+      wf->InspiralAmpVeto=0;
+      wf->IntermediateAmpVeto=0;
+      wf->RingdownAmpVeto=1;
+      break;
+    }
+    case 44:{
+      wf->modeInt=3;
+      wf->MixingOn=0;
+      wf->InspiralAmpVeto=0;
+      wf->IntermediateAmpVeto=0;
+      wf->RingdownAmpVeto=0;
+      break;
+    }
+    default:
+      {XLALPrintError("Error in IMRPhenomXHM_SetHMWaveformVariables: mode selected is not currently available. Modes available are ((2,|2|),(2,|1|),(3,|2|),(3,|3|),(4,|4|)).\n");}
+  }
+
+    /* Here we select the version of the fits and of the reconstruction that will be used in the code.
+       Through XLALSimInspiralWaveformParamsLookupPhenomXHM(Inspiral/Intermediate/Ringdown)(Amp/Phase)Version we call the version of the fits used by the phase in each region.
+       Currently there is only one version available and is tagged by the release date in the format mmyyyy (122019)*/
+  wf->IMRPhenomXHMInspiralPhaseVersion       = XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralPhaseVersion(LALParams);//122019
+  wf->IMRPhenomXHMIntermediatePhaseVersion   = XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediatePhaseVersion(LALParams); //122019
+  wf->IMRPhenomXHMRingdownPhaseVersion       = XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownPhaseVersion(LALParams); //122019
+  wf->IMRPhenomXHMInspiralAmpFitsVersion     = XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralAmpFitsVersion(LALParams); //122018
+  wf->IMRPhenomXHMIntermediateAmpFitsVersion = XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediateAmpFitsVersion(LALParams); //122018
+  wf->IMRPhenomXHMRingdownAmpFitsVersion     = XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownAmpFitsVersion(LALParams); //122018
+  /* Reconstruction version for the amplitude */
+  wf->IMRPhenomXHMInspiralAmpVersion         = XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralAmpVersion(LALParams); //3  (3 collocation points)
+  wf->IMRPhenomXHMIntermediateAmpVersion     = XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediateAmpVersion(LALParams); //2   (2 collocation points)
+  wf->IMRPhenomXHMRingdownAmpVersion         = XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownAmpVersion(LALParams); //0  (0 collocation points)
+
+
+  // Default collocation points for amplitude
+  wf->nCollocPtsInspAmp  = wf->IMRPhenomXHMInspiralAmpVersion;
+  wf->nCollocPtsInterAmp = wf->IMRPhenomXHMIntermediateAmpVersion;
+
+  if(wf->modeTag==32){ wf->nCollocPtsInterPhase=6;}
+  else {wf->nCollocPtsInterPhase=5;}
+
+  /* Phase : Ringdown */
+  wf->nCollocPtsRDPhase= 0;
+  if(wf->modeTag==32) {wf->nCollocPtsRDPhase=N_MAX_COEFFICIENTS_PHASE_RING;}
+
+  /* Limit between comparable and extreme mass ratios for the phase */
+  wf->etaEMR=0.05;
+
+  /* Spin parameterisations: add here spin pars used for the higher modes that are not included in the 22 struct */
+  wf->chi_s = (wf22->chi1L + wf22->chi2L)*0.5;
+  wf->chi_a = (wf22->chi1L - wf22->chi2L)*0.5;
+
+  /* Ringdown and damping frequencies*/
+  wf->fRING = (qnms->fring_lm[wf->modeInt](wf22->afinal))/wf22->Mfinal;
+  wf->fDAMP = (qnms->fdamp_lm[wf->modeInt](wf22->afinal))/wf22->Mfinal;
+
+  /* If (l,m)=(3,2), load the mixing coeffs to transform the spheroidal-harmonic ringdown ansatz back to spherical-harmonic */
+  if(wf->modeTag==32)
+  {
+    IMRPhenomXHM_Initialize_MixingCoeffs(wf,wf22);
+  }
+
+  /* Linear part of the 22 phase. timeshift * ff + phaseshift. */
+  wf->timeshift =0;//XLALSimIMRPhenomXLinb(wf22->eta, wf22->chiPNHat, wf22->dchi, wf22->delta);
+  wf->phaseshift=0;//XLALSimIMRPhenomXLina(wf22->eta, wf22->chiPNHat, wf22->dchi, wf22->delta);
+  // current time-alignment of the hybrids
+  REAL8 psi4tostrain=XLALSimIMRPhenomXPsi4ToStrain(wf22->eta, wf22->STotR, wf22->dchi);
+  wf->DeltaT= -2.*LAL_PI*(500+psi4tostrain);
+
+}
+
+/* Store function names containing phase coefficient/collocation point fits in pPhase->[Inspiral|Intermediate|Ringdown]PhaseFits */
+void IMRPhenomXHM_FillPhaseFitsArray(IMRPhenomXHMPhaseCoefficients *pPhase){
+
+  /* Here we fill some vectors of functions. Each function is the fit for one collocation point/coefficient.
+  There are three vectors, one for each region: inspiral, intermediate and ringdown.
+  The explicit fits can be found in the files of the corresponding region: IMRPhenomXHM_inspiral.c, _intermediate.c, _ringdown.c
+  */
+
+  //21
+  pPhase->InspiralPhaseFits[0]=IMRPhenomXHM_Insp_Phase_21_lambda;
+  pPhase->InspiralPhaseFits[1]=IMRPhenomXHM_Insp_Phase_33_lambda;
+  pPhase->InspiralPhaseFits[2]=IMRPhenomXHM_Insp_Phase_32_lambda;
+  pPhase->InspiralPhaseFits[3]=IMRPhenomXHM_Insp_Phase_44_lambda;
+
+  //21
+  pPhase->IntermediatePhaseFits[0]=IMRPhenomXHM_Inter_Phase_21_p1;
+  pPhase->IntermediatePhaseFits[1]=IMRPhenomXHM_Inter_Phase_21_p2;
+  pPhase->IntermediatePhaseFits[2]=IMRPhenomXHM_Inter_Phase_21_p3;
+  pPhase->IntermediatePhaseFits[3]=IMRPhenomXHM_Inter_Phase_21_p4;
+  pPhase->IntermediatePhaseFits[4]=IMRPhenomXHM_Inter_Phase_21_p5;
+  pPhase->IntermediatePhaseFits[5]=IMRPhenomXHM_Inter_Phase_21_p6;
+
+  //33
+  pPhase->IntermediatePhaseFits[6]=IMRPhenomXHM_Inter_Phase_33_p1;
+  pPhase->IntermediatePhaseFits[7]=IMRPhenomXHM_Inter_Phase_33_p2;
+  pPhase->IntermediatePhaseFits[8]=IMRPhenomXHM_Inter_Phase_33_p3;
+  pPhase->IntermediatePhaseFits[9]=IMRPhenomXHM_Inter_Phase_33_p4;
+  pPhase->IntermediatePhaseFits[10]=IMRPhenomXHM_Inter_Phase_33_p5;
+  pPhase->IntermediatePhaseFits[11]=IMRPhenomXHM_Inter_Phase_33_p6;
+
+  //32
+  pPhase->IntermediatePhaseFits[12]=IMRPhenomXHM_Inter_Phase_32_p1;
+  pPhase->IntermediatePhaseFits[13]=IMRPhenomXHM_Inter_Phase_32_p2;
+  pPhase->IntermediatePhaseFits[14]=IMRPhenomXHM_Inter_Phase_32_p3;
+  pPhase->IntermediatePhaseFits[15]=IMRPhenomXHM_Inter_Phase_32_p4;
+  pPhase->IntermediatePhaseFits[16]=IMRPhenomXHM_Inter_Phase_32_p5;
+  pPhase->IntermediatePhaseFits[17]=IMRPhenomXHM_Inter_Phase_32_p6;
+
+  //44
+  pPhase->IntermediatePhaseFits[18]=IMRPhenomXHM_Inter_Phase_44_p1;
+  pPhase->IntermediatePhaseFits[19]=IMRPhenomXHM_Inter_Phase_44_p2;
+  pPhase->IntermediatePhaseFits[20]=IMRPhenomXHM_Inter_Phase_44_p3;
+  pPhase->IntermediatePhaseFits[21]=IMRPhenomXHM_Inter_Phase_44_p4;
+  pPhase->IntermediatePhaseFits[22]=IMRPhenomXHM_Inter_Phase_44_p5;
+  pPhase->IntermediatePhaseFits[23]=IMRPhenomXHM_Inter_Phase_44_p6;
+
+  //32 Spheroidal
+  pPhase->RingdownPhaseFits[0]=IMRPhenomXHM_Ringdown_Phase_32_p1;
+  pPhase->RingdownPhaseFits[1]=IMRPhenomXHM_Ringdown_Phase_32_p2;
+  pPhase->RingdownPhaseFits[2]=IMRPhenomXHM_Ringdown_Phase_32_p3;
+  pPhase->RingdownPhaseFits[3]=IMRPhenomXHM_Ringdown_Phase_32_p4;
+
+
+}
+
+/* Store function names containing amplitude coeff./collocation point fits in pAmp->[Inspiral|Intermediate|Ringdown]AmpFits */
+void IMRPhenomXHM_FillAmpFitsArray(IMRPhenomXHMAmpCoefficients *pAmp){
+
+  /* Here we fill some vectors of functions. Each function is the fit for one collocation point/coefficient.
+  There are three vectors, one for each region: inspiral, intermediate and ringdown.
+  The explicit fits can be found in the files of the corresponding region: IMRPhenomXHM_inspiral.c, _intermediate.c, _ringdown.c
+  */
+
+  //******Inspiral Fits for collocation points******/
+
+  //21                                                      //Frequency of the collocation point
+  pAmp->InspiralAmpFits[0]  = IMRPhenomXHM_Insp_Amp_21_iv1; //fcutInsp
+  pAmp->InspiralAmpFits[1]  = IMRPhenomXHM_Insp_Amp_21_iv2; //fcutInsp*0.75
+  pAmp->InspiralAmpFits[2]  = IMRPhenomXHM_Insp_Amp_21_iv3; //fcutInsp*0.5
+
+  //33
+  pAmp->InspiralAmpFits[3]  = IMRPhenomXHM_Insp_Amp_33_iv1; //fcutInsp
+  pAmp->InspiralAmpFits[4]  = IMRPhenomXHM_Insp_Amp_33_iv2; //fcutInsp*0.75
+  pAmp->InspiralAmpFits[5]  = IMRPhenomXHM_Insp_Amp_33_iv3; //fcutInsp*0.5
+
+  //32
+  pAmp->InspiralAmpFits[6]  = IMRPhenomXHM_Insp_Amp_32_iv1; //fcutInsp
+  pAmp->InspiralAmpFits[7]  = IMRPhenomXHM_Insp_Amp_32_iv2; //fcutInsp*0.75
+  pAmp->InspiralAmpFits[8]  = IMRPhenomXHM_Insp_Amp_32_iv3; //fcutInsp*0.5
+
+  //44
+  pAmp->InspiralAmpFits[9]  = IMRPhenomXHM_Insp_Amp_44_iv1; //fcutInsp
+  pAmp->InspiralAmpFits[10] = IMRPhenomXHM_Insp_Amp_44_iv2; //fcutInsp*0.75
+  pAmp->InspiralAmpFits[11] = IMRPhenomXHM_Insp_Amp_44_iv3; //fcutInsp*0.5
+
+
+  /*****Intermediate Fits for EMR collocation points, 2 Intermediate regions*****/
+
+  //21                                                           //Frequency of the collocation point
+  pAmp->IntermediateAmpFits[0] = IMRPhenomXHM_Inter_Amp_21_int1; //fcutInsp + (fcutRD-fcutInsp)/3
+  pAmp->IntermediateAmpFits[1] = IMRPhenomXHM_Inter_Amp_21_int2; //fcutInsp + 2(fcutRD-fcutInsp)/3
+
+  //33
+  pAmp->IntermediateAmpFits[2] = IMRPhenomXHM_Inter_Amp_33_int1; //fcutInsp + (fcutRD-fcutInsp)/3
+  pAmp->IntermediateAmpFits[3] = IMRPhenomXHM_Inter_Amp_33_int2; //fcutInsp + 2(fcutRD-fcutInsp)/3
+
+  //32
+  pAmp->IntermediateAmpFits[4] = IMRPhenomXHM_Inter_Amp_32_int1; //fcutInsp + (fcutRD-fcutInsp)/3
+  pAmp->IntermediateAmpFits[5] = IMRPhenomXHM_Inter_Amp_32_int2; //fcutInsp + 2(fcutRD-fcutInsp)/3
+
+  //44
+  pAmp->IntermediateAmpFits[6] = IMRPhenomXHM_Inter_Amp_44_int1; //fcutInsp + (fcutRD-fcutInsp)/3
+  pAmp->IntermediateAmpFits[7] = IMRPhenomXHM_Inter_Amp_44_int2; //fcutInsp + 2(fcutRD-fcutInsp)/3
+
+  //21                                                           //fInt1 = fcutInsp + (fcutRD-fcutInsp)/3
+  pAmp->IntermediateAmpFits[8] = IMRPhenomXHM_Inter_Amp_21_int0; //fcutInsp + (fInt1 - fcutInsp)/3
+  pAmp->IntermediateAmpFits[9] = IMRPhenomXHM_Inter_Amp_21_dint0;//fcutInsp + (fInt1 - fcutInsp)/3
+
+  //33
+  pAmp->IntermediateAmpFits[10] = IMRPhenomXHM_Inter_Amp_33_int0; //fcutInsp + (fInt1 - fcutInsp)/3
+  pAmp->IntermediateAmpFits[11] = IMRPhenomXHM_Inter_Amp_33_dint0;//fcutInsp + (fInt1 - fcutInsp)/3
+
+  //32
+  pAmp->IntermediateAmpFits[12] = IMRPhenomXHM_Inter_Amp_32_int0; //fcutInsp + (fInt1 - fcutInsp)/3
+  pAmp->IntermediateAmpFits[13] = IMRPhenomXHM_Inter_Amp_32_dint0;//fcutInsp + (fInt1 - fcutInsp)/3
+
+  //44
+  pAmp->IntermediateAmpFits[14] = IMRPhenomXHM_Inter_Amp_44_int0; //fcutInsp + (fInt1 - fcutInsp)/3
+  pAmp->IntermediateAmpFits[15] = IMRPhenomXHM_Inter_Amp_44_dint0;//fcutInsp + (fInt1 - fcutInsp)/3
+
+
+  /****Ringdown Fits for coefficients*****/
+
+  //21
+  pAmp->RingdownAmpFits[0]  = IMRPhenomXHM_RD_Amp_21_alambda;
+  pAmp->RingdownAmpFits[1]  = IMRPhenomXHM_RD_Amp_21_lambda;
+  pAmp->RingdownAmpFits[2]  = IMRPhenomXHM_RD_Amp_21_sigma;
+
+  //33
+  pAmp->RingdownAmpFits[3]  = IMRPhenomXHM_RD_Amp_33_alambda;
+  pAmp->RingdownAmpFits[4]  = IMRPhenomXHM_RD_Amp_33_lambda;
+  pAmp->RingdownAmpFits[5]  = IMRPhenomXHM_RD_Amp_33_sigma; //currently constant
+
+  //32
+  pAmp->RingdownAmpFits[6]  = IMRPhenomXHM_RD_Amp_32_alambda;
+  pAmp->RingdownAmpFits[7]  = IMRPhenomXHM_RD_Amp_32_lambda;
+  pAmp->RingdownAmpFits[8]  = IMRPhenomXHM_RD_Amp_32_sigma; //currently constant
+
+  //44
+  pAmp->RingdownAmpFits[9]  = IMRPhenomXHM_RD_Amp_44_alambda;
+  pAmp->RingdownAmpFits[10] = IMRPhenomXHM_RD_Amp_44_lambda;
+  pAmp->RingdownAmpFits[11] = IMRPhenomXHM_RD_Amp_44_sigma; //currently constant
+
+
+}
+
+
+/***************************************************/
+/*                                                 */
+/*         Amplitude Cutting Frequencies           */
+/*                                                 */
+/***************************************************/
+
+/* Inspiral cutting frequency for the Amplitude */
+double IMRPhenomXHM_Amplitude_fcutInsp(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+  //Return the end frequency of the inspiral region and the beginning of the intermediate for the amplitude of one mode.
+
+  int  version  = pWFHM->IMRPhenomXHMInspiralAmpFitsVersion;
+  double emm    = 1.*(pWFHM->emm);
+  double fring  = pWFHM->fRING;
+  double eta    = pWF22->eta;
+  double chi1   = pWF22->chi1L;
+  double chieff = pWF22->chiEff;
+  double fMECO  = pWFHM->fMECOlm;
+  double fISCO  = (pWF22->fISCO)*emm*0.5;
+  double fcut = 0.;   //Cutting frequency for comparable mass ratios
+  //fcutEMR is the cutting frequency for extreme mass ratios that is given by a fit to the frequncy of a particular geometrical structure of the amplitude
+  double fcutEMR = 1.25*emm*((0.011671068725758493 - 0.0000858396080377194*chi1 + 0.000316707064291237*pow(chi1,2))*(0.8447212540381764 + 6.2873167352395125*eta))/(1.2857082764038923 - 0.9977728883419751*chi1);
+
+  switch(version){
+    case 122018: // default version
+    {
+      switch(pWFHM->modeTag)
+      {
+        case 21:{
+          if(eta < 0.023795359904818562){ //for EMR (q>40.)
+            fcut = fcutEMR;
+          }
+          else{                //for comparable q
+            fcut = fMECO + (0.75-0.235*chieff - 5./6.*chieff*chieff)*fabs(fISCO-fMECO);
+          }
+          break;
+        }
+        case 33:{
+          if(eta < 0.04535147392290249){ //for EMR (q>20.)
+            fcut = fcutEMR;
+          }
+          else{                //for comparable q
+            fcut = fMECO + (0.75-0.235*chieff-5./6.*chieff)*fabs(fISCO-fMECO);
+          }
+          break;
+        }
+        case 32:{
+          if(eta < 0.04535147392290249){ //for extreme mass ratios (q>20)
+            fcut = fcutEMR;
+          }
+          else{               //for comparable mass ratios
+            fcut = fMECO + (0.75-0.235*fabs(chieff))*fabs(fISCO-fMECO);
+            fcut = fcut*fring/pWF22->fRING;
+          }
+          break;
+        }
+        case 44:{
+          if(eta <  0.04535147392290249){  //for EMR (q>20)
+            fcut = fcutEMR;
+          }
+          else{                  //for comparable q
+            fcut = fMECO + (0.75-0.235*chieff)*fabs(fISCO-fMECO);
+          }
+          break;
+        }
+      }
+      break;
+    }
+    default: {XLALPrintError("Error in IMRPhenomXHM_Intermediate_CollocPtsFreqs: version is not valid. Version recommended is 122018.");}
+  }
+  return fcut;
+}
+
+/* Ringdown cutting frequency for the amplitude */
+double IMRPhenomXHM_Amplitude_fcutRD(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+  //Returns the end of the intermediate region and the beginning of the ringdown for the amplitude of one mode
+
+  double fring = pWFHM->fRING, fdamp=pWFHM->fDAMP;
+  int  version = pWFHM->IMRPhenomXHMRingdownAmpFitsVersion;
+  double eta   = pWF22->eta;
+  double chi1  = pWF22->chi1L;
+  double fcut = 0.;  //This is the cutting frequency
+
+  switch(version){
+    case 122018: // default version
+    {
+      switch(pWFHM->modeTag)
+      {
+        case 21:{
+          fcut = 0.75*fring;
+          break;
+        }
+        case 33:{
+          fcut = 0.95*fring;
+          break;
+        }
+        case 32:{
+          double fRD22 = pWF22->fRING;
+          double  c = 0.5, r=5.;
+          if(eta < 0.0453515){
+            //for extreme mass ratios (q>20)
+            fcut = (fring*exp(c*r) + fRD22*exp(r*chi1))/(exp(c*r) + exp(r*chi1)) - fdamp;  //This is a smooth step function between fRING (preferred by negative spins) and fRD22 (preferred by positive)
+          }else{
+            //for comparable mass ratios
+            fcut = fRD22;
+          }
+          if(0.02126654064272212<eta && eta<0.12244897959183673 && chi1>0.95) // for 6 < q < 45
+          {
+             fcut = fring - 2.*fdamp;
+          }
+          break;
+        }
+        case 44:{
+          fcut = 0.9*fring;
+          break;
+        }
+      }
+      break;
+    }
+    default: {XLALPrintError("Error in IMRPhenomXHM_Intermediate_CollocPtsFreqs: version is not valid. Version is recommended is 122018.");}
+  }
+  return fcut;
+}
+
+/***************************************************/
+/*                                                 */
+/*  Phase Cutting & Collocation Points Frequencies */
+/*                                                 */
+/***************************************************/
+
+/* GetfcutInsp  */
+double GetfcutInsp(IMRPhenomXWaveformStruct *pWF22, IMRPhenomXHMWaveformStruct *pWFHM){
+  double MECOf=pWF22->fMECO;
+  double eta_factor=1.0+0.001*(0.25/pWF22->eta-1.);
+
+  return (eta_factor*pWFHM->emm*0.5*MECOf);
+}
+
+
+/********************** INTERMEDIATE PHASE COLLOCATION POINTS ******************/
+void IMRPhenomXHM_Intermediate_CollocPtsFreqs(IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+  //The frequencies are stored in the struct pPhase, which is initialized with new values as the code starts to work on each mode.
+
+  double fring = pWFHM->fRING, fdamp=pWFHM->fDAMP;
+  int version  = pWFHM->IMRPhenomXHMIntermediatePhaseVersion;
+
+    switch(version){
+        case 122019: // default version
+        {
+            double fcut= GetfcutInsp(pWF22,pWFHM);
+            pPhase->CollocationPointsFreqsPhaseInter[0]=fcut;
+
+            if(pWFHM->modeTag==32){
+
+
+                double fRD22 = pWF22->fRING, fdamp22 = pWF22->fDAMP;
+                double fEnd= fRD22- 0.5*fdamp22;
+                pPhase->CollocationPointsFreqsPhaseInter[1]=(sqrt(3)*(fcut - fEnd) + 2*(fcut + fEnd))/4.;
+                pPhase->CollocationPointsFreqsPhaseInter[2]=(3*fcut + fEnd)/4.;
+                pPhase->CollocationPointsFreqsPhaseInter[3]=(fcut + fEnd)/2.;
+                // we use first and second derivative at fEnd, so this frequency is duplicated here
+                pPhase->CollocationPointsFreqsPhaseInter[4]= fEnd;
+                pPhase->CollocationPointsFreqsPhaseInter[5]= fEnd;
+                pPhase->fPhaseMatchIM = fEnd;
+                // correct cutting frequency for EMR with negative spins
+                if(pWF22->eta<0.01&&pWF22->chi1L<0) pPhase->fPhaseMatchIM=pPhase->fPhaseMatchIM*(1.2-0.25*pWF22->chi1L);
+
+
+            }
+
+            else{
+
+                pPhase->CollocationPointsFreqsPhaseInter[1]=(sqrt(3)*(fcut - fring) + 2*(fcut + fring))/4.;
+                pPhase->CollocationPointsFreqsPhaseInter[2]=(3*fcut + fring)/4.;
+                pPhase->CollocationPointsFreqsPhaseInter[3]=(fcut + fring)/2.;
+                pPhase->CollocationPointsFreqsPhaseInter[4]=(fcut + 3*fring)/4.;
+                pPhase->CollocationPointsFreqsPhaseInter[5]=(fcut + 7*fring)/8.;
+                pPhase->fPhaseMatchIM = fring-fdamp;
+
+            }
+
+            break;
+        }
+    default: {XLALPrintError("Error in IMRPhenomXHM_Intermediate_CollocPtsFreqs: version is not valid. Version recommended is 122019.");}
+  }
+
+    pPhase->fPhaseMatchIN = pWFHM->fMECOlm;
+}
+
+/********************** RINGDOWN PHASE COLLOCATION POINTS ******************/
+
+// this function initializes the frequencies of the collocation points for the spheroidal ringdown reconstruction
+void IMRPhenomXHM_Ringdown_CollocPtsFreqs(IMRPhenomXHMPhaseCoefficients *pPhase,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+  //The frequencies are stored in the struct pPhase, which is initialized with new values as the code starts to work on each mode.
+
+  double fringlm = pWFHM->fRING, fdamplm = pWFHM->fDAMP;
+  double fring22 = pWF22->fRING;
+
+  pPhase->CollocationPointsFreqsPhaseRD[0] = fring22;
+  pPhase->CollocationPointsFreqsPhaseRD[2] = fringlm - 0.5*fdamplm;
+  pPhase->CollocationPointsFreqsPhaseRD[1] = fringlm - 1.5*fdamplm;
+  pPhase->CollocationPointsFreqsPhaseRD[3] = fringlm + 0.5*fdamplm;
+}
+
+
+/*******************************************/
+/*                                         */
+/*       COMPUTE AMPLITUDE COEFFICIENTS    */
+/*                                         */
+/*******************************************/
+
+/*** Post-Newtonian Inspiral Ansatz Coefficients ***/
+void IMRPhenomXHM_GetPNAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXWaveformStruct *pWF22){
+
+  /* Fill pAmp with the coefficients of the power series in frequency of the Forier Domain Post-Newtonian Inspiral Ansatz.
+  The 21 mode by default does not used the power series because it breaks down before the end of the inspiral, but it corresponding power series is available here. */
+
+  /* The ansatz in Fourier Domain is built as follows: we multiply the Time-domain Post-Newtonian series up to 3PN by the phasing factor given by the Stationary-Phase-Approximation,
+  and the we reexpand in powers of f up to 3PN.
+  The only difference with the 21 is that this does not perform the last reexpansion, so it is not a real power series but it is a quantity better behaved. */
+
+  /* The coefficients below correspond to those in eqs E10-E14 in arXiv:2001.10914 */
+
+  int inspversion = pWFHM->IMRPhenomXHMInspiralAmpFitsVersion;
+  double chiA = pWFHM->chi_a;
+  double chiS = pWFHM->chi_s;
+  double eta  = pWF22->eta, delta = pWF22->delta;
+  double PI   = powers_of_lalpiHM.itself;
+
+  const double prefactors[] = {sqrt(2)/3., 0.75*sqrt(5/7.), sqrt(5/7.)/3., 4*sqrt(2)/9*sqrt(5/7.)};
+  pAmp->PNglobalfactor = pow(2./(pWFHM->emm),-7/6.)*prefactors[pWFHM->modeInt]; //This is to compensate that we rescale data with the leading order of the 22
+
+  switch(inspversion){
+    case 122018: // default version
+    {
+      switch(pWFHM->modeTag)
+      {
+        case 21:{
+          if(pWFHM->useFAmpPN == 1){
+            Get21PNAmplitudeCoefficients(pAmp, pWF22);
+            pAmp->pnInitial = 0.;
+            pAmp->pnOneThird = 0.;
+            pAmp->pnTwoThirds = 0.;
+            pAmp->pnThreeThirds = 0.;
+            pAmp->pnFourThirds = 0.;
+            pAmp->pnFiveThirds = 0.;
+            pAmp->pnSixThirds = 0.;
+          }
+          else{
+            IMRPhenomX_UsefulPowers powers_of_2d1;
+            IMRPhenomX_Initialize_Powers(&powers_of_2d1, 2.);
+            pAmp->pnInitial = 0.;
+            pAmp->pnOneThird = delta*powers_of_lalpiHM.one_third*powers_of_2d1.one_third;
+            pAmp->pnTwoThirds = (-3*(chiA + chiS*delta))/2.*powers_of_lalpiHM.two_thirds*powers_of_2d1.two_thirds;
+            pAmp->pnThreeThirds = (335*delta + 1404*delta*eta)/672.*powers_of_lalpiHM.itself*powers_of_2d1.itself;
+            pAmp->pnFourThirds = (3427*chiA - (I*672)*delta + 3427*chiS*delta - 8404*chiA*eta - 3860*chiS*delta*eta - 1344*delta*PI - (I*672)*delta*log(16))/1344.*powers_of_lalpiHM.four_thirds*powers_of_2d1.four_thirds;
+            pAmp->pnFiveThirds = (-155965824*chiA*chiS - 964357*delta + 432843264*chiA*chiS*eta - 23670792*delta*eta + 24385536*chiA*PI + 24385536*chiS*delta*PI - 77982912*delta*chiA*chiA + 81285120*delta*eta*chiA*chiA - 77982912*delta*chiS*chiS + 39626496*delta*eta*chiS*chiS + 21535920*delta*eta*eta)/8.128512e6*powers_of_lalpiHM.five_thirds*powers_of_2d1.five_thirds;
+            pAmp->pnSixThirds = (143063173*chiA - (I*1350720)*delta + 143063173*chiS*delta - 546199608*chiA*eta - (I*72043776)*delta*eta - 169191096*chiS*delta*eta - 9898560*delta*PI + 20176128*delta*eta*PI - (I*5402880)*delta*log(2) - (I*17224704)*delta*eta*log(2) + 61725888*chiS*delta*chiA*chiA - 81285120*chiS*delta*eta*chiA*chiA + 20575296*pow(chiA,3) - 81285120*eta*pow(chiA,3) + 61725888*chiA*chiS*chiS - 165618432*chiA*eta*chiS*chiS + 20575296*delta*pow(chiS,3) - 1016064*delta*eta*chiS*chiS*chiS + 128873808*chiA*eta*eta - 3859632*chiS*delta*eta*eta)/5.419008e6*powers_of_lalpiHM.two*powers_of_2d1.two;
+          }
+          break;
+        }
+        case 33:{
+          IMRPhenomX_UsefulPowers powers_of_2d3;
+          IMRPhenomX_Initialize_Powers(&powers_of_2d3, 2./3.);
+          pAmp->pnInitial = 0.;
+          pAmp->pnOneThird = delta*powers_of_lalpiHM.one_third*powers_of_2d3.one_third;
+          pAmp->pnTwoThirds = 0.;
+          pAmp->pnThreeThirds = (-1945*delta + 2268*delta*eta)/672.*powers_of_lalpiHM.itself*powers_of_2d3.itself;
+          pAmp->pnFourThirds = (325*chiA - (I*504)*delta + 325*chiS*delta - 1120*chiA*eta - 80*chiS*delta*eta + 120*delta*PI + (I*720)*delta*log(1.5))/120.*powers_of_lalpiHM.four_thirds*powers_of_2d3.four_thirds;
+          pAmp->pnFiveThirds = (-2263282560*chiA*chiS - 1077664867*delta + 9053130240*chiA*chiS*eta - 5926068792*delta*eta - 1131641280*delta*chiA*chiA + 4470681600*delta*eta*chiA*chiA - 1131641280*delta*chiS*chiS + 55883520*delta*eta*chiS*chiS + 2966264784*delta*eta*eta)/4.4706816e8*powers_of_lalpiHM.five_thirds*powers_of_2d3.five_thirds;
+          pAmp->pnSixThirds = (22007835*chiA + (I*26467560)*delta + 22007835*chiS*delta - 80190540*chiA*eta - (I*98774368)*delta*eta - 31722300*chiS*delta*eta - 9193500*delta*PI + 17826480*delta*eta*PI - (I*37810800)*delta*log(1.5) + (I*37558080)*delta*eta*log(1.5) - 12428640*chiA*eta*eta - 6078240*chiS*delta*eta*eta)/2.17728e6*powers_of_lalpiHM.two*powers_of_2d3.two;
+          break;
+        }
+        case 32:{
+          pAmp->pnInitial = 0.;
+          pAmp->pnOneThird = 0.;
+          pAmp->pnTwoThirds = (-1 + 3*eta)*powers_of_lalpiHM.two_thirds;
+          pAmp->pnThreeThirds = -4*chiS*eta*powers_of_lalpiHM.itself;
+          pAmp->pnFourThirds = (10471 - 61625*eta + 82460*eta*eta)/10080.*powers_of_lalpiHM.four_thirds;
+          pAmp->pnFiveThirds = ((I*2520) - 3955*chiS - 3955*chiA*delta - (I*11088)*eta + 10810*chiS*eta + 11865*chiA*delta*eta - 12600*chiS*eta*eta)/840.*powers_of_lalpiHM.five_thirds;
+          pAmp->pnSixThirds = (824173699 + 2263282560*chiA*chiS*delta - 26069649*eta - 15209631360*chiA*chiS*delta*eta + 3576545280*chiS*eta*PI + 1131641280*chiA*chiA - 7865605440*eta*chiA*chiA + 1131641280*chiS*chiS - 11870591040*eta*chiS*chiS - 13202119896*eta*eta + 13412044800*chiA*chiA*eta*eta + 5830513920*chiS*chiS*eta*eta + 5907445488*pow(eta,3))/4.4706816e8*powers_of_lalpiHM.two;
+          break;
+        }
+        case 44:{
+          IMRPhenomX_UsefulPowers powers_of_2d4;
+          IMRPhenomX_Initialize_Powers(&powers_of_2d4, 0.5);
+          pAmp->pnInitial = 0.;
+          pAmp->pnOneThird = 0.;
+          pAmp->pnTwoThirds = (1 - 3*eta)*powers_of_lalpiHM.two_thirds*powers_of_2d4.two_thirds;
+          pAmp->pnThreeThirds = 0.;
+          pAmp->pnFourThirds = (-158383 + 641105*eta - 446460*eta*eta)/36960.*powers_of_lalpiHM.four_thirds*powers_of_2d4.four_thirds;
+          pAmp->pnFiveThirds = ((I*-1008) + 565*chiS + 565*chiA*delta + (I*3579)*eta - 2075*chiS*eta - 1695*chiA*delta*eta + 240*PI - 720*eta*PI + (I*960)*log(2) - (I*2880)*eta*log(2) + 1140*chiS*eta*eta)/120.*powers_of_lalpiHM.five_thirds*powers_of_2d4.five_thirds;
+          pAmp->pnSixThirds = (7888301437 - 147113366400*chiA*chiS*delta - 745140957231*eta + 441340099200*chiA*chiS*delta*eta - 73556683200*chiA*chiA + 511264353600*eta*chiA*chiA - 73556683200*chiS*chiS + 224302478400*eta*chiS*chiS + 2271682065240*eta*eta - 871782912000*chiA*chiA*eta*eta - 10897286400*chiS*chiS*eta*eta - 805075876080*pow(eta,3))/2.90594304e10*powers_of_lalpiHM.two*powers_of_2d4.two;
+          break;
+        }
+      }
+      break;
+    }
+    default: {XLALPrintError("Error in IMRPhenomXHM_GetPNAmplitudeCoefficients: version is not valid. Version recommended is 122018. ");}
+  }
+}
+
+/*** Post-Newtonian Inspiral Ansatz Coefficients for the 21 mode ***/
+void Get21PNAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXWaveformStruct* pWF22){
+
+  /* The 21 ansatz in Fourier Domain is built multiplying the Time-domain Post-Newtonian series up to 3PN by the phasing factor given by the Stationary-Phase-Approximatio */
+
+  double m1  = pWF22->m1;
+  double m2  = pWF22->m2;
+  double m12 = m1*m1;
+  double m22 = m2*m2;
+  double m13 = m12*m1;
+  double m23 = m22*m2;
+  double m14 = m13*m1;
+  double m24 = m23*m2;
+  double m15 = m14*m1;
+  double m25 = m24*m2;
+  double m16 = m15*m1;
+
+  double chi1   = pWF22->chi1L;
+  double chi2   = pWF22->chi2L;
+  double chiS   = (chi1 + chi2)*0.5;
+  double chiA   = (chi1 - chi2)*0.5;
+  double delta  = pWF22->delta;
+  double eta    = pWF22->eta;
+  double chi12  = chi1*chi1;
+  double chi22  = chi2*chi2;
+  double Sc     = m12*chi1 + m22*chi2;
+  double Sigmac = m2*chi2 - m1*chi1;
+
+  IMRPhenomX_UsefulPowers powers_of_2d1;
+  IMRPhenomX_Initialize_Powers(&powers_of_2d1, 2.);
+  double logof2 = powers_of_2d1.log;
+  double log4   = 1.3862943611198906;
+  double EulerGamma = 0.5772156649015329;
+
+  /* Complex coefficients of the Time-Domain Post-Newtonian expansion. */
+
+  double factor = 8*pWF22->eta*powers_of_lalpiHM.two_thirds*powers_of_2d1.two_thirds*powers_of_lalpiHM.sqrt/sqrt(5.);
+  pAmp->PNTDfactor = factor;
+  pAmp->x05 = I*delta/3*powers_of_2d1.one_third*powers_of_lalpiHM.one_third;
+  pAmp->x1  = -I*0.5*(chiA + chiS*delta)*powers_of_2d1.two_thirds*powers_of_lalpiHM.two_thirds;
+  pAmp->x15 = I*delta*(-17./28 + 5*eta/7.)/3.*powers_of_2d1.itself*powers_of_lalpiHM.itself;
+  pAmp->x2  = ( I*(-43./21*delta*Sc + (-79.+139*eta)/42.*Sigmac) + I/3*delta*(powers_of_lalpiHM.itself + I*(-0.5-2*logof2)))*powers_of_2d1.four_thirds*powers_of_lalpiHM.four_thirds;
+  pAmp->x25 = I*delta*((-43-509*eta)/126. + 79*eta*eta/168.)/3.*powers_of_2d1.five_thirds*powers_of_lalpiHM.five_thirds;
+  pAmp->x3  = I*delta*( (-17. + 6.*eta)/28.*powers_of_lalpiHM.itself + I*(17/56. + eta*(-353/28. - 3.*logof2/7.) + 17.*logof2/14.))/3.*powers_of_2d1.two*powers_of_lalpiHM.two;
+
+
+  /* Coefficients of the phasing factor expansion */
+  /* These coefficients correspond to those in equation E4 of arXiv:2001.10914. */
+  pAmp->xdot5 = -(m1*m2*(-838252800*m1*m2 - 419126400*m12 - 419126400*m22)/3.274425e7)*powers_of_2d1.five_thirds*powers_of_2d1.five_thirds*powers_of_lalpiHM.five_thirds*powers_of_lalpiHM.five_thirds;
+  pAmp->xdot6 = -(m1*m2*(1152597600*m2*m13 + 926818200*m22 + 2494800*m1*m2*(743 + 462*m22) + 1247400*m12*(743 + 1848*m22))/3.274425e7)*powers_of_2d1.four*powers_of_lalpiHM.four;
+  pAmp->xdot65 = -(m1*m2*(-34927200*m1*m2*(-(m2*(75*chi1 + 376*chi2*m2)) + 96*powers_of_lalpiHM.itself) - 34927200*(-(m2*(75*chi2 + 188*(chi1 + chi2)*m2)) + 48*powers_of_lalpiHM.itself)*m12 - 2619540000*chi1*m13 + 13132627200*chi1*m2*m13 +
+  6566313600*chi1*m14 - 34927200*(chi2*(75 - 188*m2)*m2 + 48*powers_of_lalpiHM.itself)*m22)/3.274425e7)*powers_of_2d1.eight_thirds*powers_of_2d1.five_thirds*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.five_thirds;
+  pAmp->xdot7 = -(m1*m2*(207900*m2*(-13661 - 19908*chi1*chi2 + 10206*chi12 + 10206*chi22)*m13 - 23100*(34103 + 91854*chi22)*m22 - 1373803200*m14*m22 +
+  23100*m1*m2*(-2*(34103 + 45927*chi12 + 45927*chi22) + 9*(-13661 - 19908*chi1*chi2 + 10206*chi12 + 10206*chi22)*m22) - 2747606400*m13*m23 -
+  23100*m12*(34103 + 91854*chi12 - 18*(-13661 - 19908*chi1*chi2 + 10206*chi12 + 10206*chi22)*m22 + 59472*m24))/3.274425e7)*powers_of_2d1.seven_thirds*powers_of_2d1.seven_thirds*powers_of_lalpiHM.seven_thirds*powers_of_lalpiHM.seven_thirds;
+  pAmp->xdot75 = -(m1*m2*(-4036586400*chi1*m13 + 5821200*m2*(5861*chi1 + 1701*powers_of_lalpiHM.itself)*m13 + 17059026600*chi1*m14 + 14721814800*chi1*m2*m14 - 34962127200*chi1*m2*m15 +
+  207900*(2*chi2*m2*(-9708 + 41027*m2) + 12477*powers_of_lalpiHM.itself)*m22 - 14721814800*chi2*m13*m22 - 69924254400*chi1*m14*m22 - 34962127200*(chi1 + chi2)*m13*m23 +
+  207900*m12*(3*powers_of_lalpiHM.itself*(4159 + 31752*m22) + 2*m2*(9708*chi2 + 41027*(chi1 + chi2)*m2 - 35406*chi1*m22 - 168168*chi2*m23)) +
+  415800*m1*m2*(9708*chi1*m2 + 82054*chi2*m22 + 3*powers_of_lalpiHM.itself*(4159 + 7938*m22) + 35406*chi2*m23 - 84084*chi2*m24))/3.274425e7)*powers_of_2d1.eight_thirds*powers_of_2d1.seven_thirds*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.seven_thirds;
+  pAmp->xdot8 = -(m1*m2*(- 10548014400*chi1*powers_of_lalpiHM.itself*m13 - 63392868000*chi1*chi2*m2*m14 + 34927200*chi1*(-375*chi1 + 752*powers_of_lalpiHM.itself)*m14 + 63392868000*chi12*m15-
+  153213984000*m2*chi12*m15 - 76606992000*chi12*m16 - 63392868000*chi1*(chi1 - chi2)*m13*m22 -
+  51975*(4869 + 2711352*chi1*chi2 + 1702428*chi12 + 228508*chi22)*m14*m22 - 103950*(4869 + 2711352*chi1*chi2 + 228508*chi12 + 228508*chi22)*m13*m23 +
+  906328500*m15*m23 + 1812657000*m14*m24 + 906328500*m13*m25 +
+  1925*m2*m13*(56198689 + 13635864*chi1*chi2 + 27288576*chi1*powers_of_lalpiHM.itself + 30746952*chi12 + 3617892*chi22 - 2045736*powers_of_lalpiHM.two) -
+  3*m22*(16447322263 - 2277918720*EulerGamma - 23284800*chi2*m2*(-151 + 376*m2)*powers_of_lalpiHM.itself - 2277918720*log4 + 2321480700*chi22 + 4365900000*chi22*m22 -
+  21130956000*chi22*m23 + 25535664000*chi22*m24 + 745113600*powers_of_lalpiHM.two) +
+  m12*(6833756160*EulerGamma + 10548014400*chi2*m2*powers_of_lalpiHM.itself + 63392868000*(chi1 - chi2)*chi2*m23 - 51975*(4869 + 2711352*chi1*chi2 + 228508*chi12 + 1702428*chi22)*m24 -
+  3850*m22*(-56198689 + 13580136*chi1*chi2 - 6822144*(chi1 + chi2)*powers_of_lalpiHM.itself - 6976422*chi12 - 6976422*chi22 + 2045736*powers_of_lalpiHM.two) -
+  3*(16447322263 - 2277918720*log4 + 2321480700*chi12 + 745113600*powers_of_lalpiHM.two)) +
+  m1*m2*(13667512320*EulerGamma + 10548014400*chi1*m2*powers_of_lalpiHM.itself - 63392868000*chi1*chi2*m23 - 153213984000*chi22*m24 -
+    1925*m22*(-56198689 - 13635864*chi1*chi2 - 27288576*chi2*powers_of_lalpiHM.itself - 3617892*chi12 - 30746952*chi22 + 2045736*powers_of_lalpiHM.two) -
+    6*(16447322263 - 2277918720*log4 + 1160740350*chi12 + 1160740350*chi22 + 745113600*powers_of_lalpiHM.two)))/3.274425e7)*powers_of_2d1.eight_thirds*powers_of_2d1.eight_thirds*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.eight_thirds;
+    pAmp->xdot8Log = -(m1*m2*3416878080)/3.274425e7*powers_of_2d1.eight_thirds*powers_of_2d1.eight_thirds*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.eight_thirds;
+    pAmp->xdot85 = -(m1*m2*(-14891068500*chi1*m13 + 1925*m2*(97151928*chi1 + 6613488*chi2 - 12912300*powers_of_lalpiHM.itself)*m13 + 87143248500*chi1*m14 + 33313480200*chi1*m2*m14 - 198816225300*chi1*m2*m15 +
+    57750*(2*chi2*m2*(-128927 + 754487*m2) + 7947*powers_of_lalpiHM.itself)*m22 - 33313480200*chi2*m13*m22 - 138600*(3399633*chi1 + 530712*chi2 + 182990*powers_of_lalpiHM.itself)*m14*m22 -
+    35665037100*chi1*m15*m22 + 84184254000*chi1*m16*m22 -
+    23100*m1*m2*(15*powers_of_lalpiHM.itself*(-2649 + 71735*m22) + m2*(-(chi1*(644635 + 551124*m2)) + chi2*m2*(-8095994 - 1442142*m2 + 8606763*m22))) -
+    69300*(4991769*(chi1 + chi2) + 731960*powers_of_lalpiHM.itself)*m13*m23 + 35665037100*chi2*m14*m23 + 170726094000*chi1*m15*m23 + 2357586000*chi2*m15*m23 +
+    35665037100*chi1*m13*m24 + 88899426000*(chi1 + chi2)*m14*m24 + 9702000*(243*chi1 + 17597*chi2)*m13*m25 -
+    11550*m12*(15*powers_of_lalpiHM.itself*(-2649 + 286940*m22 + 146392*m24) + 2*m2*
+    (-644635*chi2 - 4874683*(chi1 + chi2)*m2 + 1442142*chi1*m22 + 54*(58968*chi1 + 377737*chi2)*m23 + 1543941*chi2*m24 - 3644340*chi2*m25)))/3.274425e7)*powers_of_2d1.eight_thirds*powers_of_2d1.eight_thirds*powers_of_2d1.one_third*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.eight_thirds*powers_of_lalpiHM.one_third;
+
+    pAmp->log2pi_two_thirds = log(powers_of_lalpiHM.two_thirds * powers_of_2d1.two_thirds);
+
+  }
+
+/*** PHENOM AMPLITUDE COEFFICIENTS ***/
+void IMRPhenomXHM_GetAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22) {
+
+    /* Take all the phenom coefficients accross the three regions (inspiral, intermeidate and ringdown) and all the needed parameters to reconstruct the amplitude (including mode-mixing). */
+
+    // Options for the extrapolation of the model outside the calibration region
+    if(((pWFHM->modeTag==44) || (pWFHM->modeTag==33)) && pWF22->q>7. && pWF22->chi1L > 0.95){
+      pAmp->useInspAnsatzRingdown = 1;
+    }
+    else{
+      pAmp->useInspAnsatzRingdown = 0;
+    }
+    pAmp->WavyInsp = 0;
+    pAmp->WavyInt  = 0;
+    if(pWFHM->modeTag==21){
+      pAmp->WavyInsp = 1;
+      pAmp->WavyInt  = 1;
+    }
+    if(pWFHM->modeTag==32){
+      pAmp->WavyInsp = 1;
+    }
+
+    // Take the cutting frequencies at the inspiral and ringdown
+    pAmp->fAmpMatchIN  = IMRPhenomXHM_Amplitude_fcutInsp(pWFHM, pWF22);
+    pAmp->fAmpMatchIM  = IMRPhenomXHM_Amplitude_fcutRD(pWFHM, pWF22);
+
+    #if DEBUG == 1
+    printf("\n\n*** IMRPhenomXHM_GetAmplitudeCoefficients ***\n\n");
+    printf("fring_%i = %.16f\n", pWFHM->modeTag, pWFHM->fRING);
+    printf("fdamp_%i = %.16f\n", pWFHM->modeTag, pWFHM->fDAMP);
+    printf("fcutInsp_%i = %.16f \n", pWFHM->modeTag, pAmp->fAmpMatchIN);
+    printf("fcutRD_%i   = %.16f \n", pWFHM->modeTag, pAmp->fAmpMatchIM);
+    #endif
+
+    /* Compute the frequencies for Intermediate collocation points. */
+    /* It is done now because with the inspiral veto fAmpMatchIN will change, and we need the original here. */
+    double df = pAmp->fAmpMatchIM - pAmp->fAmpMatchIN;
+    pAmp->CollocationPointsFreqsAmplitudeInter[0] =  pAmp->fAmpMatchIN + df/3. ;
+    pAmp->CollocationPointsFreqsAmplitudeInter[1] =  pAmp->fAmpMatchIN + df*2./3.;
+
+    int nCollocPtsInspAmp  = pWFHM->nCollocPtsInspAmp;
+    int nCollocPtsInterAmp = pWFHM->nCollocPtsInterAmp;
+
+    int modeint = pWFHM->modeInt;
+
+    #if DEBUG == 1
+    printf("nCollocPtsInspAmp  = %i \n",nCollocPtsInspAmp);
+    printf("nCollocPtsInterAmp = %i \n",nCollocPtsInterAmp);
+    #endif
+
+
+    /*** Proceed region by region ***/
+
+    /*****************/
+    /*    INSPIRAL   */
+    /*****************/
+    #if DEBUG == 1
+    printf("\n**** INSPIRAL ****\n\n");
+    printf("IMRPhenomXHMInspiralAmpVersion = %i\r\n",pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    #endif
+
+    /* Take Frequency Domain Post-Newtonian Amplitude Coefficients */
+    IMRPhenomXHM_GetPNAmplitudeCoefficients(pAmp, pWFHM, pWF22);
+
+    #if DEBUG == 1
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnInitial),cimag(pAmp->pnInitial));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnOneThird),cimag(pAmp->pnOneThird));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnTwoThirds),cimag(pAmp->pnTwoThirds));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnThreeThirds),cimag(pAmp->pnThreeThirds));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnFourThirds),cimag(pAmp->pnFourThirds));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnFiveThirds),cimag(pAmp->pnFiveThirds));
+    printf("PN coeff %.16f   %.16f\n", creal(pAmp->pnSixThirds),cimag(pAmp->pnSixThirds));
+    #endif
+
+    // Initialize frequencies of colloc points   !!!! ASSUMING YOU HAVE 3 COLLOC POINTS
+    pAmp->CollocationPointsFreqsAmplitudeInsp[0] = 1.0  * pAmp->fAmpMatchIN;
+    pAmp->CollocationPointsFreqsAmplitudeInsp[1] = 0.75 * pAmp->fAmpMatchIN;
+    pAmp->CollocationPointsFreqsAmplitudeInsp[2] = 0.5  * pAmp->fAmpMatchIN;
+
+    double fcutInsp, f1, f2, f3;
+    fcutInsp = pAmp->fAmpMatchIN;                      // Matching frequency between inspiral and intermediate
+    f1 = pAmp->CollocationPointsFreqsAmplitudeInsp[0]; // Frequency of colloc point 1 = 1.*fcutInsp
+    f2 = pAmp->CollocationPointsFreqsAmplitudeInsp[1]; // Frequency of colloc point 2 = 0.75*fcutInsp
+    f3 = pAmp->CollocationPointsFreqsAmplitudeInsp[2]; // Frequency of colloc point 3 = 0.5*fcutInsp
+
+    // Compute the useful powers of fcutInsp, f1, f2, f3. Remembers: f3 < f2 < f1 = fcutInsp.
+    IMRPhenomX_UsefulPowers powers_of_fcutInsp, powers_of_f1, powers_of_f2, powers_of_f3;
+    IMRPhenomX_Initialize_Powers(&powers_of_fcutInsp, fcutInsp);  // fcutInsp and f1 are the same but we keep them separated if in the future we change the frequencies of the collocatio points.
+    IMRPhenomX_Initialize_Powers(&powers_of_f1, f1);
+    IMRPhenomX_Initialize_Powers(&powers_of_f2, f2);
+    IMRPhenomX_Initialize_Powers(&powers_of_f3, f3);
+
+    // Compute the values of Post-Newtoninan ansatz (without the pseudo-PN terms) at the frequencies of the collocation points.
+    double PNf1, PNf2, PNf3;
+    PNf1 = IMRPhenomXHM_Inspiral_PNAmp_Ansatz(&powers_of_f1, pWFHM, pAmp);
+    PNf2 = IMRPhenomXHM_Inspiral_PNAmp_Ansatz(&powers_of_f2, pWFHM, pAmp);
+    PNf3 = IMRPhenomXHM_Inspiral_PNAmp_Ansatz(&powers_of_f3, pWFHM, pAmp);
+
+    pAmp->PNAmplitudeInsp[0] = PNf1;
+    pAmp->PNAmplitudeInsp[1] = PNf2;
+    pAmp->PNAmplitudeInsp[2] = PNf3;
+
+    // Initialize values of collocation points at the previous 3 frequencies. They are taken from the parameter space fits.
+    for(int i = 0; i<nCollocPtsInspAmp; i++)
+    {
+      pAmp->CollocationPointsValuesAmplitudeInsp[i] = fabs(pAmp->InspiralAmpFits[modeint*nCollocPtsInspAmp+i](pWF22->eta,pWF22->chiPNHat,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMInspiralAmpFitsVersion));
+    }
+
+    // Values of the collocation point minus the Post-Newtonian value. This gives a "collocation point" for the pseudo-PN part.
+    // This way is more convenient becuase the reconstuction does not depended on the PN ansatz used.
+    REAL8 iv1, iv2, iv3;
+    iv1 = pAmp->CollocationPointsValuesAmplitudeInsp[0] - PNf1;
+    iv2 = pAmp->CollocationPointsValuesAmplitudeInsp[1] - PNf2;
+    iv3 = pAmp->CollocationPointsValuesAmplitudeInsp[2] - PNf3;
+
+
+    #if DEBUG == 1
+    printf("\nAmplitude pseudo collocation points before veto\n");
+    printf("fAmpMatchIN = %.16f\n",pAmp->fAmpMatchIN);
+    printf("F1   = %.16f\n", f1);
+    printf("F2   = %.16f\n", f2);
+    printf("F3   = %.16f\n\n", f3);
+    printf("I1   = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInsp[0]);
+    printf("I2   = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInsp[1]);
+    printf("I3   = %.16f\n\n", pAmp->CollocationPointsValuesAmplitudeInsp[2]);
+    printf("PNf1 = %.16f\n", PNf1);
+    printf("PNf2 = %.16f\n", PNf2);
+    printf("PNf3 = %.16f\n\n", PNf3);
+    REAL8 piv1, piv2, piv3;
+    piv1 = pAmp->CollocationPointsValuesAmplitudeInsp[0]*pWF22->ampNorm*powers_of_f1.m_seven_sixths;
+    piv2 = pAmp->CollocationPointsValuesAmplitudeInsp[1]*pWF22->ampNorm*powers_of_f2.m_seven_sixths;
+    piv3 = pAmp->CollocationPointsValuesAmplitudeInsp[2]*pWF22->ampNorm*powers_of_f3.m_seven_sixths;
+    printf("p1   = %.16f\n", piv1);
+    printf("p2   = %.16f\n", piv2);
+    printf("p3   = %.16f\n\n", piv3);
+    printf("V1   = %.16f\n", iv1);
+    printf("V2   = %.16f\n", iv2);
+    printf("V3   = %.16f\n\n", iv3);
+    #endif
+
+    /*
+       VETO: Choose the collocations points to use.
+       Outside of the callibration region the collocation points can have a wavy behaviour so we remove some of them.
+    */
+    if(pWFHM->InspiralAmpVeto == 1){
+      IMRPhenomXHM_Inspiral_Amplitude_Veto(&iv1, &iv2, &iv3, &powers_of_f1, &powers_of_f2, &powers_of_f3, pAmp, pWFHM);
+    }
+    #if DEBUG == 1
+    printf("\nInspiral Veto: AmpVersion = %i",pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    #endif
+    /* The 32 mode in this corner of the parameter space always uses the PN only */
+    if(pWFHM->modeTag==32 && pWF22->q>2.5 && pWF22->chi1L<-0.9 && pWF22->chi2L<-0.9) pWFHM->IMRPhenomXHMInspiralAmpVersion = 0;
+    /* The 32 mode in this corner of the parameter space removes the last collocation point */
+    if(pWFHM->modeTag==32 && pWF22->q>2.5 && pWF22->chi1L<-0.6 && pWF22->chi2L>0. && iv1!=0){
+      pWFHM->IMRPhenomXHMInspiralAmpVersion = pWFHM->IMRPhenomXHMInspiralAmpVersion - 1;
+      iv1 = 0.;
+    }
+    /* The 33 mode in this corner of the parameter space removes the last collocation point */
+    if(pWFHM->modeTag==33 && (1.2>pWF22->q && pWF22->q>1. && pWF22->chi1L<-0.1 && pWF22->chi2L>0. && iv1!=0)){//November
+      pWFHM->IMRPhenomXHMInspiralAmpVersion = pWFHM->IMRPhenomXHMInspiralAmpVersion - 1;
+      iv1 = 0.;
+    }
+    #if DEBUG == 1
+    printf("\nInspiral Veto: AmpVersion = %i", pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    #endif
+    //********* Remember that f3 < f2 < f1 !!!!! *****************
+    /* Check for wavy collocation points. Only when we have 3 coll points. */
+    if(pWFHM->IMRPhenomXHMInspiralAmpVersion == 3 && pAmp->WavyInsp == 1){
+        if(WavyPoints(pAmp->CollocationPointsValuesAmplitudeInsp[0]*powers_of_f1.m_seven_sixths,pAmp->CollocationPointsValuesAmplitudeInsp[1]*powers_of_f2.m_seven_sixths,pAmp->CollocationPointsValuesAmplitudeInsp[2]*powers_of_f3.m_seven_sixths)==1){
+           iv2 = 0;
+           #if DEBUG == 1
+           printf("\nWavy Inspiral\n");
+           #endif
+           pWFHM->IMRPhenomXHMInspiralAmpVersion = pWFHM->IMRPhenomXHMInspiralAmpVersion - 1;
+         }
+    }
+    #if DEBUG == 1
+    printf("\nInspiral Veto: AmpVersion = %i",pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    printf("\niv1 iv2 iv3 %e %e %e\n", iv1, iv2, iv3);
+    #endif
+    // Rename collocation points and frequencies.
+    if(iv2==0){
+      #if DEBUG == 1
+          printf("\niv2 = 0\n");
+      #endif
+        iv2 = iv3;
+        iv3 = 0.;
+        powers_of_f2 = powers_of_f3;
+    }
+    if(iv1==0){
+      #if DEBUG == 1
+          printf("\niv1 = 0\n");
+      #endif
+        iv1 = iv2;
+        powers_of_f1 = powers_of_f2;
+        powers_of_fcutInsp = powers_of_f1;
+        iv2 = iv3;
+        iv3 = 0.;
+        powers_of_f2 = powers_of_f3;
+    }
+    if(pWFHM->IMRPhenomXHMInspiralAmpVersion == 0)  // when using PN we take fcutInsp = fMECO_lm
+    {
+      IMRPhenomX_Initialize_Powers(&powers_of_fcutInsp, (pWFHM->fMECOlm));
+    }
+
+    // Update the Inspiral cutting frequency to the last collocation point alive.
+    pAmp->fAmpMatchIN = powers_of_fcutInsp.itself;
+    // End of VETO
+
+
+    #if DEBUG == 1
+    printf("\nAmplitude pseudo collocation points after veto\n");
+    printf("fAmpMatchIN = %.16f\n", pAmp->fAmpMatchIN);
+    printf("F1   = %.16f\n", powers_of_f1.itself);
+    printf("F2   = %.16f\n", powers_of_f2.itself);
+    printf("F3   = %.16f\n", powers_of_f3.itself);
+    printf("V1   = %.16f\n", iv1);
+    printf("V2   = %.16f\n", iv2);
+    printf("V3   = %.16f\n", iv3);
+    #endif
+
+    /* Get the pseudo-PN coefficients. */
+    /* The whole inspiral ansatz is given by PNAnsatz(f) + pseudo-PN(f),  with pseudo-PN(f) = rho1 *(f/fcutInsp)^(7/3) + rho2(f/fcutInsp)^(8/3) + rho3(f/fcutInsp)^(9/3).
+    The coefficients are computed demanding that the pseudo-PN part at the three collocation points frequencies returns the actual collocation points: iv1, iv2, iv3.   */
+    pAmp->rho1 = IMRPhenomXHM_Inspiral_Amp_rho1(iv1, iv2, iv3, &powers_of_fcutInsp, &powers_of_f1, &powers_of_f2, &powers_of_f3, pWFHM);
+    pAmp->rho2 = IMRPhenomXHM_Inspiral_Amp_rho2(iv1, iv2, iv3, &powers_of_fcutInsp, &powers_of_f1, &powers_of_f2, &powers_of_f3, pWFHM);
+    pAmp->rho3 = IMRPhenomXHM_Inspiral_Amp_rho3(iv1, iv2, iv3, &powers_of_fcutInsp, &powers_of_f1, &powers_of_f2, &powers_of_f3, pWFHM);
+
+    #if DEBUG == 1
+    printf("\nAmplitude pseudo PN coeffcients after veto\n");
+    printf("rho1 = %.16f\n",pAmp->rho1);
+    printf("rho2 = %.16f\n",pAmp->rho2);
+    printf("rho3 = %.16f\n",pAmp->rho3);
+    #endif
+
+    // To avoid passing an extra argument to IMRPhenomXHM_Inspiral_Amp_Ansatz we store this powers in pAmp.
+    pAmp->fcutInsp_seven_thirds = powers_of_fcutInsp.seven_thirds;
+    pAmp->fcutInsp_eight_thirds = powers_of_fcutInsp.eight_thirds;
+    pAmp->fcutInsp_three = powers_of_fcutInsp.three;
+
+
+    /*****************/
+    /*    RINGDOWN   */
+    /*****************/
+    #if DEBUG == 1
+    printf("\n\n**** RINGDOWN ****\n\n");
+    #endif
+
+    // We have three "fitted" coefficients across parameter space: alambda, lambda and sigma. Sigma will be constat for all the modes except the 21.
+    pAmp->alambda = fabs(pAmp->RingdownAmpFits[modeint*3](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownAmpFitsVersion));
+    pAmp->lambda  = pAmp->RingdownAmpFits[modeint*3+1](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownAmpFitsVersion);
+    pAmp->sigma   = pAmp->RingdownAmpFits[modeint*3+2](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownAmpFitsVersion);
+    pAmp->lc      = 1./12.;
+
+    #if DEBUG == 1
+    printf("\nuseInspAnsatzRigndown = %i\n",pAmp->useInspAnsatzRingdown);
+    printf("alambda = %.16f\r\n",pAmp->alambda);
+    #endif
+
+    // For some cases with extreme spins there is almost no merger and the transition to the ringdown is very sharp.
+    // The coefficients of the ringdown do not work well here and we take an approximation of the inspiral.
+    if(pAmp->useInspAnsatzRingdown==1){
+      // The Ringdown amp at fAmpMatchIM is set to be 0.9 the amplitude in the last inspiral collocation point
+      pAmp->alambda = 0.9*fabs(IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_fcutInsp, pWFHM, pAmp)/(IMRPhenomXHM_RD_Amp_Ansatz(pAmp->fAmpMatchIM, pWFHM, pAmp)/pAmp->alambda));
+    }
+
+    #if DEBUG == 1
+    printf("alambda = %.16f\r\n",pAmp->alambda);
+    printf("lambda  = %.16f\r\n",pAmp->lambda);
+    printf("sigma   = %.16f\r\n",pAmp->sigma);
+    printf("lc      = %.16f\r\n",pAmp->lc);
+    #endif
+
+
+    /*******************/
+    /*   INTERMEDIATE  */
+    /*******************/
+    #if DEBUG == 1
+    printf("\n\n**** INTERMEDIATE ****\n\n");
+    #endif
+
+    // Initialize values of collocation points. They are taken from the parameter space fits.
+    for(int i = 0; i<nCollocPtsInterAmp; i++)
+    {
+      pAmp->CollocationPointsValuesAmplitudeInter[i] = fabs(pAmp->IntermediateAmpFits[modeint*nCollocPtsInterAmp+i](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMIntermediateAmpFitsVersion));
+    }
+
+    /* For reconstructing the intermediate region we need value and derivative at the beginning and at the end of the intermediate region, given by the inspiral and ringdown ansatzs.
+    And also the two values at the two intermediate collocation points. This gives 6 parameters, that will determine the 6 coefficients of the inverse of the 5th order polynomial
+    that we use for reconstruction.
+    This is the default behaviour, however the veto conditions can reduce the order of the polynomial.
+    */
+
+    double F1, F2, F3, F4;  //Frequencies of the collocation points in the intermediate region
+    F1     = powers_of_fcutInsp.itself;
+    F2     = pAmp->CollocationPointsFreqsAmplitudeInter[0];
+    F3     = pAmp->CollocationPointsFreqsAmplitudeInter[1];
+    F4     = pAmp->fAmpMatchIM;
+
+    #if DEBUG == 1
+    printf("F1 = %.16f\n",F1);
+    printf("F2 = %.16f\n",F2);
+    printf("F3 = %.16f\n",F3);
+    printf("F4 = %.16f\n\n",F4);
+    #endif
+
+    // Initialize useful powers.
+    IMRPhenomX_UsefulPowers powers_of_F1;
+    IMRPhenomX_Initialize_Powers(&powers_of_F1,F1);
+    IMRPhenomX_UsefulPowers powers_of_F4;
+    IMRPhenomX_Initialize_Powers(&powers_of_F4,F4);
+
+    // Compute values at the boundaries (rescaled ansatz with the leading order of the 22).
+    double inspF1 = IMRPhenomXHM_Inspiral_Amp_Ansatz(&powers_of_F1, pWFHM, pAmp);
+    double rdF4;
+    if (pWFHM->MixingOn == 1){
+      rdF4 = cabs(SpheroidalToSpherical(F4, &powers_of_F4, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22));
+    }else{
+      rdF4 = IMRPhenomXHM_RD_Amp_Ansatz(F4, pWFHM, pAmp);
+    };
+
+    // Compute derivatives at the boundaries (rescaled ansatz with the leading order of the 22).
+    double d1, d4;
+    d1     = IMRPhenomXHM_Inspiral_Amp_NDAnsatz(&powers_of_F1,pWFHM,pAmp);
+    if(pWFHM->MixingOn==1){
+      d4 = IMRPhenomXHM_RD_Amp_NDAnsatz(F4, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF22);
+    }else{
+      d4 = IMRPhenomXHM_RD_Amp_DAnsatz(F4, pWFHM, pAmp);
+    }
+
+    #if DEBUG == 1
+    printf("d1 = %.16f\n",d1);
+    printf("d4 = %.16f\n",d4);
+    #endif
+
+    // Derivatives at the boundaries of the whole ansatz.
+    d1     = ((7.0/6.0) * pow(F1,1.0/6.0) / inspF1) - ( pow(F1,7.0/6.0) * d1 / (inspF1*inspF1) );
+    d4     = ((7.0/6.0) * pow(F4,1.0/6.0) / rdF4)   - ( pow(F4,7.0/6.0) * d4 / (rdF4*rdF4) );
+
+    #if DEBUG == 1
+    printf("d1 = %.16f\n",d1);
+    printf("d4 = %.16f\n\n",d4);
+    #endif
+
+    // These values will feed the reconstruction function of the intermediate for getting the coefficients of the polynomial
+    double V1, V2, V3, V4;
+
+    pWFHM->IMRPhenomXHMIntermediateAmpVersion = 105; // by default use 5th order polynomial
+
+    V1 = powers_of_F1.m_seven_sixths * inspF1;
+    V2 = pAmp->CollocationPointsValuesAmplitudeInter[0];
+    V3 = pAmp->CollocationPointsValuesAmplitudeInter[1];
+    V4 = powers_of_F4.m_seven_sixths * rdF4;
+
+    #if DEBUG == 1
+    printf("Before intermediate veto \n");
+    printf("V1 = %.16f\n",V1);
+    printf("V2 = %.16f\n",V2);
+    printf("V3 = %.16f\n",V3);
+    printf("V4 = %.16f\n",V4);
+    printf("rdF4 = %.16f\n",rdF4);
+    printf("F4.m_seven_sixths = %.16f\n\n",powers_of_F4.m_seven_sixths);
+    #endif
+
+    // VETO: outside of the calibration region some collocation points are bad behaved. We veto them and change the type of reconstruction now.
+
+    if(pAmp->useInspAnsatzRingdown==1){
+      //For these extreme cases we do not use intermediate collocation points -> third order polynomial.
+      V2 = 1.;
+      V3 = 1.;
+      pWFHM->IMRPhenomXHMIntermediateAmpVersion = 101; /*Linear reconstruction*/
+      #if DEBUG == 1
+      printf("VETO: useInspAnsatzRingdown\n");
+      printf("V2 = %.16f\n",V2);
+      printf("V3 = %.16f\n",V3);
+      #endif
+    }
+
+    // The reconstruction function is the inverse of a polynomial. That we demand pass through the points V1, V2, V3, V4 and has the derivatives d1, d4 at the boundaries.
+    // For simplicity we coded the reconstruction of the polynomial (Update_Intermediate_Amplitude_Coefficients), so we have to feed it with inverse values.
+    V1  = 1.0 / V1;
+    V2  = 1.0 / V2;
+    V3  = 1.0 / V3;
+    V4  = 1.0 / V4;
+
+    #if DEBUG == 1
+    printf("\nAfter Veto and inverse \n");
+    printf("V1 = %.16f\n",V1);
+    printf("V2 = %.16f\n",V2);
+    printf("V3 = %.16f\n",V3);
+    printf("V4 = %.16f\n",V4);
+    printf("IMRPhenomXHMIntermediateAmpVersion = %i \n\n", pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+    #endif
+
+
+    /* If the case does not have extreme mass ratio it skips the next block */
+
+
+    /****** JUST EMR cases, 2 INTERMEDIATE REGIONS ******/
+
+    /* For EMR cases the amplitude shows a more pronounced drop off at the end of the inspiral.
+    To model this we split the intermediate region in two.
+    We add an extra collocation point between the end of the inspiral and the first intermediate collocation point, F0.
+    From fcutInsp to FO we use a 4th order polynomial, and from F0 to fcutRD we use the usual 5th that is computed after this block. */
+
+    if(pWFHM->AmpEMR==1){
+      #if DEBUG == 1
+      printf("*** TWO INTERMEDIATE REGIONS ***\n\n");
+      #endif
+
+      // Here we compute the first intermediate region with the inverse of a 4th polynomial.
+      // For this we use point and derivative at fcutInsp and F0 (4 coefficients) and the value at the first collocation point (F2), with the total of 5 coefficients.
+
+      double F0, V0, d0, F0_seven_sixths;  //Frequency, value, derivative and useful power at the extra collocation point for EMR
+
+      F0 = F1 + (F2-F1)/3.;
+      pAmp->fAmpMatchInt12 = F0;
+
+      // Take the value and derivative from the parameter space fits.
+      V0 = pAmp->IntermediateAmpFits[modeint*nCollocPtsInterAmp+8](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMIntermediateAmpFitsVersion);
+      d0 = pAmp->IntermediateAmpFits[modeint*nCollocPtsInterAmp+9](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMIntermediateAmpFitsVersion);
+
+      #if DEBUG == 1
+      printf("F0 = %.16f\n",F0);
+      printf("V0 = %.16f\n",V0);
+      printf("d0 = %.16f\n",d0);
+      #endif
+
+      F0_seven_sixths = pow(F0,7.0/6.0);
+
+      d0 = ((7.0/6.0) / (V0*F0))   - ( d0 / (V0*V0*F0_seven_sixths) );
+      V0 = 1. / V0;
+
+      #if DEBUG == 1
+      printf("1/V0 = %.16f\n",V0);
+      printf("1/d0 = %.16f\n",d0);
+      #endif
+
+      // Get the coefficients of the polynomial for the first intermediate region
+      pAmp->alpha0 = IMRPhenomXHM_Intermediate_Amp_delta0(d1,d0,V1,V2,V3,V0,F1,F2,F3,F0,104); //V3 and F3 will not be used when calling with 104
+      pAmp->alpha1 = IMRPhenomXHM_Intermediate_Amp_delta1(d1,d0,V1,V2,V3,V0,F1,F2,F3,F0,104);
+      pAmp->alpha2 = IMRPhenomXHM_Intermediate_Amp_delta2(d1,d0,V1,V2,V3,V0,F1,F2,F3,F0,104);
+      pAmp->alpha3 = IMRPhenomXHM_Intermediate_Amp_delta3(d1,d0,V1,V2,V3,V0,F1,F2,F3,F0,104);
+      pAmp->alpha4 = IMRPhenomXHM_Intermediate_Amp_delta4(d1,d0,V1,V2,V3,V0,F1,F2,F3,F0,104);
+
+      #if DEBUG == 1
+      printf("Intermediate 1: feed values \n");
+      printf("d1 = %.16f\n", d1);
+      printf("d0 = %.16f\n", d0);
+      printf("d4 = %.16f\n", d4);
+      printf("V1 = %.16f\n", V1);
+      printf("V0 = %.16f\n", V0);
+      printf("V2 = %.16f\n", V2);
+      printf("V3 = %.16f\n", V3);
+      printf("V4 = %.16f\n", V4);
+      printf("F1 = %.16f\n", F1);
+      printf("F0 = %.16f\n", F0);
+      printf("F2 = %.16f\n", F2);
+      printf("F3 = %.16f\n", F3);
+      printf("F4 = %.16f\n", F4);
+      #endif
+
+      #if DEBUG == 1
+      printf("\nIntermediate 1: polynomial coeffcients \r\n");
+      printf("alpha0 = %.16f\n", pAmp->alpha0);
+      printf("alpha1 = %.16f\n", pAmp->alpha1);
+      printf("alpha2 = %.16f\n", pAmp->alpha2);
+      printf("alpha3 = %.16f\n", pAmp->alpha3);
+      printf("alpha4 = %.16f\n", pAmp->alpha4);
+      #endif
+
+      //Update left collocation point for the 2nd intermediate region
+      F1 = F0;
+      V1 = V0;
+      d1 = d0;
+
+      /**** END of first Intermediate region ****/
+    }
+    else{  /** This part is used both when we have a single intermediate region and for the second intermediate region **/
+      pAmp->fAmpMatchInt12 = 0;
+      pAmp->alpha0 = 1;
+      pAmp->alpha1 = 1;
+      pAmp->alpha2 = 1;
+      pAmp->alpha3 = 1;
+      pAmp->alpha4 = 1;
+
+      /** More vetos ***/
+      if(pWFHM->IntermediateAmpVeto == 1 && pWFHM->IMRPhenomXHMIntermediateAmpVersion==105){  // only 21 mode
+        IMRPhenomXHM_Intermediate_Amplitude_Veto(&V2, &V3, pWFHM, pWF22); // this changes the order of the polynomial to 4 or 3
+        #if DEBUG == 1
+        printf("VETO: Intermediate Amp Veto\n");
+        printf("V2 = %.16f\n",V2);
+        printf("V3 = %.16f\n",V3);
+        #endif
+      }
+
+      if(pWFHM->RingdownAmpVeto == 1){    // only 21, 32 mode
+        IMRPhenomXHM_Ringdown_Amplitude_Veto(&V2, &V3, V4, pWFHM, pWF22); // If satisfied, remove the 2 inter collocation points
+        #if DEBUG == 1
+        printf("VETO: Ringdown Amp Veto\n");
+        printf("V2 = %.16f\n",V2);
+        printf("V3 = %.16f\n",V3);
+        #endif
+      }
+
+      if(pWFHM->IMRPhenomXHMIntermediateAmpVersion==105 && pAmp->WavyInt==1){
+        if(WavyPoints(V2,V3,V4)==1){
+          V3 = V2;
+          F3 = F2;
+          V2 = 1.;
+          pWFHM->IMRPhenomXHMIntermediateAmpVersion=1042;
+          #if DEBUG == 1
+          printf("VETO: Wavy Inter colloc points\n");
+          printf("V2 = %.16f\n",V2);
+          printf("V3 = %.16f\n",V3);
+          #endif
+        }
+      }
+
+      if((pWF22->q>40. && pWF22->chi1L>0.9 && V2!=1 && V3!=1) ||
+      (pWFHM->modeTag==32 && (pWFHM->IMRPhenomXHMIntermediateAmpVersion != 101) && ((pWF22->q>2.5 && pWF22->chi1L<-0.6 && pWF22->chi2L>0) || (pWF22->chi1L<-0.9&&pWF22->chi2L<-0.9))) ||
+      (pWFHM->modeTag==21 && pWF22->eta<0.23 && pWF22->chi1L>0.7 && pWF22->chi2L<-0.5)){
+        V2 = 1.;
+        V3 = 1.;
+        pWFHM->IMRPhenomXHMIntermediateAmpVersion = 1032;
+        #if DEBUG == 1
+        printf("VETO: veto regions\n");
+        printf("V2 = %.16f\n",V2);
+        printf("V3 = %.16f\n",V3);
+        #endif
+      }
+      /*** End of vetos **/
+    }
+
+    // The reconstruction function (Update_Intermediate_Amplitude_Coefficients) assumes that F3 is the point with value.
+    // If F3 was removed in the veto the we replace it with F2
+    if(V3 == 1.){
+      V3 = V2;
+      F3 = F2;
+      V2 = 1.;
+    }
+
+    /*
+    Reconstruct the phenomenological coefficients for the intermediate ansatz
+    */
+
+    // Store the values for the reconstruction.
+    pAmp->v1 = V1;
+    pAmp->v2 = V2;
+    pAmp->v3 = V3;
+    pAmp->v4 = V4;
+    pAmp->f1 = F1;
+    pAmp->f2 = F2;
+    pAmp->f3 = F3;
+    pAmp->f4 = F4;
+    pAmp->d1 = d1;
+    pAmp->d4 = d4;
+
+    #if DEBUG == 1
+    printf("\nIntermediate Amplitude Input \r\n");
+    printf("\nIMRPhenomXHMIntermediateAmpVersion = %i \r\n", pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+    printf("V1 = %.16f\n", V1);
+    printf("V2 = %.16f\n", V2);
+    printf("V3 = %.16f\n", V3);
+    printf("V4 = %.16f\n", V4);
+    printf("F1 = %.16f\n", F1);
+    printf("F2 = %.16f\n", F2);
+    printf("F3 = %.16f\n", F3);
+    printf("F4 = %.16f\n", F4);
+    printf("d1 = %.16f\n", d1);
+    printf("d4 = %.16f\n", d4);
+    printf("fAmpMatchIn = %.16f\n", pAmp->fAmpMatchIN);
+    #endif
+
+    // Compute the coefficients of the polynomial
+    Update_Intermediate_Amplitude_Coefficients(pAmp, pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+
+
+    #if DEBUG == 1
+    printf("\nIntermediate polynomial coeffcients Before ChoosePolOrder \r\n");
+    printf("\nIMRPhenomXHMIntermediateAmpVersion = %i \r\n", pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+    printf("delta0 = %.16f\n", pAmp->delta0);
+    printf("delta1 = %.16f\n", pAmp->delta1);
+    printf("delta2 = %.16f\n", pAmp->delta2);
+    printf("delta3 = %.16f\n", pAmp->delta3);
+    printf("delta4 = %.16f\n", pAmp->delta4);
+    printf("delta5 = %.16f\n", pAmp->delta5);
+    printf("fAmpMatchIn = %.16f\n", pAmp->fAmpMatchIN);
+    #endif
+
+    // Check that the polynomial does not cross zero, because the actual reconstructing function is the inverse of this polynomial
+    // If it crosses zero, then remove one collocation and lower the order of the polynomial.
+    ChoosePolOrder(pWFHM, pAmp);
+
+    #if DEBUG == 1
+    printf("\nIMRPhenomXHMIntermediateAmpVersion = %i \r\n", pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+    printf("\nIntermediate polynomial coeffcients After ChoosePolOrder\r\n");
+    printf("delta0 = %.16f\n", pAmp->delta0);
+    printf("delta1 = %.16f\n", pAmp->delta1);
+    printf("delta2 = %.16f\n", pAmp->delta2);
+    printf("delta3 = %.16f\n", pAmp->delta3);
+    printf("delta4 = %.16f\n", pAmp->delta4);
+    printf("delta5 = %.16f\n", pAmp->delta5);
+    printf("fAmpMatchIn = %.16f\n", pAmp->fAmpMatchIN);
+    #endif
+  }
+
+
+/*******************************************/
+/*                                         */
+/*          COMPUTE PHASE COEFFICIENTS     */
+/*                                         */
+/*******************************************/
+
+/*  This function is an expansion in the frequency of the real part of the 21-amplitude, following the convention of Eq.(2.2) in the paper  */
+/*  This function occasionally changes sign, so we need to keep track of this to correct the WF's phase, since the amplitude of IMRPhenomXHM is positive by construction */
+int IMRPhenomXHM_PN21AmpSign (double ff,IMRPhenomXWaveformStruct *wf22){
+
+    double eta,chi1,chi2;
+    eta =wf22->eta;
+    chi1=wf22->chi1L;
+    chi2=wf22->chi2L;
+    double delta=sqrt(1 - 4*eta);
+
+    double output=(-16*delta*eta*ff*pow(LAL_PI,1.5))/(3.*sqrt(5)) + (4*pow(2,0.3333333333333333)*(chi1 - chi2 + delta *(chi1+ chi2))*eta*pow(ff,1.3333333333333333)*pow(LAL_PI,1.8333333333333333))/sqrt(5) + (2*pow(2,0.6666666666666666)*eta*(306*delta - 360*delta*eta)*pow(ff,1.6666666666666667)*pow(LAL_PI,2.1666666666666665))/(189.*sqrt(5));
+
+    if(output>=0) return(1);
+    else return(-1);
+  }
+
+/*  compute phase coefficients */
+void IMRPhenomXHM_GetPhaseCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22, UNUSED LALDict *lalParams) {
+
+    int ell=pWFHM->ell;
+    int emm=pWFHM->emm;
+
+    /* Pre-initialize all phenomenological coefficients */
+
+    //inspiral
+    // these will be computed by rescaling IMRPhenomX inspiral coefficients
+    for(int i=0; i<NMAX_INSPIRAL_COEFFICIENTS; i++)
+    {
+      pPhase->phi[i]=0.;
+      pPhase->phiL[i]=0.;
+    }
+
+    //intermediate
+    // will be determined by solving linear system at collocation points (see Eqs. (5.5)-(5.6) in the paper)
+    pPhase->c0 = 0.0;
+    pPhase->c1 = 0.0;
+    pPhase->c2 = 0.0;
+    pPhase->c3 = 0.0;
+    pPhase->c4 = 0.0;
+    pPhase->cL = 0.0;
+    // ringdown spherical
+    // these will be obtained by rescaling the 22 ringdown parameters (see Eq. (6.5) in the paper)
+    pPhase->alpha0 = 0.0;
+    pPhase->alpha2 = 0.0;
+    pPhase->alphaL = 0.0;
+
+
+    // set number of collocation points used (depends on the mode)
+    int nCollocationPts_inter=pWFHM->nCollocPtsInterPhase;
+    // define mass-ratio that discriminates between EMR and rest of cases
+    double eta_m1=1./pWF22->eta;
+    // store mode tag
+    int modeint=pWFHM->modeInt;
+
+    IMRPhenomX_UsefulPowers powers_of_f;
+
+    //initialize frequencies of colloc points in intermediate region
+    IMRPhenomXHM_Intermediate_CollocPtsFreqs(pPhase,pWFHM,pWF22);
+
+
+    //for each collocation point, call fit giving the value of the phase derivative at that point
+    for(int i = 0; i<N_MAX_COEFFICIENTS_PHASE_INTER; i++)
+    {
+        pPhase->CollocationPointsValuesPhaseInter[i] = pPhase->IntermediatePhaseFits[modeint*N_MAX_COEFFICIENTS_PHASE_INTER+i](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMIntermediatePhaseVersion);
+        // time-shift wf so that modes peak around t=0
+        // our hybrids are built so that their inverse FT peaks ~500 M before the end of the time-interval. Our reconstructed WFs will have the same normalization, so we shift the phase here so that the modes peak around t=0
+        pPhase->CollocationPointsValuesPhaseInter[i]=pPhase->CollocationPointsValuesPhaseInter[i]+pWFHM->DeltaT;
+    }
+
+    double fcutRD=pPhase->fPhaseMatchIM;
+    double fcutInsp=pPhase->fPhaseMatchIN;
+
+
+
+    /************** Inspiral: rescale PhenX and apply PN corrections *********/
+
+
+    //collect all the phenX inspiral coefficients
+    double phenXnonLog[]={pPhase22->phi0,pPhase22->phi1,pPhase22->phi2,pPhase22->phi3,pPhase22->phi4,pPhase22->phi5,pPhase22->phi6,pPhase22->phi7,pPhase22->phi8,pPhase22->phi9,0.,0,0};
+    double phenXLog[]={0.,0.,0.,0.,0.,pPhase22->phi5L,pPhase22->phi6L,0.,pPhase22->phi8L,pPhase22->phi9L,0,0,0};
+    double pseudoPN[]={0.,0.,0.,0.,0.,0.,0.,0.,pPhase22->sigma1,pPhase22->sigma2,pPhase22->sigma3,pPhase22->sigma4,pPhase22->sigma5};
+
+
+    //rescale the coefficients of phenX by applying phi_lm(f)~m/2 *phi_22(2/m f)
+    // for more details, see Appendix D of the paper
+    double m_over_2=emm*0.5, two_over_m=1./m_over_2;
+
+    double fact=pPhase22->phiNorm/pWF22->eta;
+
+    for(int i=0; i< NMAX_INSPIRAL_COEFFICIENTS; i++){
+
+      phenXnonLog[i]=phenXnonLog[i]*fact;
+      phenXLog[i]=phenXLog[i]*fact;
+      pseudoPN[i]=pseudoPN[i]*fact;
+
+      // scaling the logarithmic terms introduces some extra contributions in the non-log terms
+      pPhase->phi[i]=(phenXnonLog[i]+pseudoPN[i]-phenXLog[i]*log(m_over_2))*pow(m_over_2,(8-i)/3.);
+      pPhase->phiL[i]=phenXLog[i]*pow(m_over_2,(8-i)/3.);
+    }
+
+
+    // if the mass-ratio is not extreme, use the complex PN amplitudes to correct the orbital phase at linear order in f
+    // see Eq. (4.12) in the paper
+    if(pWF22->eta>0.01){
+      pPhase->LambdaPN=IMRPhenomXHM_Insp_Phase_LambdaPN(pWF22->eta, pWFHM->modeTag);
+      #if DEBUG == 1
+      printf("Add phase shift from PN complex amplitude\n");
+      #endif
+
+    }
+    // else use some phenomenological fits: the fits give the coefficient of a linear-in-f term to be added to the orbital phase
+    else{
+
+      pPhase->LambdaPN= pPhase->InspiralPhaseFits[pWFHM->modeInt](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMInspiralPhaseVersion);
+      #if DEBUG == 1
+      printf("\nLambdaPN = %.16f\n", pPhase->LambdaPN);
+      #endif
+    }
+
+    pPhase->phi[8]= pPhase->phi[8]+ pPhase->LambdaPN;
+
+
+    /****************************************
+    *********** Intermediate-ringdown region ********
+    ****************************************/
+
+    // below we set up the linear system to be solved in the intermediate region
+
+
+    /* GSL objects for solving system of equations via LU decomposition */
+    gsl_vector *b, *x;
+    gsl_matrix *A;
+    gsl_permutation *p;
+    int s;
+
+    p = gsl_permutation_alloc(nCollocationPts_inter);
+    b = gsl_vector_alloc(nCollocationPts_inter);
+    x = gsl_vector_alloc(nCollocationPts_inter);
+    A = gsl_matrix_alloc(nCollocationPts_inter,nCollocationPts_inter);
+
+
+    // for high-spin cases: avoid sharp transitions for 21 mode by extending the inspiral region into the intermediate one
+
+    if(pWFHM->modeTag==21&&pWF22->STotR>=0.8){
+
+        double insp_vals[3], FF, diff12, diff23;
+        for(int i=0; i<3; i++){
+            FF=two_over_m*pPhase->CollocationPointsFreqsPhaseInter[i];
+            IMRPhenomX_Initialize_Powers(&powers_of_f,FF);
+            insp_vals[i]=1./pWF22->eta*IMRPhenomX_dPhase_22(FF,&powers_of_f,pPhase22,pWF22);
+        }
+
+        diff12=insp_vals[0]-insp_vals[1];
+        diff23=insp_vals[1]-insp_vals[2];
+
+        pPhase->CollocationPointsValuesPhaseInter[1]=pPhase->CollocationPointsValuesPhaseInter[2]+diff23;
+        pPhase->CollocationPointsValuesPhaseInter[0]=pPhase->CollocationPointsValuesPhaseInter[1]+diff12;
+
+    }
+
+
+    // choose collocation points according to spin/mass ratio
+    // current catalogue of simulations include some cases that create unphysical effects in the fits -> we need to use different subset of collocation points according to the parameters (we have to pick 5 out of 6 available fits)
+    /* cpoints_indices is an array of integers labelling the collocation points chosen in each case, e.g.
+     cpoints_indices={0,1,3,4,5} would mean that we are discarding the 3rd collocation points in the reconstructio */
+
+    int cpoints_indices[nCollocationPts_inter];
+    cpoints_indices[0]=0;
+    cpoints_indices[1]=1;
+    cpoints_indices[4]=5;
+
+
+    if((pWF22->eta<pWFHM->etaEMR)||(emm==ell&&pWF22->STotR>=0.8)||(pWFHM->modeTag==33&&pWF22->STotR<0))
+    {
+        cpoints_indices[2]=3;
+        cpoints_indices[3]=4;
+    }
+    else if(pWF22->STotR>=0.8&&pWFHM->modeTag==21){
+
+        cpoints_indices[2]=2;
+        cpoints_indices[3]=4;
+    }
+
+    else{
+        cpoints_indices[2]=2;
+        cpoints_indices[3]=3;
+    }
+
+
+
+
+    switch(pWFHM->MixingOn){
+            // mode-mixing off: mode does not show significant mode-mixing
+            // the MixingOn flag is automatically switched off for the modes 21,33,44
+      case 0:
+      {
+
+          /************ Ringdown **************/
+
+          /* ansatz:
+           alpha0 + ((fRDlm^2) alpha2)/(f^2)  + alphaL*(fdamplm)/((fdamplm)^2 + (f - fRDlm)^2)*/
+
+        //compute alpha2 by rescaling the coefficient of the 22-reconstruction
+        double wlm;
+        if(pWFHM->ell==pWFHM->emm) wlm=2;
+        else wlm=pWFHM->emm/3.;
+
+        pPhase->alpha2=1./pow(pWFHM->fRING,2)*wlm*IMRPhenomXHM_RD_Phase_22_alpha2(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion);
+
+
+        // compute alphaL
+        pPhase->alphaL=eta_m1*IMRPhenomXHM_RD_Phase_22_alphaL(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion);
+
+        #if DEBUG == 1
+        printf("alpha2_fit=%f\n",IMRPhenomXHM_RD_Phase_22_alpha2(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion));
+        printf("Ringdown parameters: \n alpha2=%f \n alphaL=%f\n",pPhase->alpha2,pPhase->alphaL);
+        # endif
+
+        // compute spherical-harmonic phase and its first derivative at matching frequency --used to glue RD and intermediate regions--
+        IMRPhenomX_Initialize_Powers(&powers_of_f,fcutRD);
+        pPhase->phi0RD=IMRPhenomXHM_RD_Phase_AnsatzInt(fcutRD, &powers_of_f,pWFHM, pPhase);
+        pPhase->dphi0RD=IMRPhenomXHM_RD_Phase_Ansatz(fcutRD, &powers_of_f,pWFHM, pPhase);
+
+
+          /************ Intermediate **************/
+
+
+        // set up the linear system by calling the fits of the intermediate-region collocation points
+        for(int i=0; i<nCollocationPts_inter; i++){
+
+          int ind=cpoints_indices[i];
+          gsl_vector_set(b,i,pPhase->CollocationPointsValuesPhaseInter[ind]);
+          REAL8 ff=pPhase->CollocationPointsFreqsPhaseInter[ind], ffm1=1./ff, ffm2=ffm1*ffm1;
+          REAL8 fpowers[]={1., (pWFHM->fDAMP)/(pow(pWFHM->fDAMP,2)+pow(ff-(pWFHM->fRING),2)),ffm1,ffm2,ffm2*ffm2, ffm1*ffm2};
+          for(int j=0; j<nCollocationPts_inter; j++)
+          gsl_matrix_set(A,i,j,fpowers[j]);
+        }
+
+        break;
+      }
+
+      // mode-mixing on (the MixingOn flag is automatically switched on when reconstructing the 32 mode)
+      case 1:
+      {
+
+        // for the 32 mode, the ringdown waveform is computed outside of the dedicated amplitude and phase routines, by calling SpheroidalToSpherical
+        // compute dphi/df and d2phi/df2 at fcutRD starting from rotation of spheroidal ansatz: these values will then enter the linear system that determines the coefficients in the intermediate region
+
+        // we compute derivatives by applying finite-difference schemes. In total we will need the value of the phase at three points around fcutRD
+
+        // we first compute the full spherical-harmonic-basis waveforms at three points
+        double complex SphericalWF[3];
+        double fstep=0.0000001;
+
+        for(int i=0; i<3; i++){
+
+          double FF=fcutRD+(i-1)*fstep;
+          IMRPhenomX_UsefulPowers powers_of_FF;
+          IMRPhenomX_Initialize_Powers(&powers_of_FF,FF);
+          SphericalWF[i]=SpheroidalToSpherical(FF, &powers_of_FF, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22);
+
+        }
+
+
+        long double phase_args[]={fmodl(carg(SphericalWF[0]),2.*LAL_PI),fmodl(carg(SphericalWF[1]),2.*LAL_PI),fmodl(carg(SphericalWF[2]),2.*LAL_PI)};
+
+        // make sure that all the three points belong to the same branch of mod
+        for(int i=0; i<3; i++){
+
+            if(phase_args[i]>0)
+                phase_args[i]-=2.*LAL_PI;
+
+        }
+
+        // store spherical-harmonic phase at fcutRD
+        pPhase->phi0RD=phase_args[1];
+        long double fstep_m1= 1./fstep;
+        // we apply the FD schemes to get first and second phase derivatives at fcutRD
+        pPhase->dphi0RD=0.5*fstep_m1*(phase_args[2]-phase_args[0]);
+        double d2phi0RD=fstep_m1*fstep_m1*(phase_args[2]-2.*phase_args[1]+phase_args[0]);
+
+        #if DEBUG == 1
+        printf("dphi0ref=%f\t d2phi0ref=%f\n",pPhase->dphi0RD,d2phi0RD);
+        # endif
+
+          // To achieve a smoother transition with the intermediate region (IR), we feed into the intermediate-region reconstruction the first and second derivative of the reconstructed ringdown phase, see Eq. (5.6)
+
+
+        // first derivative
+          // if the mass-ratio is not extreme, we use the derivative computed using the FD scheme above, else we keep the original value of the fit
+          // in the second case, we will therefore need to glue intermediate and ringdown region later
+        if(pWF22->eta>pWFHM->etaEMR){
+          pPhase->CollocationPointsFreqsPhaseInter[nCollocationPts_inter-2]=fcutRD;
+          pPhase->CollocationPointsValuesPhaseInter[nCollocationPts_inter-2]=pPhase->dphi0RD;
+        }
+        // second derivative
+        pPhase->CollocationPointsFreqsPhaseInter[nCollocationPts_inter-1]=fcutRD;
+        pPhase->CollocationPointsValuesPhaseInter[nCollocationPts_inter-1]=d2phi0RD;
+
+
+        // set up the linear system to determine the intermediate region coefficients
+        for(int i=0; i<nCollocationPts_inter; i++){
+
+          gsl_vector_set(b,i,pPhase->CollocationPointsValuesPhaseInter[i]);
+          REAL8 ff=pPhase->CollocationPointsFreqsPhaseInter[i], ffm1=1./ff, ffm2=ffm1*ffm1;
+          REAL8 fpowers[]={1., (pWFHM->fDAMP)/(pow(pWFHM->fDAMP,2)+pow(ff-(pWFHM->fRING),2)),ffm1,ffm2,ffm2*ffm2, ffm1*ffm2};
+          for(int j=0; j<nCollocationPts_inter; j++)
+          gsl_matrix_set(A,i,j,fpowers[j]);
+
+        }
+
+        // set the last point to equal the second derivative of the rotated spheroidal ansatz
+        int cpoint_ind=nCollocationPts_inter-1;
+        gsl_vector_set(b,cpoint_ind,pPhase->CollocationPointsValuesPhaseInter[cpoint_ind]);
+        REAL8 ff=pPhase->CollocationPointsFreqsPhaseInter[cpoint_ind];
+        REAL8 ffm1=1./ff, ffm2=ffm1*ffm1, ffm3=ffm2*ffm1, ffm4=ffm2*ffm2, ffm5=ffm3*ffm2;
+
+        REAL8 fpowers[]={0.,-2*(pWFHM->fDAMP)*(ff-(pWFHM->fRING))/pow((pow(pWFHM->fDAMP,2)+pow(ff-(pWFHM->fRING),2)),2),-ffm2, -2.* ffm3, -4.*ffm5,-3* ffm4};
+        for(int j=0; j<nCollocationPts_inter; j++){
+          gsl_matrix_set(A,cpoint_ind,j,fpowers[j]);
+        }
+
+
+        #if DEBUG == 1
+        printf("Collocation points for intermediate ansatz %i:\n",nCollocationPts_inter);
+        for(int i=0;i<nCollocationPts_inter; i++)
+        printf("p%d={%.13f,%.13f};\n",i,pPhase->CollocationPointsFreqsPhaseInter[i],pPhase->CollocationPointsValuesPhaseInter[i]);
+        #endif
+
+        break;
+
+
+
+      }
+
+      default:{XLALPrintError("Error in IMRPhenomXHM_GetPhaseCoefficients:mode-mixing not properly initialized.\n");}
+
+    }
+
+
+    // at this point we have initizialized all the collocation points in the intermediate region, so we can solve to get the coefficients of the ansatz
+
+    /* In the intermediate region , the most general ansatz is
+    (c0 + c1 /f + c2 /(f)^2 + c4 /(f)^4 + c3 /f^3 +cL fdamp/((fdamp)^2 + (f - fRD )^2))*/
+
+    /* We now solve the system A x = b via an LU decomposition */
+    gsl_linalg_LU_decomp(A,p,&s);
+    gsl_linalg_LU_solve(A,p,b,x);
+
+    pPhase->c0 = gsl_vector_get(x,0); // x[0]; // c0
+    pPhase->cL = gsl_vector_get(x,1); // x[1] // cL
+    pPhase->c1 = gsl_vector_get(x,2); // x[2]; // c1
+    pPhase->c2 = gsl_vector_get(x,3); // x[3]; // c2
+    pPhase->c4 = gsl_vector_get(x,4); // x[4]; // c4
+
+    // currently the 32 mode is calibrated using one extra point
+    if ((pWFHM->modeTag)== 32)
+    { pPhase->c3 = gsl_vector_get(x,5);  //c3
+
+      // if the mass-ratio is extreme, we need to glue intermediate and ringdown region, as explained above
+      if(pWF22->eta<pWFHM->etaEMR)
+      {
+        IMRPhenomX_Initialize_Powers(&powers_of_f,fcutRD);
+        pPhase->c0=pPhase->c0+pPhase->dphi0RD-IMRPhenomXHM_Inter_Phase_Ansatz(fcutRD, &powers_of_f,pWFHM, pPhase);
+
+      }
+    }
+
+    #if DEBUG == 1
+    printf("Intermediate region coefficients:\n");
+    printf("c0=%f\n c1=%f\n c2=%f\n c3=%f\n c4=%f\n cL=%f\n", pPhase->c0,pPhase->c1,pPhase->c2,pPhase->c3,pPhase->c4,pPhase->cL);
+    #endif
+
+    gsl_vector_free(b);
+    gsl_vector_free(x);
+    gsl_matrix_free(A);
+    gsl_permutation_free(p);
+
+
+    /****************** end of ringdown and inspiral reconstruction **************/
+
+    //glue inspiral and intermediate
+    IMRPhenomX_Initialize_Powers(&powers_of_f,fcutInsp);
+
+    pPhase->C1INSP=IMRPhenomXHM_Inter_Phase_Ansatz(fcutInsp, &powers_of_f,pWFHM, pPhase)-IMRPhenomXHM_Inspiral_Phase_Ansatz(fcutInsp, &powers_of_f, pPhase);
+    pPhase->CINSP=-(pPhase->C1INSP*fcutInsp)+IMRPhenomXHM_Inter_Phase_AnsatzInt(fcutInsp, &powers_of_f,pWFHM, pPhase)-IMRPhenomXHM_Inspiral_Phase_AnsatzInt(fcutInsp, &powers_of_f, pPhase);
+
+    //glue ringdown and intermediate regions
+    IMRPhenomX_Initialize_Powers(&powers_of_f,fcutRD);
+
+    pPhase->C1RD=IMRPhenomXHM_Inter_Phase_Ansatz(fcutRD, &powers_of_f,pWFHM, pPhase)-pPhase->dphi0RD;
+    pPhase->CRD=-pPhase->C1RD*fcutRD+IMRPhenomXHM_Inter_Phase_AnsatzInt(fcutRD, &powers_of_f,pWFHM, pPhase)-pPhase->phi0RD;
+
+    // we now have a C1 reconstruction of the phase
+    // below we align each mode so that at low-f its relative phase wrt the 22 agrees with PN
+    double falign;
+    //somehow arbitary cutoff to pick frequency for alignment: must be in the inspiral region
+    if(pWF22->eta>pWFHM->etaEMR)
+    falign=0.6*m_over_2*pWF22->fMECO;
+    else
+    falign=m_over_2*pWF22->fMECO;
+
+    IMRPhenomX_UsefulPowers powers_of_falign;
+    IMRPhenomX_Initialize_Powers(&powers_of_falign,falign);
+    IMRPhenomX_Initialize_Powers(&powers_of_f,two_over_m*falign);
+
+    /* compute explicitly the phase normalization to be applied to IMRPhenomX, when mode-mixing is on this will have been already computed in GetSpheroidalCoefficients */
+    if(pWFHM->MixingOn==0){
+      IMRPhenomX_UsefulPowers powers_of_MfRef;
+      IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF22->MfRef);
+      IMRPhenomX_Phase_22_ConnectionCoefficients(pWF22,pPhase22);
+      pWFHM->timeshift=IMRPhenomX_TimeShift_22(pPhase22, pWF22);
+      pWFHM->phiref22 = -1./pWF22->eta*IMRPhenomX_Phase_22(pWF22->MfRef, &powers_of_MfRef, pPhase22, pWF22) - pWFHM->timeshift*pWF22->MfRef - pWFHM->phaseshift + 2.0*pWF22->phi0 + LAL_PI_4;
+    }
+
+    // we determine the phase normalization of each mode by imposing Eq. (4.13), i.e. phi_lm(fref)-m/2 phi_22(2/m fref)~3.*LAL_PI_4*(1-m_over_2)
+    double deltaphiLM=m_over_2*(1./pWF22->eta*IMRPhenomX_Phase_22(two_over_m*falign, &powers_of_f,pPhase22,pWF22)+pWFHM->phaseshift + pWFHM->phiref22)+pWFHM->timeshift*falign-3.*LAL_PI_4*(1-m_over_2)-(IMRPhenomXHM_Inspiral_Phase_AnsatzInt(falign, &powers_of_falign,pPhase)+pPhase->C1INSP*falign+pPhase->CINSP);
+    pPhase->deltaphiLM=fmod(deltaphiLM,2.*LAL_PI);
+
+    #if DEBUG == 1
+    printf("\n****** Connection coefficients of 22 in %i******\n", pWFHM->modeTag);
+    printf("%.6f %.6f %.6f %.6f %.6f\n", pPhase22->C1Int, pPhase22->C2Int, pPhase22->C1MRD, pPhase22->C1MRD, IMRPhenomX_Phase_22(two_over_m*falign, &powers_of_f,pPhase22,pWF22));
+    #endif
+
+
+    // for the 21, we need to make sure the sign of the PN amplitude is positive, else we'll need to flip its phase by Pi
+    if ((pWFHM->modeTag)== 21)
+    {
+      int ampsign=IMRPhenomXHM_PN21AmpSign(0.008,pWF22);
+      // the sign of the 21 amplitude changes across the parameter space, we add Pi to the phase to account for this - remember that the amplitude of the model is positive by construction
+      if(ampsign>0) pPhase->deltaphiLM+=LAL_PI;
+
+    }
+
+    // all the coefficients have been now stored
+  // print parameters to file if in debugging mode
+  #if DEBUG == 1
+  FILE *file;
+  char fileSpec[40];
+  sprintf(fileSpec, "PhaseParameters%i.dat", pWFHM->modeTag);
+
+  file = fopen(fileSpec,"w");
+
+  fprintf(file,"\n*** %i Mode ***\n", pWFHM->modeTag);
+
+  fprintf(file,"\n*** Intrinsic Parameters ***\n");
+  fprintf(file,"eta   = %.16f\n", pWF22->eta);
+  fprintf(file,"chi1z = %.16f\n", pWF22->chi1L);
+  fprintf(file,"chi2z = %.16f\n", pWF22->chi2L);
+
+  fprintf(file,"\n*** QNM Frequencies ***\n");
+  fprintf(file,"fRINGlm = %.16f\n", pWFHM->fRING);
+  fprintf(file,"fDAMPlm = %.16f\n", pWFHM->fDAMP);
+
+
+  fprintf(file,"\n*** Phase Inspiral ***\n");
+  fprintf(file,"Lambda = %.16f\n", pPhase->LambdaPN);
+
+  fprintf(file,"\n*** Phase Intermediate ***\n f_i\t dphi(f_i)\n");
+
+  for(int i = 0; i<N_MAX_COEFFICIENTS_PHASE_INTER; i++)
+      fprintf(file, "%.16f \t %.16f \n", pPhase->CollocationPointsFreqsPhaseInter[i], pPhase->IntermediatePhaseFits[pWFHM->modeInt*N_MAX_COEFFICIENTS_PHASE_INTER+i](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMIntermediatePhaseVersion));
+
+
+  if(pWFHM->modeTag==32){
+      fprintf(file,"\n*** Mixing Coefficients ***\n");
+      fprintf(file,"222 = %.16f  %.16f *I\n", creal(pWFHM->mixingCoeffs[0]), cimag(pWFHM->mixingCoeffs[0]));
+      fprintf(file,"223 = %.16f  %.16f *I\n", creal(pWFHM->mixingCoeffs[1]), cimag(pWFHM->mixingCoeffs[1]));
+      fprintf(file,"322 = %.16f  %.16f *I\n", creal(pWFHM->mixingCoeffs[2]), cimag(pWFHM->mixingCoeffs[2]));
+      fprintf(file,"323 = %.16f  %.16f *I\n", creal(pWFHM->mixingCoeffs[3]), cimag(pWFHM->mixingCoeffs[3]));
+
+      fprintf(file, "\n*** Ringdown Phase Spheroidal ***\n f_i \t dphi(f_i)\n");
+      for(int i=0; i<pWFHM->nCollocPtsRDPhase; i++)
+          fprintf(file, "%.16f \t %.16f \n", pPhase->CollocationPointsFreqsPhaseRD[i],pPhase->RingdownPhaseFits[i](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion));
+      fprintf(file,"Deltadphi=%.16f\n Deltaphi=%.16f \n", IMRPhenomXHM_RD_Phase_32_SpheroidalTimeShift(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion),IMRPhenomXHM_RD_Phase_32_SpheroidalPhaseShift(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion));
+
+  }
+
+  else{
+      fprintf(file, "\n*** Ringdown phase ***\n");
+      fprintf(file,"alpha2=%.16f\n alphaL=%.16f",pPhase->alpha2,pPhase->alphaL);
+  }
+
+  fclose(file);
+  #endif
+
+  }
+
+
+
+/* Reconstruct the coefficients of the ringdown phase in a spheroidal-harmonics basis --only for the 32 mode    */
+void  GetSpheroidalCoefficients(IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+
+    int nCollocationPts_RD_Phase = pWFHM->nCollocPtsRDPhase;
+    double CollocValuesPhaseRingdown[nCollocationPts_RD_Phase];
+    double CollocFreqsPhaseRingdown[nCollocationPts_RD_Phase];
+
+    #if DEBUG == 1
+    printf("Declare Colloc Values and Freqs:\n");
+    #endif
+    // define gsl variables
+    gsl_vector *b, *x;
+    gsl_matrix *A;
+    gsl_permutation *p;
+    int s;
+
+    p = gsl_permutation_alloc(nCollocationPts_RD_Phase);
+    b = gsl_vector_alloc(nCollocationPts_RD_Phase);
+    x = gsl_vector_alloc(nCollocationPts_RD_Phase);
+    A = gsl_matrix_alloc(nCollocationPts_RD_Phase,nCollocationPts_RD_Phase);
+
+    IMRPhenomXHM_Ringdown_CollocPtsFreqs(pPhase,pWFHM, pWF22);
+
+    #if DEBUG == 1
+    printf("Initialize RD CollocPtsFreqs:\n");
+    #endif
+
+    // first fill-in the collocation points for the phase
+    for(int i=0; i<nCollocationPts_RD_Phase; i++)
+    {
+
+      CollocValuesPhaseRingdown[i] =pPhase->RingdownPhaseFits[i](pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion);
+      CollocFreqsPhaseRingdown[i] =pPhase->CollocationPointsFreqsPhaseRD[i];
+      gsl_vector_set(b,i,CollocValuesPhaseRingdown[i]);
+      REAL8 ff=CollocFreqsPhaseRingdown[i], ffm1=1./ff, ffm2=ffm1*ffm1;
+      REAL8 fpowers[]={1., (pWFHM->fDAMP)/(pow(pWFHM->fDAMP,2)+pow(ff-(pWFHM->fRING),2)),ffm2,ffm2*ffm2};
+      for(int j=0; j<nCollocationPts_RD_Phase; j++)
+      gsl_matrix_set(A,i,j,fpowers[j]);
+
+    }
+
+    #if DEBUG == 1
+    printf("Collocation points in ringdown region:\n");
+    for(int i=0; i<nCollocationPts_RD_Phase; i++){
+      printf("p%d=(%f,%f)\n",i+1,CollocFreqsPhaseRingdown[i],CollocValuesPhaseRingdown[i]);
+    }
+
+    #endif
+    // solve the linear system of Eq. (6.8)
+    gsl_linalg_LU_decomp(A,p,&s);
+    gsl_linalg_LU_solve(A,p,b,x);
+
+    /* ansatz: alpha0 + (alpha2)/(f^2)+ (alpha4)/(f^4)  + alphaL*(fdamplm)/((fdamplm)^2 + (f - fRDlm)^2)*/
+
+    pPhase->alpha0_S = gsl_vector_get(x,0);
+    pPhase->alphaL_S = gsl_vector_get(x,1);
+    pPhase->alpha2_S = gsl_vector_get(x,2);
+    pPhase->alpha4_S = gsl_vector_get(x,3);
+
+    #if DEBUG == 1
+    printf("**********\n alpha0_S=%f \n alphaL_S=%f \n alpha2_S=%f \n alpha4_S=%f \n \n ", pPhase->alpha0_S, pPhase->alphaL_S, pPhase->alpha2_S, pPhase->alpha4_S);
+    #endif
+
+    gsl_vector_free(b);
+    gsl_vector_free(x);
+    gsl_matrix_free(A);
+    gsl_permutation_free(p);
+
+    //  we have reconstructed the "shape" of the spheroidal ringdown phase derivative, dphiS, but we need to adjust the relative time and phase shift of the final phiS wrt IMRPhenomX
+
+    IMRPhenomX_UsefulPowers powers_of_FREF;
+    /*************** time-shift of spheroidal ansatz *******************/
+    double frefRD=pWF22->fRING+pWF22->fDAMP;
+    IMRPhenomX_Initialize_Powers(&powers_of_FREF,frefRD);
+    // here we call a fit for dphiS(fref)-dphi22(fref)
+    double tshift=IMRPhenomXHM_RD_Phase_32_SpheroidalTimeShift(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion);
+
+    // we compute dphi22(fref)
+    IMRPhenomX_Phase_22_ConnectionCoefficients(pWF22,pPhase22);
+    pWFHM->timeshift=IMRPhenomX_TimeShift_22(pPhase22, pWF22);
+    double dphi22ref=1./pWF22->eta*IMRPhenomX_dPhase_22(frefRD, &powers_of_FREF,pPhase22,pWF22)+pWFHM->timeshift;
+
+    // we impose that dphiS(fref)-dphi22(fref) has the value given by our fit
+    pPhase->alpha0_S = pPhase->alpha0_S +dphi22ref+tshift-IMRPhenomXHM_RD_Phase_Ansatz(frefRD,&powers_of_FREF,pWFHM,pPhase);
+
+    /*************** phase-shift of spheroidal ansatz *******************/
+    frefRD=pWF22->fRING;
+    IMRPhenomX_Initialize_Powers(&powers_of_FREF,frefRD);
+
+    /* we compute phi22(fref) */
+    IMRPhenomX_UsefulPowers powers_of_MfRef;
+    IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF22->MfRef);
+    pWFHM->phiref22 = -1./pWF22->eta*IMRPhenomX_Phase_22(pWF22->MfRef, &powers_of_MfRef, pPhase22, pWF22) - pWFHM->timeshift*pWF22->MfRef - pWFHM->phaseshift + 2.0*pWF22->phi0 + LAL_PI_4;
+    double phi22ref=1./pWF22->eta*IMRPhenomX_Phase_22(frefRD, &powers_of_FREF,pPhase22,pWF22) + pWFHM->timeshift*frefRD + pWFHM->phaseshift + pWFHM->phiref22;
+    // we call a fit for Mod[phiS(fref)-phi22(fref),2*Pi]
+    double phishift=IMRPhenomXHM_RD_Phase_32_SpheroidalPhaseShift(pWF22->eta,pWF22->STotR,pWF22->chi1L,pWF22->chi2L,pWFHM->IMRPhenomXHMRingdownPhaseVersion);
+
+    pPhase->phi0_S = 0;
+    //we adjust the relative phase of our reconstruction
+    pPhase->phi0_S= phi22ref-IMRPhenomXHM_RD_Phase_AnsatzInt(frefRD,&powers_of_FREF,pWFHM,pPhase)+phishift;
+
+
+    #if DEBUG == 1
+    printf("**********\n alpha0_S=%f \n alphaL_S=%f \n alpha2_S=%f \n alpha4_S=%f \n \n ", pPhase->alpha0_S, pPhase->alphaL_S, pPhase->alpha2_S, pPhase->alpha4_S);
+    printf("**********\n **Spheroidal reconstruction parameters:**\n \n phi0_S=%f \n alpha0_S=%f \n alphaL_S=%f \n alpha2_S=%f \n alpha4_S=%f \n \n ",pPhase->phi0_S, pPhase->alpha0_S, pPhase->alphaL_S, pPhase->alpha2_S, pPhase->alpha4_S);
+    #endif
+
+
+  }
+
+
+/**************************************/
+/*                                    */
+/*  Spheroidal -> Spherical rotation  */
+/*                                    */
+/**************************************/
+/* The rotation consists of a linear transformation using the mixing coefficients given by Berti [10.1103/PhysRevD.90.064012].
+
+  h32_spherical = a1 * h22_spheroidal + a2 * h32_spheroidal,  where a1, a2 are the mixing coefficients.
+
+  Since the 22 is the most dominant mode, it will not show a significant mixing with any other mode,
+  so we can assume that h22_spheroidal = h22_spherical
+*/
+
+  // In principle this could be generalized to the 43 mode: for the time being, assume the mode solved for is only the 32.
+  double complex SpheroidalToSpherical(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMAmpCoefficients *pAmplm, IMRPhenomXHMPhaseCoefficients *pPhaselm, IMRPhenomXHMWaveformStruct *pWFlm, IMRPhenomXWaveformStruct *pWF22)
+  {
+    // Compute the 22 mode using PhenomX functions. This gives the 22 mode rescaled with the leading order.  This is because the 32 is also rescaled.
+    double amp22=XLALSimIMRPhenomXRingdownAmplitude22AnsatzAnalytical(ff, pWF22->fRING, pWF22->fDAMP, pAmp22->gamma1, pAmp22->gamma2, pAmp22->gamma3);
+    double phi22=1./pWF22->eta*IMRPhenomX_Phase_22(ff, powers_of_f, pPhase22,pWF22) + pWFlm->timeshift*ff + pWFlm->phaseshift + pWFlm->phiref22;
+    complex double wf22R = amp22*cexp(I * phi22);
+    // Compute 32 mode in spheroidal.
+    double amplm=IMRPhenomXHM_RD_Amp_Ansatz(ff, pWFlm, pAmplm);
+    double philm=IMRPhenomXHM_RD_Phase_AnsatzInt(ff, powers_of_f,pWFlm, pPhaselm);
+    // Do the rotation.
+    double complex sphericalWF_32=conj(pWFlm->mixingCoeffs[2]) * wf22R + conj(pWFlm->mixingCoeffs[3])*amplm*cexp(I*philm);
+    return sphericalWF_32;
+
+  }
+
+  // If the 22 mode has been previously computed, we use it here for the rotation.
+  double complex SpheroidalToSphericalRecycle(double ff, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmplm, IMRPhenomXHMPhaseCoefficients *pPhaselm, IMRPhenomXHMWaveformStruct *pWFlm)
+  {
+    // The input 22 in the whole 22, and for the rotation we have to rescaled with the leading order. This is because the 32 is also rescaled.
+    complex double wf22R = wf22/(powers_of_f->m_seven_sixths * pWFlm->Amp0);
+    // Compute 32 mode in spheroidal.
+    double amplm=IMRPhenomXHM_RD_Amp_Ansatz(ff, pWFlm, pAmplm);
+    double philm=IMRPhenomXHM_RD_Phase_AnsatzInt(ff, powers_of_f,pWFlm, pPhaselm);
+    // Do the rotation
+    double complex sphericalWF_32 = conj(pWFlm->mixingCoeffs[2])*wf22R  +  conj(pWFlm->mixingCoeffs[3])*amplm*cexp(I*philm);
+    return sphericalWF_32;
+
+  }
+
+
+  /**************************************/
+  /*                                    */
+  /*  RECONSTRUCTION FUNCTIONS THROUGH  */
+  /*     INSPIRAL, MERGER & RINGDOWN    */
+  /*                                    */
+  /**************************************/
+
+  /* These functions return the amplitude/phase for a given input frequency.
+     They are piece-wise functions that distiguish between inspiral, intermediate and ringdown
+     and call the corresponding reconstruction function.
+  */
+
+  /*******************************************************************************/
+  /*  Compute IMRPhenomXHM AMPLITUDE given an amplitude coefficients struct pAmp */
+  /*******************************************************************************/
+
+  // WITHOUT mode mixing. It returns the whole amplitude (in NR units) without the normalization factor of the 22: sqrt[2 * eta / (3 * pi^(1/3))]
+  double IMRPhenomXHM_Amplitude_noModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMWaveformStruct *pWF) {
+
+    // If it is an odd mode and equal black holes case this mode is zero.
+    if(pWF->Ampzero==1){
+      return 0.;
+    }
+
+    double factor = powers_of_f->m_seven_sixths;
+
+    // Use step function to only calculate IMR regions in approrpiate frequency regime
+    // Inspiral range
+    if (!IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIN))
+    {
+      double AmpIns =  IMRPhenomXHM_Inspiral_Amp_Ansatz(powers_of_f, pWF, pAmp);
+      return AmpIns*factor;
+    }
+    // MRD range
+    if (IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIM))
+    {
+      double AmpMRD = IMRPhenomXHM_RD_Amp_Ansatz(powers_of_f->itself, pWF, pAmp);
+      return AmpMRD*factor;
+    }
+    /* Intermediate range */
+    // First intermediate region.
+    if ((pWF->AmpEMR==1) && !IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchInt12))
+    {
+      INT4 tmp = pAmp->InterAmpPolOrder;
+      pAmp->InterAmpPolOrder = 1042;
+      double AmpInt1 = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+      pAmp->InterAmpPolOrder = tmp;
+      return AmpInt1;
+    }
+    //Second intermediate region
+    double AmpInt = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+    return AmpInt;
+  }
+
+  // WITH mode mixing. It returns the whole amplitude (in NR units) without the normalization factor of the 22: sqrt[2 * eta / (3 * pi^(1/3))].
+  double IMRPhenomXHM_Amplitude_ModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22) {
+    double factor = powers_of_f->m_seven_sixths;
+    // Use step function to only calculate IMR regions in approrpiate frequency regime
+    // Inspiral range
+    if (!IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIN))
+    {
+      double AmpIns =  IMRPhenomXHM_Inspiral_Amp_Ansatz(powers_of_f, pWF, pAmp);
+      return AmpIns*factor;
+    }
+    // MRD range
+    if (IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIM))
+    {
+      double AmpMRD = cabs(SpheroidalToSpherical(f, powers_of_f, pAmp22, pPhase22, pAmp, pPhase, pWF, pWF22));
+      return AmpMRD*factor;
+    }
+    /* Intermediate range */
+    // First intermediate region
+    if ((pWF->AmpEMR==1) && !IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchInt12))
+    {
+      INT4 tmp = pAmp->InterAmpPolOrder;
+      pAmp->InterAmpPolOrder = 1042;
+      double AmpInt1 = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+      pAmp->InterAmpPolOrder = tmp;
+      return AmpInt1;
+    }
+    //Second intermediate region
+    double AmpInt = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+    return AmpInt;
+  }
+
+  // WITH mode mixing and recycling the previously computed 22 mode. It returns the whole amplitude (in NR units) without the normalization factor of the 22: sqrt[2 * eta / (3 * pi^(1/3))].
+  double IMRPhenomXHM_Amplitude_ModeMixingRecycle(double f, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF) {
+    //  double f_seven_sixths = powers_of_f->seven_sixths;
+    double factor = powers_of_f->m_seven_sixths;
+    // Use step function to only calculate IMR regions in approrpiate frequency regime
+    // Inspiral range
+    if (!IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIN))
+    {
+      double AmpIns =  IMRPhenomXHM_Inspiral_Amp_Ansatz(powers_of_f, pWF, pAmp);
+      return AmpIns*factor;
+    }
+    // MRD range
+    if (IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchIM))
+    {
+      double AmpMRD = cabs(SpheroidalToSphericalRecycle(f, powers_of_f, wf22, pAmp, pPhase, pWF));
+      return AmpMRD*factor;
+    }
+    /* Intermediate range */
+    // First intermediate region
+    if ((pWF->AmpEMR==1) && !IMRPhenomX_StepFuncBool(f, pAmp->fAmpMatchInt12))
+    {
+      INT4 tmp = pAmp->InterAmpPolOrder;
+      pAmp->InterAmpPolOrder = 1042;
+      double AmpInt1 = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+      pAmp->InterAmpPolOrder = tmp;
+      return AmpInt1;
+    }
+    //Second intermediate region
+    double AmpInt = IMRPhenomXHM_Intermediate_Amp_Ansatz(powers_of_f, pAmp);
+    return AmpInt;
+  }
+
+
+  /*******************************************************************************/
+  /*  Compute IMRPhenomXHM PHASE given a phase coefficients struct pPhase        */
+  /*******************************************************************************/
+
+  // WITHOUT mode mixing.
+  double IMRPhenomXHM_Phase_noModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF, UNUSED IMRPhenomXWaveformStruct *pWF22)
+  {
+    // Inspiral range, f < fPhaseInsMax
+    if (!IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIN))
+    {
+      double PhiIns = IMRPhenomXHM_Inspiral_Phase_AnsatzInt(f, powers_of_f, pPhase);
+      return PhiIns + pPhase->C1INSP*f + pPhase->CINSP + pPhase->deltaphiLM;
+    }
+    // MRD range, f > fPhaseIntMax
+    if (IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIM))
+    {
+      double PhiMRD = IMRPhenomXHM_RD_Phase_AnsatzInt(f, powers_of_f, pWF, pPhase);
+      return PhiMRD + pPhase->C1RD*f + pPhase->CRD + pPhase->deltaphiLM;
+    }
+    //Intermediate range, fPhaseInsMax < f < fPhaseIntMax
+    double PhiInt = IMRPhenomXHM_Inter_Phase_AnsatzInt(f, powers_of_f, pWF, pPhase);
+    return PhiInt + pPhase->deltaphiLM;
+  }
+
+  // WITH mode mixing.
+  double IMRPhenomXHM_Phase_ModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF,  IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22)
+  {
+    // Inspiral range, f < fPhaseInsMax
+    if (!IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIN))
+    {
+      double PhiIns = IMRPhenomXHM_Inspiral_Phase_AnsatzInt(f, powers_of_f, pPhase);
+      return PhiIns + pPhase->C1INSP*f + pPhase->CINSP + pPhase->deltaphiLM;
+    }
+    // MRD range, f > fPhaseIntMax
+    if (IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIM))
+    {
+      double PhiMRD = carg(SpheroidalToSpherical(f, powers_of_f, pAmp22, pPhase22, pAmp, pPhase, pWF, pWF22));
+      return PhiMRD + pPhase->C1RD*f + pPhase->CRD + pPhase->deltaphiLM;
+    }
+    //Intermediate range, fPhaseInsMax < f < fPhaseIntMax
+    double PhiInt = IMRPhenomXHM_Inter_Phase_AnsatzInt(f, powers_of_f, pWF, pPhase);
+    return PhiInt + pPhase->deltaphiLM;
+  }
+
+  // WITH mode mixing and recycling the previously computed 22 mode.
+  double IMRPhenomXHM_Phase_ModeMixingRecycle(double f, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF)
+  {
+    // Inspiral range, f < fPhaseInsMax
+    if (!IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIN))
+    {
+      double PhiIns = IMRPhenomXHM_Inspiral_Phase_AnsatzInt(f, powers_of_f, pPhase);
+      return PhiIns + pPhase->C1INSP*f + pPhase->CINSP + pPhase->deltaphiLM;
+    }
+    // MRD range, f > fPhaseIntMax
+    if (IMRPhenomX_StepFuncBool(f, pPhase->fPhaseMatchIM))
+    {
+      double PhiMRD = carg(SpheroidalToSphericalRecycle(f, powers_of_f, wf22, pAmp, pPhase, pWF));
+      return PhiMRD + pPhase->C1RD*f + pPhase->CRD + pPhase->deltaphiLM;
+    }
+    //Intermediate range, fPhaseInsMax < f < fPhaseIntMax
+    double PhiInt = IMRPhenomXHM_Inter_Phase_AnsatzInt(f, powers_of_f, pWF, pPhase);
+    return PhiInt + pPhase->deltaphiLM;
+  }
+
+
+  /*****************/
+  /*   DEBUGGING   */
+  /*****************/
+
+  // This is just for debugging. It prints some interesting parameters to a file.
+  int ParametersToFile(
+    IMRPhenomXWaveformStruct *pWF,                /**< Wf structure for the 22 mode*/
+    IMRPhenomXHMWaveformStruct *pWFHM,            /**< Wf structure for the lm mode*/
+    IMRPhenomXHMAmpCoefficients *pAmp,            /**< Coefficients struct of the lm Amplitude */
+    UNUSED IMRPhenomXHMPhaseCoefficients *pPhase  /**< Coefficients struct of the lm Phase */
+  )
+  {
+
+    FILE *file;
+    char fileSpec[40];
+    sprintf(fileSpec, "Parameters%i.dat", pWFHM->modeTag);
+    printf("\nOutput Parameter file: %s\r\n",fileSpec);
+    file = fopen(fileSpec,"w");
+
+    fprintf(file,"\n*** %i Mode ***\n", pWFHM->modeTag);
+
+    fprintf(file,"\n*** Intrinsic Parameters ***\n");
+    fprintf(file,"eta   = %.16f\n", pWF->eta);
+    fprintf(file,"chi1z = %.16f\n", pWF->chi1L);
+    fprintf(file,"chi2z = %.16f\n", pWF->chi2L);
+
+    fprintf(file,"\n*** Extrinsic Parameters ***\n");
+    fprintf(file,"distance    = %.16f\n", pWF->distance);
+    fprintf(file,"inclination = %.16f\n", pWF->inclination);
+    fprintf(file,"phiRef      = %.16f\n", pWF->phifRef);
+    fprintf(file,"fRef        = %.16f\n", pWF->fRef);
+    fprintf(file,"m1_SI       = %.16f\n", pWF->m1_SI);
+    fprintf(file,"m2_SI       = %.16f\n", pWF->m2_SI);
+
+    fprintf(file,"\n*** Frequency Grid ***\n");
+    fprintf(file,"deltaF = %.16f\n", pWF->deltaF);
+    fprintf(file,"fMin   = %.16f\n", pWF->fMin);
+    fprintf(file,"fMax   = %.16f\n", pWF->fMax);
+
+    fprintf(file,"\n*** QNM Frequencies ***\n");
+    fprintf(file,"fRING22 = %.16f\n", pWF->fRING);
+    fprintf(file,"fDAMP22 = %.16f\n", pWF->fDAMP);
+    fprintf(file,"fRINGlm = %.16f\n", pWFHM->fRING);
+    fprintf(file,"fDAMPlm = %.16f\n", pWFHM->fDAMP);
+
+    fprintf(file,"\n*** Amplitude Frequencies ***\n");
+    fprintf(file,"fInsp1         = %.16f\n", pAmp->CollocationPointsFreqsAmplitudeInsp[0]);
+    fprintf(file,"fInsp2         = %.16f\n", pAmp->CollocationPointsFreqsAmplitudeInsp[1]);
+    fprintf(file,"fInsp3         = %.16f\n", pAmp->CollocationPointsFreqsAmplitudeInsp[2]);
+    fprintf(file,"fAmpMatchIN    = %.16f\n", pAmp->fAmpMatchIN);
+    fprintf(file,"fAmpMatchInt12 = %.16f\n", pAmp->fAmpMatchInt12);
+    fprintf(file,"fInt1          = %.16f\n", pAmp->CollocationPointsFreqsAmplitudeInter[0]);
+    fprintf(file,"fInt2          = %.16f\n", pAmp->CollocationPointsFreqsAmplitudeInter[1]);
+    fprintf(file,"fAmpMatchIM    = %.16f\n", pAmp->fAmpMatchIM);
+
+    fprintf(file,"\n*** Amplitude Collocation Points ***\n");
+    fprintf(file,"A_fInsp1 = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInsp[0]);
+    fprintf(file,"A_fInsp2 = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInsp[1]);
+    fprintf(file,"A_fInsp3 = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInsp[2]);
+    fprintf(file,"A_fInt1  = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInter[0]);
+    fprintf(file,"A_fInt2  = %.16f\n", pAmp->CollocationPointsValuesAmplitudeInter[1]);
+
+    fprintf(file,"\n*** Amplitude Coefficients ***\n");
+    fprintf(file,"rho1    = %.16f\n", pAmp->rho1); //Inspiral coefficients
+    fprintf(file,"rho2    = %.16f\n", pAmp->rho2);
+    fprintf(file,"rho3    = %.16f\n", pAmp->rho3);
+    fprintf(file,"delta0  = %.16f\n", pAmp->delta0); //Intermediate region
+    fprintf(file,"delta1  = %.16f\n", pAmp->delta1);
+    fprintf(file,"delta2  = %.16f\n", pAmp->delta2);
+    fprintf(file,"delta3  = %.16f\n", pAmp->delta3);
+    fprintf(file,"delta4  = %.16f\n", pAmp->delta4);
+    fprintf(file,"delta5  = %.16f\n", pAmp->delta5);
+    fprintf(file,"alambda = %.20f\n", pAmp->alambda); //Ringdown region
+    fprintf(file,"lambda  = %.16f\n", pAmp->lambda);
+    fprintf(file,"sigma   = %.16f\n", pAmp->sigma);
+    fprintf(file,"lc      = %.16f\n", pAmp->lc);
+    fprintf(file,"alpha0  = %.16f\n", pAmp->alpha0); //First Intermediate region (only for EMR)
+    fprintf(file,"alpha1  = %.16f\n", pAmp->alpha1);
+    fprintf(file,"alpha2  = %.16f\n", pAmp->alpha2);
+    fprintf(file,"alpha3  = %.16f\n", pAmp->alpha3);
+    fprintf(file,"alpha4  = %.16f\n", pAmp->alpha4);
+
+    fprintf(file,"\n*** Amplitude Intermediate Input ***\n");
+    fprintf(file,"f1 = %.16f\n", pAmp->f1);
+    fprintf(file,"f2 = %.16f\n", pAmp->f2);
+    fprintf(file,"f3 = %.16f\n", pAmp->f3);
+    fprintf(file,"f4 = %.16f\n", pAmp->f4);
+    fprintf(file,"v1 = %.16f\n", pAmp->v1);
+    fprintf(file,"v2 = %.16f\n", pAmp->v2);
+    fprintf(file,"v3 = %.16f\n", pAmp->v3);
+    fprintf(file,"v4 = %.16f\n", pAmp->v4);
+    fprintf(file,"d1 = %.16f\n", pAmp->d1);
+    fprintf(file,"d4 = %.16f\n", pAmp->d4);
+
+    fprintf(file,"\n*** PN Amplitude Inspiral ***\n");
+    fprintf(file,"PN_f1 = %.16f\n", pAmp->PNAmplitudeInsp[0]);
+    fprintf(file,"PN_f2 = %.16f\n", pAmp->PNAmplitudeInsp[1]);
+    fprintf(file,"PN_f3 = %.16f\n", pAmp->PNAmplitudeInsp[2]);
+
+    fprintf(file,"\n*** Amplitude Versions ***\n");
+    fprintf(file,"InspiralFits      = %i\n", pWFHM->IMRPhenomXHMInspiralAmpFitsVersion);
+    fprintf(file,"IntermediateFits  = %i\n", pWFHM->IMRPhenomXHMIntermediateAmpFitsVersion);
+    fprintf(file,"RDFits            = %i\n", pWFHM->IMRPhenomXHMRingdownAmpFitsVersion);
+    fprintf(file,"InspiralRecon     = %i\n", pWFHM->IMRPhenomXHMInspiralAmpVersion);
+    fprintf(file,"IntermediateRecon = %i\n", pWFHM->IMRPhenomXHMIntermediateAmpVersion);
+    fprintf(file,"RDRecon           = %i\n", pWFHM->IMRPhenomXHMRingdownAmpVersion);
+
+    fprintf(file,"\n*** Amplitude Extra ***\n");
+    fprintf(file,"AmpEMR  = %i\n", pWFHM->AmpEMR);
+    fprintf(file,"Ampzero = %i\n", pWFHM->Ampzero);
+
+    if(pWFHM->modeTag==32){
+      fprintf(file,"\n*** Mixing Coefficients ***\n");
+      fprintf(file,"222 = %.16f %.16f\n", creal(pWFHM->mixingCoeffs[0]), cimag(pWFHM->mixingCoeffs[0]));
+      fprintf(file,"223 = %.16f %.16f\n", creal(pWFHM->mixingCoeffs[1]), cimag(pWFHM->mixingCoeffs[1]));
+      fprintf(file,"322 = %.16f %.16f\n", creal(pWFHM->mixingCoeffs[2]), cimag(pWFHM->mixingCoeffs[2]));
+      fprintf(file,"323 = %.16f %.16f\n", creal(pWFHM->mixingCoeffs[3]), cimag(pWFHM->mixingCoeffs[3]));
+    }
+
+    fclose(file);
+
+    return 0;
+  }
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_internals.h b/lalsimulation/lib/LALSimIMRPhenomXHM_internals.h
new file mode 100644
index 0000000000000000000000000000000000000000..47d3bc023ee30812ced9ffc01a0f9e31b3c7eead
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_internals.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+//
+//  LALSimIMRPhenomXHM_internals.h
+//
+//
+//  Created by Marta on 06/02/2019.
+//
+
+
+#ifndef _LALSIM_IMR_PHENOMXHM_INTERNALS_H
+#define _LALSIM_IMR_PHENOMXHM_INTERNALS_H
+
+
+#ifdef __cplusplus
+extern "C" {
+  #endif
+  #ifdef __GNUC__
+  #define UNUSED __attribute__((unused))
+  #else
+  #define UNUSED
+  #endif
+
+
+  #include <stdlib.h>
+  #include <stdio.h>
+  #include <math.h>
+  #include <complex.h>
+  #include <gsl/gsl_errno.h>
+  #include <gsl/gsl_spline.h>
+
+  #include <lal/LALStdlib.h>
+  #include <lal/LALConstants.h>
+  #include <lal/Date.h>
+  #include <lal/FrequencySeries.h>
+  #include <lal/Units.h>
+
+  #include "LALSimIMRPhenomXHM_structs.h"
+  #include "LALSimIMRPhenomX_internals.h"
+
+  #include <lal/LALSimIMR.h>
+
+  /* GSL Header Files */
+  #include <gsl/gsl_vector.h>
+  #include <gsl/gsl_matrix.h>
+  #include <gsl/gsl_linalg.h>
+
+
+  #define NMAX_INSPIRAL_COEFFICIENTS 13
+
+  //  You should not declare static functions here, since this file is included in other files apart form the source one.
+
+  /*********** Useful Powers of pi **************/
+  extern IMRPhenomX_UsefulPowers powers_of_lalpiHM;
+
+  /**************** QNMs and mixing coefficients ************** */
+  void IMRPhenomXHM_Initialize_QNMs(QNMFits *qnmsFits);
+  void IMRPhenomXHM_Initialize_MixingCoeffs(IMRPhenomXHMWaveformStruct *wf,IMRPhenomXWaveformStruct *wf22);
+
+  /****************** Initialization of higher-mode waveform struct ******************/
+  void IMRPhenomXHM_SetHMWaveformVariables(int ell, int emm, IMRPhenomXHMWaveformStruct *wf, IMRPhenomXWaveformStruct *wf22, QNMFits *qnms,LALDict *LALParams);
+
+
+  /*************** AMPLITUDE ****************/
+
+  /***************** set pointers to par-space fits *******************/
+  void IMRPhenomXHM_FillAmpFitsArray(IMRPhenomXHMAmpCoefficients *pAmp);
+
+  /***************** Cutting frequencies for amplitude ******************************/
+  double IMRPhenomXHM_Amplitude_fcutInsp(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+  double IMRPhenomXHM_Amplitude_fcutRD(IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+
+  /***************** Amplitude coefficients ****************/
+  void IMRPhenomXHM_GetAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+  void IMRPhenomXHM_GetPNAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXWaveformStruct *pWF22);
+  void Get21PNAmplitudeCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXWaveformStruct *pWF22);
+
+  /**************** Amplitude reconstruction ******************/
+  // Functions that return suitable ansatz at a given frequency
+  double IMRPhenomXHM_Amplitude_noModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMWaveformStruct *pWF);
+  double IMRPhenomXHM_Amplitude_ModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF,  IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22);
+  double IMRPhenomXHM_Amplitude_ModeMixingRecycle(double f, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF);
+
+
+
+  /***************** PHASE *******************/
+
+  /***************** set pointers to par-space fits *******************/
+  void IMRPhenomXHM_FillPhaseFitsArray(IMRPhenomXHMPhaseCoefficients *pPhase);
+  void IMRPhenomXHM_Intermediate_CollocPtsFreqs(IMRPhenomXHMPhaseCoefficients *pPhase,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+
+  /***************** intermediate region reconstruction utilities *******************/
+  void EquidistantNodes(double nodes[], double fmin, double fmax, int npts);
+  double GetfcutInsp(IMRPhenomXWaveformStruct *pWF22, IMRPhenomXHMWaveformStruct *pWFHM);
+
+  /***************** spheroidal->spherical harmonic conversion  *******************/
+  double complex SpheroidalToSpherical(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMAmpCoefficients *pAmplm, IMRPhenomXHMPhaseCoefficients *pPhaselm, IMRPhenomXHMWaveformStruct *pWFlm, IMRPhenomXWaveformStruct *pWF22);
+  double complex SpheroidalToSphericalRecycle(double ff, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmplm, IMRPhenomXHMPhaseCoefficients *pPhaselm, IMRPhenomXHMWaveformStruct *pWFlm);
+
+  /***************** spheroidal-harmonic ringdown reconstruction ********************/
+  void IMRPhenomXHM_Ringdown_CollocPtsFreqs(IMRPhenomXHMPhaseCoefficients *pPhase,IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+  void GetSpheroidalCoefficients(IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+
+  /***************** phase coefficients *****************/
+  int IMRPhenomXHM_PN21AmpSign (double ff,IMRPhenomXWaveformStruct *wf22);
+  void IMRPhenomXHM_GetPhaseCoefficients(IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22, LALDict *lalParams);
+
+  /**************** Phase reconstruction ******************/
+  // functions that return suitable ansatz at a given frequency
+  double IMRPhenomXHM_Phase_noModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF,IMRPhenomXWaveformStruct *pWF22);
+  double IMRPhenomXHM_Phase_ModeMixing(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF,IMRPhenomXAmpCoefficients *pAmp22, IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22);
+  double IMRPhenomXHM_Phase_ModeMixingRecycle(double f, IMRPhenomX_UsefulPowers *powers_of_f, COMPLEX16 wf22, IMRPhenomXHMAmpCoefficients *pAmp, IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWF);
+
+
+  // Debugging function
+  int ParametersToFile(
+    IMRPhenomXWaveformStruct *pWF,           /**< Wf structure for the 22 mode*/
+    IMRPhenomXHMWaveformStruct *pWFHM,         /**< Wf structure for the lm mode*/
+    IMRPhenomXHMAmpCoefficients *pAmp,         /**< Coefficients struct of the lm Amplitude */
+    UNUSED IMRPhenomXHMPhaseCoefficients *pPhase      /**< Coefficients struct of the lm Phase */
+  );
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* LALSimIMRPhenomXHM_internals_h */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.c b/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc0380e90a2cfbe374a4f137460825a02810fa23
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.c
@@ -0,0 +1,2547 @@
+/*
+ * Copyright (C) 2019 Cecilio García Quirós, Sascha Husa
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+ /* This code applies the multibanding technique described in arXiv:2001.10897 to the model IMRPhenomXHM described in arXiv:2001.10914. */
+
+#include <complex.h>
+
+#include <stdio.h>
+#include <math.h>
+
+#include "LALSimIMRPhenomXHM_multiband.h"
+
+
+/*****************************************************/
+/*                                                   */
+/*                MULTIBANDING GRIDS                 */
+/*                                                   */
+/*****************************************************/
+
+/* Build IMRPhenomXMultiBandingGridStruct object, equally-spaced grid */
+IMRPhenomXMultiBandingGridStruct XLALSimIMRPhenomXGridComp(
+  REAL8 fSTART,  /**< Starting frequency of the uniform bin **/
+  REAL8 fEND,    /**< Ending frequency of the uniform bin **/
+  REAL8 mydf     /**< Frequency spacing of the bin **/
+) {
+
+  IMRPhenomXMultiBandingGridStruct myGrid;
+
+  REAL8 Deltaf, maxfreq;
+  INT4 nCoarseIntervals;
+
+  Deltaf = fEND - fSTART;
+  nCoarseIntervals = (int)ceil(Deltaf/mydf);
+  maxfreq = fSTART + mydf * nCoarseIntervals;
+
+  /* Model Version Parameters */
+  myGrid.debug = DEBUG;
+  myGrid.nIntervals = nCoarseIntervals;
+  myGrid.xStart = fSTART;
+  myGrid.xEndRequested = fEND;
+  myGrid.xEndFrom_xStart_dx = maxfreq;
+  myGrid.xMax = maxfreq;
+  myGrid.deltax = mydf;
+  myGrid.Length = nCoarseIntervals + 1;
+
+  #if DEBUG == 1
+  printf("\nGridComp: fSTART = %.16f",fSTART);
+  printf("\nGridComp: xMax = %.16f",maxfreq);
+  printf("\nGridComp: Length = %i",nCoarseIntervals+1);
+  printf("\nGridComp: x0 = %e : x1 = %e : length = %d : mydf = %e\n", myGrid.xStart, myGrid.xMax, myGrid.Length, mydf);
+  #endif
+
+  return myGrid;
+}
+
+/* Build non equally-spaced coarse frequency grid */
+INT4 XLALSimIMRPhenomXMultibandingGrid(
+  REAL8 fstartIn,                             /**< Minimun frequency in NR unit s**/
+  REAL8 fend,                                 /**< End of inspiral frequency bins **/
+  REAL8 MfLorentzianEnd,                      /**< Determines the last frequency bin **/
+  REAL8 Mfmax,                                /**< Maximun frequency in NR units **/
+  REAL8 evaldMf,                              /**< Spacing of the uniform frequency grid (NR units) **/
+  REAL8 dfpower,                              /**< decaying frequency power to estimate frequency spacing **/
+  REAL8 dfcoefficient,                        /**< multiplying factor to the estimate of the frequency spacing **/
+  IMRPhenomXMultiBandingGridStruct *allGrids, /**<[out] list of non-uniform frequency bins**/
+  REAL8 dfmerger,                             /**<[out] Spacing merger bin**/
+  REAL8 dfringdown                            /**<[out] Spacing ringdown bin**/
+){
+  // the df power law: df = dfcoefficient f^dfpower
+
+  INT4 index, intdfRatio;
+  // Variables to control the subgrids to be computed
+  INT4 preComputeFirstGrid, nMergerGrid, nRingdownGrid, nDerefineInspiralGrids;
+
+  /* Object to store information about one subgrid */
+  IMRPhenomXMultiBandingGridStruct coarseGrid;
+  coarseGrid.xMax = fstartIn;
+
+  REAL8 df0, FrequencyFactor=1, nextfSTART, origLogFreqFact;
+  REAL8 fSTART, mydf = evaldMf, fEND, fEndGrid0,fStartInspDerefinement, fEndInsp;
+
+  /* Number of fine freq points between two coarse freq points */
+  /* The numerator of this quantity corresponds to eqs. 2.8, 2.9 in arXiv:2001.10897. */
+  REAL8 const dfRatio = dfcoefficient * pow(fstartIn, dfpower)/evaldMf;
+
+  REAL8 df0original = dfRatio*evaldMf;
+  coarseGrid.deltax = df0original;
+
+  #if DEBUG == 1
+  printf("\ndfcoefficient = %.16e", dfcoefficient);
+  printf("\nfstartIn = %.16e", fstartIn);
+  printf("\ndfpower = %.16e", dfpower);
+  printf("\nevaldMf = %.16e", evaldMf);
+  printf("\ndfRatio = %.16e\n", dfRatio);
+  #endif
+
+  if (dfRatio < 1.0) {
+    /* User asks for a df that is coarser than one predicted by the multibanding criteria, so we take the users's df  */
+    #if DEBUG == 1
+    printf("\n****Adjusting frequency factors!****\n");
+    #endif
+    preComputeFirstGrid = 1;
+    intdfRatio = 1;
+    df0 = evaldMf;
+    fEndGrid0 = pow(evaldMf/dfcoefficient,1./dfpower);
+    fStartInspDerefinement = fEndGrid0 + 2 * df0;
+    #if DEBUG == 1
+    printf("\nevaldMf = %.6f\n", fEndGrid0);
+    printf("\ndfcoefficient = %.6f\n", dfcoefficient);
+    printf("\ndfpower = %.6f\n", dfpower);
+    printf("\nfEndGrid0 = %.6f\n", fEndGrid0);
+    #endif
+  }
+  else {
+    #if DEBUG == 1
+    printf("proceed without preComputeFirstGrid!");
+    #endif
+    preComputeFirstGrid = 0;
+    intdfRatio = (int)floor(dfRatio);
+    fStartInspDerefinement = fstartIn;
+  }
+
+  df0 = evaldMf * intdfRatio;
+
+  #if DEBUG == 1
+  printf("\nintdfRatio = %d\n", intdfRatio);
+  printf("\nfStartInspDerefinement  = %e\n", fStartInspDerefinement );
+  printf("\ndf0, df0original, evaldMf  = %.6e %.6e %.6e\n", df0, df0original, evaldMf );
+  #endif
+
+
+  if (fStartInspDerefinement >= fend) {
+    fEndInsp = fStartInspDerefinement;
+    nDerefineInspiralGrids = 0;
+  }
+  else
+  {
+    // Compute the number of inspiral subgrids needed and the ending frequency
+    FrequencyFactor = pow(2., (1./dfpower));
+    origLogFreqFact = logbase(FrequencyFactor, fend/fStartInspDerefinement);   // This is eq 2.40 in arXiv:2001.10897
+
+    nDerefineInspiralGrids=(int)(ceil(origLogFreqFact));
+    fEndInsp = fStartInspDerefinement * pow(FrequencyFactor,nDerefineInspiralGrids);  // estimate, could change due to boundary effects? maybe need one grid less
+
+    #if DEBUG == 1
+    printf("FrequencyFactor, fend, fStartInspDerefinement, origLogFreqFact: %e : %e : %e :%e\n", FrequencyFactor, fend, fStartInspDerefinement, origLogFreqFact);
+    printf("df0/evaldMf = %e\n", df0/evaldMf);
+    printf("Factor in frequency between adjacent inspiral grids = %e\n",  FrequencyFactor);
+    printf("Number of subgrids required = %d :  unrounded =  : %e\n",  nDerefineInspiralGrids, origLogFreqFact);
+    #endif
+  }
+
+  #if DEBUG == 1
+  printf("\nMfMECO = %.16e\n fEndInsp = %.16e\n MfLorentzianEnd = %.16e\n Mfmax = %.16e\n", fend, fEndInsp, MfLorentzianEnd, Mfmax);
+  #endif
+
+  /* Adjust transition frequencies for special cases. */
+  if (fEndInsp + evaldMf >= MfLorentzianEnd) {
+    nMergerGrid   = 0;
+    if (fEndInsp + evaldMf >= Mfmax) {
+      nRingdownGrid = 0;
+    } else {
+      nRingdownGrid = 1;
+    }
+  } else {
+    nMergerGrid   = 1;
+    nRingdownGrid = 1;
+    if(MfLorentzianEnd > Mfmax){
+      nRingdownGrid = 0;
+    }
+  }
+
+
+  #if DEBUG == 1
+  printf("nMergerGrid = %d\n", nMergerGrid);
+  printf("nRingdownGrid = %d\n", nRingdownGrid);
+  printf("fStartInspDerefinement = %e\n",  fStartInspDerefinement);
+  printf("fEndInsp = %e\n",  fEndInsp);
+  #endif
+
+
+  // Precompute the first grid if needed
+  if (preComputeFirstGrid > 0) {
+
+    mydf = evaldMf;
+    coarseGrid = XLALSimIMRPhenomXGridComp(fstartIn,fEndGrid0,mydf);
+
+    allGrids[0] = coarseGrid;
+    allGrids[0].intdfRatio = 1;
+    #if DEBUG == 1
+    printf("\nAdding preComputeFirstGrid %i\n",preComputeFirstGrid);
+    printf("xStart: %.6f\n", allGrids[0].xStart);
+    printf("xEnd: %.6f\n", allGrids[0].xEndRequested);
+    printf("Length: %i\n", allGrids[0].Length);
+    printf("deltax: %.6e\n", allGrids[0].deltax);
+    printf("xMax: %.6f\n", allGrids[0].xMax);
+    #endif
+
+    fStartInspDerefinement = coarseGrid.xMax;
+    df0  = 2*coarseGrid.deltax;
+    df0original = 2*df0original;
+  }
+
+
+  // Loop over inspiral derefinement grids
+  if (nDerefineInspiralGrids > 0) {
+    index = 0;
+    nextfSTART = fStartInspDerefinement;
+    #if DEBUG == 1
+    printf("nDerefineInspiralGrids before loop = %d\n", nDerefineInspiralGrids);
+    #endif
+
+    while (index < nDerefineInspiralGrids) {
+      if(df0original < evaldMf){
+        #if DEBUG == 1
+          printf("\nAdjusting freq factors!!\n");
+        #endif
+        mydf = evaldMf;
+        intdfRatio = 1;
+      }
+      else{
+        intdfRatio = (int)floor(df0original/evaldMf);
+        mydf = evaldMf*intdfRatio;
+      }
+      if(index + preComputeFirstGrid == 0){
+         fSTART = nextfSTART;
+      }
+      else{
+        fSTART = nextfSTART + mydf;
+      }
+      fEND = fSTART * FrequencyFactor;
+
+      #if DEBUG == 1
+      printf("\n(index, fSTART, fEND) = (%d, %e, %e, %e)\n", index + preComputeFirstGrid, fSTART, fEND, mydf);
+      #endif
+
+      coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, fEND, mydf);
+
+      #if DEBUG == 1
+      printf("xStart: %.16e\n", coarseGrid.xStart);
+      printf("xEnd: %.16e\n", coarseGrid.xEndRequested);
+      printf("Length: %i\n", coarseGrid.Length);
+      printf("deltax: %.16e\n", coarseGrid.deltax);
+      printf("mydf: %.16e\n", mydf);
+      printf("xMax: %.16e\n", coarseGrid.xMax);
+      printf("intdfRatio = %i\n", intdfRatio);
+      #endif
+
+      df0original = 2*df0original;
+      //nextmydf   = 2 * mydf;
+      nextfSTART = coarseGrid.xMax;
+
+      allGrids[index + preComputeFirstGrid] = coarseGrid;
+      allGrids[index+preComputeFirstGrid].intdfRatio = intdfRatio;
+
+      index = index + 1;
+    }
+    fEndInsp = coarseGrid.xMax;
+  }
+  else{
+    #if DEBUG == 1
+    printf("\nSkipping Inspiral Loop %i\n", nDerefineInspiralGrids);
+    #endif
+    if (preComputeFirstGrid > 0){
+      fEndInsp = coarseGrid.xMax;
+    }
+  }
+
+  #if DEBUG == 1
+  printf("\nfStartInspDerefinement after loop = %e\n",  fStartInspDerefinement);
+  printf("fEndInsp after loop = %e\n",  fEndInsp);
+  printf("nDerefineInspiralGrids = %i\n", nDerefineInspiralGrids);
+  #endif
+
+  // Add merger grid
+  if (nMergerGrid > 0) {
+    df0original = dfmerger; //check if the Delta_f given by the Lorentzian is smaller than at the beginning of the merger bin.
+    if(2*coarseGrid.deltax < dfmerger){
+      df0original = 2*coarseGrid.deltax;
+    }
+    if(df0original < evaldMf){
+      #if DEBUG == 1
+        printf("\nAdjusting freq factors!!\n");
+      #endif
+      mydf = evaldMf;
+      intdfRatio = 1;
+    }
+    else{
+      intdfRatio = (int)floor(df0original/evaldMf);
+      mydf = evaldMf*intdfRatio;
+    }
+    fSTART = fEndInsp + mydf;
+
+    if(fEndInsp == fstartIn){
+      fSTART = fEndInsp;
+    }
+
+    INT4 mergerIndex = 0;
+
+    if(fSTART > MfLorentzianEnd){
+      nMergerGrid = 0;
+      #if DEBUG == 1
+      printf("\nNOT adding merger grid\n");
+      #endif
+    }
+    else{
+      coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, MfLorentzianEnd, mydf);
+      mergerIndex = preComputeFirstGrid + nDerefineInspiralGrids;
+
+      df0original = 2*df0original;
+
+      allGrids[mergerIndex] = coarseGrid;
+      allGrids[mergerIndex].intdfRatio = intdfRatio;
+
+      #if DEBUG == 1
+      printf("\nadding merger grid\n");
+      printf("fSTART = %.6f\n", fSTART);
+      printf("fEND = %.6f\n", coarseGrid.xMax);
+      printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
+      printf("mydf = %.16e\n", mydf);
+      printf("mergerIndex = %i\n", mergerIndex);
+      printf("intdfRatio = %i\n", intdfRatio);
+      printf("# fine points float %.16f\n", allGrids[mergerIndex].deltax/evaldMf);
+      #endif
+    }
+
+
+  }
+
+  // Add RD grid
+  if (nRingdownGrid > 0) {
+      df0original = dfringdown;
+      if(df0original < evaldMf){
+        #if DEBUG == 1
+          printf("\nAdjusting freq factors!!\n");
+        #endif
+        mydf = evaldMf;
+        intdfRatio = 1;
+      }
+      else{
+        intdfRatio = (int)floor(df0original/evaldMf);
+        mydf = evaldMf*intdfRatio;
+      }
+      fSTART = coarseGrid.xMax + mydf;
+      if(coarseGrid.xMax == fstartIn){
+        fSTART = fEndInsp;
+      }
+
+      INT4 RDindex = 0;
+
+      if(fSTART > Mfmax){
+        nRingdownGrid = 0;
+        #if DEBUG == 1
+        printf("\nNOT adding RD grid\n");
+        #endif
+      }
+      else{
+        coarseGrid = XLALSimIMRPhenomXGridComp(fSTART, Mfmax, mydf);
+
+        RDindex = preComputeFirstGrid + nDerefineInspiralGrids + nMergerGrid;
+
+        df0original = 2*df0original;
+
+        allGrids[RDindex] = coarseGrid;
+        allGrids[RDindex].intdfRatio = intdfRatio;
+
+        #if DEBUG == 1
+        printf("\nadding RD grid\n");
+        printf("Mfmax = %e\n", Mfmax);
+        printf("fSTART = %.6f\n", fSTART);
+        printf("fEND = %.6f\n", coarseGrid.xMax);
+        printf("mydf = %.16e\n", mydf);
+        printf("RDIndex = %i\n", RDindex);
+        printf("intdfRatio = %i\n", intdfRatio);
+        printf("# fine points float %.16f\n", allGrids[RDindex].deltax/evaldMf);
+        #endif
+      }
+  }
+
+  INT4 nGridsUsed = preComputeFirstGrid + nDerefineInspiralGrids + nMergerGrid+nRingdownGrid;
+  #if DEBUG == 1
+  printf("final grid length = %d\n", nGridsUsed);
+  printf("intdfRatio = %d\n", intdfRatio);
+  #endif
+
+  return nGridsUsed;
+}
+
+/**
+ * @addtogroup LALSimIMRPhenomX_c
+ * @{
+ * @name Routines for IMRPhenomXHM Multibanding
+ * @{
+ *
+ */
+
+/*****************************************************/
+/*                                                   */
+/*            MULTIBANDING WAVEFORMS                 */
+/*                                                   */
+/*****************************************************/
+
+/** Return htildelm, the waveform of one mode without mode-mixing.
+ e^(I phi) is interpolated with linear order and an iterative procedure.
+   Amplitude uses standard 1st (by default) or 3rd order interpolation with gsl. */
+int XLALSimIMRPhenomXHMMultiBandOneMode(
+  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  UINT4 ell,                           /**< l index of the mode */
+  INT4 emmIn,                            /**< m index of the mode */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = \ref f_CUT */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< Extra params */
+){
+  UINT4 emm = abs(emmIn);
+  #if DEBUG == 1
+  printf("\nMode %i %i \n",ell,emm);
+  printf("fRef_In : %e\n",fRef_In);
+  printf("m1_SI   : %e\n",m1_SI);
+  printf("m2_SI   : %e\n",m2_SI);
+  printf("chi1L   : %e\n",chi1L);
+  printf("chi2L   : %e\n\n",chi2L);
+  printf("Performing sanity checks...\n");
+  #endif
+
+  /* Sanity checks */
+  if(*htildelm)       { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT);                                   }
+  if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+  if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+  if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+  if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+  if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+  if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+  if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+
+  #if DEBUG == 1
+  printf("\n**********************************************************************\n");
+  printf("\n*                IMRPhenomXHMMultiBandOneMode        %i%i            *\n", ell, emm);
+  printf("\n**********************************************************************\n");
+  printf("\nm1, m2, chi1, chi2 %.16f %.16f %.16f %.16f\n", m1_SI/LAL_MSUN_SI, m2_SI/LAL_MSUN_SI, chi1L, chi2L);
+  #endif
+
+
+  /* When mode does not vanishes */
+  int debug = DEBUG;
+
+  // Define two powers of pi to avoid clashes between PhenomX and PhenomXHM files.
+  int status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+  status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PIHM.");
+
+  /* Initialize IMRPhenomX Waveform struct and check that it initialized correctly */
+  IMRPhenomXWaveformStruct *pWF;
+  pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef_In, phiRef, f_min, f_max, distance, 0.0, lalParams, debug);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+
+  int offset = IMRPhenomXHMMultiBandOneMode(htildelm, pWF, ell, emm, lalParams);
+
+  if(emmIn>0){
+    /* (-1)^l */
+   INT4 minus1l = 1;
+   if (ell % 2 !=0){
+     minus1l = -1;
+   }
+   #if DEBUG == 1
+    printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+    #endif
+    for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+      (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
+    }
+  }
+
+  REAL8 lastfreq;
+  /* Resize htildelm if needed */
+  if (pWF->f_max_prime < pWF->fMax)
+  { /* The user has requested a higher f_max than Mf = fCut.
+    Resize the frequency series to fill with zeros beyond the cutoff frequency. */
+    lastfreq = pWF->fMax;
+  }
+  else{  // We have to look for a power of 2 anyway. Without MBAND this step is already satisfied
+    lastfreq = pWF->f_max_prime;
+  }
+  // We want to have the length be a power of 2 + 1
+  size_t n_full = NextPow2(lastfreq / deltaF) + 1;
+  size_t n = (*htildelm)->data->length;
+
+  /* Resize the COMPLEX16 frequency series */
+  *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
+  XLAL_CHECK (*htildelm, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
+
+  LALFree(pWF);
+
+  return offset;
+
+}
+
+int IMRPhenomXHMMultiBandOneMode(
+    COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform **/
+    IMRPhenomXWaveformStruct *pWF,       /**< Waveform structure 22 mode **/
+    UINT4 ell,                           /**< First index (l,m) mode **/
+    UINT4 emm,                           /**< Second incex (l,m) mode **/
+    LALDict *lalParams                   /**< LAL dictionary **/
+)
+{
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  REAL8 deltaF = pWF->deltaF;
+  pWF->deltaF = 0; // Needed for SetupWFArraysReal function, if not introduces an extra offset in amplitude and phase.
+
+  /* Check that the frequency array will be consistent: fmin < fmax_prime */
+  /* Return the closest power of 2 */
+  size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+  /* Frequencies will be set using only the lower and upper bounds that we passed */
+  size_t iStart = (size_t) (pWF->fMin / deltaF);
+  size_t iStop  = (size_t) (pWF->f_max_prime / deltaF) + 1;
+  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+  size_t offset = iStart;
+
+
+  /* If it is odd mode with equal black holes then return array of zeros 0 */
+  if(pWF->m1_SI == pWF->m2_SI && pWF->chi1L == pWF->chi2L && emm%2!=0){  // Mode zero
+
+    *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, iStop);
+    for(unsigned int idx = 0; idx < iStop; idx++){
+      ((*htildelm)->data->data)[idx] = 0.;
+    }
+
+    return offset;
+  }
+
+  /** Mode non-zero **/
+
+
+  /* Final grid spacing, adimensional (NR) units */
+  REAL8 evaldMf = XLALSimIMRPhenomXUtilsHztoMf(deltaF, pWF->Mtot);
+
+  /* Threshold for the Multibanding. It is a measure of how restrictive it is. Smaller value implies stronger restriction, more points where evaluate the model. */
+  REAL8 resTest  = XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(lalParams);
+  UINT4 ampinterpolorder = XLALSimInspiralWaveformParamsLookupPhenomXHMAmpInterpolMB(lalParams);
+  #if DEBUG == 1
+  printf("\n***** MBAND = %i, resTest = %.16f, ampIntorder = %i\n", MBAND, resTest, ampinterpolorder);
+  #endif
+  /* Variable for the Multibanding criteria */
+  REAL8 dfpower = 11./6.;
+  REAL8 dfcoefficient = 8. * sqrt(3./5.) * LAL_PI * powers_of_lalpi.m_one_sixth * sqrt(2.)*cbrt(2) /(cbrt(emm)*emm) * sqrt(resTest * pWF->eta);
+  /* Variables for the coarse frequency grid */
+  REAL8 Mfmin = XLALSimIMRPhenomXUtilsHztoMf(iStart*deltaF, pWF->Mtot);
+  REAL8 Mfmax = XLALSimIMRPhenomXUtilsHztoMf(pWF->f_max_prime, pWF->Mtot);
+  REAL8 MfMECO, MfLorentzianEnd;
+  REAL8 dfmerger = 0., dfringdown = 0.;//, relerror = 0.001;
+
+
+  IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+  //Initialize pWFHM, pAmp(22), pPhase(22) and pass to the functions. No l, m needed
+  //populate coefficients of 22 mode, to rotate to spherical
+  IMRPhenomXAmpCoefficients   *pAmp22   = (IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+  IMRPhenomXPhaseCoefficients *pPhase22 = (IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+  IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+
+  /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
+  IMRPhenomXHMAmpCoefficients *pAmp = (IMRPhenomXHMAmpCoefficients*)XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+  IMRPhenomXHMPhaseCoefficients *pPhase = (IMRPhenomXHMPhaseCoefficients*)XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+
+  if(ell == 2 && emm ==2){
+    MfMECO = pWF->fMECO;
+    #if DEBUG == 1
+    printf("\nfRING = %e\n",pWF->fRING);
+    printf("fDAMP = %e\n",pWF->fDAMP);
+    printf("alphaL22 = %.16e", pPhase22->cLovfda/pWF->eta);
+    #endif
+    MfLorentzianEnd = pWF->fRING + 2*pWF->fDAMP;
+    IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+    dfmerger = deltaF_mergerBin(pWF->fDAMP, pPhase22->cLovfda/pWF->eta, resTest);
+    dfringdown = deltaF_ringdownBin(pWF->fDAMP, pPhase22->cLovfda/pWF->eta, pAmp22->gamma2/(pAmp22->gamma3*pWF->fDAMP),resTest);
+  }
+  else{
+    // allocate qnm struct
+    QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+    IMRPhenomXHM_Initialize_QNMs(qnms);
+    // Populate pWFHM
+    IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF,qnms, lalParams);
+    LALFree(qnms);
+
+    /* Allocate and initialize the PhenomXHM lm phase and amp coefficients struct */
+    IMRPhenomXHM_FillAmpFitsArray(pAmp);
+    IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+
+    /* Get coefficients for Amplitude and phase */
+    IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+    IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
+
+    MfMECO = pWFHM->fMECOlm;
+    MfLorentzianEnd = pWFHM->fRING + 2*pWFHM->fDAMP;
+    #if DEBUG == 1
+    printf("\nfRING = %e\n",pWFHM->fRING);
+    printf("fDAMP = %e\n",pWFHM->fDAMP);
+    printf("alphaL = %.16e", pPhase->alphaL);
+    #endif
+    dfmerger = deltaF_mergerBin(pWFHM->fDAMP, pPhase->alphaL, resTest);
+    dfringdown = deltaF_ringdownBin(pWFHM->fDAMP, pPhase->alphaL, pAmp->lambda/(pAmp->sigma*pWFHM->fDAMP), resTest);
+  }
+
+  /* Allocate memory for the list of grids. The number of grids must be less than lengthallGrids. */
+  UINT4 lengthallGrids = 20;
+  IMRPhenomXMultiBandingGridStruct *allGrids = (IMRPhenomXMultiBandingGridStruct*)XLALMalloc(lengthallGrids * sizeof(IMRPhenomXMultiBandingGridStruct));
+
+  if (allGrids == NULL)
+  {
+    #if DEBUG == 1
+    printf("Malloc of allGrids failed!\n");
+    #endif
+    return -1;
+  }
+
+  #if DEBUG == 1
+  printf("\nMfmin = %.6f\n", Mfmin);
+  printf("MfMECO = %.6f\n", MfMECO);
+  printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
+  printf("Mfmax = %.6f\n", Mfmax);
+  printf("evaldMf = %.6e\n", evaldMf);
+  printf("dfpower = %.6e\n", dfpower);
+  printf("dfcoefficient = %.6e\n", dfcoefficient);
+  printf("dfmerger = %.6e\n", dfmerger);
+  printf("dfringdown = %.6e\n", dfringdown);
+  #endif
+
+  /* Compute the coarse frequency array. It is stored in a list of grids. */
+  UINT4 nGridsUsed = XLALSimIMRPhenomXMultibandingGrid(Mfmin, MfMECO, MfLorentzianEnd, Mfmax, evaldMf, dfpower, dfcoefficient, allGrids, dfmerger, dfringdown);
+
+  #if DEBUG == 1
+  printf("allGrids[1].Length = %i\n", allGrids[0].Length);
+  #endif
+
+  /* Number of fine frequencies per coarse interval in every coarse grid */
+  INT4 mydfRatio[lengthallGrids];
+  /* Actual number of subgrids to be used. We allocated more than needed. */
+  UINT4 actualnumberofGrids = 0;
+  /* Length of coarse frequency array */
+  UINT4 lenCoarseArray = 0;
+
+  /* Transform the coarse frequency array to 1D array. */
+  // Take only the subgrids needed
+  for(UINT4 kk = 0; kk < nGridsUsed; kk++){
+    lenCoarseArray = lenCoarseArray + allGrids[kk].Length;
+    actualnumberofGrids++;
+
+    mydfRatio[kk] = allGrids[kk].intdfRatio;
+
+    #if DEBUG == 1
+    printf("\nkk = %i\n",kk);
+    printf("xStart: %.6e\n", allGrids[kk].xStart);
+    printf("xEnd: %.6e\n", allGrids[kk].xEndRequested);
+    printf("Length: %i\n", allGrids[kk].Length);
+    printf("deltax, Hz: %.6e %.6e\n", allGrids[kk].deltax, XLALSimIMRPhenomXUtilsMftoHz(allGrids[kk].deltax, pWF->Mtot));
+    printf("evaldMf, Hz: %.6e %.6e\n", evaldMf, XLALSimIMRPhenomXUtilsMftoHz(evaldMf, pWF->Mtot));
+    printf("xMax: %.16e\n", allGrids[kk].xMax);
+    printf("Mfmax: %.16e\n", Mfmax);
+    printf("# fine points %i\n", mydfRatio[kk]);
+    printf("# fine points float %.16f\n", allGrids[kk].deltax/evaldMf);
+    #endif
+
+    if(allGrids[kk].xMax + evaldMf >= Mfmax){
+      break;
+    }
+  }
+
+  // Add extra points to the coarse grid if the last freq is lower than Mfmax
+  while(allGrids[actualnumberofGrids-1].xMax < Mfmax){
+    allGrids[actualnumberofGrids-1].xMax =   allGrids[actualnumberofGrids-1].xMax +  allGrids[actualnumberofGrids-1].deltax;
+    allGrids[actualnumberofGrids-1].Length =  allGrids[actualnumberofGrids-1].Length + 1;
+    lenCoarseArray++;
+  }
+
+  #if DEBUG == 1
+  if(ell==2 && emm==2){
+    printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWF->fDAMP, pWF->Mtot));
+  }else{
+    printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWFHM->fDAMP, pWF->Mtot));
+  }
+  printf("actualnumberofGrids = %i\n", actualnumberofGrids);
+  printf("lenCoarseArray = %i\n", lenCoarseArray);
+  printf("Last grid.xMax = %.16f", allGrids[actualnumberofGrids-1].xMax);
+  #endif
+
+  // Transform coarse frequency array to 1D vector
+  REAL8 *IntLawpoints = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
+  UINT4 lenIntLawpoints = 0;
+
+  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
+    for(INT4 ll = 0; ll < allGrids[kk].Length; ll++){
+      IntLawpoints[lenIntLawpoints] = (allGrids[kk].xStart + allGrids[kk].deltax*ll);
+      lenIntLawpoints++;
+    }
+  }
+  /* End of coarse frequency array. */
+
+  #if DEBUG == 1
+  printf("\n******** Coarse frequencies array done ********* \n");
+  printf("\nlenIntLawpoints, coarse[0], coarse[-1], Mfmax, M_sec = %i %.16e %.16e %.16e %.16e\n",lenIntLawpoints, IntLawpoints[0], IntLawpoints[lenIntLawpoints-1], Mfmax, pWF->M_sec);
+  #endif
+
+  /* IntLawpoints stores the adimensional frequencies (Mf) */
+  /* coarseFreqs will store the same frequency array but in Hz */
+  /* Allocate memory for frequency array and terminate if this fails */
+  REAL8Sequence *coarseFreqs;
+  coarseFreqs = XLALCreateREAL8Sequence(lenCoarseArray);
+  if (!coarseFreqs) {XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); }
+
+  /* Populate frequency array */
+  #if DEBUG == 1
+  printf("\n***** Coarse freqs *****\n");
+  #endif
+  REAL8 divis = 1./pWF->M_sec;
+  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
+  {
+    coarseFreqs->data[ii] = IntLawpoints[ii]*divis;
+  }
+  #if DEBUG == 1
+  printf("\nFirst/Last Coarse freqs *****%.16e %.16e\n", coarseFreqs->data[0], coarseFreqs->data[coarseFreqs->length-1]);
+  #endif
+
+  /* Next we will compute amplitude and phase of one mode in the coarse frequency array. */
+
+  REAL8FrequencySeries *amplitude, *phase;
+
+  /** Compute 22 using PhenomX functions **/
+  // This is copied from IMRPhenomXASGenerateFD.
+  if(ell == 2 && emm ==2){
+    #if DEBUG == 1
+    printf("\n** Computing Amplitude and Phase of PhenomX %i **********\n", lenCoarseArray);
+    #endif
+
+    amplitude = XLALCreateREAL8FrequencySeries("amplitude22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,coarseFreqs->length);
+    phase     = XLALCreateREAL8FrequencySeries("phase22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,coarseFreqs->length);
+
+    IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+
+    /* Initialize a struct containing useful powers of Mf at fRef */
+    IMRPhenomX_UsefulPowers powers_of_MfRef;
+    int status = IMRPhenomX_Initialize_Powers(&powers_of_MfRef,pWF->MfRef);
+    XLAL_CHECK(XLAL_SUCCESS == status, status, "IMRPhenomX_Initialize_Powers failed for MfRef.\n");
+
+
+    /* Linear time and phase shifts so that model peaks near t ~ 0 */
+    REAL8 lina = 0;
+
+    IMRPhenomX_Phase_22_ConnectionCoefficients(pWF,pPhase22);
+    double linb=IMRPhenomX_TimeShift_22(pPhase22, pWF);
+
+    // Calculate IMRPhenomX phase at reference frequency
+    REAL8 phiref22 = -1./pWF->eta*IMRPhenomX_Phase_22(pWF->MfRef, &powers_of_MfRef, pPhase22, pWF) - linb*pWF->MfRef - lina + 2.0*pWF->phi0 + LAL_PI_4;
+
+
+    for(UINT4 kk = 0; kk < (coarseFreqs)->length; kk++){
+      REAL8 Mff = coarseFreqs->data[kk]*pWF->M_sec;
+      IMRPhenomX_UsefulPowers powers_of_f;
+      IMRPhenomX_Initialize_Powers(&powers_of_f,Mff);
+      amplitude->data->data[kk] = IMRPhenomX_Amplitude_22(Mff, &powers_of_f, pAmp22, pWF) * pWF->amp0;
+      phase->data->data[kk] = 1./pWF->eta*IMRPhenomX_Phase_22(Mff, &powers_of_f, pPhase22, pWF) + linb*Mff + lina + phiref22;
+    }
+  }
+  /** Higher modes **/
+  else{
+
+    #if DEBUG == 1
+    printf("\n******* Computing Coarse Amplitude And Phase ****************\n");
+    #endif
+    /* Compute coarse amplitude and phase */
+    IMRPhenomXHM_Amplitude(&amplitude, coarseFreqs, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
+    IMRPhenomXHM_Phase(&phase, coarseFreqs, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
+  }
+
+  #if DEBUG == 1
+  printf("\n******* Computed Coarse Amp and Phase **************** %i\n", coarseFreqs->length);
+  #endif
+
+  /* Transform the REAL8FrequencySeries to vector since gsl uses vectors for the interpolation.
+     gsl is only used for the amplitude but to keep the code more symmetric we transform also the phase. */
+  REAL8 *ILamplm = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
+  REAL8 *ILphaselm = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
+
+  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
+  {
+    ILamplm[ii] = ((amplitude)->data->data)[ii];
+    ILphaselm[ii] = ((phase)->data->data)[ii];
+  }
+
+  #if DEBUG == 1
+  //Save coarse amplitude and phase in file
+  FILE *file0;
+  char fileSpec0[40];
+  sprintf(fileSpec0, "coarseamplitude%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec0);
+  file0 = fopen(fileSpec0,"w");
+  fprintf(file0,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  FILE *file3;
+  char fileSpec3[40];
+  sprintf(fileSpec3, "coarsephase%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec3);
+  file3 = fopen(fileSpec3,"w");
+  fprintf(file3,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  for(UINT4 idx = 0; idx < lenCoarseArray; idx++)
+  {
+    fprintf(file0, "%.16f  %.16e \n",  coarseFreqs->data[idx], ILamplm[idx]);
+    fprintf(file3, "%.16f  %.16e \n",  coarseFreqs->data[idx], ILphaselm[idx]);
+  }
+  fclose(file0);
+  fclose(file3);
+  #endif
+
+  /* Free allocated memory */
+  XLALDestroyREAL8FrequencySeries(amplitude);
+  XLALDestroyREAL8FrequencySeries(phase);
+  XLALDestroyREAL8Sequence(coarseFreqs);
+
+  /***** Linear Interpolation of e^(I*phi) with the iterative procedure *****/
+
+  /* Estimation of the length of the fineGrid */
+  INT4 lenWF = 0;
+
+  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
+    lenWF = lenWF + (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk];
+    #if DEBUG == 1
+    printf("\nmydfRatio[%i] = %i %i %i", kk, mydfRatio[kk],allGrids[kk].Length, (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk]);
+    printf("\nlenWF = %i\n\n", lenWF);
+    #endif
+  }
+
+  // Variable to control the number of coarse points we have used
+  int pointsPrecessedSoFar = 0;
+
+  /* Allocate memory for the complex exponential and the fine equally-spaced frequency array */
+  COMPLEX16 *expphi = (COMPLEX16*)XLALMalloc(lenWF*sizeof(COMPLEX16));
+  if (expphi == NULL){
+    return -1;
+  }
+
+  REAL8 *finefreqs = (REAL8*)XLALMalloc(lenWF*sizeof(REAL8));
+  if (finefreqs == NULL){
+    return -1;
+  }
+
+  UINT4 count = 0; // Variable to track the point being filled in the fine frequency grid
+
+  /* Loop over allgrids */
+  bool stop = false;
+  for (UINT4 i = 0; i<actualnumberofGrids && !stop; i++){
+    #if DEBUG == 1
+    printf("\ni = %i\n", i);
+    #endif
+
+    UINT4 lcoarseGrid = allGrids[i].Length;
+    if(lcoarseGrid == 0){
+      break;
+    }
+
+    /* Linear Interpolation and iteration, here I get fineGridResult */
+    if(i==actualnumberofGrids-1){
+      lcoarseGrid--;
+    }
+
+    REAL8 Omega, phi0, Mfhere = 0, Mfnext = 0;
+    COMPLEX16 h0, Q;
+
+    /* Loop over the coarse points of a subgrid */
+    for(UINT4 j = 0; j < lcoarseGrid && !stop ; j++){
+      Mfhere = IntLawpoints[pointsPrecessedSoFar + j];
+      Mfnext = IntLawpoints[pointsPrecessedSoFar + j + 1];
+
+      INT4 ratio;
+      // If we are in the last coarse point of a sublist we use the number of fine points of the next subgrid.
+      if(j==lcoarseGrid-1 && i < actualnumberofGrids-1){
+        ratio = mydfRatio[i+1];
+      }
+      else{
+        ratio = mydfRatio[i];
+      }
+      if(Mfnext + evaldMf >= Mfmax){
+        double dratio = (Mfmax - Mfhere)/evaldMf + 1;
+        ratio = (int) dratio;
+        int roundratio = round((Mfmax - Mfhere)/evaldMf) + 1;
+        if(fabs(dratio-roundratio) < 0.0001) ratio = roundratio; //To get the correct rounded integer
+        /* Break the loop if you overpass the maximun frequency */
+        stop = true;
+        #if DEBUG == 1
+        printf("\nMfmax, Mfhere, evaldMf, ratio, lastfreqHz= %.16f %.16f %.16f %i %.16e\n", Mfmax, Mfhere, evaldMf, ratio, XLALSimIMRPhenomXUtilsMftoHz(Mfhere+(ratio-1)*evaldMf,pWF->Mtot) );
+        #endif
+      }
+
+      /********************************************/
+      /*     Inner Loop: linear interpolation     */
+      /********************************************/
+      UINT4 jjdx = j + pointsPrecessedSoFar;
+      if(jjdx < lenCoarseArray){
+        Omega = (ILphaselm[jjdx+ 1] - ILphaselm[jjdx])/(IntLawpoints[jjdx + 1] - IntLawpoints[jjdx]);
+      }
+      else{
+        Omega = (ILphaselm[jjdx] - ILphaselm[jjdx -1])/(IntLawpoints[jjdx] - IntLawpoints[jjdx -1]);
+      }
+      phi0 = ILphaselm[jjdx];
+
+      h0   = cexp(I*phi0);
+      Q    = cexp(I*evaldMf*Omega);
+
+      finefreqs[count] = Mfhere;
+      expphi[count]    = h0;
+      count++;
+
+      /* This loop carry out the eq. 2.32 in arXiv:2001.10897 */
+      for(int kk = 1; kk < ratio; kk++){       // Compute finefreqs and fine expphi
+        finefreqs[count] = Mfhere + evaldMf*kk;
+        expphi[count]    = Q*expphi[count-1];
+        count++;
+      }
+
+    }
+    pointsPrecessedSoFar = pointsPrecessedSoFar + lcoarseGrid;
+  }// End loop over ILgrids. count should be aprox = to lenWF
+
+  #if DEBUG == 1
+  printf("\ncount = %i\n", count);
+  #endif
+
+  #if DEBUG == 1
+  printf("\n******* Interpolate Amplitude **********\n");
+  #endif
+
+  /*** Interpolation and evaluation in fineFreqs of the amplitude ***/
+  REAL8 *fineAmp = (REAL8*)XLALMalloc(count * sizeof(REAL8));
+  interpolateAmplitude(fineAmp, IntLawpoints, ILamplm, finefreqs, lenCoarseArray, count, ampinterpolorder);
+
+  /**** Build the waveform ****/
+  // Due to round of erros, the last freq may be greater Mfmax. The difference should be less than the frequency step.
+  // Remove that extra frequency point
+  while(finefreqs[count-1] > Mfmax){
+    count--;
+  }
+  #if DEBUG == 1
+  printf("\n******* Building Waveform 2**********\n");
+  printf("\nfinefreqs[0]Hz = %.16f\n", finefreqs[0]/pWF->M_sec);
+  printf("\nfinefreqs[%i]Hz = %.16f\n", count-1, finefreqs[count-1]/pWF->M_sec);
+  printf("Mfmax in Hz = %.16f\n", Mfmax/pWF->M_sec);
+  printf("count, offset = %i %zu\n", count-1, offset);
+  printf("Mfmaxtheory = %.16f\n", (count-1+offset)*deltaF);
+  #endif
+
+  /* Intialize FrequencySeries for htildelm */
+  size_t n = count + offset;
+  XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", deltaF);
+  *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
+
+  for(int idx = 0; idx < (int) offset; idx++){
+    ((*htildelm)->data->data)[idx] = 0.;
+  }
+
+   /* (-1)^l */
+  INT4 minus1l;
+  if (ell % 2 !=0){
+    minus1l = -1;
+  }
+  else{
+    minus1l = +1;
+  }
+
+  for(UINT4 idx = 0; idx < count; idx++){
+    /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+    ((*htildelm)->data->data)[idx + offset] = minus1l * fineAmp[idx] * expphi[idx];
+  }
+
+  /* Free allocated memory */
+  LALFree(pAmp);
+  LALFree(pAmp22);
+  LALFree(pPhase);
+  LALFree(pPhase22);
+
+
+  #if DEBUG == 1
+  //Save hlm in file
+  FILE *file;
+  char fileSpec[40];
+  sprintf(fileSpec, "simulation%i%i_Multiband.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec);
+  file = fopen(fileSpec,"w");
+  fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  fprintf(file,"# Frequency (Hz)    Real    Imaginary\n");
+  COMPLEX16 data;
+  for(UINT4 idx = 0; idx < count; idx++)
+  {
+    data = expphi[idx];
+    fprintf(file, "%.16f  %.16e %.16e\n",  idx*deltaF, creal(data), cimag(data));
+  }
+  fclose(file);
+  #endif
+
+  #if DEBUG == 1
+  //Save fine amplitude and freq array in file
+  FILE *file2;
+  char fileSpec2[40];
+  sprintf(fileSpec2, "amplitude%i%i_fine.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec2);
+  file2 = fopen(fileSpec2,"w");
+  fprintf(file2,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  printf("\ncount, count + offset, len htildelm = %i %i %i\n", count, (int)(count + offset), (*htildelm)->data->length);
+  for(UINT4 idx = 0; idx < count; idx++)
+  {
+    fprintf(file2, "%.16f  %.16f %.16e\n",  finefreqs[idx], (idx+offset)*evaldMf, fineAmp[idx]);
+  }
+  fclose(file2);
+  #endif
+
+  /* Free allocated memory */
+  LALFree(expphi);
+  LALFree(finefreqs);
+  LALFree(allGrids);
+  LALFree(fineAmp);
+  LALFree(pWFHM);
+  LALFree(ILamplm);
+  LALFree(ILphaselm);
+  LALFree(IntLawpoints);
+
+  return offset;
+}
+
+
+
+/** Returns htildelm the waveform of one mode that present mode-mixing.
+The multibanding is applied to the spherical part (inspiral and intermediate) and to the spheroidal part (ringdown).
+Both are interpolated and evaluated in the fine frequency grid and the ringdown part is rotated back to spherical */
+int XLALSimIMRPhenomXHMMultiBandOneModeMixing(
+  COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+  COMPLEX16FrequencySeries *htilde22,  /**< Precomputed FD waveform of dominant mode */
+  REAL8 m1_SI,                         /**< Mass of companion 1 (kg) */
+  REAL8 m2_SI,                         /**< Mass of companion 2 (kg) */
+  REAL8 chi1L,                         /**< Dimensionless aligned spin of companion 1 */
+  REAL8 chi2L,                         /**< Dimensionless aligned spin of companion 2 */
+  UINT4 ell,                           /**< l index of the mode */
+  INT4 emmIn,                           /**< m index of the mode */
+  REAL8 distance,                      /**< Luminosity distance (m) */
+  REAL8 f_min,                         /**< Starting GW frequency (Hz) */
+  REAL8 f_max,                         /**< End frequency; 0 defaults to Mf = \ref f_CUT */
+  REAL8 deltaF,                        /**< Sampling frequency (Hz) */
+  REAL8 phiRef,                        /**< Orbital phase at fRef (rad) */
+  REAL8 fRef_In,                       /**< Reference frequency (Hz) */
+  LALDict *lalParams                   /**< Extra params */
+){
+  UINT4 emm = abs(emmIn);
+  #if DEBUG == 1
+  printf("\nMode %i %i \n",ell,emm);
+  printf("fRef_In : %e\n",fRef_In);
+  printf("m1_SI   : %e\n",m1_SI);
+  printf("m2_SI   : %e\n",m2_SI);
+  printf("chi1L   : %e\n",chi1L);
+  printf("chi2L   : %e\n\n",chi2L);
+  printf("Performing sanity checks...\n");
+  #endif
+
+  /* Sanity checks */
+  if(*htildelm)       { XLAL_CHECK(NULL != htildelm, XLAL_EFAULT);                                   }
+  if(fRef_In  <  0.0) { XLAL_ERROR(XLAL_EDOM, "fRef_In must be positive or set to 0 to ignore.\n");  }
+  if(deltaF   <= 0.0) { XLAL_ERROR(XLAL_EDOM, "deltaF must be positive.\n");                         }
+  if(m1_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m1 must be positive.\n");                             }
+  if(m2_SI    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "m2 must be positive.\n");                             }
+  if(f_min    <= 0.0) { XLAL_ERROR(XLAL_EDOM, "f_min must be positive.\n");                          }
+  if(f_max    <  0.0) { XLAL_ERROR(XLAL_EDOM, "f_max must be non-negative.\n");                      }
+  if(distance <  0.0) { XLAL_ERROR(XLAL_EDOM, "Distance must be positive and greater than 0.\n");    }
+  /*
+  	Perform a basic sanity check on the region of the parameter space in which model is evaluated. Behaviour is as follows:
+  		- For mass ratios <= 20.0 and spins <= 0.99: no warning messages.
+  		- For 1000 > mass ratio > 20 and spins <= 0.99: print a warning message that we are extrapolating outside of *NR* calibration domain.
+  		- For mass ratios > 1000: throw a hard error that model is not valid.
+  		- For spins > 0.99: throw a warning that we are extrapolating the model to extremal
+
+  */
+  REAL8 mass_ratio;
+  if(m1_SI > m2_SI)
+  {
+	  mass_ratio = m1_SI / m2_SI;
+  }
+  else
+  {
+	  mass_ratio = m2_SI / m1_SI;
+  }
+  if(mass_ratio > 20.0  ) { XLAL_PRINT_INFO("Warning: Extrapolating outside of Numerical Relativity calibration domain."); }
+  if(mass_ratio > 1000. && fabs(mass_ratio - 1000) > 1e-12) { XLAL_ERROR(XLAL_EDOM, "ERROR: Model not valid at mass ratios beyond 1000."); } // The 1e-12 is to avoid rounding errors
+  if(fabs(chi1L) > 0.99 || fabs(chi2L) > 0.99) { XLAL_PRINT_INFO("Warning: Extrapolating to extremal spins, model is not trusted."); }
+
+  #if DEBUG == 1
+  printf("\n**********************************************************************\n");
+  printf("\n*                IMRPhenomXHMMultiBandOneModeMixing  %i%i            *\n", ell, emm);
+  printf("\n**********************************************************************\n");
+  printf("\nm1, m2, chi1, chi2, f_min, f_max, deltaF  %.16f %.16f %.16f %.16f %.16f %.16f %.16f\n", m1_SI/LAL_MSUN_SI, m2_SI/LAL_MSUN_SI, chi1L, chi2L, f_min, f_max, deltaF);
+  if(htilde22 == NULL){
+    printf("*** 22 mode not computed before ***\n\n");
+  }
+  #endif
+
+
+  int debug = DEBUG;
+
+  // Define two powers of pi to avoid clashes between PhenomX and PhenomXHM files.
+  int status = IMRPhenomX_Initialize_Powers(&powers_of_lalpi, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PI.");
+  status = IMRPhenomX_Initialize_Powers(&powers_of_lalpiHM, LAL_PI);
+  XLAL_CHECK(XLAL_SUCCESS == status, status, "Failed to initialize useful powers of LAL_PIHM.");
+
+  /* Initialize IMRPhenomX Waveform struct and check that it initialized correctly */
+  IMRPhenomXWaveformStruct *pWF;
+  pWF    = XLALMalloc(sizeof(IMRPhenomXWaveformStruct));
+  status = IMRPhenomXSetWaveformVariables(pWF, m1_SI, m2_SI, chi1L, chi2L, deltaF, fRef_In, phiRef, f_min, f_max, distance, 0.0, lalParams, debug);
+  XLAL_CHECK(XLAL_SUCCESS == status, XLAL_EFUNC, "Error: IMRPhenomXSetWaveformVariables failed.\n");
+
+
+  int offset = IMRPhenomXHMMultiBandOneModeMixing(htildelm, htilde22, pWF, ell, emm, lalParams);
+
+  if(emmIn>0){
+    /* (-1)^l */
+    INT4 minus1l = 1;
+    if (ell % 2 != 0){
+        minus1l = -1;
+    }
+    #if DEBUG == 1
+    printf("\nTransforming to positive m by doing (-1)^l*Conjugate, frequencies must be negatives.\n");
+    #endif
+    for(UINT4 idx=0; idx<(*htildelm)->data->length; idx++){
+      (*htildelm)->data->data[idx] = minus1l*conj((*htildelm)->data->data[idx]);
+    }
+  }
+
+  REAL8 lastfreq;
+  /* Resize htildelm if needed */
+  if (pWF->f_max_prime < pWF->fMax)
+  { /* The user has requested a higher f_max than Mf = fCut.
+    Resize the frequency series to fill with zeros beyond the cutoff frequency. */
+    lastfreq = pWF->fMax;
+  }
+  else{  // We have to look for a power of 2 anyway. Without MBAND this step is already satisfied
+    lastfreq = pWF->f_max_prime;
+  }
+  // We want to have the length be a power of 2 + 1
+  size_t n_full = NextPow2(lastfreq / deltaF) + 1;
+  size_t n = (*htildelm)->data->length;
+
+  /* Resize the COMPLEX16 frequency series */
+  *htildelm = XLALResizeCOMPLEX16FrequencySeries(*htildelm, 0, n_full);
+  XLAL_CHECK (*htildelm, XLAL_ENOMEM, "Failed to resize waveform COMPLEX16FrequencySeries of length %zu (for internal fCut=%f) to new length %zu (for user-requested f_max=%f).", n, pWF->fCut, n_full, pWF->fMax );
+
+  LALFree(pWF);
+
+  return offset;
+
+}
+
+int IMRPhenomXHMMultiBandOneModeMixing(
+    COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+    COMPLEX16FrequencySeries *htilde22,  /**< Recycle the 22 mode if previously computed **/
+    IMRPhenomXWaveformStruct *pWF,       /**< Structure of 22 mode **/
+    UINT4 ell,                           /**< First index (l,m) mode **/
+    UINT4 emm,                           /**< Second incex (l,m) mode **/
+    LALDict *lalParams                   /**< LAL dictionary **/
+)
+{
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  REAL8 deltaF = pWF->deltaF;
+  pWF->deltaF = 0; // Needed for SetupWFArraysReal function, if not introduces an extra offset in amplitude and phase.
+
+  /* Check that the frequency array will be consistent: fmin < fmax_prime */
+  /* Return the closest power of 2 */
+  size_t npts = NextPow2(pWF->f_max_prime / deltaF) + 1;
+  /* Frequencies will be set using only the lower and upper bounds that we passed */
+  size_t iStart = (size_t) (pWF->fMin / deltaF);
+  size_t iStop  = (size_t) (pWF->f_max_prime / deltaF) + 1;
+  XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+  "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+
+  // Allocate qnm struct
+  QNMFits *qnms = (QNMFits *) XLALMalloc(sizeof(QNMFits));
+  IMRPhenomXHM_Initialize_QNMs(qnms);
+
+  // Populate pWFHM with useful parameters of each mode
+  IMRPhenomXHMWaveformStruct *pWFHM = (IMRPhenomXHMWaveformStruct *) XLALMalloc(sizeof(IMRPhenomXHMWaveformStruct));
+  IMRPhenomXHM_SetHMWaveformVariables(ell, emm, pWFHM, pWF,qnms, lalParams);
+  LALFree(qnms);
+
+  /* Final grid spacing, adimensional (NR) units */
+  REAL8 evaldMf = XLALSimIMRPhenomXUtilsHztoMf(deltaF, pWF->Mtot);
+
+  /* Threshold for the Multibanding. It is a measure of how restrictive it is. Smaller value implies stronger restriction, more points where evaluate the model. */
+  REAL8 resTest  = XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(lalParams);
+  UINT4 ampinterpolorder = XLALSimInspiralWaveformParamsLookupPhenomXHMAmpInterpolMB(lalParams);
+  #if DEBUG == 1
+  printf("\n***** MBAND = %i, resTest = %.16f, ampIntorder = %i\n", MBAND, resTest, ampinterpolorder);
+  #endif
+  /* Variable for the Multibanding criteria */
+  REAL8 dfpower = 11./6.;
+  REAL8 dfcoefficient = 8. * sqrt(3./5.) * LAL_PI * powers_of_lalpi.m_one_sixth * sqrt(2.)*cbrt(2) /(cbrt(emm)*emm) * sqrt(resTest * pWF->eta);
+  /* Variables for the coarse frequency grid */
+  REAL8 Mfmin = XLALSimIMRPhenomXUtilsHztoMf(iStart*deltaF, pWF->Mtot);
+  REAL8 Mfmax = XLALSimIMRPhenomXUtilsHztoMf(pWF->f_max_prime, pWF->Mtot);
+  REAL8 MfMECO = pWFHM->fMECOlm;                          // Separate the inspiral grid from the merger grid
+  REAL8 MfLorentzianEnd = pWFHM->fRING + 2*pWFHM->fDAMP;  // Separate the merger grid from the ringdown grid
+  REAL8 dfmerger = 0., dfringdown = 0.;
+
+  //Initialize pWFHM, pAmp(22), pPhase(22) and pass to the functions. No l, m needed
+  //populate coefficients of 22 mode, to rotate to spherical
+  IMRPhenomXAmpCoefficients   *pAmp22   = (IMRPhenomXAmpCoefficients *) XLALMalloc(sizeof(IMRPhenomXAmpCoefficients));
+  IMRPhenomXPhaseCoefficients *pPhase22 = (IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+  IMRPhenomXGetPhaseCoefficients(pWF, pPhase22);
+  //IMRPhenomX_Phase_22_ConnectionCoefficients(pWF,pPhase22);//ceci where should this go? discontinuity
+
+  /* Allocate and initialize the PhenomXHM lm amplitude coefficients struct */
+  IMRPhenomXHMAmpCoefficients *pAmp = (IMRPhenomXHMAmpCoefficients*)XLALMalloc(sizeof(IMRPhenomXHMAmpCoefficients));
+  IMRPhenomXHMPhaseCoefficients *pPhase = (IMRPhenomXHMPhaseCoefficients*)XLALMalloc(sizeof(IMRPhenomXHMPhaseCoefficients));
+
+  /* Initialize the PhenomXHM lm phase and amp coefficients struct */
+  IMRPhenomXHM_FillAmpFitsArray(pAmp);
+  IMRPhenomXHM_FillPhaseFitsArray(pPhase);
+
+  /* Get coefficients for Amplitude and phase */
+  GetSpheroidalCoefficients(pPhase, pPhase22, pWFHM, pWF);
+  IMRPhenomXGetAmplitudeCoefficients(pWF, pAmp22);
+
+  IMRPhenomXHM_GetAmplitudeCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF);
+  IMRPhenomXHM_GetPhaseCoefficients(pAmp, pPhase, pAmp22, pPhase22, pWFHM, pWF,lalParams);
+
+  dfmerger = deltaF_mergerBin(pWFHM->fDAMP, pPhase->alphaL_S, resTest);
+  dfringdown = deltaF_ringdownBin(pWFHM->fDAMP, pPhase->alphaL_S, pAmp->lambda/(pAmp->sigma*pWFHM->fDAMP), resTest);
+
+  #if DEBUG == 1
+  printf("f_min = %.6f, Mfmin = %.6f\n", pWF->fMin, Mfmin);
+  printf("f_max = %.6f, f_max_prime = %.6f, Mfmax = %.6f\n", pWF->fMax, pWF->f_max_prime, Mfmax);
+  printf("\nfRING = %e\n",pWFHM->fRING);
+  printf("fDAMP = %e\n",pWFHM->fDAMP);
+  printf("\nMfmin = %.6f\n", Mfmin);
+  printf("MfMECO = %.6f\n", MfMECO);
+  printf("MfLorentzianEnd = %.6f\n", MfLorentzianEnd);
+  printf("Mfmax = %.6f\n", Mfmax);
+  printf("evaldMf = %.6e\n", evaldMf);
+  printf("dfpower = %.6e\n", dfpower);
+  printf("dfcoefficient = %.6e\n", dfcoefficient);
+  printf("dfmerger = %.6e\n", dfmerger);
+  printf("dfringdown = %.6e\n", dfringdown);
+  printf("alphaL_S = %.16e\n", pPhase->alphaL_S);
+  #endif
+
+  /* Allocate memory for the list of grids. The number of grids must be less than lengthallGrids. */
+  UINT4 lengthallGrids = 20;
+  IMRPhenomXMultiBandingGridStruct *allGrids = (IMRPhenomXMultiBandingGridStruct*)XLALMalloc(lengthallGrids * sizeof(IMRPhenomXMultiBandingGridStruct));
+
+  if (allGrids == NULL)
+  {
+    #if DEBUG == 1
+    printf("Malloc of allGrids failed!\n");
+    #endif
+    return -1;
+  }
+
+  /* Compute the coarse frequency array. It is stored in a list of grids. */
+  UINT4 nGridsUsed = XLALSimIMRPhenomXMultibandingGrid(Mfmin, MfMECO, MfLorentzianEnd, Mfmax, evaldMf, dfpower, dfcoefficient, allGrids, dfmerger, dfringdown);
+
+  #if DEBUG == 1
+  printf("allGrids[0].Length = %i\n", allGrids[0].Length);
+  #endif
+
+  /* Number of fine frequencies per coarse interval in every coarse grid */
+  INT4 mydfRatio[lengthallGrids];
+  /* Actual number of subgrids to be used. We allocated more than needed. */
+  UINT4 actualnumberofGrids = 0;
+  /* Length of coarse frequency array */
+  UINT4 lenCoarseArray = 0;
+
+  /* Transform the coarse frequency array to 1D array. */
+  // Take only the subgrids needed
+  for(UINT4 kk = 0; kk < nGridsUsed; kk++){
+    lenCoarseArray = lenCoarseArray + allGrids[kk].Length;
+    actualnumberofGrids++;
+
+    mydfRatio[kk] = allGrids[kk].intdfRatio;
+
+    #if DEBUG == 1
+    printf("\nkk = %i\n",kk);
+    printf("xStart: %.16e\n", allGrids[kk].xStart);
+    printf("xEnd: %.16e\n", allGrids[kk].xEndRequested);
+    printf("Length: %i\n", allGrids[kk].Length);
+    printf("deltax: %.16e\n", allGrids[kk].deltax);
+    printf("evaldMf: %.16e\n", evaldMf);
+    printf("xMax: %.16e\n", allGrids[kk].xMax);
+    printf("# fine points %i\n", mydfRatio[kk]);
+    printf("Last grid.xMax = %.16f\n", allGrids[actualnumberofGrids-1].xMax);
+    #endif
+
+    if(allGrids[kk].xMax + evaldMf >= Mfmax){
+      break;
+    }
+  }
+
+  // Add extra points to the coarse grid if the last freq is lower than Mfmax
+  while(allGrids[actualnumberofGrids-1].xMax < Mfmax){
+    allGrids[actualnumberofGrids-1].xMax =   allGrids[actualnumberofGrids-1].xMax +  allGrids[actualnumberofGrids-1].deltax;
+    allGrids[actualnumberofGrids-1].Length =  allGrids[actualnumberofGrids-1].Length + 1;
+    lenCoarseArray++;
+  }
+
+  #if DEBUG == 1
+  printf("\nfDAMP = %.16e\n", XLALSimIMRPhenomXUtilsMftoHz(pWFHM->fDAMP, pWF->Mtot));
+  printf("\nactualnumberofGrids = %i\n", actualnumberofGrids);
+  printf("lenCoarseArray = %i\n", lenCoarseArray);
+  printf("Last grid.xMax = %.16f", allGrids[actualnumberofGrids-1].xMax);
+  #endif
+
+  // Transform coarse frequency array to 1D vector
+  REAL8 *IntLawpoints = (REAL8*)XLALMalloc(lenCoarseArray * sizeof(REAL8));
+  UINT4 lenIntLawpoints = 0;
+
+  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
+    for(INT4 ll = 0; ll < allGrids[kk].Length; ll++){
+      IntLawpoints[lenIntLawpoints] = (allGrids[kk].xStart + allGrids[kk].deltax*ll);
+      lenIntLawpoints++;
+    }
+  }
+
+
+
+  /* End of coarse frequency array. */
+
+  #if DEBUG == 1
+  printf("\n******** Coarse frequencies array done ********* \n");
+  printf("\nlenIntLawpoints, coarse[0], coarse[-1], Mfmax, M_sec = %i %.16e %.16e %.16e %.16e\n",lenIntLawpoints, IntLawpoints[0], IntLawpoints[lenIntLawpoints-1], Mfmax, pWF->M_sec);
+  #endif
+
+  /* IntLawpoints stores the adimensional frequencies (Mf) */
+  /* coarseFreqs will store the same frequency array but in Hz */
+  /* Allocate memory for frequency array and terminate if this fails */
+  REAL8Sequence *coarseFreqs;
+  coarseFreqs = XLALCreateREAL8Sequence(lenCoarseArray);
+  if (!coarseFreqs) { XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed."); }
+
+  /* Populate frequency array */
+  #if DEBUG == 1
+  printf("\n***** Coarse freqs *****\n");
+  #endif
+  REAL8 divis = 1./pWF->M_sec;
+  for (UINT4 ii = 0; ii < lenCoarseArray; ii++)
+  {
+    coarseFreqs->data[ii] = IntLawpoints[ii]*divis;
+  }
+  #if DEBUG == 1
+  printf("\nFirst/Last Coarse freqs *****%.16f %.16f\n", coarseFreqs->data[0], coarseFreqs->data[coarseFreqs->length-1]);
+  #endif
+
+  /* Next we will compute amplitude and phase of one mode in the coarse frequency array. For that we need to split the frequency array in the spherical and spheroidal part. */
+  /* We will compute 2 waveforms: one in the spherical part and another in the spheroidal. */
+
+  #if DEBUG == 1
+  printf("\n******* Splitting spherical/spheroidal coarseFreqs %i****************\n",lenCoarseArray);
+  #endif
+
+
+  REAL8 *IntLawpointsS = (REAL8*)XLALMalloc(lenCoarseArray*sizeof(REAL8));
+  REAL8 *IntLawpointsSS = (REAL8*)XLALMalloc(lenCoarseArray*sizeof(REAL8));
+
+  double MfRDcutMin, MfRDcutMax;
+  if(pPhase->fPhaseMatchIM < pAmp->fAmpMatchIM){
+    MfRDcutMin = pPhase->fPhaseMatchIM;
+    MfRDcutMax = pAmp->fAmpMatchIM;
+  }else{
+    MfRDcutMin = pAmp->fAmpMatchIM;
+    MfRDcutMax = pPhase->fPhaseMatchIM;
+  }
+
+  #if DEBUG == 1
+  printf("\nMfRDcutMin = %.16f, MfRDcutMax = %.16f, lastcoarseArray = %.16f\n", MfRDcutMin, MfRDcutMax, IntLawpoints[lenCoarseArray-1]);
+  #endif
+
+  /* Compute the coarse frequencies in the spherical and in the spheroidal part. */
+
+  unsigned int lencoarseS = 0, lencoarseSS = 0, enter = 0;
+  for(UINT4 idx = 0; idx < lenCoarseArray; idx++){
+    double ff =  IntLawpoints[idx];
+    if(ff > MfRDcutMin){
+      if(lencoarseSS < 1 && lencoarseS>0){ // This numbers tells how many points we add to spherical after MfRDcutMin and how many to spheroidal before MfRDcutMin
+        IntLawpointsSS[lencoarseSS] = IntLawpointsS[lencoarseS-1];
+        lencoarseSS++;
+
+        if(idx == lenCoarseArray-1){
+          IntLawpointsS[lencoarseS] = ff;
+          lencoarseS++;
+        }
+      }
+      IntLawpointsSS[lencoarseSS] = ff;
+      lencoarseSS++;
+
+      if(idx < lenCoarseArray-1 && IntLawpoints[idx+1] < MfRDcutMax){
+        IntLawpointsS[lencoarseS] = ff;
+        lencoarseS++;
+      }
+      if(idx < lenCoarseArray-1 && IntLawpoints[idx+1] > MfRDcutMax && enter<2){
+        IntLawpointsS[lencoarseS] = ff;
+        lencoarseS++;
+        enter++;
+      }
+    }
+    else{
+      IntLawpointsS[lencoarseS] = ff;
+      lencoarseS++;
+    }
+  }
+
+  #if DEBUG == 1
+  printf("\n******* Coarse Freqs Spherical/Spheroidal ****************\n");
+  printf("%i ", lencoarseS);
+  printf("%i ", lencoarseSS);
+  #endif
+
+  /* Transform spherical and spheroidal frequencies to Hz */
+  REAL8Sequence *coarseFreqsS = XLALCreateREAL8Sequence(lencoarseS);
+  REAL8Sequence *coarseFreqsSS = XLALCreateREAL8Sequence(lencoarseSS);
+  for (UINT4 ii = 0; ii < lencoarseS; ii++)
+  {
+    coarseFreqsS->data[ii] = IntLawpointsS[ii]/pWF->M_sec;
+  }
+  for (UINT4 ii = 0; ii < lencoarseSS; ii++)
+  {
+    coarseFreqsSS->data[ii] = IntLawpointsSS[ii]/pWF->M_sec;
+  }
+
+
+  #if DEBUG == 1
+  printf("\n******* Computing Coarse Phase and Amp ****************\n");
+  printf("%i ", coarseFreqsS->length);
+  printf("%i ", coarseFreqsSS->length);
+  #endif
+
+  /* Compute coarse amplitude and phase in the spherical and spheroidal part */
+  /* Declare amplitude and phase variables */
+  REAL8FrequencySeries *amplitude, *phase;
+  REAL8FrequencySeries *phaseSS, *amplitudeSS;
+
+
+  if(lencoarseS > ampinterpolorder){
+    IMRPhenomXHM_Phase(&phase, coarseFreqsS, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
+    IMRPhenomXHM_Amplitude(&amplitude, coarseFreqsS, pWF, pAmp22, pPhase22, pWFHM, pAmp, pPhase);
+  }
+  if(lencoarseSS > ampinterpolorder){
+    IMRPhenomXHM_PhaseMixing(&phaseSS, coarseFreqsSS, pWF, pWFHM, pPhase);
+    IMRPhenomXHM_AmplitudeMixing(&amplitudeSS, coarseFreqsSS, pWF, pWFHM, pAmp, pPhase);
+    #if DEBUG == 1
+    printf("\nLength@phaseSS = %i\n",phaseSS->data->length);
+    #endif
+  }
+
+
+
+  #if DEBUG == 1
+  printf("\n******* Computed Coarse Amp and Phase **************** %i\n", coarseFreqs->length);
+  #endif
+
+  /* Transform the REAL8FrequencySeries to vector since gsl uses vectors for the interpolation.
+     gsl is only used for the amplitude but to keep the code more symmetric we transform also the phase. */
+  REAL8 *ILamplm = (REAL8*)XLALMalloc(lencoarseS * sizeof(REAL8));
+  REAL8 *ILphaselm = (REAL8*)XLALMalloc(lencoarseS * sizeof(REAL8));
+  REAL8 *ILamplmSS = (REAL8*)XLALMalloc(lencoarseSS * sizeof(REAL8));
+  REAL8 *ILphaselmSS = (REAL8*)XLALMalloc(lencoarseSS * sizeof(REAL8));
+
+  if(lencoarseS > ampinterpolorder){
+    for (UINT4 ii = 0; ii < lencoarseS; ii++)
+    {
+      ILamplm[ii] = ((amplitude)->data->data)[ii];
+      ILphaselm[ii] = ((phase)->data->data)[ii];
+    }
+  }
+  if(lencoarseSS > ampinterpolorder){
+    for (UINT4 ii = 0; ii < lencoarseSS; ii++)
+    {
+      ILamplmSS[ii] = ((amplitudeSS)->data->data)[ii];
+      ILphaselmSS[ii] = ((phaseSS)->data->data)[ii];
+    }
+  }
+
+  #if DEBUG == 1
+    if(lencoarseS > ampinterpolorder) printf("\nLast spherical phases %.16f %.16f", ILphaselm[lencoarseS-2], ILphaselm[lencoarseS-1]);
+    if(lencoarseSS > ampinterpolorder) printf("\nLast spherical freqs %.16f %.16f", IntLawpoints[lencoarseS-2], IntLawpoints[lencoarseS-1]);
+  #endif
+
+  #if DEBUG == 1
+  //Save coarse amplitude and phase (spherical and spheroidal) in file
+  FILE *file0;
+  char fileSpec0[40];
+  sprintf(fileSpec0, "coarseamplitude%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec0);
+  file0 = fopen(fileSpec0,"w");
+  fprintf(file0,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  FILE *file3;
+  char fileSpec3[40];
+  sprintf(fileSpec3, "coarsephase%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec3);
+  file3 = fopen(fileSpec3,"w");
+  fprintf(file3,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  for(UINT4 idx = 0; idx < (UINT4)lencoarseS && lencoarseS>ampinterpolorder; idx++)
+  {
+    fprintf(file0, "%.16f  %.16e \n",  coarseFreqsS->data[idx], ILamplm[idx]);
+    fprintf(file3, "%.16f  %.16e \n",  coarseFreqsS->data[idx]*pWF->M_sec, ILphaselm[idx]);
+  }
+  fprintf(file3, "\n\n");
+  if(lencoarseSS > ampinterpolorder){
+    for(UINT4 idx = 0; idx < (UINT4)lencoarseSS && lencoarseSS>ampinterpolorder; idx++)
+    {
+      fprintf(file0, "%.16f  %.16e \n",  coarseFreqsSS->data[idx], ILamplmSS[idx]);
+      fprintf(file3, "%.16f  %.16e \n",  coarseFreqsSS->data[idx]*pWF->M_sec, ILphaselmSS[idx]);
+    }
+  }
+  fclose(file0);
+  fclose(file3);
+  #endif
+
+  /* Free allocated memory */
+  if(lencoarseS > ampinterpolorder){
+    XLALDestroyREAL8FrequencySeries(amplitude);
+    XLALDestroyREAL8FrequencySeries(phase);
+  }
+  if(lencoarseSS > ampinterpolorder){
+    XLALDestroyREAL8FrequencySeries(phaseSS);
+    XLALDestroyREAL8FrequencySeries(amplitudeSS);
+  }
+  XLALDestroyREAL8Sequence(coarseFreqs);
+  XLALDestroyREAL8Sequence(coarseFreqsS);
+  XLALDestroyREAL8Sequence(coarseFreqsSS);
+
+
+  /***** Linear Interpolation of e^(I*phi) with the iterative procedure *****/
+
+  /* Estimation of the length of the fineGrid */
+  INT4 lenWF = 0;
+
+  for(UINT4 kk = 0; kk < actualnumberofGrids; kk++){
+    lenWF = lenWF + (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk];
+    #if DEBUG == 1
+    printf("\nmydfRatio[%i] = %i %i %i", kk, mydfRatio[kk],allGrids[kk].Length, (allGrids[kk].Length -1) * mydfRatio[kk] + 2*mydfRatio[kk]);
+    printf("\nlenWF = %i", lenWF);
+    #endif
+  }
+
+  // Variable to control the number of coarse points we have used
+  int pointsPrecessedSoFar = 0;
+
+  /* Allocate memory for the complex exponential and the fine equally-spaced frequency array */
+  COMPLEX16 *expphi = (COMPLEX16*)XLALMalloc(lenWF*sizeof(COMPLEX16));
+  if (expphi == NULL) {
+    return -1;
+  }
+
+  REAL8 *finefreqs = (REAL8*)XLALMalloc(lenWF*sizeof(REAL8));
+  if (finefreqs == NULL){
+    return -1;
+  }
+
+  UINT4 count = 0;        // Variable to track the point being filled in the fine frequency grid
+  UINT4 coarsecount = 0;  // Variable to track the point used in the coarse frequency grid
+  UINT4 RDcutMin = 0, RDcutMax = 0;  // Variables to know where to separate the fine spherical and spheroidal part. RDcutMin is for the phase and RDcutMax for the amplitude.
+  COMPLEX16 Q32 = 0;
+  INT4 lenRD = round((Mfmax - MfRDcutMin)/evaldMf) + 3; //+3 to be safe and no run out of memory because of rounding erros
+  if(lenRD <= 0) {
+    lenRD = 1;
+  }
+
+  /* After the rotation from spheroidal to spherical we will have to add a linear part to the phase of the 32. This part is also computed using Multibanding. */
+  COMPLEX16 *linear32 = (COMPLEX16*)XLALMalloc( lenRD * sizeof(COMPLEX16));
+
+  /* Loop over allgrids */
+  bool stop = false;
+  for (UINT4 i = 0; i<actualnumberofGrids && !stop; i++){
+    #if DEBUG == 1
+    printf("\ni = %i\n", i);
+    #endif
+
+
+    /* Compute mydfRatio */
+    UINT4 lcoarseGrid = allGrids[i].Length;
+    if(lcoarseGrid == 0){
+      break;
+    }
+
+    /* Linear Interpolation and iteration */
+    if(i==actualnumberofGrids-1){
+      lcoarseGrid--;
+    }
+
+    REAL8 Omega, phi0, Mfhere = 0, Mfnext=0;
+    COMPLEX16 h0, Q;
+
+    /* Loop over the coarse points of a subgrid */
+    for(UINT4 j = 0; j < lcoarseGrid && !stop; j++){
+      Mfhere = IntLawpoints[pointsPrecessedSoFar + j];
+      Mfnext = IntLawpoints[pointsPrecessedSoFar + j + 1] ;
+
+      INT4 ratio;
+      // If we are in the last coarse point of a sublist we use the number of fine points of the next subgrid.
+      if(j==lcoarseGrid-1 && i < actualnumberofGrids-1){
+        ratio = mydfRatio[i+1];
+      }
+      else{
+        ratio = mydfRatio[i];
+      }
+      if(Mfnext + evaldMf >= Mfmax){
+        double dratio = (Mfmax - Mfhere)/evaldMf + 1;
+        ratio = (int) dratio;
+        int roundratio = round((Mfmax - Mfhere)/evaldMf) + 1;
+        if(fabs(dratio-roundratio) < 0.0001) ratio = roundratio;  // To get the correct rounded integer
+        /* Break the loop if you overpass the maximun frequency */
+        stop = true;
+        #if DEBUG == 1
+        printf("\nMfmax, Mfhere, evaldMf, ratio= %.16f %.16f %.16f %i\n", Mfmax, Mfhere, evaldMf, ratio);
+        #endif
+      }
+
+      /********************************************/
+      /*     Inner Loop: linear interpolation     */
+      /********************************************/
+      /****  Spheroidal part ****/
+      if(Mfhere > MfRDcutMin && lencoarseSS > ampinterpolorder) {
+        if(RDcutMin == 0 ){
+          MfRDcutMin = Mfhere;
+          RDcutMin = count;
+          linear32[0] = cexp( I * (pPhase->C1RD*Mfhere+pPhase->CRD + pPhase->deltaphiLM));
+          Q32 = cexp( I * evaldMf * (pPhase->C1RD));
+          #if DEBUG == 1
+              printf("\n*** Starting spheroidal part ****\n");
+              printf("Mfhere, MfRDcutMin, RDcutMin = %.16e %.16e %i\n", Mfhere, MfRDcutMin, RDcutMin);
+          #endif
+          if(lencoarseS <= ampinterpolorder){
+             coarsecount++; //When the coarse array does not have spherical part.
+          }
+        }
+
+        INT4 jdx = pointsPrecessedSoFar + j - coarsecount + 1;
+
+        phi0 = ILphaselmSS[jdx];
+
+        if(j + pointsPrecessedSoFar < lenCoarseArray){
+          Omega = (ILphaselmSS[ jdx + 1] - ILphaselmSS[jdx])/(IntLawpoints[pointsPrecessedSoFar + j + 1] - IntLawpoints[pointsPrecessedSoFar + j]);
+        }
+        else{
+          Omega = (ILphaselmSS[jdx] - ILphaselmSS[jdx - 1])/(IntLawpoints[pointsPrecessedSoFar + j] - IntLawpoints[pointsPrecessedSoFar + j -1]);
+        }
+
+        if(Mfhere > pAmp->fAmpMatchIM && RDcutMax < 1){
+          RDcutMax = count;
+        }
+      }
+      /****  Spherical part ****/
+      else{
+        UINT4 jjdx = j + pointsPrecessedSoFar;
+        if(jjdx < lenCoarseArray){
+          Omega = (ILphaselm[jjdx+ 1] - ILphaselm[jjdx])/(IntLawpoints[jjdx + 1] - IntLawpoints[jjdx]);
+        }
+        else{
+          Omega = (ILphaselm[jjdx] - ILphaselm[jjdx -1])/(IntLawpoints[jjdx] - IntLawpoints[jjdx -1]);
+
+        }
+        phi0 = ILphaselm[jjdx];
+        coarsecount++;
+      }
+
+      h0   = cexp(I*phi0);
+      Q    = cexp(I*evaldMf*Omega);
+
+      if(RDcutMin == 0 && lencoarseS>ampinterpolorder){ // Spherical part
+        finefreqs[count] = Mfhere;
+        expphi[count]    = h0;
+        count++;
+        /* This loop carry out the eq. 2.32 in arXiv:2001.10897 */
+        for(int kk = 1; kk < ratio; kk++){       // Compute finefreqs and fine expphi
+          finefreqs[count] = Mfhere + evaldMf*kk;
+          expphi[count]    = Q*expphi[count-1];
+          count++;
+        }
+      }
+      else{   // Spheroidal part
+        finefreqs[count] = Mfhere;
+        expphi[count]    = h0;
+        linear32[count - RDcutMin +1] = Q32*linear32[count - RDcutMin ];
+        count++;
+        /* This loop carry out the eq. 2.32 in arXiv:2001.10897 but for spheroidals */
+        for(int kk = 1; kk < ratio; kk++){        // Compute finefreqs and fine expphi
+          finefreqs[count] = Mfhere + evaldMf*kk;
+          expphi[count]    = Q*expphi[count-1];
+          linear32[count - RDcutMin +1] = Q32*linear32[count - RDcutMin ];
+          count++;
+        }
+      }
+    }
+    pointsPrecessedSoFar = pointsPrecessedSoFar + lcoarseGrid;
+  }// End loop over ILgrids. count should be aprox = to lenWF
+
+  if(RDcutMin == 0){
+    RDcutMin = count;
+  }
+  if(lencoarseS <= ampinterpolorder){
+    RDcutMin = 0;
+  }
+  if(RDcutMax == 0){
+    RDcutMax = count;
+  }
+
+
+  #if DEBUG == 1
+  printf("\nTheory and practice (should not be equal) %i %i \n", lencoarseS, coarsecount );
+  printf("\n******* Interpolate Amplitude **********\n");
+  #endif
+
+  /*** Interpolation and evaluation in fineFreqs of the amplitude ***/
+  REAL8 *fineAmp = (REAL8*)XLALMalloc(count * sizeof(REAL8));
+  REAL8 *fineAmpSS = (REAL8*)XLALMalloc(count * sizeof(REAL8));
+
+  interpolateAmplitudeMixing(fineAmp, fineAmpSS, IntLawpointsS, IntLawpointsSS, ILamplm, ILamplmSS, finefreqs, lencoarseS, lencoarseSS, count, RDcutMin, RDcutMax, ampinterpolorder);
+
+
+  /**** Build the waveform ****/
+  size_t offset = iStart;
+
+  #if DEBUG ==1
+  printf("\nfinefreqs[0], evaldMf, quotient, offset = %.16e %.16e %.16e %zu\n", finefreqs[0], evaldMf, finefreqs[0]/evaldMf, offset);
+  #endif
+
+  // Due to round of erros, the last freq may be greater Mfmax. The difference should be less than the frequency step.
+  // Remove that extra frequency point
+  while(finefreqs[count-1] > Mfmax){
+    count--;
+    if(RDcutMin>count) RDcutMin = count;
+    if(RDcutMax>count) RDcutMax = count;
+  }
+
+  /* Intialize FrequencySeries for htildelm */
+  size_t n = count + offset;
+  XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF ), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.", deltaF);
+  //XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / deltaF + 500*pWF->Mtot*LAL_MTSUN_SI), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df + 500M with df = %g.", deltaF);
+  *htildelm = XLALCreateCOMPLEX16FrequencySeries("htildelm: FD waveform", &(ligotimegps_zero), 0.0, deltaF, &lalStrainUnit, n);
+  for(int idx = 0; idx < (int) offset; idx++){
+    ((*htildelm)->data->data)[idx] = 0.;
+  }
+
+  #if DEBUG == 1
+  printf("\n**** pPhase->fPhaseMatchIM, pPhase->fAmpMatchIM, MfRDcutMin = %.16f %.16f %.16f \n",pPhase->fPhaseMatchIM, pAmp->fAmpMatchIM, MfRDcutMin);
+  printf("\ncount RDcutMin RDcutMax: %i %i %i\n", count, RDcutMin, RDcutMax);
+  printf("\nMfRDcutMin MfRDcutMax: %.6f %.6f\n", MfRDcutMin, MfRDcutMax);
+  //Save lm in file
+  FILE *file5;
+  char fileSpec5[40];
+  sprintf(fileSpec5, "sphericalfine%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec5);
+  file5 = fopen(fileSpec5,"w");
+  fprintf(file5,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  fprintf(file5,"# Frequency (Hz)   Fine Spherical Phase \n");
+  //Save lm in file
+  FILE *file6;
+  char fileSpec6[40];
+  sprintf(fileSpec6, "spheroidalfine%i%i.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec6);
+  file6 = fopen(fileSpec6,"w");
+  fprintf(file6,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->q, pWF->chi1L, pWF->chi2L, ell, emm);
+  fprintf(file6,"# Frequency (Hz)   Fine Spheroidal Phase \n");
+  #endif
+
+  /* (-1)^l */
+  INT4 minus1l;
+  if (ell % 2 != 0)
+  minus1l = -1;
+  else
+  minus1l = +1;
+
+  /******** Spherical part **********/
+  #if DEBUG == 1
+  printf("\nRDcutMin = %i", RDcutMin);
+  #endif
+  for(UINT4 idx = 0; idx < RDcutMin; idx++){
+    COMPLEX16 data5 =  minus1l * fineAmp[idx] * expphi[idx];
+    ((*htildelm)->data->data)[idx + offset] = data5;
+    #if DEBUG == 1
+    fprintf(file5, "%.16f  %.16e %.16e\n",(idx + offset)*deltaF, creal(data5), cimag(data5));
+    #endif
+  }
+  #if DEBUG ==1
+  fclose(file5);
+  #endif
+
+
+  /********** Rotate Spheroidal part ******************/
+  // Compute htilde22 for the ringdown part if the 22 mode was not computed  before.
+  COMPLEX16FrequencySeries *htilde22tmp;
+
+  if(htilde22 == NULL && count>RDcutMin){
+    REAL8Sequence *freqs = XLALCreateREAL8Sequence(count - RDcutMin);
+    #if DEBUG == 1
+    printf("\nBuilding RD 22 mode\n");
+    printf("\nlen@freqs, RDcutMin, count = %i %i %i\n", freqs->length, RDcutMin, count);
+    #endif
+    for(UINT4 idx = RDcutMin; idx < count; idx++){
+      freqs->data[idx-RDcutMin] = finefreqs[idx]/pWF->M_sec;
+    }
+    XLALSimIMRPhenomXASFrequencySequence(&htilde22tmp, freqs, pWF->m1_SI, pWF->m2_SI, pWF->chi1L, pWF->chi2L, pWF->distance, pWF->phiRef_In, pWF->fRef, lalParams);
+    XLALDestroyREAL8Sequence(freqs);
+  }
+  else{
+    htilde22tmp = XLALCreateCOMPLEX16FrequencySeries("htilde22: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,count-RDcutMin);
+    for(UINT4 idx = RDcutMin; idx < count; idx++){
+      htilde22tmp->data->data[idx - RDcutMin] = htilde22->data->data[idx + offset];
+    }
+  }
+
+
+
+  COMPLEX16 shift32 = 0;
+
+  #if DEBUG == 1
+  printf("\nLength@htilde22, count, RDcutMin, RDcutMax, offset %i %i %i %i %zu\n",htilde22tmp->data->length, (int)(count+offset), RDcutMin, RDcutMax, offset);
+  #endif
+  for(UINT4 idx = RDcutMin; idx < count; idx++){
+    double Mf = finefreqs[idx];
+    IMRPhenomX_UsefulPowers powers_of_f;
+    IMRPhenomX_Initialize_Powers(&powers_of_f, Mf);
+    //22 waveform complete (without rescaling)
+    //COMPLEX16 wf22 = htilde22->data->data[idx + offset];
+    COMPLEX16 wf22 = htilde22tmp->data->data[idx - RDcutMin];
+    //32 waveform in spheroidal
+    REAL8 amplm = fineAmpSS[idx-RDcutMin] * (powers_of_f.m_seven_sixths*pWFHM->Amp0);
+    COMPLEX16 expphilm = expphi[idx];
+    //Rotation to spherical with Berti's coefficients
+    shift32 = linear32[idx-RDcutMin];
+    COMPLEX16 sphericalWF_32 = (conj(pWFHM->mixingCoeffs[2])*wf22 + conj(pWFHM->mixingCoeffs[3])*amplm*expphilm)*shift32;
+    COMPLEX16 data;
+
+    // Use spheroidal phase but spherical amplitude
+    if(Mf < pAmp->fAmpMatchIM){
+      data = sphericalWF_32/cabs(sphericalWF_32) * fineAmp[idx];
+      ((*htildelm)->data->data)[idx + offset] = data * minus1l;
+    }
+    // Use spheroidal amplitude and phase
+    else{
+      data = sphericalWF_32;
+      ((*htildelm)->data->data)[idx + offset] = data * minus1l;
+    }
+    #if DEBUG == 1
+    data = ((*htildelm)->data->data)[idx + offset];
+    fprintf(file6, "%.16f  %.16e %.16e\n",(idx + offset)*deltaF, creal(data), cimag(data));
+    #endif
+  }
+  #if DEBUG == 1
+  fclose(file6);
+  #endif
+
+  /* Free allocated memory */
+  XLALDestroyCOMPLEX16FrequencySeries(htilde22tmp);
+  LALFree(pAmp);
+  LALFree(pAmp22);
+  LALFree(pPhase);
+  LALFree(pPhase22);
+  LALFree(linear32);
+
+
+  #if DEBUG == 1
+  printf("\n******* Building Waveform 2**********\n");
+  printf("\nfinefreqs[0]Hz = %.16f\n", finefreqs[0]/pWF->M_sec);
+  printf("\nfinefreqs[%i]Hz = %.16f\n", count-1, finefreqs[count-1]/pWF->M_sec);
+  printf("Mfmax in Hz = %.16f\n", Mfmax/pWF->M_sec);
+  printf("count-1, offset = %i %zu\n", count-1, offset);
+  printf("Mfmaxtheory = %.16f\n", (count-1+offset)*deltaF);
+  printf("\nlength@htildelm, count+offset = %i %zu", (*htildelm)->data->length, count+offset);
+  printf("\nf_max_prime = %.16e", pWF->f_max_prime);
+  printf("\nlastfreq true = %.16e", (*htildelm)->data->length * deltaF);
+  printf("\nlastfreq true = %.16e %.16e", creal((*htildelm)->data->data[count-1]), cimag((*htildelm)->data->data[count-1]));
+  #endif
+
+
+  #if DEBUG == 1
+  //Save hlm mode in file
+  FILE *file;
+  char fileSpec[40];
+  sprintf(fileSpec, "simulation%i%i_Multiband.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec);
+  file = fopen(fileSpec,"w");
+  fprintf(file,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->m1_SI/pWF->m2_SI, pWF->chi1L, pWF->chi2L, ell, emm);
+  fprintf(file,"# Frequency (Hz)    Real    Imaginary\n");
+  COMPLEX16 data;
+  for(UINT4 idx = 0; idx < ((*htildelm)->data->length); idx++)
+  {
+    data = ((*htildelm)->data->data)[idx];
+    fprintf(file, "%.16f  %.16e %.16e\n",  idx*deltaF, creal(data), cimag(data));
+  }
+  fclose(file);
+  #endif
+
+  #if DEBUG == 1
+  //Save fine amplitude and freq array in file
+  FILE *file2;
+  char fileSpec2[40];
+  sprintf(fileSpec2, "amplitude%i%i_fine.dat", ell,emm);
+  printf("\nOutput file: %s\r\n",fileSpec2);
+  file2 = fopen(fileSpec2,"w");
+  fprintf(file2,"# q = %.16f chi1 = %.16f chi2 = %.16f lm = %i%i\n", pWF->m1_SI/pWF->m2_SI, pWF->chi1L, pWF->chi2L, ell, emm);
+  for(UINT4 idx = 0; idx < RDcutMax && lencoarseS>ampinterpolorder; idx++)
+  {
+	  fprintf(file2, "%.16f  %.16e\n",  finefreqs[idx], fineAmp[idx]);
+  }
+  fclose(file2);
+  #endif
+
+  /* Free allocated memory */
+  LALFree(expphi);
+  LALFree(finefreqs);
+  LALFree(allGrids);
+  LALFree(fineAmp);
+  LALFree(fineAmpSS);
+  LALFree(pWFHM);
+  LALFree(ILamplm);
+  LALFree(ILamplmSS);
+  LALFree(ILphaselm);
+  LALFree(ILphaselmSS);
+  LALFree(IntLawpoints);
+  LALFree(IntLawpointsS);
+  LALFree(IntLawpointsSS);
+
+  return offset;
+}
+/** @}
+* @} **/
+
+/**************************************/
+/*      INTERPOLATING FUNCTIONS       */
+/**************************************/
+
+/* Interpolate the 2D array [coarseFreqs, coarseAmp] and evaluate in finefreqs */
+/* Interpolation uses third order */
+static int interpolateAmplitude(
+  double *fineAmp,      /**<[out] amplitude in the fine uniform grid **/
+  double coarsefreqs[], /**< non-uniform frequency array**/
+  double coarseAmp[],   /**< amplitude in the non-uniform frequency array **/
+  double finefreqs[],   /**< uniform fine frequency grid**/
+  int lengthCoarse,     /**< length of non-uniform freq array **/
+  int lengthFine,       /**< length of uniform fine freq array **/
+  int ampinterpolorder     /**< order of the gsl interpolation **/
+){
+
+  #if DEBUG == 1
+  printf("\n****Building interpolants*****\n");
+  printf("Number of points to interpolate = %i\r\n", lengthCoarse);
+  #endif
+
+  gsl_interp_accel *acc = gsl_interp_accel_alloc();
+  gsl_spline *spline;
+  switch(ampinterpolorder){
+    case 1:{
+      spline = gsl_spline_alloc(gsl_interp_linear, lengthCoarse);
+      break;
+    }
+    case 3:{
+      spline = gsl_spline_alloc(gsl_interp_cspline, lengthCoarse);
+      break;
+    }
+    default:{spline = gsl_spline_alloc(gsl_interp_cspline, lengthCoarse);}
+  }
+  gsl_spline_init(spline, coarsefreqs, coarseAmp, lengthCoarse);
+
+  #if DEBUG == 1
+  printf("\n****Loop for fine freqs*****\n");
+  #endif
+
+  for(INT4 kk = 0; kk < lengthFine; kk++){
+    if(finefreqs[kk] < coarsefreqs[0] || finefreqs[kk] > coarsefreqs[lengthCoarse-1]){
+      #if DEBUG == 1
+      printf("\nOut of coarse range: coarse[0], coarse[-1] fine[%i] %.16e %.16e %.16e\n", kk, coarsefreqs[0], coarsefreqs[lengthCoarse-1], finefreqs[kk]);
+      #endif
+      fineAmp[kk] = fineAmp[kk-1];
+    }
+    else{
+      fineAmp[kk] = gsl_spline_eval(spline, finefreqs[kk], acc);
+    }
+  }
+  #if DEBUG == 1
+  printf("\n****Free memory*****\n");
+  #endif
+  /* Free memory */
+  gsl_spline_free(spline);
+  gsl_interp_accel_free(acc);
+
+  return 0;
+
+}
+
+/* Do 2 interpolations, one in the spherical regime and other in the spheroidal. */
+static int interpolateAmplitudeMixing(
+  double *fineAmp,            /**<[out] spherical amplitude in the fine uniform grid **/
+  double *fineAmpSS,          /**<[out] spheroidal amplitude in the fine uniform grid **/
+  double coarsefreqs[],       /**< non-uniform frequency array**/
+  double coarsefreqsSS[],     /**< non-uniform frequency array spheroidal **/
+  double coarseAmp[],         /**< amplitude in the non-uniform frequency array **/
+  double coarseAmpSS[],       /**< spheroidal amplitude in the non-uniform frequency array **/
+  double finefreqs[],         /**< uniform fine frequency grid**/
+  int lengthCoarse,           /**< length of non-uniform freq array **/
+  int lengthCoarseSS,         /**< length of non-uniform freq array Sphroidal **/
+  int lengthFine,             /**< length of uniform fine freq array **/
+  int sphericalfinecount,     /**< length of spherical fine grid **/
+  int sphericalfinecountMax,  /**< length of spherical fine grid **/
+  int ampinterpolorder           /**< order of interpolation **/
+)
+{
+  int spheroidalfinecount = lengthFine - sphericalfinecount;
+
+  REAL8 *sphericalfineFreqs = (REAL8*)XLALMalloc(sphericalfinecountMax * sizeof(REAL8));
+  REAL8 *spheroidalfineFreqs = (REAL8*)XLALMalloc(spheroidalfinecount * sizeof(REAL8));
+
+  for(int i = 0; i < sphericalfinecountMax; i++){
+    sphericalfineFreqs[i] = finefreqs[i];
+  }
+  for(int i = 0; i < spheroidalfinecount; i++){
+    spheroidalfineFreqs[i] = finefreqs[i + sphericalfinecount];
+  }
+
+  if(lengthCoarse > ampinterpolorder) interpolateAmplitude(fineAmp, coarsefreqs, coarseAmp, sphericalfineFreqs, lengthCoarse, sphericalfinecountMax, ampinterpolorder);
+  if(lengthCoarseSS > ampinterpolorder) interpolateAmplitude(fineAmpSS, coarsefreqsSS, coarseAmpSS, spheroidalfineFreqs,  lengthCoarseSS, spheroidalfinecount, ampinterpolorder);
+
+  #if DEBUG == 1
+  //Save lm in file
+  FILE *file2;
+  char fileSpec2[40];
+  sprintf(fileSpec2, "amplitude%i%i_fineSS.dat", 3,2);
+  printf("\nOutput file: %s\r\n",fileSpec2);
+  file2 = fopen(fileSpec2,"w");
+  REAL8 data2;
+  for(long int idx = 0; idx < spheroidalfinecount; idx++)
+  {
+    data2 = fineAmpSS[idx]; // uninitialised value
+    fprintf(file2, "%.16f  %.16e\n",  finefreqs[ sphericalfinecount + idx], data2);
+  }
+  fclose(file2);
+  #endif
+
+  LALFree(sphericalfineFreqs);
+  LALFree(spheroidalfineFreqs);
+
+  return 0;
+
+}
+
+
+/****************************************/
+/*                                      */
+/*         AUXILIARY FUNCTIONS          */
+/*                                      */
+/****************************************/
+
+/* Set up frequency array and frequency series for amplitude or phase */
+// We pass it the coarse frequency array so it just initialize amplitude or phase.
+static int SetupWFArraysReal(
+  REAL8Sequence **freqs,           /**<[out] Frequency array to evaluate model **/
+  REAL8FrequencySeries **amphase,  /**<[out] Initialize amplitude or phase with the length of freqs **/
+  REAL8Sequence *freqs_In,         /**< Input frequency array or fmin, fmax **/
+  IMRPhenomXWaveformStruct *pWF,   /**< Structure of the 22 mode **/
+  LIGOTimeGPS ligotimegps_zero     /**< Needed to initialize amphase **/
+){
+
+  /* Inherit minimum and maximum frequencies to generate wavefom from input frequency grid */
+  double f_min = freqs_In->data[0];
+  double f_max = freqs_In->data[freqs_In->length - 1];
+
+  /* Size of array */
+  size_t npts     = 0;
+
+  /* Index shift between freqs and the frequency series */
+  UNUSED UINT4 offset    = 0;
+
+  #if DEBUG == 1
+  printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
+  #endif
+
+  /* If deltaF is non-zero then we need to generate a uniformly sampled frequency grid of spacing deltaF. Start at f = 0. */
+  if(pWF->deltaF > 0)
+  {
+    #if DEBUG == 1
+    printf("\n******* deltaF > 0 ************\n");
+    #endif
+    /* Return the closest power of 2 */
+    npts = NextPow2(f_max / pWF->deltaF) + 1;
+
+    /* Debug information */
+    if(pWF->debug)
+    {
+      #if DEBUG == 1
+      printf("npts     = %zu\n",npts);
+      printf("fMin     = %.4f\n",f_min);
+      printf("fMax     = %.4f\n",f_max);
+      printf("dF       = %.4f\n",pWF->deltaF);
+      #endif
+    }
+
+    /* Coalescence time is fixed to t=0, shift by overall length in time.  */
+    XLAL_CHECK(XLALGPSAdd(&ligotimegps_zero, -1. / pWF->deltaF), XLAL_EFUNC, "Failed to shift the coalescence time to t=0. Tried to apply a shift of -1/df with df = %g.",pWF->deltaF);
+    #if DEBUG == 1
+    printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
+    #endif
+    /* Initialize the htilde frequency series */
+    *amphase = XLALCreateREAL8FrequencySeries("amphase: FD waveform",&ligotimegps_zero,0.0,pWF->deltaF,&lalStrainUnit,npts);
+    /* Check that frequency series generated okay */
+    XLAL_CHECK(*amphase,XLAL_ENOMEM,"Failed to allocate REAL8FrequencySeries of length %zu for f_max = %f, deltaF = %g.\n",npts,f_max,pWF->deltaF);
+
+    /* Frequencies will be set using only the lower and upper bounds that we passed */
+    size_t iStart = (size_t) (f_min / pWF->deltaF);
+    size_t iStop  = (size_t) (f_max / pWF->deltaF) + 1;
+
+    XLAL_CHECK ( (iStop <= npts) && (iStart <= iStop), XLAL_EDOM,
+    "minimum freq index %zu and maximum freq index %zu do not fulfill 0<=ind_min<=ind_max<=htilde->data>length=%zu.", iStart, iStop, npts);
+    #if DEBUG == 1
+    printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
+    #endif
+    /* Allocate memory for frequency array and terminate if this fails */
+    (*freqs) = XLALCreateREAL8Sequence(iStop - iStart);
+    #if DEBUG == 1
+    printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
+    #endif
+    if (!(*freqs))
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+    #if DEBUG == 1
+    printf("f_min, f_max = %.6f %.6f \n",f_min,f_max);
+    #endif
+    /* Populate frequency array */
+    for (UINT4 i = iStart; i < iStop; i++)
+    {
+      (*freqs)->data[i-iStart] = i * pWF->deltaF;
+    }
+    offset = iStart;
+  }
+  else
+  {
+    #if DEBUG == 1
+    printf("\n******* deltaF = 0 ************\n");
+    #endif
+    /* freqs is a frequency grid with non-uniform spacing, so we start at the lowest given frequency */
+    npts      = freqs_In->length;
+    *amphase = XLALCreateREAL8FrequencySeries("amphase: FD waveform, 22 mode", &ligotimegps_zero, f_min, pWF->deltaF, &lalStrainUnit, npts);
+
+    XLAL_CHECK (*amphase, XLAL_ENOMEM, "Failed to allocated waveform REAL8FrequencySeries of length %zu from sequence.", npts);
+
+    offset = 0;
+    (*freqs)  = XLALCreateREAL8Sequence(freqs_In->length);
+
+    /* Allocate memory for frequency array and terminate if this fails */
+    if (!(*freqs))
+    {
+      XLAL_ERROR(XLAL_EFUNC, "Frequency array allocation failed.");
+    }
+
+    /* Populate frequency array */
+    for (UINT4 i = 0; i < freqs_In->length; i++)
+    {
+      (*freqs)->data[i] = freqs_In->data[i];
+    }
+  }//end freqs
+  memset((*amphase)->data->data, 0, npts * sizeof(REAL8));
+  XLALUnitMultiply(&((*amphase)->sampleUnits), &((*amphase)->sampleUnits), &lalSecondUnit);
+
+  return offset;
+}
+
+
+/** Functions to compute coarse amplitude and phase **/
+
+/* Spherical amplitude evaluated in an input frequency array */
+static int IMRPhenomXHM_Amplitude(
+  REAL8FrequencySeries **amplm,           /**<[out] amplitude of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXAmpCoefficients *pAmp22,      /**< Amplitude coefficients 22 */
+  IMRPhenomXPhaseCoefficients *pPhase22,  /**< Phase coefficients 22 */
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  IMRPhenomXHMPhaseCoefficients *pPhase  /**< Phase coefficients 22 */
+)
+{
+
+  #if DEBUG == 1
+  printf("\n **** IMRPhenomXHM_Amplitude **** \n");
+  printf("\nf_min, f_max = %.16e %.16e\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  int status = 0;
+  REAL8Sequence *freqs;
+  UINT4 offset = SetupWFArraysReal(&freqs, amplm, freqs_In, pWF, ligotimegps_zero);
+
+  #if DEBUG == 1
+  printf("\n***Length@freqs, offset %i %i",freqs_In->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
+  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
+  #endif
+
+  if(pWFHM->Ampzero==0){
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    UINT4 initial_status = XLAL_SUCCESS;
+    REAL8 Msec = pWF->M_sec;
+    REAL8 amp;
+
+    /* Loop over frequencies to generate waveform */
+    if(pWFHM->MixingOn==1){
+      for (UINT4 idx = 0; idx < freqs->length; idx++)
+      {
+        REAL8 Mf = Msec * freqs->data[idx];
+        initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+        if(initial_status != XLAL_SUCCESS)
+        {
+          status = initial_status;
+          XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+        }
+        else
+        {
+          amp = IMRPhenomXHM_Amplitude_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+          /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+          ((*amplm)->data->data)[idx+offset] = pWFHM->Amp0 * amp;
+        }
+      }
+    }
+    else{
+      for (UINT4 idx = 0; idx < freqs->length; idx++)
+      {
+        REAL8 Mf = Msec * freqs->data[idx];
+        initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+        if(initial_status != XLAL_SUCCESS)
+        {
+          status = initial_status;
+          XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+        }
+        else
+        {
+          amp = IMRPhenomXHM_Amplitude_noModeMixing(Mf, &powers_of_Mf, pAmp, pWFHM);
+          /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+          ((*amplm)->data->data)[idx+offset] = pWFHM->Amp0 * amp;
+        }
+      }
+    }
+  }
+  /* Free allocated memory */
+  XLALDestroyREAL8Sequence(freqs);
+
+  return status;
+}
+
+
+/* Ringdown amplitude ansatz evaluated in an input frequency array */
+static int IMRPhenomXHM_AmplitudeMixing(
+  REAL8FrequencySeries **amplm,           /**<[out] amplitude of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  UNUSED IMRPhenomXHMPhaseCoefficients *pPhase  /**< Phase coefficients 22 */
+)
+{
+  #if DEBUG == 1
+  printf("\n **** IMRPhenomXHM_Amplitude **** \n");
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  int status = 0;
+  REAL8Sequence *freqs;
+  UINT4 offset = SetupWFArraysReal(&freqs, amplm, freqs_In, pWF, ligotimegps_zero);
+
+  #if DEBUG == 1
+  printf("\n***Length@freqs, offset %i %i",freqs_In->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
+  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
+  #endif
+
+  /* Loop over frequencies to generate waveform */
+  if(pWFHM->Ampzero==0){
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    UINT4 initial_status = XLAL_SUCCESS;
+    REAL8 Msec = pWF->M_sec;
+    REAL8 amp;
+
+    for (UINT4 idx = 0; idx < freqs->length; idx++)
+    {
+      REAL8 Mf = Msec * freqs->data[idx];
+      initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+      if(initial_status != XLAL_SUCCESS)
+      {
+        status = initial_status;
+        XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+      }
+      else
+      {
+        amp = IMRPhenomXHM_RD_Amp_Ansatz(powers_of_Mf.itself, pWFHM, pAmp);
+        /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+        ((*amplm)->data->data)[idx+offset] =  amp;
+      }
+    }
+  }
+  /* Free allocated memory */
+  XLALDestroyREAL8Sequence(freqs);
+
+  return status;
+
+}
+
+/* Spherical phase evaluated in an input frequency array */
+static int IMRPhenomXHM_Phase(
+  REAL8FrequencySeries **phaselm,         /**<[out] phase of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXAmpCoefficients *pAmp22,      /**< Amplitude coefficients 22 */
+  IMRPhenomXPhaseCoefficients *pPhase22,  /**< Phase coefficients 22 */
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  IMRPhenomXHMPhaseCoefficients *pPhase  /**< Phase coefficients 22 */
+)
+{
+  #if DEBUG == 1
+  printf("\n **** IMRPhenomXHM_Phase **** \n");
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  int status = 0;
+  REAL8Sequence *freqs;
+  UINT4 offset = SetupWFArraysReal(&freqs, phaselm, freqs_In, pWF, ligotimegps_zero);
+
+  #if DEBUG == 1
+  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
+  #endif
+
+  if(pWFHM->Ampzero==0){
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    UINT4 initial_status = XLAL_SUCCESS;
+    REAL8 Msec = pWF->M_sec;
+    REAL8 phi;
+
+    /* Loop over frequencies to generate waveform */
+    if(pWFHM->MixingOn==1){
+      //double twopi_m1=1./(2.*LAL_PI);
+      UINT4 enter = 1;
+      REAL8 Mf = Msec * freqs->data[0];
+      initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+      if(initial_status != XLAL_SUCCESS)
+      {
+        status = initial_status;
+        XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+      }
+      else
+      {
+        //REAL8 phiprevious = 0;
+        for (UINT4 idx = 0; idx < freqs->length; idx++)
+        {
+          Mf = Msec * freqs->data[idx];
+          initial_status = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+          if(initial_status != XLAL_SUCCESS)
+          {
+            status = initial_status;
+            XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+          }
+          else
+          {
+            phi = IMRPhenomXHM_Phase_ModeMixing(Mf, &powers_of_Mf, pAmp, pPhase, pWFHM, pAmp22, pPhase22, pWF);
+            /* Only the first coarse point in the RD needs the unwrapping.
+            If we remove the enter condition we would get a nice and smooth coarse phase up to pAmp->fAmpMatchIM. */
+            if(Mf > pPhase->fPhaseMatchIM && idx>0 && enter == 1){
+              #if DEBUG == 1
+                  printf("\nExtrapolating intermediate phase out of its range for one point\n");
+              #endif
+              phi = IMRPhenomXHM_Inter_Phase_AnsatzInt(Mf, &powers_of_Mf, pWFHM, pPhase);
+              phi = phi + pPhase->deltaphiLM;
+              //phi = phi+2.*LAL_PI*round((phiprevious-phi)*twopi_m1);
+              enter = 0;
+            }
+            //phiprevious = phi;
+            /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+            ((*phaselm)->data->data)[idx+offset] = phi;
+          }
+        }
+      }
+    }
+    else{
+      /* Loop over frequencies to generate waveform */
+      for (UINT4 idx = 0; idx < freqs->length; idx++)
+      {
+        REAL8 Mf    = Msec * freqs->data[idx];
+        initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+        if(initial_status != XLAL_SUCCESS)
+        {
+          status = initial_status;
+          XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+        }
+        else
+        {
+          phi = IMRPhenomXHM_Phase_noModeMixing(Mf, &powers_of_Mf, pPhase, pWFHM, pWF);
+          /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+          ((*phaselm)->data->data)[idx+offset] = phi;
+        }
+      }
+    }
+  }
+  /* Free allocated memory */
+  XLALDestroyREAL8Sequence(freqs);
+
+  return status;
+}
+
+
+/* Ringdown phase ansatz evaluated in an input frequency array */
+static int IMRPhenomXHM_PhaseMixing(
+  REAL8FrequencySeries **phaselm,         /**<[out] phase of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMPhaseCoefficients *pPhase  /**< Phase coefficients 22 */
+)
+{
+  #if DEBUG == 1
+  printf("\n **** IMRPhenomXHM_PhaseMixing **** \n");
+  #endif
+
+  /* Set LIGOTimeGPS */
+  LIGOTimeGPS ligotimegps_zero = LIGOTIMEGPSZERO; // = {0,0}
+
+  int status = 0;
+  REAL8Sequence *freqs;
+  UINT4 offset = SetupWFArraysReal(&freqs, phaselm, freqs_In, pWF, ligotimegps_zero);
+
+  #if DEBUG == 1
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs_In->data[0], freqs_In->data[freqs_In->length-1]);
+  printf("\n***Length@freqs, offset %i %i",freqs->length,offset);
+  printf("\n\nfstart, fend = %.16f %.16f\n\n", freqs->data[0], freqs->data[freqs->length-1]);
+  #endif
+
+  if(pWFHM->Ampzero==0){
+    IMRPhenomX_UsefulPowers powers_of_Mf;
+    UINT4 initial_status = XLAL_SUCCESS;
+    REAL8 Msec = pWF->M_sec;
+    REAL8 phi;
+
+    /* Loop over frequencies to generate waveform */
+    for (UINT4 idx = 0; idx < freqs->length; idx++)
+    {
+      REAL8 Mf    = Msec * freqs->data[idx];
+      initial_status     = IMRPhenomX_Initialize_Powers(&powers_of_Mf,Mf);
+      if(initial_status != XLAL_SUCCESS)
+      {
+        status = initial_status;
+        XLALPrintError("IMRPhenomX_Initialize_Powers failed for Mf, initial_status=%d",initial_status);
+      }
+      else
+      {
+        phi = IMRPhenomXHM_RD_Phase_AnsatzInt(Mf, &powers_of_Mf, pWFHM, pPhase);
+        /* Reconstruct waveform: h(f) = A(f) * Exp[I phi(f)] */
+        ((*phaselm)->data->data)[idx+offset] = phi;
+      }
+    }
+  }
+  /* Free allocated memory */
+  XLALDestroyREAL8Sequence(freqs);
+
+  return status;
+}
+
+/* Log function */
+static double logbase(double base, double x) {
+  return (log(x) / log(base));
+}
+
+/* Right hand of eq. 2.27 in arXiv:2001.10897. */
+static double deltaF_mergerBin(REAL8 fdamp, REAL8 alpha4, REAL8 abserror)
+{
+      double aux = sqrt(sqrt(3.)*3);
+      return 4. * fdamp * sqrt(abserror/fabs(alpha4)) / aux;
+}
+
+/* Correspond to eqs. 2.28 and 2.31 in arXiv:2001.10897 */
+static double deltaF_ringdownBin(REAL8 fdamp, REAL8 alpha4, REAL8 LAMBDA, REAL8 abserror){
+  double dfphase = 5*fdamp*sqrt(abserror*0.5/fabs(alpha4));
+  double dfamp   = sqrt(2*abserror)/fabs(LAMBDA);
+  if (dfphase <= dfamp){
+    return dfphase;
+  }
+  else{
+    return dfamp;
+  }
+}
+
+// static double deltaF_ringdownBinAmp(REAL8 fdamp, REAL8 lambda, REAL8 sigma, REAL8 relerror){
+//    return sqrt(sqrt(24.*relerror))*sigma*fdamp/lambda;
+// }
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.h b/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.h
new file mode 100644
index 0000000000000000000000000000000000000000..73d9c5d8dda0e1b28a9b7b0627aeb1d2892070cf
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_multiband.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2019 Cecilio García Quirós, Sascha Husa
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+ /* This code applies the multibanding technique described in arXiv:2001.10897 to the model IMRPhenomXHM described in arXiv:2001.10914. */
+
+#ifndef _LALSIM_IMR_PHENOMXHM_MULTIBAND_H
+#define _LALSIM_IMR_PHENOMXHM_MULTIBAND_H
+
+#ifdef __cplusplus
+extern "C" {
+  #endif
+  #ifdef __GNUC__
+  #define UNUSED __attribute__((unused))
+  #else
+  #define UNUSED
+  #endif
+
+#include "LALSimIMRPhenomX_internals.h"
+
+/*** Core functions to call the waveform with multibanding ***/
+int IMRPhenomXHMMultiBandOneMode(
+    COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform **/
+    IMRPhenomXWaveformStruct *pWF,       /**< Structure of 22 mode **/
+    UINT4 ell,                           /**< First index (l,m) mode **/
+    UINT4 emm,                           /**< Second incex (l,m) mode **/
+    LALDict *lalParams                   /**< LAL dictionary **/
+);
+
+int IMRPhenomXHMMultiBandOneModeMixing(
+    COMPLEX16FrequencySeries **htildelm, /**< [out] FD waveform */
+    COMPLEX16FrequencySeries *htilde22,  /**< Recycle the 22 mode if previously computed **/
+    IMRPhenomXWaveformStruct *pWF,       /**< Structure of 22 mode **/
+    UINT4 ell,                           /**< First index (l,m) mode **/
+    UINT4 emm,                           /**< Second incex (l,m) mode **/
+    LALDict *lalParams                   /**< LAL dictionary **/
+);
+
+/*** Set up frequency array and initialize amplitude/phase frequency series ***/
+static int SetupWFArraysReal(
+  REAL8Sequence **freqs,           /**<[out] Frequency array to evaluate model **/
+  REAL8FrequencySeries **amphase,  /**<[out] Initialize amplitude or phase with the length of freqs **/
+  REAL8Sequence *freqs_In,         /**< Input frequency array or fmin, fmax **/
+  IMRPhenomXWaveformStruct *pWF,   /**< Structure of the 22 mode **/
+  LIGOTimeGPS ligotimegps_zero     /**< Needed to initialize amphase **/
+);
+
+/*** Functions to compute coarse amplitude and phase ***/
+
+static int IMRPhenomXHM_Amplitude(
+  REAL8FrequencySeries **amplm,           /**<[out] amplitude of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXAmpCoefficients *pAmp22,      /**< Amplitude coefficients 22 */
+  IMRPhenomXPhaseCoefficients *pPhase22,  /**< Phase coefficients 22 */
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  IMRPhenomXHMPhaseCoefficients *pPhase   /**< Phase coefficients 22 */
+);
+
+static int IMRPhenomXHM_AmplitudeMixing(
+  REAL8FrequencySeries **amplm,           /**<[out] amplitude of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  IMRPhenomXHMPhaseCoefficients *pPhase   /**< Phase coefficients 22 */
+);
+
+static int IMRPhenomXHM_Phase(
+  REAL8FrequencySeries **phaselm,         /**<[out] phase of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXAmpCoefficients *pAmp22,      /**< Amplitude coefficients 22 */
+  IMRPhenomXPhaseCoefficients *pPhase22,  /**< Phase coefficients 22 */
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMAmpCoefficients *pAmp,      /**< Amplitude coefficients lm */
+  IMRPhenomXHMPhaseCoefficients *pPhase   /**< Phase coefficients 22 */
+);
+
+static int IMRPhenomXHM_PhaseMixing(
+  REAL8FrequencySeries **phaselm,         /**<[out] phase of hlm mode **/
+  REAL8Sequence *freqs_In,                /**< Frequency array to evaluate model or fmin, fmax  **/
+  IMRPhenomXWaveformStruct *pWF,          /**< Structure of the 22 mode **/
+  IMRPhenomXHMWaveformStruct *pWFHM,      /**< waveform parameters lm mode */
+  IMRPhenomXHMPhaseCoefficients *pPhase   /**< Phase coefficients 22 */
+);
+
+/* Log function */
+static double logbase(double base, double x);
+
+
+/**** Multibanding grids ****/
+
+typedef struct tagIMRPhenomXMultiBandingGridStruct
+{
+        /* Debug flag */
+        INT4 debug;
+
+        /* Model Version Parameters */
+        INT4  nIntervals;           //
+        INT4  Length;               //
+        INT4  intdfRatio;
+
+        REAL8 xStart;               //
+        REAL8 xEndRequested;        //
+        REAL8 xEndFrom_xStart_dx;   //
+        REAL8 xMax;                 //
+        REAL8 deltax;               //
+
+}IMRPhenomXMultiBandingGridStruct;
+
+/* Equally spaced grid */
+IMRPhenomXMultiBandingGridStruct XLALSimIMRPhenomXGridComp(
+  REAL8 fSTART,  /**< Starting frequency of the uniform bin **/
+  REAL8 fEND,    /**< Ending frequency of the uniform bin **/
+  REAL8 mydf     /**< Frequency spacing of the bin **/
+);
+
+/* Non-uniform spaced grid */
+INT4 XLALSimIMRPhenomXMultibandingGrid(
+  REAL8 fstartIn,                             /**< Minimun frequency in NR unit s**/
+  REAL8 fend,                                 /**< End of inspiral frequency bins **/
+  REAL8 MfLorentzianEnd,                      /**< Determines the last frequency bin **/
+  REAL8 Mfmax,                                /**< Maximun frequency in NR units **/
+  REAL8 evaldMf,                              /**< Spacing of the uniform frequency grid (NR units) **/
+  REAL8 dfpower,                              /**< decaying frequency power to estimate frequency spacing **/
+  REAL8 dfcoefficient,                        /**< multiplying factor to the estimate of the frequency spacing **/
+  IMRPhenomXMultiBandingGridStruct *allGrids, /**<[out] list of non-uniform frequency bins**/
+  REAL8 dfmerger,                             /**<[out] Spacing merger bin**/
+  REAL8 dfringdown                            /**<[out] Spacing ringdown bin**/
+);
+
+/**** Interpolating functions ****/
+static int interpolateAmplitude(
+  double *fineAmp,      /**<[out] amplitude in the fine uniform grid **/
+  double coarsefreqs[], /**< non-uniform frequency array**/
+  double coarseAmp[],   /**< amplitude in the non-uniform frequency array **/
+  double finefreqs[],   /**< uniform fine frequency grid**/
+  int lengthCoarse,     /**< length of non-uniform freq array **/
+  int lengthFine,       /**< length of uniform fine freq array **/
+  int ampinterpolorder     /**< order of the gsl interpolation **/
+);
+
+static int interpolateAmplitudeMixing(
+  double *fineAmp,      /**<[out] amplitude in the fine uniform grid **/
+  double *fineAmpSS,      /**<[out] spheroidal amplitude in the fine uniform grid **/
+  double coarsefreqs[], /**< non-uniform frequency array**/
+  double coarsefreqsSS[], /**< non-uniform frequency array spheroidal **/
+  double coarseAmp[],   /**< amplitude in the non-uniform frequency array **/
+  double coarseAmpSS[],  /**< spheroidal amplitude in the non-uniform frequency array **/
+  double finefreqs[],   /**< uniform fine frequency grid**/
+  int lengthCoarse,     /**< length of non-uniform freq array **/
+  int lengthCoarseSS,     /**< length of non-uniform freq array Sphroidal **/
+  int lengthFine,        /**< length of uniform fine freq array **/
+  int sphericalfinecount,     /**< length of spherical fine grid **/
+  int sphericalfinecountMax,     /**< length of spherical fine grid **/
+  int ampinterpolorder  /**< order of interpolation **/
+);
+
+static double deltaF_mergerBin(REAL8 fdamp, REAL8 alpha4, REAL8 abserror);
+static double deltaF_ringdownBin(REAL8 fdamp, REAL8 alpha4, REAL8 LAMBDA, REAL8 abserror);
+
+  #ifdef __cplusplus
+}
+#endif
+
+#endif /* LALSimIMRPhenomXHM_multiband_h */
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.c b/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.c
new file mode 100644
index 0000000000000000000000000000000000000000..bdf2c393eb72f6373efbced7d1948518e813f647
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.c
@@ -0,0 +1,311 @@
+
+/*
+ * Copyright (C) 2019  Marta Colleoni, Cecilio García Quirós
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+ /*
+    This file contains the functions for the fits of the ringdown and damping frequencies for each mode
+    and the fits for the real and imaginary part of the mixing coefficients (only for the 32 mode).
+    The fits build on data taken from https://pages.jh.edu/~eberti2/ringdown/, see also https://arxiv.org/abs/gr-qc/0512160 and https://arxiv.org/abs/1408.1860. Explicit expressions are given in the supplementary material, in IMRPhenomXHM_PhaseFits.nb, as well as in the dedicated folders QNMs and MixingCoefficients, see https://dcc.ligo.org/LIGO-P2000011 and https://arxiv.org/abs/2001.10914
+ */
+
+#include "LALSimIMRPhenomXHM_qnm.h"
+
+
+static double evaluate_QNMfit_fring21(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fring21 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+
+  return_val = (0.059471695665734674 - 0.07585416297991414*finalDimlessSpin + 0.021967909664591865*x2 - 0.0018964744613388146*x3 + 0.001164879406179587*x4 - 0.0003387374454044957*x5)/(1 - 1.4437415542456158*finalDimlessSpin + 0.49246920313191234*x2);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fdamp21(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fdamp21 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+
+  return_val = (2.0696914454467294 - 3.1358071947583093*finalDimlessSpin + 0.14456081596393977*x2 + 1.2194717985037946*x3 - 0.2947372598589144*x4 + 0.002943057145913646*x5)/(146.1779212636481 - 219.81790388304876*finalDimlessSpin + 17.7141194900164*x2 + 75.90115083917898*x3 - 18.975287709794745*x4);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fring33(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fring33 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (0.09540436245212061 - 0.22799517865876945*finalDimlessSpin + 0.13402916709362475*x2 + 0.03343753057911253*x3 - 0.030848060170259615*x4 - 0.006756504382964637*x5 + 0.0027301732074159835*x6)/(1 - 2.7265947806178334*finalDimlessSpin + 2.144070539525238*x2 - 0.4706873667569393*x4 + 0.05321818246993958*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fdamp33(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fdamp33 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+
+  return_val = (0.014754148319335946 - 0.03124423610028678*finalDimlessSpin + 0.017192623913708124*x2 + 0.001034954865629645*x3 - 0.0015925124814622795*x4 - 0.0001414350555699256*x5)/(1 - 2.0963684630756894*finalDimlessSpin + 1.196809702382645*x2 - 0.09874113387889819*x4);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fring32(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fring32 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (0.09540436245212061 - 0.13628306966373951*finalDimlessSpin + 0.030099881830507727*x2 - 0.000673589757007597*x3 + 0.0118277880067919*x4 + 0.0020533816327907334*x5 - 0.0015206141948469621*x6)/(1 - 1.6531854335715193*finalDimlessSpin + 0.5634705514193629*x2 + 0.12256204148002939*x4 - 0.027297817699401976*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fdamp32(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fdamp32 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+
+  return_val = (0.014754148319335946 - 0.03445752346074498*finalDimlessSpin + 0.02168855041940869*x2 + 0.0014945908223317514*x3 - 0.0034761714223258693*x4)/(1 - 2.320722660848874*finalDimlessSpin + 1.5096146036915865*x2 - 0.18791187563554512*x4);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fring44(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fring44 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (0.1287821193485683 - 0.21224284094693793*finalDimlessSpin + 0.0710926778043916*x2 + 0.015487322972031054*x3 - 0.002795401084713644*x4 + 0.000045483523029172406*x5 + 0.00034775290179000503*x6)/(1 - 1.9931645124693607*finalDimlessSpin + 1.0593147376898773*x2 - 0.06378640753152783*x4);
+  return return_val;
+}
+
+static double evaluate_QNMfit_fdamp44(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_fdamp44 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (0.014986847152355699 - 0.01722587715950451*finalDimlessSpin - 0.0016734788189065538*x2 + 0.0002837322846047305*x3 + 0.002510528746148588*x4 + 0.00031983835498725354*x5 + 0.000812185411753066*x6)/(1 - 1.1350205970682399*finalDimlessSpin - 0.0500827971270845*x2 + 0.13983808071522857*x4 + 0.051876225199833995*x6);
+  return return_val;
+}
+
+
+static double evaluate_QNMfit_re_l2m2lp2(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_re_l2m2lp2 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (1 - 2.2956993576253635*finalDimlessSpin + 1.461988775298876*x2 + 0.0043296365593147035*x3 - 0.1695667458204109*x4 - 0.0006267849034466508*x5)/(1 - 2.2956977727459043*finalDimlessSpin + 1.4646339137818438*x2 - 0.16843226886562457*x4 - 0.00007150540890128118*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_im_l2m2lp2(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_im_l2m2lp2 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (finalDimlessSpin*(0.3826673013161342 - 0.47531267226013896*finalDimlessSpin - 0.05898102880105067*x2 + 0.0724525431346487*x3 + 0.054714637311702986*x4 + 0.024544862718252784*x5))/(-38.70835035062785 + 69.82140084545878*finalDimlessSpin - 27.99036444363243*x2 - 4.152310472191899*x4 + 1.*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_re_l3m2lp2(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_re_l3m2lp2 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+
+  return_val = (finalDimlessSpin*(0.47513455283841244 - 0.9016636384605536*finalDimlessSpin + 0.3844811236426182*x2 + 0.0855565148647794*x3 - 0.03620067426672167*x4 - 0.006557249133752502*x5))/(-6.76894063440646 + 15.170831931186493*finalDimlessSpin - 9.406169787571082*x2 + 1.*x4);
+  return return_val;
+}
+
+static double evaluate_QNMfit_im_l3m2lp2(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_im_l3m2lp2 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (finalDimlessSpin*(-2.8704762147145533 + 4.436434016918535*finalDimlessSpin - 1.0115343326360486*x2 - 0.08965314412106505*x3 - 0.4236810894599512*x4 - 0.041787576033810676*x5))/(-171.80908957903395 + 272.362882450877*finalDimlessSpin - 76.68544453077854*x2 - 25.14197656531123*x4 + 1.*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_re_l2m2lp3(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_re_l2m2lp3 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (finalDimlessSpin*(18.522563276099167 - 37.978140351289014*finalDimlessSpin + 19.030390708998894*x2 + 3.0355668591803386*x3 - 2.210028290847915*x4 - 0.37117112862247975*x5))/(164.52480238697507 - 377.9093045285145*finalDimlessSpin + 243.3353695550844*x2 - 30.79738566181734*x4 + 1.*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_im_l2m2lp3(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_im_l2m2lp3 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (finalDimlessSpin*(-49.7688437256778 + 120.43773704442333*finalDimlessSpin - 82.95323455645332*x2 + 1.721453011852496*x3 + 11.540237244397877*x4 - 0.9819458637589314*x5))/(2858.5790831181725 - 6305.619505422591*finalDimlessSpin + 3825.6742092829054*x2 - 377.7822297815406*x4 + 1.*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_re_l3m2lp3(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_re_l3m2lp3 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (1 - 2.107852425643677*finalDimlessSpin + 1.1906393634562715*x2 + 0.02244848864087732*x3 - 0.09593447799423722*x4 - 0.0021343381708933025*x5 - 0.005319515989331159*x6)/(1 - 2.1078515887706324*finalDimlessSpin + 1.2043484690080966*x2 - 0.08910191596778137*x4 - 0.005471749827809503*x6);
+  return return_val;
+}
+
+static double evaluate_QNMfit_im_l3m2lp3(double finalDimlessSpin){
+
+  double return_val;
+
+  if (fabs(finalDimlessSpin) > 1.0) {
+    XLAL_ERROR(XLAL_EDOM, "PhenomXHM evaluate_QNMfit_im_l3m2lp3 function: |finalDimlessSpin| > 1.0 not supported");
+  }
+
+  double x2= finalDimlessSpin*finalDimlessSpin;
+  double x3= x2*finalDimlessSpin;
+  double x4= x2*x2;
+  double x5= x3*x2;
+  double x6= x3*x3;
+
+  return_val = (finalDimlessSpin*(12.45701482868677 - 29.398484595717147*finalDimlessSpin + 18.26221675782779*x2 + 1.9308599142669403*x3 - 3.159763242921214*x4 - 0.0910871567367674*x5))/(345.52914639836257 - 815.4349339779621*finalDimlessSpin + 538.3888932415709*x2 - 69.3840921447381*x4 + 1.*x6);
+  return return_val;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.h b/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb0c3b2a53c37c42f056004d645d819e8da431b7
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_qnm.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019  Marta Colleoni, Cecilio García Quirós
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ *
+ */
+
+#ifndef _LALSIM_IMR_PHENOMXHM_QNM_H
+#define _LALSIM_IMR_PHENOMXHM_QNM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Declaration of the functions for the ringdown and damping frequency fits for each mode.
+static double evaluate_QNMfit_fring21(double finalDimlessSpin);
+static double evaluate_QNMfit_fdamp21(double finalDimlessSpin);
+static double evaluate_QNMfit_fring33(double finalDimlessSpin);
+static double evaluate_QNMfit_fdamp33(double finalDimlessSpin);
+static double evaluate_QNMfit_fring32(double finalDimlessSpin);
+static double evaluate_QNMfit_fdamp32(double finalDimlessSpin);
+static double evaluate_QNMfit_fring44(double finalDimlessSpin);
+static double evaluate_QNMfit_fdamp44(double finalDimlessSpin);
+
+// Declaration of the functions for the mixing coefficients (only 32 mode)
+static double evaluate_QNMfit_re_l2m2lp2(double finalDimlessSpin);
+static double evaluate_QNMfit_im_l2m2lp2(double finalDimlessSpin);
+static double evaluate_QNMfit_re_l3m2lp2(double finalDimlessSpin);
+static double evaluate_QNMfit_im_l3m2lp2(double finalDimlessSpin);
+static double evaluate_QNMfit_re_l2m2lp3(double finalDimlessSpin);
+static double evaluate_QNMfit_im_l2m2lp3(double finalDimlessSpin);
+static double evaluate_QNMfit_re_l3m2lp3(double finalDimlessSpin);
+static double evaluate_QNMfit_im_l3m2lp3(double finalDimlessSpin);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.c b/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.c
new file mode 100644
index 0000000000000000000000000000000000000000..197644345b1fffc1f75d6eb945153e2030318633
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ *
+ */
+
+#include "LALSimIMRPhenomXHM_ringdown.h"
+
+/* Include fits of the Ringdown related quantities and the ansatz for amplitude and phase */
+
+/* These parameter-space fits are documented in the supplementary material of https://dcc.ligo.org/P2000011-v2.
+   There are 2 Mathematica notebooks (one for amplitude and one for phase) that read the fits data and automatically generate the C-code below.
+   For more information read https://git.ligo.org/waveforms/reviews/imrphenomx/blob/master/documentation/ParspaceFits/README and the documentation in the notebooks. */
+
+
+/****************************************/
+/*                                      */
+/*              AMPLITUDE               */
+/*                                      */
+/****************************************/
+
+/* Fits over parameter space for the ringdown amplitude coefficients (alambda, lambda, sigma) for each mode. */
+
+// The spin parameter S = (m1^2*chi1 + m2^2*chi2)/(m1^2 + m2^2)
+
+
+// alambda, lambda and sigma are the coefficients of the ringdown ansatz, see Eq. (6.2)
+
+
+static double IMRPhenomXHM_RD_Amp_21_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,S2,S3;
+    switch (RDAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(eta - 4.*eta2)*(0.00734983387668636 - 0.0012619735607202085*eta + 0.01042318959002753*eta2);
+            double eqSpin = sqrt(eta - 4.*eta2)*S*(-0.004839645742570202 - 0.0013927779195756036*S + eta2*(-0.054621206928483663 + 0.025956604949552205*S + 0.020360826886107204*S2));
+            double uneqSpin = -0.018115657394753674*(chi1 - 1.*chi2)*eta2*(1. - 10.539795474715346*eta2*delta);
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_21_a: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_21_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,S2;
+    switch (RDAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            S2 = pow(S,2);
+            double noSpin = 0.5566284518926176 + 0.12651770333481904*eta + 1.8084545267208734*eta2;
+            double eqSpin = (0.29074922226651545 + eta2*(-2.101111399437034 - 3.4969956644617946*S) + eta*(0.059317243606471406 - 0.31924748117518226*S) + 0.27420263462336675*S)*S;
+            double uneqSpin = 1.0122975748481835*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_21_lambda: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_33_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+  UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,S2,delta=sqrt(1-4*eta);
+  switch (RDAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      eta6 = pow(eta,6);
+      S2 = pow(S,2);
+      double noSpin = sqrt(eta - 4.*eta2)*(0.013700854227665184 + 0.01202732427321774*eta + 0.0898095508889557*eta2);
+      double eqSpin = sqrt(eta - 4.*eta2)*(0.0075858980586079065 + eta*(-0.013132320758494439 - 0.018186317026076343*S) + 0.0035617441651710473*S)*S;
+      double uneqSpin = eta4*(chi2*(-0.09802218411554885 - 0.05745949361626237*S) + chi1*(0.09802218411554885 + 0.05745949361626237*S) + eta2*(chi1*(-4.2679864481479886 - 11.877399902871485*S) + chi2*(4.2679864481479886 + 11.877399902871485*S))*delta);
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_33_alambda: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_33_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+  UNUSED double total=0,eta2,S2,S3,delta=sqrt(1-4*eta);
+  switch (RDAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      S2 = pow(S,2);
+      S3 = pow(S,3);
+      double noSpin = 0.7435306475478924 - 0.06688558533374556*eta + 1.471989765837694*eta2;
+      double eqSpin = S*(0.19457194111990656 + 0.07564220573555203*S + eta*(-0.4809350398289311 + 0.17261430318577403*S - 0.1988991467974821*S2));
+      double uneqSpin = 1.8881959341735146*(chi1 - 1.*chi2)*eta2*delta;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_33_lambda: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_32_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+  UNUSED double total=0,eta2,eta3,eta4,eta5,eta6,eta7,eta8,eta9,S2;
+  switch (RDAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      eta4 = pow(eta,4);
+      eta5 = pow(eta,5);
+      eta6 = pow(eta,6);
+      eta7 = pow(eta,7);
+      eta8 = pow(eta,8);
+      eta9 = pow(eta,9);
+      S2 = pow(S,2);
+      double noSpin = 0.00012587900257140724 + 0.03927886286971654*eta - 0.8109309606583066*eta2 + 8.820604907164254*eta3 - 51.43344812454074*eta4 + 141.81940900657446*eta5 - 140.0426973304466*eta6;
+      double eqSpin = S*(-0.00006001471234796344 + eta4*(-0.7849112300598181 - 2.09188976953315*S) + eta2*(0.08311497969032984 - 0.15569578955822236*S) + eta*(-0.01083175709906557 + 0.00568899459837252*S) - 0.00009363591928190229*S + 1.0670798489407887*eta3*S);
+      double uneqSpin = -0.04537308968659669*pow(chi1 - 1.*chi2,2)*eta2*(1. - 8.711096029480697*eta + 18.362371966229926*eta2) + (chi1 - 1.*chi2)*(-297.36978685672733 + 3103.2516759087644*eta - 10001.774055779177*eta2 + 9386.734883473799*eta3)*eta6;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_32_alambda: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_32_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+  UNUSED double total=0,eta2,eta3,S2,delta=sqrt(1.-4*eta);
+  switch (RDAmpFlag){
+    case 122018:{
+      eta2 = pow(eta,2);
+      eta3 = pow(eta,3);
+      S2 = pow(S,2);
+      double noSpin = (sqrt(1. - 3.*eta)*(0.0341611244787871 - 0.3197209728114808*eta + 0.7689553234961991*eta2))/(0.048429644168112324 - 0.43758296068790314*eta + eta2);
+      double eqSpin = sqrt(1. - 3.*eta)*S*(0.11057199932233873 + eta2*(25.536336676250748 - 71.18182757443142*S) + 9.790509295728649*eta*S + eta3*(-56.96407763839491 + 175.47259563543165*S));
+      double uneqSpin = -5.002106168893265*pow(chi1 - 1.*chi2,2)*eta2*delta;
+      total = noSpin + eqSpin + uneqSpin;
+      break;
+    }
+    default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_32_lambda: version is not valid. Recommended version is 122018.");}
+  }
+  return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_44_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,S2,S3;
+    switch (RDAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            S2 = pow(S,2);
+            S3 = pow(S,3);
+            double noSpin = sqrt(eta - 3.*eta2)*(0.007904587819112173 + 0.09558474985614368*eta - 2.663803397359775*eta2 + 28.298192768381554*eta3 - 136.10446022757958*eta4 + 233.23167528016833*eta5);
+            double eqSpin = sqrt(eta - 3.*eta2)*S*(0.0049703757209330025 + 0.004122811292229324*S + eta*(-0.06166686913913691 + 0.014107365722576927*S)*S + eta2*(-0.2945455034809188 + 0.4139026619690879*S - 0.1389170612199015*S2) + eta3*(0.9225758392294605 - 0.9656098473922222*S + 0.19708289555425246*S2) + 0.000657528128497184*S2);
+            double uneqSpin = 0.00659873279539475*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_44_a: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_44_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2,eta3,eta4,eta5,eta6,eta7;
+    switch (RDAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            eta5 = pow(eta,5);
+            eta6 = pow(eta,6);
+            eta7 = pow(eta,7);
+            double noSpin = 0.7702864948772887 + 32.81532373698395*eta - 1625.1795901450212*eta2 + 31305.458876573215*eta3 - 297375.5347399236*eta4 + 1.4726521941846698e6*eta5 - 3.616582470072637e6*eta6 + 3.4585865843680725e6*eta7;
+            double eqSpin = (-0.03011582009308575*S + 0.09034746027925727*eta*S + 1.8738784391649446*eta2*S - 5.621635317494836*eta3*S)/(-1.1340218677260014 + S);
+            double uneqSpin = 0.959943270591552*pow(chi1 - 1.*chi2,2)*eta2 + 0.853573071529436*(chi1 - 1.*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_44_lambda: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_21_sigma(double eta, double S, double chi1, double chi2, int RDAmpFlag) {
+    UNUSED double total=0, delta=sqrt(1. - 4.*eta),eta2;
+    switch (RDAmpFlag){
+        case 122018:{
+            eta2 = pow(eta,2);
+            double noSpin = 1.2922261617161441 + 0.0019318405961363861*eta;
+            double eqSpin = (0.04927982551108649 - 0.6703778360948937*eta + 2.6625014134659772*eta2)*S;
+            double uneqSpin = 1.2001101665670462*(chi1 + pow(chi1,2) - 2.*chi1*chi2 + (-1. + chi2)*chi2)*eta2*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_21_sigma: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_33_sigma(UNUSED double eta, UNUSED double S, UNUSED double chi1, UNUSED double chi2, int RDAmpFlag) {
+    UNUSED double total=0;
+    switch (RDAmpFlag){
+        case 122018:{
+            double noSpin = 1.3;
+            double eqSpin = 0.;
+            double uneqSpin = 0.;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_33_sigma: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_32_sigma(UNUSED double eta, UNUSED double S, UNUSED double chi1, UNUSED double chi2, int RDAmpFlag) {
+    UNUSED double total=0;
+    switch (RDAmpFlag){
+        case 122018:{
+            double noSpin = 1.33;
+            double eqSpin = 0.;
+            double uneqSpin = 0.;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_32_sigma: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Amp_44_sigma(UNUSED double eta, UNUSED double S, UNUSED double chi1, UNUSED double chi2, int RDAmpFlag) {
+    UNUSED double total=0;
+    switch (RDAmpFlag){
+        case 122018:{
+            double noSpin = 1.33;
+            double eqSpin = 0.;
+            double uneqSpin = 0.;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Amp_44_sigma: version is not valid. Recommended version is 122018.");}
+    }
+    return total;
+}
+
+
+/************** Amplitude Ringdown Ansatz *************/
+
+// For the modes with mixing this is the ansatz of the spheroidal part.
+static double IMRPhenomXHM_RD_Amp_Ansatz(double ff, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXHMAmpCoefficients *pAmp){
+
+    int RDAmpFlag = pWF->IMRPhenomXHMRingdownAmpVersion;
+    double frd = pWF->fRING;
+    double fda = pWF->fDAMP;
+    double dfr = ff - frd;
+    double dfd = fda * pAmp->sigma;
+    double lc  = pAmp->lc;
+    double ampRD;
+
+    switch ( RDAmpFlag )
+    {
+        case 0: /* Canonical, 3 fitted coefficients + fring, fdamp, lc that are fixed. sigma is also fixed except for the 21 mode. */
+        {
+            ampRD = (fda *fabs(pAmp->alambda) * pAmp->sigma)*exp(- dfr * pAmp->lambda / dfd )/ (dfr*dfr + dfd*dfd)*pow(ff,-lc);
+            break;
+        }
+        default:
+        {
+            XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_lm_Ansatz: IMRPhenomXHMRingdownAmpFitsVersion is not valid. Use version 0. \n");
+        }
+    }
+
+    return ampRD;
+}
+
+
+/*** Derivative of the RD Ansatz for modes without mixing ***/
+
+static double IMRPhenomXHM_RD_Amp_DAnsatz(double ff, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXHMAmpCoefficients *pAmp){
+
+    int RDAmpFlag = pWF->IMRPhenomXHMRingdownAmpVersion;
+    double frd = pWF->fRING;
+    double fda = pWF->fDAMP;
+    double dfd = fda * pAmp->sigma;
+    double lc  = pAmp->lc;
+    double lambda = pAmp->lambda;
+    double DampRD;
+    double numerator,denom,expon;
+
+    switch ( RDAmpFlag )
+    {
+        case 0:  /* Canonical, 3 fitted coefficients + fring, fdamp, lc that are fixed. sigma is also fixed except for the 21 mode. */
+        {
+            numerator = fabs(pAmp->alambda)*pow(ff,-1.-lc)*( dfd*lc*(frd*frd + dfd*dfd)
+                                                           + ff*( frd*frd*lambda - 2.*dfd*frd*(1.+lc) + dfd*dfd*lambda)
+                                                           + ff*ff*( -2.*lambda*frd + dfd*(2.+lc) )
+                                                           + ff*ff*ff*( lambda )
+                                                           );
+            denom = frd*frd + dfd*dfd - ff*2.*frd + ff*ff;
+            expon = exp(-(ff-frd)*lambda/dfd);
+            DampRD = -numerator*expon/(denom*denom);
+            break;
+        }
+        default:
+        {
+            XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_lm_Ansatz: IMRPhenomXHMRingdownAmpFitsVersion is not valid. Use version 0. \n");
+        }
+    }
+
+    return DampRD;
+}
+
+/*** Derivative of the RD Ansatz for modes with mixing ***/
+// It can not be obtained analytically, so we use finite difference of 4th order
+static double IMRPhenomXHM_RD_Amp_NDAnsatz(double ff, IMRPhenomXHMAmpCoefficients *pAmp,  IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXAmpCoefficients *pAmp22,  IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22){
+
+    double df = 10e-10;
+    double Nder;
+    double fun2R = ff + 2*df;
+    double funR  = ff + df;
+    double funL  = ff - df;
+    double fun2L = ff - 2*df;
+    IMRPhenomX_UsefulPowers powers_of_fun;
+
+    IMRPhenomX_Initialize_Powers(&powers_of_fun,fun2R);
+    fun2R = cabs(SpheroidalToSpherical(fun2R, &powers_of_fun, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22));
+
+    IMRPhenomX_Initialize_Powers(&powers_of_fun,funR);
+    funR  = cabs(SpheroidalToSpherical(funR, &powers_of_fun, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22));
+
+    IMRPhenomX_Initialize_Powers(&powers_of_fun,funL);
+    funL  = cabs(SpheroidalToSpherical(funL, &powers_of_fun, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22));
+
+    IMRPhenomX_Initialize_Powers(&powers_of_fun,fun2L);
+    fun2L = cabs(SpheroidalToSpherical(fun2L, &powers_of_fun, pAmp22, pPhase22, pAmp, pPhase, pWFHM, pWF22));
+
+    Nder = (-fun2R + 8*funR - 8*funL + fun2L )/(12*df);
+
+    return Nder;
+
+}
+
+/* There are cases for some modes where the ringdown amplitude is very low compared to the inspiral and the intermediate reconstruction fails to connect them.
+   For those cases we remove the two collocation points and reconstruct with a third order polynomial or with a linear one for the 32 mode. */
+void IMRPhenomXHM_Ringdown_Amplitude_Veto(double *V2, double *V3, double V4, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22){
+
+    double threshold;
+    if(pWFHM->modeTag == 32){
+      threshold = 0.1/(pWF22->ampNorm);
+      if(1./V4 < threshold){
+          *V2 = 1.;
+          *V3 = 1.;
+          pWFHM->IMRPhenomXHMIntermediateAmpVersion = 101;
+      }
+    }
+    else{
+      threshold = 0.01/(pWF22->ampNorm);
+      if(1./V4 < threshold){
+          *V2 = 1.;
+          *V3 = 1.;
+          pWFHM->IMRPhenomXHMIntermediateAmpVersion = 1032;
+      }
+    }
+}
+
+
+
+/****************************************/
+/*                                      */
+/*              PHASE                   */
+/*                                      */
+/****************************************/
+
+/* Fits over parameter space for the ringdown phase quantities. */
+
+// The spin parameter S = (m1^2*chi1 + m2^2*chi2)/(m1^2 + m2^2)
+
+static double IMRPhenomXHM_RD_Phase_22_alpha2(double eta, double S, double chi1, double chi2, int RDPhaseFlag) {
+    double total=0,eta2,eta3,eta4,delta=sqrt(1-4*eta);
+    switch (RDPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            double noSpin = 0.2088669311744758 - 0.37138987533788487*eta + 6.510807976353186*eta2 - 31.330215053905395*eta3 + 55.45508989446867*eta4;
+            double eqSpin = ((0.2393965714370633 + 1.6966740823756759*eta - 16.874355161681766*eta2 + 38.61300158832203*eta3)*S)/(1. - 0.633218538432246*S);
+            double uneqSpin = (chi1 - 1.*chi2)*(0.9088578269496244*pow(eta,2.5) + 15.619592332008951*(chi1 - 1.*chi2)*pow(eta,3.5))*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Phase_22_alpha2: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Phase_22_alphaL(double eta, double S, double chi1, double chi2, int RDPhaseFlag) {
+    UNUSED double total=0, delta=sqrt(1.- 4.*eta),eta2,eta3,eta4,S2;
+    switch (RDPhaseFlag){
+        case 122019:{
+            eta2 = pow(eta,2);
+            eta3 = pow(eta,3);
+            eta4 = pow(eta,4);
+            S2 = pow(S,2);
+            double noSpin = eta*(-1.1926122248825484 + 2.5400257699690143*eta - 16.504334734464244*eta2 + 27.623649807617376*eta3);
+            double eqSpin = eta3*S*(35.803988443700824 + 9.700178927988006*S - 77.2346297158916*S2) + eta*S*(0.1034526554654983 - 0.21477847929548569*S - 0.06417449517826644*S2) + eta2*S*(-4.7282481007397825 + 0.8743576195364632*S + 8.170616575493503*S2) + eta4*S*(-72.50310678862684 - 39.83460092417137*S + 180.8345521274853*S2);
+            double uneqSpin = (-0.7428134042821221*chi1*pow(eta,3.5) + 0.7428134042821221*chi2*pow(eta,3.5) + 17.588573345324154*pow(chi1,2)*pow(eta,4.5) - 35.17714669064831*chi1*chi2*pow(eta,4.5) + 17.588573345324154*pow(chi2,2)*pow(eta,4.5))*delta;
+            total = noSpin + eqSpin + uneqSpin;
+            break;
+        }
+        default:{XLAL_ERROR_REAL8(XLAL_EINVAL,"Error in IMRPhenomXHM_RD_Phase_22_alphaL: version is not valid. Recommended version is 122019.");}
+    }
+    return total;
+}
+
+/**************** 32 specific fits ***************/
+static double IMRPhenomXHM_RD_Phase_32_SpheroidalTimeShift(double eta, double S, double chi1, double chi2, UNUSED int RDPhaseFlag) {
+
+    double total,eta2,eta3,eta4,eta5,S2,S3,S4;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    eta4 = pow(eta,4);
+    eta5 = pow(eta,5);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = 11.851438981981772 + 167.95086712701223*eta - 4565.033758777737*eta2 + 61559.132976189896*eta3 - 364129.24735853914*eta4 + 739270.8814129328*eta5;
+    double eqSpin = (9.506768471271634 + 434.31707030999445*eta - 8046.364492927503*eta2 + 26929.677144312944*eta3)*S + (-5.949655484033632 - 307.67253970367034*eta + 1334.1062451631644*eta2 + 3575.347142399199*eta3)*S2 + (3.4881615575084797 - 2244.4613237912527*eta + 24145.932943269272*eta2 - 60929.87465551446*eta3)*S3 + (15.585154698977842 - 2292.778112523392*eta + 24793.809334683185*eta2 - 65993.84497923202*eta3)*S4;
+    double uneqSpin = 465.7904934097202*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+
+static double IMRPhenomXHM_RD_Phase_32_SpheroidalPhaseShift(double eta, double S, double chi1, double chi2, UNUSED int RDPhaseFlag) {
+    double total,eta2,eta3,eta4,eta5,eta6,eta7,S2,S3,S4;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    eta4 = pow(eta,4);
+    eta5 = pow(eta,5);
+    eta6 = pow(eta,6);
+    eta7 = pow(eta,7);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = -1.3328895897490733 - 22.209549522908667*eta + 1056.2426481245027*eta2 - 21256.376324666326*eta3 + 246313.12887984765*eta4 - 1.6312968467540336e6*eta5 + 5.614617173188322e6*eta6 - 7.612233821752137e6*eta7;
+    double eqSpin = (S*(-1.622727240110213 + 0.9960210841611344*S - 1.1239505323267036*S2 - 1.9586085340429995*S3 + eta2*(196.7055281997748 + 135.25216875394943*S + 1086.7504825459278*S2 + 546.6246807461155*S3 - 312.1010566468068*S4) + 0.7638287749489343*S4 + eta*(-47.475568056234245 - 35.074072557604445*S - 97.16014978329918*S2 - 34.498125910065156*S3 + 24.02858084544326*S4) + eta3*(62.632493533037625 - 22.59781899512552*S - 2683.947280170815*S2 - 1493.177074873678*S3 + 805.0266029288334*S4)))/(-2.950271397057221 + 1.*S);
+    double uneqSpin = (sqrt(1. - 4.*eta)*(chi2*pow(eta,2.5)*(88.56162028006072 - 30.01812659282717*S) + chi2*eta2*(43.126266433486435 - 14.617728550838805*S) + chi1*eta2*(-43.126266433486435 + 14.617728550838805*S) + chi1*pow(eta,2.5)*(-88.56162028006072 + 30.01812659282717*S)))/(-2.950271397057221 + 1.*S);
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+
+// collocation points
+static double IMRPhenomXHM_Ringdown_Phase_32_p1(double eta, double S, double chi1, double chi2, UNUSED int RingdownPhaseFlag) {
+    double total,eta2,eta3,eta4,eta5,S2,S3,S4,S5;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    eta4 = pow(eta,4);
+    eta5 = pow(eta,5);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    S5 = pow(S,5);
+    double noSpin = 3169.372056189274 + 426.8372805022653*eta - 12569.748101922158*eta2 + 149846.7281073725*eta3 - 817182.2896823225*eta4 + 1.5674053633767858e6*eta5;
+    double eqSpin = (19.23408352151287 - 1762.6573670619173*eta + 7855.316419853637*eta2 - 3785.49764771212*eta3)*S + (-42.88446003698396 + 336.8340966473415*eta - 5615.908682338113*eta2 + 20497.5021807654*eta3)*S2 + (13.918237996338371 + 10145.53174542332*eta - 91664.12621864353*eta2 + 201204.5096556517*eta3)*S3 + (-24.72321125342808 - 4901.068176970293*eta + 53893.9479532688*eta2 - 139322.02687945773*eta3)*S4 + (-61.01931672442576 - 16556.65370439302*eta + 162941.8009556697*eta2 - 384336.57477596396*eta3)*S5;
+    double uneqSpin = (chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2*(641.2473192044652 - 1600.240100295189*chi1*eta + 1600.240100295189*chi2*eta + 13275.623692212472*eta*S);
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+// collocation points
+static double IMRPhenomXHM_Ringdown_Phase_32_p2(double eta, double S, double chi1, double chi2, UNUSED int RingdownPhaseFlag) {
+    double total,eta2,eta3,S2,S3,S4;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = 3131.0260952676376 + 206.09687819102305*eta - 2636.4344627081873*eta2 + 7475.062269742079*eta3;
+    double eqSpin = (49.90874152040307 - 691.9815135740145*eta - 434.60154548208334*eta2 + 10514.68111669422*eta3)*S + (97.3078084654917 - 3458.2579971189534*eta + 26748.805404989867*eta2 - 56142.13736008524*eta3)*S2 + (-132.49105074500454 + 429.0787542102207*eta + 7269.262546204149*eta2 - 27654.067482558712*eta3)*S3 + (-227.8023564332453 + 5119.138772157134*eta - 34444.2579678986*eta2 + 69666.01833764123*eta3)*S4;
+    double uneqSpin = 477.51566939885424*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+// collocation points
+static double IMRPhenomXHM_Ringdown_Phase_32_p3(double eta, double S, double chi1, double chi2, UNUSED int RingdownPhaseFlag) {
+    double total,eta2,eta3,S2,S3,S4;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = 3082.803556599222 + 76.94679795837645*eta - 586.2469821978381*eta2 + 977.6115755788503*eta3;
+    double eqSpin = (45.08944710349874 - 807.7353772747749*eta + 1775.4343704616288*eta2 + 2472.6476419567534*eta3)*S + (95.57355060136699 - 2224.9613131172046*eta + 13821.251641893134*eta2 - 25583.314298758105*eta3)*S2 + (-144.96370424517866 + 2268.4693587493093*eta - 10971.864789147161*eta2 + 16259.911572457446*eta3)*S3 + (-227.8023564332453 + 5119.138772157134*eta - 34444.2579678986*eta2 + 69666.01833764123*eta3)*S4;
+    double uneqSpin = 378.2359918274837*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+// collocation points
+static double IMRPhenomXHM_Ringdown_Phase_32_p4(double eta, double S, double chi1, double chi2, UNUSED int RingdownPhaseFlag) {
+    double total,eta2,S2,S3,S4;
+    eta2 = pow(eta,2);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = 3077.0657367004565 + 64.99844502520415*eta - 357.38692756785395*eta2;
+    double eqSpin = (34.793450080444714 - 986.7751755509875*eta - 9490.641676924794*pow(eta,3) + 5700.682624203565*eta2)*S + (57.38106384558743 - 1644.6690499868596*eta - 19906.416384606226*pow(eta,3) + 11008.881935880598*eta2)*S2 + (-126.02362949830213 + 3169.3397351803583*eta + 62863.79877094988*pow(eta,3) - 26766.730897942085*eta2)*S3 + (-169.30909412804587 + 4900.706039920717*eta + 95314.99988114933*pow(eta,3) - 41414.05689348732*eta2)*S4;
+    double uneqSpin = 390.5443469721231*(chi1 - 1.*chi2)*sqrt(1. - 4.*eta)*eta2;
+    total = noSpin + eqSpin + uneqSpin;
+
+    return total;
+}
+
+
+/**************  ANSATZ PHASE DERIVATIVE **************/
+
+static double IMRPhenomXHM_RD_Phase_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXHMPhaseCoefficients *pPhase){
+
+    double invf2 = powers_of_f->m_two;
+    double frd   = pWFHM->fRING;
+    double fda   = pWFHM->fDAMP;
+    double dphaseRD;
+
+    switch ( pWFHM->MixingOn )
+    {
+        case 0:
+        {
+            /*  rescaling of the 22 ansatz -- used for (21),(33),(44) */
+            /*ansatz:
+             alpha0 + ((fRDlm^2) alpha2)/(f^2)  + alphaL*(fdamplm)/((fdamplm)^2 + (f - fRDlm)^2)*/
+            dphaseRD = ( pPhase->alpha0 +  frd*frd*(pPhase->alpha2)*invf2 + ( (pPhase->alphaL)* fda/(fda*fda +(ff - frd)*(ff - frd)) ) );
+            break;
+
+        }
+        case 1:
+        {
+            /*  calibration of spheroidal ringdown waveform for (32) */
+            /* ansatz: alpha0 + (alpha2)/(f^2)+ (alpha4)/(f^4)  + alphaL*(fdamplm)/((fdamplm)^2 + (f - fRDlm)^2)*/
+            double invf4 = powers_of_f->m_four;
+            dphaseRD = ( pPhase->alpha0_S +  (pPhase->alpha2_S)*invf2 + (pPhase->alpha4_S)*invf4 +( (pPhase->alphaL_S)* fda/(fda*fda +(ff - frd)*(ff - frd)) ) );
+            break;
+        }
+        default:
+        {XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_RD_Phase_Ansatz: version is not valid. Use version 0 for modes (2,1),(3,3),(4,4) and 1 for (3,2).\n");}
+    }
+    return dphaseRD;
+}
+
+/**************  ANSATZ INTEGRATED PHASE **************/
+
+static double IMRPhenomXHM_RD_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXHMPhaseCoefficients *pPhase){
+
+    double invf   = powers_of_f->m_one;
+    double phaseRD;
+    double frd=pWFHM->fRING;
+    double fda=pWFHM->fDAMP;
+
+    switch ( pWFHM->MixingOn )
+    {
+        case 0:
+        {
+            /*  rescaling of the 22 ansatz -- used for (21),(33),(44) */
+            /*ansatz:
+             alpha0 f - fRDlm^2*alpha2)/f  + alphaL*ArcTan[(f - fRDlm)/fdamplm]*/
+            phaseRD = pPhase->alpha0*ff -frd*frd *(pPhase->alpha2)*invf +  (pPhase->alphaL)* atan((ff-frd)/fda);
+            break;
+        }
+        case 1:
+        {
+            /*  calibration of spheroidal ringdown waveform for (32) */
+            /* ansatz: f alpha0 - (alpha4)/(3 f^3) - (alpha2)/f + alphaL ArcTan[(f - fRDlm)/fdamplm]*/
+            double invf3 = powers_of_f->m_three;
+            phaseRD = pPhase->phi0_S+pPhase->alpha0_S*ff -(pPhase->alpha2_S)*invf -1./3.*(pPhase->alpha4_S)*invf3 +(pPhase->alphaL_S)* atan((ff-frd)/fda);
+            break;
+        }
+        default:
+        {XLAL_ERROR(XLAL_EDOM, "Error in IMRPhenomXHM_RD_Phase_AnsatzInt: version is not valid. Use version 0 for modes (2,1),(3,3),(4,4) and 1 for (3,2).\n");}
+    }
+    return phaseRD;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.h b/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.h
new file mode 100644
index 0000000000000000000000000000000000000000..831e2d714fe5eefd03178a35291f7c9996ebb053
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_ringdown.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio Garcia Quiros
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ *
+ */
+
+
+#ifndef LALSIMIMRPHENOMXHM_RINGDOWN_H
+#define LALSIMIMRPHENOMXHM_RINGDOWN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    #ifdef __GNUC__
+    #define UNUSED __attribute__((unused))
+    #else
+    #define UNUSED
+    #endif
+
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+#include "LALSimIMRPhenomXHM_structs.h"
+
+
+    //----AMPLITUDE----
+
+    //Fits of the ringdown coefficients over parameter space
+    static double IMRPhenomXHM_RD_Amp_21_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_21_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_33_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_33_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_32_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_32_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_44_alambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_44_lambda(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_21_sigma(double eta, double S, double chi1, double chi2, int RDAmpFlag);
+    static double IMRPhenomXHM_RD_Amp_33_sigma(double eta, double S, double chi1, double chi2, int RDAmpFlag);// currently constant
+    static double IMRPhenomXHM_RD_Amp_32_sigma(double eta, double S, double chi1, double chi2, int RDAmpFlag);// currently constant
+    static double IMRPhenomXHM_RD_Amp_44_sigma(double eta, double S, double chi1, double chi2, int RDAmpFlag);// currently constant
+
+    //ansatz, and its derivative: analytical for no mixing and numerical for mixing
+    static double IMRPhenomXHM_RD_Amp_Ansatz(double ff, IMRPhenomXHMWaveformStruct *pWF,  IMRPhenomXHMAmpCoefficients *pAmp);
+    static double IMRPhenomXHM_RD_Amp_DAnsatz(double ff, IMRPhenomXHMWaveformStruct *pWF, IMRPhenomXHMAmpCoefficients *pAmp);
+    static double IMRPhenomXHM_RD_Amp_NDAnsatz(double ff, IMRPhenomXHMAmpCoefficients *pAmp,  IMRPhenomXHMPhaseCoefficients *pPhase, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXAmpCoefficients *pAmp22,  IMRPhenomXPhaseCoefficients *pPhase22, IMRPhenomXWaveformStruct *pWF22);
+
+    // Feeding the ansatz with the coefficients is how we get the final reconstruction
+
+    //veto
+    static void IMRPhenomXHM_Ringdown_Amplitude_Veto(double *pV2, double *pV3, double V4, IMRPhenomXHMWaveformStruct *pWFHM, IMRPhenomXWaveformStruct *pWF22);
+
+
+    //----PHASE-----
+
+    // no mixing fits
+    static double IMRPhenomXHM_RD_Phase_22_alpha2(double eta, double S, double chi1, double chi2, int RDPhaseFlag);
+    static double IMRPhenomXHM_RD_Phase_22_alphaL(double eta, double S, double chi1, double chi2, int RDPhaseFlag);
+    // 32 specific fits
+    static double IMRPhenomXHM_RD_Phase_32_SpheroidalTimeShift(double eta, double S, double chi1, double chi2, int RDPhaseFlag);
+    static double IMRPhenomXHM_RD_Phase_32_SpheroidalPhaseShift(double eta, double S, double chi1, double chi2, int RDPhaseFlag);
+    static double IMRPhenomXHM_Ringdown_Phase_32_p1(double eta, double S, double chi1, double chi2, int RingdownPhaseFlag);
+    static double IMRPhenomXHM_Ringdown_Phase_32_p2(double eta, double S, double chi1, double chi2, int RingdownPhaseFlag);
+    static double IMRPhenomXHM_Ringdown_Phase_32_p3(double eta, double S, double chi1, double chi2, int RingdownPhaseFlag);
+    static double IMRPhenomXHM_Ringdown_Phase_32_p4(double eta, double S, double chi1, double chi2, int RingdownPhaseFlag);
+
+    //ansatz
+    static double IMRPhenomXHM_RD_Phase_Ansatz(double ff,IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXHMPhaseCoefficients *pPhase);
+    static double IMRPhenomXHM_RD_Phase_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f,IMRPhenomXHMWaveformStruct *pWFHM,  IMRPhenomXHMPhaseCoefficients *pPhase);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif 
diff --git a/lalsimulation/lib/LALSimIMRPhenomXHM_structs.h b/lalsimulation/lib/LALSimIMRPhenomXHM_structs.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb2f7716a10528710a658f5fa860b0b11cd1a800
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomXHM_structs.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 Marta Colleoni, Cecilio García Quirós
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+//
+//  LALSimIMRPhenomXHM_structs.h
+//
+//  Created by Marta on 13/02/2019.
+//
+#ifndef LALSimIMRPhenomXHM_structs_h
+#define LALSimIMRPhenomXHM_structs_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <lal/LALAtomicDatatypes.h>
+
+#define N_HIGHERMODES_IMPLEMENTED 4 // lm = (21, 33, 32, 44)
+
+#define N_MAX_COEFFICIENTS_PHASE_INS 13       //Maximun number of coefficients of the inspiral ansatz
+#define N_MAX_COEFFICIENTS_PHASE_INTER 6      //Maximun number of coefficients of the intermediate ansatz
+#define N_MAX_COEFFICIENTS_PHASE_RING 4       //Maximun number of coefficients of the ringdown ansatz
+
+#define N_MAX_COEFFICIENTS_AMPLITUDE_INS 3    //Maximun number of collocation points in the inspiral
+#define N_MAX_COEFFICIENTS_AMPLITUDE_INTER 4  //Maximun number of collocation points in the intermediate. The fourth is for the EMR
+#define N_MAX_COEFFICIENTS_AMPLITUDE_RING 3   //Maximun number of coefficients in the ringdown. Only 21 has 3, the rest 2.
+
+
+// Data structure to hold QNM frequencies
+typedef double (*fitQNM_fring) (double finalDimlessSpin);
+typedef double (*fitQNM_fdamp) (double finalDimlessSpin);
+
+typedef struct tagQNMFits {
+ 	fitQNM_fring fring_lm[N_HIGHERMODES_IMPLEMENTED];
+ 	fitQNM_fdamp fdamp_lm[N_HIGHERMODES_IMPLEMENTED];
+} QNMFits;
+
+
+// General fit function. This is a type for defining the functions for the parameter space fits.
+typedef double (*ParameterSpaceFit) (double eta, double S, double chi1, double chi2, int flag);
+
+// Waveform struct.  Store useful variable specific of the higher modes that are not in 22 IMRPhenomXWaveformStruct or that need to be updated mode-by-mode. */
+typedef struct tagIMRPhenomXHMWaveformStruct
+{
+        /* Model Version Parameters */
+        INT4  IMRPhenomXHMInspiralPhaseVersion;
+        INT4  IMRPhenomXHMIntermediatePhaseVersion;
+        INT4  IMRPhenomXHMRingdownPhaseVersion;
+
+        INT4  IMRPhenomXHMInspiralAmpFitsVersion;
+        INT4  IMRPhenomXHMIntermediateAmpFitsVersion;
+        INT4  IMRPhenomXHMRingdownAmpFitsVersion;
+
+        INT4  IMRPhenomXHMInspiralAmpVersion;
+        INT4  IMRPhenomXHMIntermediateAmpVersion;
+        INT4  IMRPhenomXHMRingdownAmpVersion;
+
+
+        /* Spin Parameters */
+        REAL8 chi_s, chi_a;  // (chi1 +/- chi2)/2
+
+        /* MECO, Ringdown and Damping Frequencies */
+				REAL8 fMECOlm;  // = wf22->fMECO*m/2
+        REAL8 fRING;
+        REAL8 fDAMP;
+
+        /* Limit between comparable and extreme mass ratios for the phase */
+        REAL8 etaEMR;
+
+        /* The PhenomXAS functions returns the phase without a linear part that is not relevant for the matches.
+          We need this linear part for the multimode waveform. timeshift * f + phaseshift */
+        REAL8 timeshift;
+        REAL8 phaseshift;
+        REAL8 phiref22;  //Correction to apply to PhX phase for returning phiRef at reference frequency
+
+        /* mode labels ad tags*/
+        INT4 ell;      // spherical harmomic l
+        INT4 emm;      // spherical harmomic m
+        INT4 modeInt;
+        INT4 modeTag;
+
+        /* Number collocation points */
+        INT4 nCollocPtsInterPhase;
+        INT4 nCollocPtsRDPhase;
+        INT4 nCollocPtsInspAmp;
+        INT4 nCollocPtsInterAmp;
+
+        /* variable to control use of mode-mixing routines */
+        INT4 MixingOn;
+
+        // 2x2 matrix containing the mixing coefficients of the lm mode with the nearest dominant neighbour
+        COMPLEX8 mixingCoeffs[4];
+        COMPLEX8 mu22, mu32;
+
+        /* Variables to control use of Amplitude Veto for removing certain collocation points. */
+        INT4 InspiralAmpVeto, IntermediateAmpVeto, RingdownAmpVeto;
+
+        // The same than in WF22, sqrt(2*eta/3)/Pi, this is the normalization factor of the leading order of the 22.
+        REAL8 ampNorm;
+
+        // Variable to control if the case is EMR and apply the two intermediate regions for the amplitude
+        INT4 AmpEMR;
+
+        // Variable to control if the odd modes are zero
+        INT4 Ampzero;
+
+        // Multiply by Amp0 to transform NR amplitude to physical amplitude (= pWF22->ampNorm * pWF22->amp0 )
+        REAL8 Amp0;
+
+        // Variable to control the use of FAmpPN function for 21 instead of the power series
+        INT4 useFAmpPN;
+    
+        /* time-shift of the peak of the hybrids' 22 wrt end of the waveform*/
+        REAL8 DeltaT;
+
+    } IMRPhenomXHMWaveformStruct;
+
+
+    /******************* AMPLITUDE ****************/
+
+    // Store the coefficients needed to perform the amplitude reconstruction
+    typedef struct tagIMRPhenomXHMAmpCoefficients
+    {
+            /* Cutting frequencies */
+            REAL8 fAmpMatchIN;    // Inspiral -> Intermediate
+            REAL8 fAmpMatchInt12; // Intermediate1 -> Intermediate2. Only for EMR cases
+            REAL8 fAmpMatchIM;    // Intermediate -> Ringdown
+
+            /* PN Amplitude Prefactors */
+            COMPLEX16 pnInitial, pnOneThird, pnTwoThirds, pnThreeThirds, pnFourThirds, pnFiveThirds, pnSixThirds, pnSevenThirds, pnEightThirds,pnNineThirds;
+
+            /* PN Amplitude global prefactor */
+            REAL8 PNglobalfactor;
+
+            /* Coefficients of the pseudo-PN terms */
+            REAL8 rho1, rho2, rho3;
+
+            /* Coefficients of the polynomial in the intermediate region. 5th order by default */
+            REAL8 delta0, delta1, delta2, delta3, delta4, delta5;
+
+            /* Coefficients of the polynomial in the first intermediate region (for EMR only). 4th order.*/
+            REAL8 alpha0, alpha1, alpha2, alpha3, alpha4;
+
+            /* Coefficients of the Ringdown ansatz */
+            REAL8 alambda, lambda, sigma, lc;
+
+            // fits of coefficients/collocation points
+            ParameterSpaceFit InspiralAmpFits[N_HIGHERMODES_IMPLEMENTED*N_MAX_COEFFICIENTS_AMPLITUDE_INS];
+            ParameterSpaceFit IntermediateAmpFits[N_HIGHERMODES_IMPLEMENTED*N_MAX_COEFFICIENTS_AMPLITUDE_INTER];
+            ParameterSpaceFit RingdownAmpFits[N_HIGHERMODES_IMPLEMENTED*N_MAX_COEFFICIENTS_AMPLITUDE_RING];
+
+            /* Flag to set how many collocation points the inspiral region uses  */
+            REAL8 CollocationPointsValuesAmplitudeInsp[N_MAX_COEFFICIENTS_AMPLITUDE_INS];
+            REAL8 CollocationPointsFreqsAmplitudeInsp[N_MAX_COEFFICIENTS_AMPLITUDE_INS];
+
+            /* Flag to set how many collocation points the intermediate region uses */
+            REAL8 CollocationPointsFreqsAmplitudeInter[N_MAX_COEFFICIENTS_AMPLITUDE_INTER];
+            REAL8 CollocationPointsValuesAmplitudeInter[N_MAX_COEFFICIENTS_AMPLITUDE_INTER];
+
+            // Frequencies, values and derivatives for the intermediate reconstruction
+            // The frequencies are the same than in CollocationPointsFreqsAmplitudeInsp for the corresponding mode,
+            // but in this way they are easier accesible.
+            REAL8 f1,f2,f3,f4,v1,v2,v3,v4,d1,d4;
+
+            // Order of the polynomial in the intermediate region. 5th->105, for the first EMR region is 1042
+            INT4 InterAmpPolOrder;
+
+    				// Store the PN amplitude at the frequencies of the collocation points in the inspiral
+    				REAL8 PNAmplitudeInsp[N_MAX_COEFFICIENTS_AMPLITUDE_INS];
+
+            // For the pseudo part of Inspiral Amplitude ansatz. Used in LALSimIMRPhenomXHM_inspiral.c
+            REAL8 fcutInsp_seven_thirds;
+            REAL8 fcutInsp_eight_thirds;
+            REAL8 fcutInsp_three;
+
+            // Coefficients of the phasing factor coming from the SPA and time-domain Post-newtonian series, only for the 21 mode
+            REAL8 xdot5, xdot6, xdot65, xdot7, xdot75, xdot8, xdot8Log, xdot85, log2pi_two_thirds;
+            COMPLEX16 x05, x1, x15, x25, x2, x3;
+            REAL8 PNTDfactor;
+
+            // Variable to control the use of the inspiral ansatz to compute the amplitude at fmaxCalc
+            INT4 useInspAnsatzRingdown;
+
+            // Variables to control if we have to check that the collocation points are wavy
+            INT4 WavyInsp, WavyInt;
+
+            // Amp0 = wf22->ampNorm * wf22->amp0. Multiplying by this gives the amp factor of the 22 and transform to "physical" units
+            REAL8 Amp0;
+
+    } IMRPhenomXHMAmpCoefficients;
+
+
+/*************** PHASE *****************/
+
+// Store the coefficients needed to perform the phase reconstruction
+typedef struct tagIMRPhenomXHMPhaseCoefficients
+{
+        /* Phase Transition Frequencies */
+        REAL8 fPhaseMatchIN;
+        REAL8 fPhaseMatchIM;
+    
+        REAL8 deltaphiLM;
+         
+        /* These are the RD phenomenological coefficients, with mode-mixing off */
+        REAL8 alpha0, alpha2, alphaL;
+        REAL8 phi0RD, dphi0RD;
+
+        /* These are the RD phenomenological coefficients, with mode-mixing on: they give a phenomenological representation of the spheroidal-harmonic phase */
+        REAL8 phi0_S, alpha0_S, alpha2_S, alpha4_S, alphaL_S;
+
+        /* These are the intermediate phenomenological coefficients */
+        REAL8 c0, c1, c2, c3, c4, cL;
+        REAL8 CRD, C1RD, CINSP, C1INSP;
+
+        /* These are the inspiral phenomenological coefficients */
+        REAL8 phi[N_MAX_COEFFICIENTS_PHASE_INS];
+        REAL8 phiL[N_MAX_COEFFICIENTS_PHASE_INS];
+        REAL8 LambdaPN;
+
+        // fits of coefficients/collocation points
+        ParameterSpaceFit InspiralPhaseFits[N_HIGHERMODES_IMPLEMENTED];
+        ParameterSpaceFit IntermediatePhaseFits[N_HIGHERMODES_IMPLEMENTED*N_MAX_COEFFICIENTS_PHASE_INTER];
+        ParameterSpaceFit RingdownPhaseFits[N_MAX_COEFFICIENTS_PHASE_RING];
+
+        /* Flag to set how many collocation points the RD region uses --used only for the 32 mode */
+        INT4  NCollocationPointsRD;
+        REAL8 CollocationPointsValuesPhaseRD[N_MAX_COEFFICIENTS_PHASE_RING];
+        REAL8 CollocationPointsFreqsPhaseRD[N_MAX_COEFFICIENTS_PHASE_RING];
+
+        /* Flag to set how many collocation points the intermediate region uses */
+        INT4  NCollocationPointsInt;
+        REAL8 CollocationPointsFreqsPhaseInter[N_MAX_COEFFICIENTS_PHASE_INTER];
+        REAL8 CollocationPointsValuesPhaseInter[N_MAX_COEFFICIENTS_PHASE_INTER];
+
+} IMRPhenomXHMPhaseCoefficients;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LALSimIMRPhenomXHM_structs_h */
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_inspiral.c b/lalsimulation/lib/LALSimIMRPhenomX_inspiral.c
new file mode 100644
index 0000000000000000000000000000000000000000..058c741a5386839ccb109d71a137b7715b8f9698
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_inspiral.c
@@ -0,0 +1,815 @@
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ */
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+
+#include <lal/XLALError.h>
+
+#include "LALSimIMRPhenomX_utilities.h"
+#include "LALSimIMRPhenomX_internals.h"
+
+/******************************* IMRPhenomX Amplitude Functions: Inspiral *******************************/
+/*
+	Phenomenological coefficients for pseudo-PN corrections to TaylorF2 insiral:
+	Amp(f,eta,chi1,chi2) = TF2(f,eta,chi1,chi2) + A0 * ( delta1*f**(7/3) + delta2*f**(8/3) + delta3*f**(9/3) )
+*/
+
+
+/*
+    Value of amplitude collocation point at 2/4 f^A_T, defined in Eq. 5.7 of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Amp_22_v2(double eta, double S, double dchi, double delta, int InsAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+  double eta4 = (eta3*eta);
+
+  double S2 = (S*S);
+  double S3 = (S2*S);
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( InsAmpFlag )
+	{
+		case 103:
+		{
+      noSpin = (-0.015178276424448592 - 0.06098548699809163*eta + 0.4845148547154606*eta2)/(1. + 0.09799277215675059*eta);
+
+      eqSpin = ((0.02300153747158323 + 0.10495263104245876*eta2)*S + (0.04834642258922544 - 0.14189350657140673*eta)*eta*S3
+                    + (0.01761591799745109 - 0.14404522791467844*eta2)*S2)/(1. - 0.7340448493183307*S);
+
+      uneqSpin = dchi*delta*eta4*(0.0018724905795891192 + 34.90874132485147*eta);
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_v2: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*
+    Value of amplitude collocation point at 3/4 f^A_T, defined in Eq. 5.7 of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Amp_22_v3(double eta, double S, double dchi, double delta, int InsAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+  double eta4 = (eta3*eta);
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( InsAmpFlag )
+	{
+		case 103:
+		{
+      noSpin = (-0.058572000924124644 - 1.1970535595488723*eta + 8.4630293045015*eta2)/(1. + 15.430818840453686*eta);
+
+      eqSpin = ((-0.08746408292050666 + eta*(-0.20646621646484237 - 0.21291764491897636*S)
+                  + eta2*(0.788717372588848 + 0.8282888482429105*S) - 0.018924013869130434*S)*S)/(-1.332123330797879 + 1.*S);
+
+      uneqSpin = dchi*delta*eta4*(0.004389995099201855 + 105.84553997647659*eta);
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_v3: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*
+    Value of amplitude collocation point at 4/4 f^A_T, defined in Eq. 5.7 of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Amp_22_v4(double eta, double S, double dchi, double delta, int InsAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+  double eta4 = (eta3*eta);
+
+  double S2 = (S*S);
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( InsAmpFlag )
+	{
+		case 103:
+		{
+      noSpin = (-0.16212854591357853 + 1.617404703616985*eta - 3.186012733446088*eta2 + 5.629598195000046*eta3)/(1. + 0.04507019231274476*eta);
+
+      eqSpin = (S*(1.0055835408962206 + eta2*(18.353433894421833 - 18.80590889704093*S) - 0.31443470118113853*S
+                  + eta*(-4.127597118865669 + 5.215501942120774*S) + eta3*(-41.0378120175805
+                    + 19.099315016873643*S)))/(5.852706459485663 - 5.717874483424523*S + 1.*S2);
+
+      uneqSpin = dchi*delta*eta4*(0.05575955418803233 + 208.92352600701068*eta);
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_v4: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*
+    f1 = freq. at 2/4 f^A_T
+    f2 = freq. at 3/4 f^A_T
+    f3 = freq. at 4/4 f^A_T
+
+    v1 = Value of collocation point at f1
+    v2 = Value of collocation point at f2
+    v3 = Value of collocation point at f3
+
+    These expressions do *not* depend on calibration if model assumes:
+    TF2 + rho1 f^(7/3) + rho2 f^(8/3) + rho3 f^(9/3)
+*/
+
+/* Get Pseudo PN coefficient at f^(7/3) */
+static double IMRPhenomX_Inspiral_Amp_22_rho1(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag)
+{
+  double retVal;
+
+  switch ( InsAmpFlag )
+  {
+    case 103:
+    {
+      double f1p1o3, f2p1o3, f3p1o3;
+      double f1p7o3, f1p8o3, f2p7o3, f2p8o3, f3p7o3, f3p8o3;
+
+      f1p1o3 = cbrt(F1); // f1^(1/3)
+      f2p1o3 = cbrt(F2); // f2^(1/3)
+      f3p1o3 = cbrt(F3); // f3^(1/3)
+
+      f1p7o3 = pow_7_of(f1p1o3); // f1^(7/3)
+      f1p8o3 = f1p7o3 * f1p1o3;  // f1^(8/3)
+
+      f2p7o3 = pow_7_of(f2p1o3); // f2^(7/3)
+      f2p8o3 = f2p7o3 * f2p1o3;  // f2^(8/3)
+
+      f3p7o3 = pow_7_of(f3p1o3); // f3^(7/3)
+      f3p8o3 = f3p7o3 * f3p1o3;  // f3^(8/3)
+
+      retVal = (-(f2p8o3*(F3*F3*F3)*v1) + F2*F2*F2*f3p8o3*v1 + f1p8o3*(F3*F3*F3)*v2 - F1*F1*F1*f3p8o3*v2 - f1p8o3*(F2*F2*F2)*v3 + F1*F1*F1*f2p8o3*v3)
+                      / (f1p7o3*(f1p1o3 - f2p1o3)*f2p7o3*(f1p1o3 - f3p1o3)*(f2p1o3 - f3p1o3)*f3p7o3);
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_rho1: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+  }
+
+  return retVal;
+}
+
+/* Get Pseudo PN coefficient at f^(8/3) */
+static double IMRPhenomX_Inspiral_Amp_22_rho2(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag)
+{
+  double retVal;
+
+  switch ( InsAmpFlag )
+  {
+    case 103:
+    {
+      double f1p1o3, f2p1o3, f3p1o3;
+      double f1p7o3, f2p7o3, f3p7o3;
+
+      f1p1o3 = cbrt(F1); // f1^(1/3)
+      f2p1o3 = cbrt(F2); // f2^(1/3)
+      f3p1o3 = cbrt(F3); // f3^(1/3)
+
+      f1p7o3 = pow_7_of(f1p1o3); // f1^(7/3)
+
+      f2p7o3 = pow_7_of(f2p1o3); // f2^(7/3)
+
+      f3p7o3 = pow_7_of(f3p1o3); // f3^(7/3)
+
+      retVal = ( f2p7o3*(F3*F3*F3)*v1 - F2*F2*F2*f3p7o3*v1 - f1p7o3*(F3*F3*F3)*v2 + F1*F1*F1*f3p7o3*v2 + f1p7o3*(F2*F2*F2)*v3 - F1*F1*F1*f2p7o3*v3 )
+                        / (f1p7o3*(f1p1o3 - f2p1o3)*f2p7o3*(f1p1o3 - f3p1o3)*(f2p1o3 - f3p1o3)*f3p7o3);
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_rho2: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+  }
+
+  return retVal;
+}
+
+/* Get Pseudo PN coefficient at f^(9/3) */
+static double IMRPhenomX_Inspiral_Amp_22_rho3(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag)
+{
+  double retVal;
+
+  switch ( InsAmpFlag )
+  {
+    case 103:
+    {
+      double f1p1o3, f2p1o3, f3p1o3;
+      double f1p7o3, f1p8o3, f2p7o3, f2p8o3, f3p7o3, f3p8o3;
+
+      f1p1o3 = cbrt(F1); // f1^(1/3)
+      f2p1o3 = cbrt(F2); // f2^(1/3)
+      f3p1o3 = cbrt(F3); // f3^(1/3)
+
+      f1p7o3 = pow_7_of(f1p1o3); // f1^(7/3)
+      f1p8o3 = f1p7o3 * f1p1o3;  // f1^(8/3)
+
+      f2p7o3 = pow_7_of(f2p1o3); // f2^(7/3)
+      f2p8o3 = f2p7o3 * f2p1o3;  // f2^(8/3)
+
+      f3p7o3 = pow_7_of(f3p1o3); // f3^(7/3)
+      f3p8o3 = f3p7o3 * f3p1o3;  // f3^(8/3)
+
+      retVal = ( f2p8o3*f3p7o3*v1 - f2p7o3*f3p8o3*v1 - f1p8o3*f3p7o3*v2 + f1p7o3*f3p8o3*v2 + f1p8o3*f2p7o3*v3 - f1p7o3*f2p8o3*v3 )
+                        / ( f1p7o3*(f1p1o3 - f2p1o3)*f2p7o3*(f1p1o3 - f3p1o3)*(f2p1o3 - f3p1o3)*f3p7o3 );
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_rho3: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+  }
+
+  return retVal;
+}
+
+
+/*
+ *  TaylorF2 PN Amplitude + pseudo-PN coefficients
+ */
+static double IMRPhenomX_Inspiral_Amp_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
+{
+  double pnAmp;
+
+  int InsAmpFlag = pWF->IMRPhenomXInspiralAmpVersion;
+
+  switch ( InsAmpFlag )
+  {
+    case 103:
+    {
+      // Re-factor expression
+      pnAmp = (
+          pAmp->pnInitial // 1.0
+        + powers_of_Mf->one_third      * pAmp->pnOneThird
+        + powers_of_Mf->two_thirds     * pAmp->pnTwoThirds
+        + Mf                           * pAmp->pnThreeThirds
+        + Mf*(
+          + powers_of_Mf->one_third    * pAmp->pnFourThirds
+          + powers_of_Mf->two_thirds   * pAmp->pnFiveThirds
+          + Mf                         * pAmp->pnSixThirds
+          + Mf*(
+            + powers_of_Mf->one_third  * pAmp->rho1
+            + powers_of_Mf->two_thirds * pAmp->rho2
+            + Mf                       * pAmp->rho3
+            )
+          )
+      );
+      break;
+    }
+    default :
+    {
+        pnAmp = 0.0;
+    }
+  }
+
+  return pnAmp;
+}
+
+/*
+ *  Derivative of TaylorF2 PN Amplitude + pseudo-PN coefficients
+ */
+static double IMRPhenomX_Inspiral_Amp_22_DAnsatz(double Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp) {
+
+  double DAmpIns;
+
+  int InsAmpFlag = pWF->IMRPhenomXInspiralAmpVersion;
+
+  switch ( InsAmpFlag )
+  {
+    case 103:
+    {
+      double eta   = pWF->eta;
+      double chi1L = pWF->chi1L;
+      double chi2L = pWF->chi2L;
+      double rho1  = pAmp->rho1;
+      double rho2  = pAmp->rho2;
+      double rho3  = pAmp->rho3;
+
+      double chi1L2 = chi1L  * chi1L;
+      double chi1L3 = chi1L2 * chi1L;
+      double chi2L2 = chi2L  * chi2L;
+
+      double eta2   = eta*eta;
+      double eta3   = eta*eta2;
+      double Mf2    = Mf*Mf;
+      double LALPi  = LAL_PI;
+
+      double delta  = pWF->delta;
+
+      DAmpIns =
+      ( ((chi2L*(81 - 81*delta - 44*eta) + chi1L*(81*(1 + delta) - 44*eta))*LALPi)/48.
+      + ((-969 + 1804*eta)*pow(LALPi,2./3.))/(1008.*pow(Mf,1/3.))
+      + ((-27312085 - 10287648*chi2L2 + 10287648*chi2L2*delta - 10287648*chi1L2*(1 + delta)
+         + 24*(-1975055 + 857304*chi1L2 - 994896*chi1L*chi2L + 857304*chi2L2)*eta + 35371056*eta2)*pow(LALPi,4./3.)*pow(Mf,1./3.))/6.096384e6
+      + (5*pow(LALPi,5./3.)*(-6048*chi1L3*(-1 - delta + (3 + delta)*eta) + chi1L*(287213*(1 + delta) - 4*(93414 + 2083*delta)*eta - 35632*eta2)
+               + chi2L*(-((287213 + 6048*chi2L2)*(-1 + delta)) + 4*(-93414 + 1512*chi2L2*(-3 + delta) + 2083*delta)*eta - 35632*eta2)
+               + 42840*(-1 + 4*eta)*LALPi)*pow(Mf,2./3.))/96768.
+       - (pow(LALPi,2.0)*(-336*(-3248849057 + 1809550512*chi1L2 - 2954929824*chi1L*chi2L + 1809550512*chi2L2)*eta2 - 324322727232*eta3
+             + 7*(177520268561 + 29362199328*chi2L2 - 29362199328*chi2L2*delta + 29362199328*chi1L2*(1 + delta)
+             + 12160253952*(chi1L + chi2L + chi1L*delta - chi2L*delta)*LALPi)
+             + 12*eta*(-545384828789 + 49568837472*chi1L*chi2L - 12312458928*chi2L2 - 21943440288*chi2L2*delta
+             + 77616*chi1L2*(-158633 + 282718*delta) - 8345272320*(chi1L + chi2L)*LALPi
+             + 21384760320*pow(LALPi,2.0)))*Mf)/3.0042980352e10
+       + (7.0/3.0)*pow(Mf,4.0/3.0)*rho1 + (8.0/3.0)*pow(Mf,5.0/3.0)*rho2 + 3*Mf2*rho3 );
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Amp_22_DAnsatz: IMRPhenomXInspiralAmpVersion is not valid.\n");
+    }
+  }
+
+  return DAmpIns;
+}
+
+/******************************* Phase Functions: Inspiral *******************************/
+/*
+	Phenomenological coefficients for pseudo-PN corrections to TaylorF2 insiral:
+	Psi(f,eta,chi1,chi2) = TF2(f,eta,chi1,chi2) + (1/eta) * ( alpha0 + alpha1*f**(3/3) + (3/4)*alpha2*f**(4/3) + (3/5)*alpha3*f**(5/3) + (1/2)*alpha4*f**(6/3) )
+*/
+
+/*
+	This code is designed and intended to be modular. If a new PN TaylorF2 approximant is produced or a new fit against NR
+	hybrids generated, then you can add the fit to the collocation points by simply adding in the extra case.
+
+	This is intended to avoid a massive over-duplication of near-identical functions.
+*/
+
+/*
+    Value of phase collocation point at v_3. See section VII.A of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Phase_22_v3(double eta, double S, double dchi, double delta, int InspPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+	double eta4  = eta3*eta;
+	double eta5  = eta4*eta;
+
+	double S2    = S*S;
+	double S3    = S2*S;
+
+  double dchi2 = dchi*dchi;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( InspPhaseFlag )
+	{
+		case 104: 			/* Canonical, 3 pseudo PN terms */
+		{
+      noSpin = (15415.000000000007 + 873401.6255736464*eta + 376665.64637025696*eta2 - 3.9719980569125614e6*eta3 + 8.913612508054944e6*eta4)/(1. + 46.83697749859996*eta);
+
+      eqSpin = (S*(397951.95299014193 - 207180.42746987*S + eta3*(4.662143741417853e6 - 584728.050612325*S - 1.6894189124921719e6*S2) + eta*(-1.0053073129700898e6 + 1.235279439281927e6*S - 174952.69161683554*S2) - 130668.37221912303*S2 + eta2*(-1.9826323844247842e6 + 208349.45742548333*S + 895372.155565861*S2)))/(-9.675704197652225 + 3.5804521763363075*S + 2.5298346636273306*S2 + 1.*S3);
+
+      uneqSpin = -1296.9289110696955*dchi2*eta + dchi*delta*eta*(-24708.109411857182 + 24703.28267342699*eta + 47752.17032707405*S);
+
+  		break;
+		}
+		case 105:				/* Canonical, 4 pseudo PN terms */
+		{
+      noSpin = (11717.332402222377 + 4.972361134612872e6*eta + 2.137585030930089e7*eta2 - 8.882868155876668e7*eta3 + 2.4104945956043008e8*eta4 - 2.3143426271719798e8*eta5)/(1. + 363.5524719849582*eta);
+
+      eqSpin = (S*(52.42001436116159 - 50.547943589389966*S + eta3*S*(-15355.56020802297 + 20159.588079899433*S) + eta2*(-286.9576245212502 + 2795.982637986682*S - 2633.1870842242447*S2) - 1.0824224105690476*S2 + eta*(-123.78531181532225 + 136.1961976556154*S - 7.534890781638552*S3) + 5.973206330664007*S3 + eta4*(1777.2176433016125 + 24069.288079063674*S - 44794.9522164669*S2 + 1584.1515277998406*S3)))/(-0.0015307616935628491 + (0.0010676159178395538 - 0.25*eta3 + 1.*eta4)*S);
+
+      uneqSpin = -1357.9794908614106*dchi2*eta + dchi*delta*eta*(-23093.829989687543 + 21908.057881789653*eta + 49493.91485992256*S);
+
+  		break;
+		}
+		case 114:				/* Extended, 3 pseudo PN terms */
+		{
+      noSpin = (68014.00000000003 + 1.1513072539654972e6*eta - 2.725589921577228e6*eta2 + 312571.92531733884*eta3)/(1. + 17.48539665509149*eta);
+
+      eqSpin = (S*(-34467.00643820664 + 99693.81839115614*eta + 144345.24343461913*eta4 + (23618.044919850676 - 89494.69555164348*eta + 725554.5749749158*eta4 - 103449.15865381068*eta2)*S + (10350.863429774612 - 73238.45609787296*eta + 3.559251543095961e6*eta4 + 888228.5439003729*eta2 - 3.4602940487291473e6*eta3)*S2))/(1. - 0.056846656084188936*S - 0.32681474740130184*S2 - 0.30562055811022015*S3);
+
+      uneqSpin = -1182.4036752941936*dchi2*eta + dchi*delta*eta*(-0.39185419821851025 - 99764.21095663306*eta + 41826.177356107364*S);
+
+  		break;
+		}
+		case 115:				/* Extended, 4 pseudo PN terms */
+		{
+      noSpin = (60484.00000000003 + 4.370611564781374e6*eta - 5.785128542827255e6*eta2 - 8.82141241633613e6*eta3 + 1.3406996319926713e7*eta4)/(1. + 70.89393713617065*eta);
+
+      eqSpin = (S*(21.91241092620993 - 32.57779678272056*S + eta2*(-102.4982890239095 + 2570.7566494633033*S - 2915.1250015652076*S2) + 8.130585173873232*S2 + eta*(-28.158436727309365 + 47.42665852824481*S2) + eta3*(-1635.6270690726785 - 13745.336370568011*S + 19539.310912464192*S2) + 1.2792283911312285*S3 + eta4*(5558.382039622131 + 21398.7730201213*S - 37773.40511355719*S2 + 768.6183344184254*S3)))/(-0.0007758753818017038 + (0.0005304023864415552 - 0.25000000000000006*eta3 + 1.*eta4)*S);
+
+      uneqSpin = -1223.769262298142*dchi2*eta + dchi*delta*eta*(-16.705471562129436 - 93771.93750060834*eta + 43675.70151058481*S);
+
+  		break;
+		}
+    default:
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Phase_22_v3: NPseudoPN requested is not valid.\n");
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+    Value of phase collocation point for d13 = v1 - v3. See section VII.A of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Phase_22_d13(double eta, double S, double dchi, double delta, int InspPhaseFlag){
+
+	double eta2 = eta*eta;
+	double eta3 = eta2*eta;
+	double eta4 = eta3*eta;
+	double eta5 = eta4*eta;
+
+	double S2   = S*S;
+	double S3   = S2*S;
+	double S4   = S3*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( InspPhaseFlag )
+	{
+		case 104: 			/* Canonical, 3 pseudo PN terms */
+		{
+      noSpin = (-17294.000000000007 - 19943.076428555978*eta + 483033.0998073767*eta2)/(1. + 4.460294035404433*eta);
+
+      eqSpin = (S*(68384.62786426462 + 67663.42759836042*S - 2179.3505885609297*S2 + eta*(-58475.33302037833 + 62190.404951852535*S + 18298.307770807573*S2 - 303141.1945565486*S3) + 19703.894135534803*S3 + eta2*(-148368.4954044637 - 758386.5685734496*S - 137991.37032619823*S2 + 1.0765877367729193e6*S3) + 32614.091002011017*S4))/(2.0412979553629143 + 1.*S);
+
+      uneqSpin = 12017.062595934838*dchi*delta*eta;
+  		break;
+		}
+		case 105:				/* Canonical, 4 pseudo PN terms */
+		{
+      noSpin = (-14234.000000000007 + 16956.107542097994*eta + 176345.7518697656*eta2)/(1. + 1.294432443903631*eta);
+
+      eqSpin = (S*(814.4249470391651 + 539.3944162216742*S + 1985.8695471257474*S2 + eta*(-918.541450687484 + 2531.457116826593*S - 14325.55532310136*S2 - 19213.48002675173*S3) + 1517.4561843692861*S3 + eta2*(-517.7142591907573 - 14328.567448748548*S + 21305.033147575057*S2 + 50143.99945676916*S3)))/(0.03332712934306297 + 0.0025905919215826172*S + (0.07388087063636305 - 0.6397891808905215*eta + 1.*eta2)*S2);
+
+      uneqSpin = dchi*delta*eta*(0.09704682517844336 + 69335.84692284222*eta);
+
+  		break;
+		}
+		case 114:				/* Extended, 3 pseudo PN terms */
+		{
+      noSpin = (-36664.000000000015 + 277640.10051158903*eta - 581120.4916255298*eta2 + 1.415628418251648e6*eta3 - 7.640937162029471e6*eta4 + 1.1572710625359124e7*eta5)/(1. - 4.011038704323779*eta);
+
+      eqSpin = (S*(-38790.01253014577 - 50295.77273512981*S + 15182.324439704937*S2 + eta2*(57814.07222969789 + 344650.11918139807*S + 17020.46497164955*S2 - 574047.1384792664*S3) + 24626.598127509922*S3 + eta*(23058.264859112394 - 16563.935447608965*S - 36698.430436426395*S2 + 105713.91549712936*S3)))/(-1.5445637219268247 - 0.24997068896075847*S + 1.*S2);
+
+      uneqSpin = 74115.77361380383*dchi*delta*eta2;
+
+  		break;
+		}
+		case 115:				/* Extended, 4 pseudo PN terms */
+		{
+      noSpin = (-29240.00000000001 - 12488.41035199958*eta + 1.3911845288427814e6*eta2 - 3.492477584609041e6*eta3)/(1. + 2.6711462529779824*eta - 26.80876660227278*eta2);
+
+      eqSpin = (S*(-29536.155624432842 - 40024.5988680615*S + 11596.401177843705*S2 + eta2*(122185.06346551726 + 351091.59147835104*S - 37366.6143666202*S2 - 505834.54206320125*S3) + 20386.815769841945*S3 + eta*(-9638.828456576934 - 30683.453790630676*S - 15694.962417099561*S2 + 91690.51338194775*S3)))/(-1.5343852108869265 - 0.2215651087041266*S + 1.*S2);
+
+      uneqSpin = 68951.75344813892*dchi*delta*eta2;
+
+  		break;
+		}
+    default:
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Phase_22_d13: NPseudoPN requested is not valid.\n");
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+    Value of phase collocation point for d23 = v2 - v3. See section VII.A of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Phase_22_d23(double eta, double S, double dchi, double delta, int InspPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+	
+	double dchi2 = dchi * dchi;
+
+	double S2    = S*S;
+	double S3    = S2*S;
+	double S4    = S3*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( InspPhaseFlag )
+	{
+		case 104: 			/* Canonical, 4 pseudo PN coefficients */
+		{
+      noSpin = (-7579.300000000004 - 120297.86185566607*eta + 1.1694356931282217e6*eta2 - 557253.0066989232*eta3)/(1. + 18.53018618227582*eta);
+
+      eqSpin = (S*(-27089.36915061857 - 66228.9369155027*S + eta2*(150022.21343386435 - 50166.382087278434*S - 399712.22891153296*S2) - 44331.41741405198*S2 + eta*(50644.13475990821 + 157036.45676788126*S + 126736.43159783827*S2) + eta3*(-593633.5370110178 - 325423.99477314285*S + 847483.2999508682*S2)))/(-1.5232497464826662 - 3.062957826830017*S - 1.130185486082531*S2 + 1.*S3);
+
+      uneqSpin = 3843.083992827935*dchi*delta*eta;
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 pseudo PN coefficients */
+		{
+      noSpin = (-7520.900000000003 - 49463.18828584058*eta + 437634.8057596484*eta2)/(1. + 9.10538019868398*eta);
+
+      eqSpin = (S*(25380.485895523005 + 30617.553968012628*S + 5296.659585425608*S2 + eta*(-49447.74841021405 - 94312.78229903466*S - 5731.614612941746*S3) + 2609.50444822972*S3 + 5206.717656940992*S4 + eta2*(54627.758819129864 + 157460.98527210607*S - 69726.85196686552*S2 + 4674.992397927943*S3 + 20704.368650323784*S4)))/(1.5668927528319367 + 1.*S);
+
+      uneqSpin = -95.38600275845481*dchi2*eta + dchi*delta*eta*(3271.8128884730654 + 12399.826237672185*eta + 9343.380589951552*S);
+
+  		break;
+		}
+		case 114:				/* Extended, 4 pseudo PN coefficients */
+		{
+      noSpin = (-17762.000000000007 - 1.6929191194109183e6*eta + 8.420903644926643e6*eta2)/(1. + 98.061533474615*eta);
+
+      eqSpin = (S*(-46901.6486082098 - 83648.57463631754*S + eta2*(1.2502334322912344e6 + 1.4500798116821344e6*S - 1.4822181506831646e6*S2) - 41234.966418619966*S2 + eta*(-24017.33452114588 - 15241.079745314566*S + 136554.48806839858*S2) + eta3*(-3.584298922116994e6 - 3.9566921791790277e6*S + 4.357599992831832e6*S2)))/(-3.190220646817508 - 3.4308485421201387*S - 0.6347932583034377*S2 + 1.*S3);
+
+      uneqSpin = 24906.33337911219*dchi*delta*eta2;
+
+  		break;
+		}
+		case 115:				/* Extended, 5 pseudo PN coefficients */
+		{
+      noSpin = (-18482.000000000007 - 1.2846128476247871e6*eta + 4.894853535651343e6*eta2 + 3.1555931338015324e6*eta3)/(1. + 82.79386070797756*eta);
+
+      eqSpin = (S*(-19977.10130179636 - 24729.114403562427*S + 10325.295899053815*S2 + eta*(30934.123894659646 + 58636.235226102894*S - 32465.70372990005*S2 - 38032.16219587224*S3) + 15485.725898689267*S3 + eta2*(-38410.1127729419 - 87088.84559983511*S + 61286.73536122325*S2 + 42503.913487705235*S3)))/(-1.5148031011828222 - 0.24267195338525768*S + 1.*S2);
+
+      uneqSpin = 5661.027157084334*dchi*delta*eta;
+
+  		break;
+		}
+    default:
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Phase_22_d23: NPseudoPN requested is not valid.\n");
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+    Value of phase collocation point for d43 = v4 - v3. See section VII.A of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Phase_22_d43(double eta, double S, double dchi, double delta, int InspPhaseFlag){
+
+	double eta2 = eta*eta;
+	double eta3 = eta2*eta;
+	double eta4 = eta3*eta;
+
+	double S2   = S*S;
+	double S3   = S2*S;
+	
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( InspPhaseFlag )
+	{
+		case 104: 			/* Canonical, 3 pseudo PN coefficients */
+		{
+      noSpin = (2439.000000000001 - 31133.52170083207*eta + 28867.73328134167*eta2)/(1. + 0.41143032589262585*eta);
+
+      eqSpin = (S*(16116.057657391262 + eta3*(-375818.0132734753 - 386247.80765802023*S) + eta*(-82355.86732027541 - 25843.06175439942*S) + 9861.635308837876*S + eta2*(229284.04542668918 + 117410.37432997991*S)))/(-3.7385208695213668 + 0.25294420589064653*S + 1.*S2);
+
+      uneqSpin = 194.5554531509207*dchi*delta*eta;
+
+  		break;
+		}
+		case 105:				/* Canonical, 4 pseudo PN coefficients */
+		{
+      noSpin = (4085.300000000002 + 62935.7755506329*eta - 1.3712743918777364e6*eta2 + 5.024685134555112e6*eta3 - 3.242443755025284e6*eta4)/(1. + 20.889132970603523*eta - 99.39498823723363*eta2);
+
+      eqSpin = (S*(-299.6987332025542 - 106.2596940493108*S + eta3*(2383.4907865977148 - 13637.11364447208*S - 14808.138346145908*S2) + eta*(1205.2993091547498 - 508.05838536573464*S - 1453.1997617403304*S2) + 132.22338129554674*S2 + eta2*(-2438.4917103042208 + 5032.341879949591*S + 7026.9206794027405*S2)))/(0.03089183275944264 + 1.*eta3*S - 0.010670764224621489*S2);
+
+      uneqSpin = -1392.6847421907178*dchi*delta*eta;
+
+  		break;
+		}
+		case 114:				/* Extended, 3 pseudo PN coefficients */
+		{
+      noSpin = (5749.000000000003 - 37877.95816426952*eta)/(1. + 1.1883386102990128*eta);
+
+      eqSpin = ((-4285.982163759047 + 24558.689969419473*eta - 49270.2296311733*eta2)*S + eta*(-24205.71407420114 + 70777.38402634041*eta)*S2 + (2250.661418551257 + 187.95136178643946*eta - 11976.624134935797*eta2)*S3)/(1. - 0.7220334077284601*S);
+
+      uneqSpin = dchi*delta*eta*(339.69292150803585 - 3459.894150148715*S);
+
+  		break;
+		}
+		case 115:				/* Extended, 4 pseudo PN coefficients */
+		{
+      noSpin = (9760.400000000005 + 9839.852773121198*eta - 398521.0434645335*eta2 + 267575.4709475981*eta3)/(1. + 6.1355249449135005*eta);
+
+      eqSpin = (S*(-1271.406488219572 + eta2*(-9641.611385554736 - 9620.333878140807*S) - 1144.516395171019*S + eta*(5155.337817255137 + 4450.755534615418*S)))/(0.1491519640750958 + (-0.0008208549820159909 - 0.15468508831447628*eta + 0.7266887643762937*eta2)*S + (0.02282542856845755 - 0.445924460572114*eta + 1.*eta2)*S2);
+
+      uneqSpin = -1366.7949288045616*dchi*delta*eta;
+
+  		break;
+		}
+    default:
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Phase_22_d43: NPseudoPN requested is not valid.\n");
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+    Value of phase collocation point for d53 = v5 - v3. See section VII.A of arXiv:2001.11412
+   
+    Effective spin parameterization used = chiPNHat
+*/
+static double IMRPhenomX_Inspiral_Phase_22_d53(double eta, double S, double dchi, double delta, int InspPhaseFlag){
+
+	double eta2 = eta*eta;
+	double eta3 = eta2*eta;
+
+	double S2   = S*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( InspPhaseFlag )
+	{
+		case 104: 			/* This should not be called for 4 pseudo-PN coefficients. Return 0 and print warning just in case... */
+		{
+			XLAL_ERROR_REAL8(XLAL_EINVAL, "Calling IMRPhenomX_Inspiral_Phase_22_d53 but trying to pass InspPhaseFlag for 4 pseudo-PN coefficients. Check this.\n");
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 pseudo PN coefficients */
+		{
+      noSpin = (5474.400000000003 + 131008.0112992443*eta - 1.9692364337640922e6*eta2 + 1.8732325307375633e6*eta3)/(1. + 32.90929274981482*eta);
+
+      eqSpin = (S*(18609.016486281424 - 1337.4947536109685*S + eta2*(219014.98908698096 - 307162.33823247004*S - 124111.02067626518*S2) - 7394.9595046977365*S2 + eta*(-87820.37490863055 + 53564.4178831741*S + 34070.909093771494*S2) + eta3*(-248096.84257893753 + 536024.5354098587*S + 243877.65824670633*S2)))/(-1.5282904337787517 + 1.*S);
+
+      uneqSpin = -429.1148607925461*dchi*delta*eta;
+
+  		break;
+		}
+		case 114:				/* Extended, 4 pseudo PN coefficients */
+		{
+			XLAL_ERROR_REAL8(XLAL_EINVAL, "Calling IMRPhenomX_Inspiral_Phase_22_d53 but trying to pass InspPhaseFlag for 4 pseudo-PN coefficients. Check this.\n");
+		}
+		case 115:				/* Extended, 5 pseudo PN terms */
+		{
+      noSpin = (12971.000000000005 - 93606.05144508784*eta + 102472.4473167639*eta2)/(1. - 0.8909484992212859*eta);
+
+      eqSpin = (S*(16182.268123259992 + 3513.8535400032874*S + eta2*(343388.99445324624 - 240407.0282222587*S - 312202.59917289804*S2) - 10814.056847109632*S2 + eta*(-94090.9232151429 + 35305.66247590705*S + 65450.36389642103*S2) + eta3*(-484443.15601144277 + 449511.3965208116*S + 552355.592066788*S2)))/(-1.4720837917195788 + 1.*S);
+
+      uneqSpin = -494.2754225110706*dchi*delta*eta;
+
+  		break;
+		}
+    default:
+    {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Inspiral_Phase_22_d53: NPseudoPN requested is not valid.\n");
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+		See section VII.A of arXiv:2001.11412
+
+		This function solves for the pseudo-PN coefficients. The structure of the equations is:
+
+			c + alpha * x + beta * x^2 + gamma * x^3 + xi * x^4
+
+		where x = f^(1/3).
+
+		For 3 pseudo-PN parameters, we solve for: (c,alpha,beta,gamma).
+		For 4 pseudo-PN parameters, we solve for: (c,alpha,beta,gamma,xi).
+
+		Phase Derivative: TaylorF2 + pseudo-PN coefficients
+*/
+static double IMRPhenomX_Inspiral_Phase_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase)
+{
+    double phaseIN;
+
+    // Assemble PN phase derivative series
+  	phaseIN  = pPhase->dphi0; 																						    // f^{0/3}
+  	phaseIN += pPhase->dphi1 	* powers_of_Mf->one_third; 								      // f^{1/3}
+  	phaseIN += pPhase->dphi2 	* powers_of_Mf->two_thirds; 									    // f^{2/3}
+  	phaseIN += pPhase->dphi3 	* Mf; 									        // f^{3/3}
+  	phaseIN += pPhase->dphi4 	* powers_of_Mf->four_thirds; 							      // f^{4/3}
+  	phaseIN += pPhase->dphi5 	* powers_of_Mf->five_thirds; 							      // f^{5/3}
+  	phaseIN += pPhase->dphi6  * powers_of_Mf->two;													    // f^{6/3}
+  	phaseIN += pPhase->dphi6L * powers_of_Mf->two * powers_of_Mf->log;			    // f^{6/3}, Log[f]
+  	phaseIN += pPhase->dphi7  * powers_of_Mf->seven_thirds;									  // f^{7/3}
+  	phaseIN += pPhase->dphi8  * powers_of_Mf->eight_thirds;									  // f^{8/3}
+  	phaseIN += pPhase->dphi8L * powers_of_Mf->eight_thirds * powers_of_Mf->log;	// f^{8/3}
+  	phaseIN += pPhase->dphi9  * powers_of_Mf->three;														// f^{9/3}
+  	phaseIN += pPhase->dphi9L * powers_of_Mf->three * powers_of_Mf->log;				// f^{9/3}
+
+  	// Add pseudo-PN Coefficient
+  	phaseIN += ( 		pPhase->a0 * powers_of_Mf->eight_thirds
+  								+ pPhase->a1 * powers_of_Mf->three
+  								+ pPhase->a2 * powers_of_Mf->eight_thirds * powers_of_Mf->two_thirds
+  								+ pPhase->a3 * powers_of_Mf->eight_thirds * powers_of_Mf->itself
+  								+ pPhase->a4 * powers_of_Mf->eight_thirds * powers_of_Mf->four_thirds
+  							);
+
+  	phaseIN  = phaseIN * powers_of_Mf->m_eight_thirds * (5.0 / (128.0 * powers_of_lalpi.five_thirds));
+
+    return phaseIN;
+}
+
+/**
+ * Ansatz for the inspiral phase.
+ * The TaylorF2 coefficients are defined elsewhere.
+ */
+static double IMRPhenomX_Inspiral_Phase_22_AnsatzInt(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase)
+{
+
+  // Assemble PN phasing series
+  //const double v    = powers_of_Mf->one_third * powers_of_lalpi.one_third; // v = (\pi M f)^{1/3}
+  //const double logv = log(v);
+
+  // Sum up phasing contributions
+  double phasing    = 0.0;
+
+  /* The PN Phasing series is normalised by: 3 / (128 * eta * pi^{5/3} ) */
+  /* 0  */ phasing += pPhase->phi0;                                                   // f^{-5/3}, v = 0;  Newt.
+  /* 1  */ phasing += pPhase->phi1  * powers_of_Mf->one_third;                        // f^{-4/3}, v = 1;  0.5PN
+  /* 2  */ phasing += pPhase->phi2  * powers_of_Mf->two_thirds;                       // f^{-3/3}, v = 2;  1.0PN
+  /* 3  */ phasing += pPhase->phi3  * Mf;                                             // f^{-2/3}, v = 3;  1.5PN
+  /* 4  */ phasing += pPhase->phi4  * powers_of_Mf->four_thirds;                      // f^{-1/3}, v = 4;  2.0PN
+  /* 5  */ phasing += pPhase->phi5  * powers_of_Mf->five_thirds;                      // f^{0},    v = 5;  2.5PN; phi_initial = - LAL_PI_4
+  /* 5L */ phasing += pPhase->phi5L * powers_of_Mf->five_thirds * powers_of_Mf->log;  // f^{0},    v = 5;  2.5PN Log terms.
+  /* 6  */ phasing += pPhase->phi6  * powers_of_Mf->two;                              // f^{+1/3}; v = 6;  3.0PN
+  /* 6L */ phasing += pPhase->phi6L * powers_of_Mf->two * powers_of_Mf->log;          // f^{+1/3}; v = 6;  3.0PN Log terms.
+  /* 7  */ phasing += pPhase->phi7  * powers_of_Mf->seven_thirds;                     // f^{+2/3}: v = 7;  3.5PN
+  /* 8  */ phasing += pPhase->phi8  * powers_of_Mf->eight_thirds;                     // f^{+3/3}; v = 8;  4.0PN
+  /* 8  */ phasing += pPhase->phi8L * powers_of_Mf->eight_thirds * powers_of_Mf->log; // f^{+3/3}; v = 8;  4.0PN Log terms.
+  /* 9  */ phasing += pPhase->phi9  * powers_of_Mf->three;                            // f^{+4/3}; v = 9;  4.5PN
+  /* 9  */ phasing += pPhase->phi9L * powers_of_Mf->three * powers_of_Mf->log;        // f^{+4/3}; v = 9;  4.5PN
+
+  // Now add in the pseudo-PN Coefficients
+  phasing += (  pPhase->sigma1 * powers_of_Mf->eight_thirds
+              + pPhase->sigma2 * powers_of_Mf->three
+              + pPhase->sigma3 * powers_of_Mf->one_third  * powers_of_Mf->three
+              + pPhase->sigma4 * powers_of_Mf->two_thirds * powers_of_Mf->three
+              + pPhase->sigma5 * powers_of_Mf->itself     * powers_of_Mf->three
+            );
+
+  // This completes the TaylorF2 PN phasing series
+  phasing = phasing * pPhase->phiNorm * powers_of_Mf->m_five_thirds;
+
+  /* Add initial phasing: -pi/4 */
+  //phasing += pPhase->phi_initial;
+
+  return phasing;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_inspiral.h b/lalsimulation/lib/LALSimIMRPhenomX_inspiral.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c3e4d6b9b03419e327f98ccda02efdead9ebde5
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_inspiral.h
@@ -0,0 +1,71 @@
+#ifndef _LALSIM_IMR_PHENOMX_INSPIRAL_H
+#define _LALSIM_IMR_PHENOMX_INSPIRAL_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+
+/********************************* IMRPhenomX: Amplitude Functions *********************************/
+//static double IMRPhenomX_Inspiral_Amp_22_v1(double eta, double S, double dchi, double delta, int InsAmpFlag);
+static double IMRPhenomX_Inspiral_Amp_22_v2(double eta, double S, double dchi, double delta, int InsAmpFlag);
+static double IMRPhenomX_Inspiral_Amp_22_v3(double eta, double S, double dchi, double delta, int InsAmpFlag);
+static double IMRPhenomX_Inspiral_Amp_22_v4(double eta, double S, double dchi, double delta, int InsAmpFlag);
+
+static double IMRPhenomX_Inspiral_Amp_22_rho1(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag);
+static double IMRPhenomX_Inspiral_Amp_22_rho2(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag);
+static double IMRPhenomX_Inspiral_Amp_22_rho3(double v1, double v2, double v3, double F1, double F2, double F3, int InsAmpFlag);
+
+static double IMRPhenomX_Inspiral_Amp_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+static double IMRPhenomX_Inspiral_Amp_22_DAnsatz(double Mf, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+
+/********************************* IMRPhenomX: Phase Functions *********************************/
+static double IMRPhenomX_Inspiral_Phase_22_v3(double eta, double S, double dchi, double delta, int InspPhaseFlag);
+static double IMRPhenomX_Inspiral_Phase_22_d13(double eta, double S, double dchi, double delta, int InspPhaseFlag);
+static double IMRPhenomX_Inspiral_Phase_22_d23(double eta, double S, double dchi, double delta, int InspPhaseFlag);
+static double IMRPhenomX_Inspiral_Phase_22_d43(double eta, double S, double dchi, double delta, int InspPhaseFlag);
+static double IMRPhenomX_Inspiral_Phase_22_d53(double eta, double S, double dchi, double delta, int InspPhaseFlag);
+
+static double IMRPhenomX_Inspiral_Phase_22_Ansatz(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase);
+static double IMRPhenomX_Inspiral_Phase_22_AnsatzInt(double Mf, IMRPhenomX_UsefulPowers *powers_of_Mf, IMRPhenomXPhaseCoefficients *pPhase);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// of #ifndef _LALSIM_IMR_PHENOMX_INSPIRAL_H
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_intermediate.c b/lalsimulation/lib/LALSimIMRPhenomX_intermediate.c
new file mode 100644
index 0000000000000000000000000000000000000000..7c7832f8acf491b1289d86f1d77dd2b5b02c7d89
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_intermediate.c
@@ -0,0 +1,1428 @@
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ * \file
+ *
+ * \brief Internal function for IMRPhenomX phenomenological waveform model, arXiv:2001.11412
+ *
+ */
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+
+#include "LALSimIMRPhenomX_intermediate.h"
+
+
+/******************************* IMRPhenomX Amplitude Functions *******************************/
+
+/******************************* Amplitude Functions: Merger   *******************************/
+
+/*
+	See section VI. B of arXiv:2001.11412
+
+    Value of intermediate amplitude collocation vA point at f_2, defined in Table II of arXiv:2001.11412
+   
+    Effective spin parameterization used = StotR
+*/
+static double IMRPhenomX_Intermediate_Amp_22_vA(double eta, double S, double dchi, double delta, int IntAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+
+  double S2 = S*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( IntAmpFlag )
+	{
+    case 104:
+	{
+
+		noSpin = (1.4873184918202145 + 1974.6112656679577*eta + 27563.641024162127*eta2 - 19837.908020966777*eta3)/(1. + 143.29004876335128*eta + 458.4097306093354*eta2);
+
+		eqSpin = (S*(27.952730865904343 + eta*(-365.55631765202895 - 260.3494489873286*S) + 3.2646808851249016*S + 3011.446602208493*eta2*S - 19.38970173389662*S2 + eta3*(1612.2681322644232 - 6962.675551371755*S + 1486.4658089990298*S2)))/(12.647425554323242 - 10.540154508599963*S + 1.*S2);
+
+		uneqSpin = dchi*delta*(-0.016404056649860943 - 296.473359655246*eta)*eta2;
+
+  		break;
+	}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_vA: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104. \n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*	
+	See section VI. B of arXiv:2001.11412. Collocation point for 5th order polynomial ansatz.
+
+    Value of intermediate amplitude collocation point v2 at f_2, defined in Table I of arXiv:2001.11412
+   
+    Effective spin parameterization used = StotR
+*/
+static double IMRPhenomX_Intermediate_Amp_22_v2(double eta, double S, double dchi, double delta, int IntAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+
+  double S2 = S*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( IntAmpFlag )
+	{
+		case 1043: // 1043 is used in IMRPhenomXHM
+		case 105:
+		{
+      noSpin = (2.2436523786378983 + 2162.4749081764216*eta + 24460.158604784723*eta2 - 12112.140570900956*eta3)/(1. + 120.78623282522702*eta + 416.4179522274108*eta2);
+
+      eqSpin = (S*(6.727511603827924 + eta2*(414.1400701039126 - 234.3754066885935*S) - 5.399284768639545*S
+                  + eta*(-186.87972530996245 + 128.7402290554767*S)))/(3.24359204029217 - 3.975650468231452*S + 1.*S2);
+
+      uneqSpin = dchi*delta*(-59.52510939953099 + 13.12679437100751*eta)*eta2;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v2: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104 (should not call *_Amp_22_v2). \n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*	
+	See section VI. B of arXiv:2001.11412. Collocation point for 5th order polynomial ansatz.
+
+    Value of intermediate amplitude collocation point v3 at f_3, defined in Table I of arXiv:2001.11412
+   
+    Effective spin parameterization used = StotR
+*/
+static double IMRPhenomX_Intermediate_Amp_22_v3(double eta, double S, double dchi, double delta, int IntAmpFlag){
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+
+  double S2 = S*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( IntAmpFlag )
+	{
+		case 1043: // 1043 is used in IMRPhenomXHM
+		case 105:
+		{
+      noSpin = (1.195392410912163 + 1677.2558976605421*eta + 24838.37133975971*eta2 - 17277.938868280915*eta3)/(1. + 144.78606839716073*eta + 428.8155916011666*eta2);
+
+      eqSpin = (S*(-2.1413952025647793 + 0.5719137940424858*S + eta*(46.61350006858767 + 0.40917927503842105*S - 11.526500209146906*S2)
+      + 1.1833965566688387*S2 + eta2*(-84.82318288272965 - 34.90591158988979*S + 19.494962340530186*S2)))/(-1.4786392693666195 + 1.*S);
+
+      uneqSpin = dchi*delta*(-333.7662575986524 + 532.2475589084717*eta)*eta3;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104 (should not call *_Amp_22_v3). \n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+}
+
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta0(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+	{
+    case 1043:  //no left derivative; 1043 is used in IMRPhenomXHM
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+
+      retVal = (-(d4*f1*f1mf2*f1mf3*f1mf4*f2*f2mf3*f2mf4*f3*f3mf4*f4) - f1*f1mf3*f1mf42*f3*f3mf42*f42*v2 +
+      f24*(-(f1*f1mf42*f42*v3) + f33*(f42*v1 + f12*v4 - 2*f1*f4*v4) + f3*f4*(f43*v1 + 2*f13*v4 - 3*f12*f4*v4) - f32*(2*f43*v1 + f13*v4 - 3*f1*f42*v4)) +
+      f2*f4*(f12*f1mf42*f43*v3 - f34*(f43*v1 + 2*f13*v4 - 3*f12*f4*v4) - f32*f4*(f44*v1 + 3*f14*v4 - 4*f13*f4*v4) + 2*f33*(f44*v1 + f14*v4 - 2*f12*f42*v4)) +
+      f22*(-(f1*f1mf42*(2*f1 + f4)*f43*v3) + f3*f42*(f44*v1 + 3*f14*v4 - 4*f13*f4*v4) + f34*(2*f43*v1 + f13*v4 - 3*f1*f42*v4) - f33*(3*f44*v1 + f14*v4 - 4*f1*f43*v4)) +
+      f23*(f1*f1mf42*(f1 + 2*f4)*f42*v3 - f34*(f42*v1 + f12*v4 - 2*f1*f4*v4) + f32*(3*f44*v1 + f14*v4 - 4*f1*f43*v4) - 2*f3*(f45*v1 + f14*f4*v4 - 2*f12*f43*v4)))/(f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+      break;
+    }
+    case 104:
+		{
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((-(d4*f12*f1mf22*f1mf4*f2*f2mf4*f4) + d1*f1*f1mf2*f1mf4*f2*f2mf42*f42 + f42*(f2*f2mf42*(-4*f12 + 3*f1*f2 + 2*f1*f4 - f2*f4)*v1 + f12*f1mf43*v2) +
+     f12*f1mf22*f2*(f1*f2 - 2*f1*f4 - 3*f2*f4 + 4*f42)*v4)/(f1mf22*f1mf43*f2mf42));
+
+  		break;
+		}
+		case 105:
+		{
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (-(d4*f12*f1mf22*f1mf32*f1mf4*f2*f2mf3*f2mf4*f3*f3mf4*f4) - d1*f1*f1mf2*f1mf3*f1mf4*f2*f2mf3*f2mf42*f3*f3mf42*f42 + 5*f13*f24*f33*f42*v1 - 4*f12*f25*f33*f42*v1 - 5*f13*f23*f34*f42*v1 +
+         3*f1*f25*f34*f42*v1 + 4*f12*f23*f35*f42*v1 - 3*f1*f24*f35*f42*v1 - 10*f13*f24*f32*f43*v1 + 8*f12*f25*f32*f43*v1 + 5*f12*f24*f33*f43*v1 - 4*f1*f25*f33*f43*v1 + 10*f13*f22*f34*f43*v1 -
+         5*f12*f23*f34*f43*v1 - f25*f34*f43*v1 - 8*f12*f22*f35*f43*v1 + 4*f1*f23*f35*f43*v1 + f24*f35*f43*v1 + 5*f13*f24*f3*f44*v1 - 4*f12*f25*f3*f44*v1 + 15*f13*f23*f32*f44*v1 -
+         10*f12*f24*f32*f44*v1 - f1*f25*f32*f44*v1 - 15*f13*f22*f33*f44*v1 + 5*f1*f24*f33*f44*v1 + 2*f25*f33*f44*v1 - 5*f13*f2*f34*f44*v1 + 10*f12*f22*f34*f44*v1 - 5*f1*f23*f34*f44*v1 +
+         4*f12*f2*f35*f44*v1 + f1*f22*f35*f44*v1 - 2*f23*f35*f44*v1 - 10*f13*f23*f3*f45*v1 + 5*f12*f24*f3*f45*v1 + 2*f1*f25*f3*f45*v1 - f12*f23*f32*f45*v1 + 2*f1*f24*f32*f45*v1 - f25*f32*f45*v1 +
+         10*f13*f2*f33*f45*v1 + f12*f22*f33*f45*v1 - 3*f24*f33*f45*v1 - 5*f12*f2*f34*f45*v1 - 2*f1*f22*f34*f45*v1 + 3*f23*f34*f45*v1 - 2*f1*f2*f35*f45*v1 + f22*f35*f45*v1 + 5*f13*f22*f3*f46*v1 +
+         2*f12*f23*f3*f46*v1 - 4*f1*f24*f3*f46*v1 - 5*f13*f2*f32*f46*v1 - f1*f23*f32*f46*v1 + 2*f24*f32*f46*v1 - 2*f12*f2*f33*f46*v1 + f1*f22*f33*f46*v1 + 4*f1*f2*f34*f46*v1 - 2*f22*f34*f46*v1 -
+         3*f12*f22*f3*f47*v1 + 2*f1*f23*f3*f47*v1 + 3*f12*f2*f32*f47*v1 - f23*f32*f47*v1 - 2*f1*f2*f33*f47*v1 + f22*f33*f47*v1 - f17*f33*f42*v2 + 2*f16*f34*f42*v2 - f15*f35*f42*v2 + 2*f17*f32*f43*v2 -
+         f16*f33*f43*v2 - 4*f15*f34*f43*v2 + 3*f14*f35*f43*v2 - f17*f3*f44*v2 - 4*f16*f32*f44*v2 + 8*f15*f33*f44*v2 - 3*f13*f35*f44*v2 + 3*f16*f3*f45*v2 - 8*f14*f33*f45*v2 + 4*f13*f34*f45*v2 +
+         f12*f35*f45*v2 - 3*f15*f3*f46*v2 + 4*f14*f32*f46*v2 + f13*f33*f46*v2 - 2*f12*f34*f46*v2 + f14*f3*f47*v2 - 2*f13*f32*f47*v2 + f12*f33*f47*v2 + f17*f23*f42*v3 - 2*f16*f24*f42*v3 +
+         f15*f25*f42*v3 - 2*f17*f22*f43*v3 + f16*f23*f43*v3 + 4*f15*f24*f43*v3 - 3*f14*f25*f43*v3 + f17*f2*f44*v3 + 4*f16*f22*f44*v3 - 8*f15*f23*f44*v3 + 3*f13*f25*f44*v3 - 3*f16*f2*f45*v3 +
+         8*f14*f23*f45*v3 - 4*f13*f24*f45*v3 - f12*f25*f45*v3 + 3*f15*f2*f46*v3 - 4*f14*f22*f46*v3 - f13*f23*f46*v3 + 2*f12*f24*f46*v3 - f14*f2*f47*v3 + 2*f13*f22*f47*v3 - f12*f23*f47*v3 +
+         f12*f1mf22*f1mf32*f2*f2mf3*f3*(f4*(-3*f2*f3 + 4*(f2 + f3)*f4 - 5*f42) + f1*(f2*f3 - 2*(f2 + f3)*f4 + 3*f42))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+    }
+	}
+
+  return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta1(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+  {
+    case 1043:  //no left derivative; 1043 is used in IMRPhenomXHM
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double v1mv2 = v1-v2;
+      UNUSED double v2mv3 = v2-v3;
+      UNUSED double v2mv4 = v2-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal =(d4*f1mf4*f2mf4*f3mf4*(f1*f2*f3 + f2*f3*f4 + f1*(f2 + f3)*f4) + (f4*(f12*f1mf42*f43*v2mv3 + f34*(f43*v1mv2 +
+        3*f12*f4*v2mv4 + 2*f13*(-v2 + v4)) + f32*f4*(f44*v1mv2 + 4*f13*f4*v2mv4 + 3*f14*(-v2 + v4)) + 2*f33*(f44*(-v1 + v2)
+        + f14*v2mv4 + 2*f12*f42*(-v2 + v4)) + 2*f23*(f44*v1mv3 + f34*v1mv4 + 2*f12*f42*v3mv4 + 2*f32*f42*(-v1 + v4) + f14*(-v3 + v4))
+        + f24*(3*f32*f4*v1mv4 + f43*(-v1 + v3) + 2*f13*v3mv4 + 2*f33*(-v1 + v4) + 3*f12*f4*(-v3 + v4)) + f22*f4*(4*f33*f4*v1mv4 + f44*(-v1 + v3)
+        + 3*f14*v3mv4 + 3*f34*(-v1 + v4) + 4*f13*f4*(-v3 + v4))))/(f1mf2*f1mf3*f2mf3))/(f1mf42*f2mf42*f3mf42);
+
+      break;
+    }
+    case 104:
+    {
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((d4*f1*f1mf22*f1mf4*f2mf4*(2*f2*f4 + f1*(f2 + f4)) + f4*(-(d1*f1mf2*f1mf4*f2mf42*(2*f1*f2 + (f1 + f2)*f4)) -
+        2*f1*(f44*(v1 - v2) + 3*f24*(v1 - v4) + f14*(v2 - v4) + 4*f23*f4*(-v1 + v4)
+        + 2*f13*f4*(-v2 + v4) + f1*(2*f43*(-v1 + v2) + 6*f22*f4*(v1 - v4) + 4*f23*(-v1 + v4)))))/(f1mf22*f1mf43*f2mf42));
+
+
+      break;
+    }
+    case 105:
+    {
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (d4*f1*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f1*f2*f3 + 2*f2*f3*f4 + f1*(f2 + f3)*f4) +
+        f4*(d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(2*f1*f2*f3 + f2*f3*f4 + f1*(f2 + f3)*f4) +
+        f1*(f16*(f43*(v2 - v3) + 2*f33*(v2 - v4) + 3*f22*f4*(v3 - v4) + 3*f32*f4*(-v2 + v4) + 2*f23*(-v3 + v4)) +
+        f13*f4*(f45*(-v2 + v3) + 5*f34*f4*(v2 - v4) + 4*f25*(v3 - v4) + 4*f35*(-v2 + v4) + 5*f24*f4*(-v3 + v4)) +
+        f14*(3*f45*(v2 - v3) + 2*f35*(v2 - v4) + 5*f34*f4*(v2 - v4) + 10*f23*f42*(v3 - v4) + 10*f33*f42*(-v2 + v4) + 2*f25*(-v3 + v4) + 5*f24*f4*(-v3 + v4)) +
+        f15*(3*f44*(-v2 + v3) + 2*f33*f4*(v2 - v4) + 5*f32*f42*(v2 - v4) + 4*f24*(v3 - v4) + 4*f34*(-v2 + v4) + 2*f23*f4*(-v3 + v4) + 5*f22*f42*(-v3 + v4)) -
+        5*f12*(-(f32*f3mf42*f43*(v1 - v2)) + 2*f23*(f44*(-v1 + v3) + 2*f32*f42*(v1 - v4) + f34*(-v1 + v4)) + f24*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) +
+        f22*f4*(f44*(v1 - v3) + 3*f34*(v1 - v4) + 4*f33*f4*(-v1 + v4))) +
+        f1*(-(f32*f3mf42*(4*f3 + 3*f4)*f43*(v1 - v2)) + 2*f23*(f45*(-v1 + v3) + 5*f34*f4*(v1 - v4) + 4*f35*(-v1 + v4)) + 4*f25*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) -
+        5*f24*f4*(f43*(v1 - v3) + 2*f33*(v1 - v4) + 3*f32*f4*(-v1 + v4)) + 3*f22*f4*(f45*(v1 - v3) + 4*f35*(v1 - v4) + 5*f34*f4*(-v1 + v4))) -
+        2*(-(f33*f3mf42*f44*(v1 - v2)) + f24*(2*f45*(-v1 + v3) + 5*f33*f42*(v1 - v4) + 3*f35*(-v1 + v4)) + f25*(f44*(v1 - v3) + 3*f34*(v1 - v4) + 4*f33*f4*(-v1 + v4)) +
+        f23*f4*(f45*(v1 - v3) + 4*f35*(v1 - v4) + 5*f34*f4*(-v1 + v4))))))/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+    }
+  }
+
+  return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta2(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+  {
+    case 1043:  //no left derivative: v1, v2, v3, v4, d4; 1043 is used in IMRPhenomXHM
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f46 = f44*f42;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double v1mv2 = v1-v2;
+      UNUSED double v2mv3 = v2-v3;
+      UNUSED double v2mv4 = v2-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal = (-(d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4*(f3*f4 + f2*(f3 + f4) + f1*(f2 + f3 + f4))) - 2*f34*f43*v1 + 3*f33*f44*v1 - f3*f46*v1 - f14*f33*v2 + f13*f34*v2 + 3*f14*f3*f42*v2 - 3*f1*f34*f42*v2 -
+      2*f14*f43*v2 - 4*f13*f3*f43*v2 + 4*f1*f33*f43*v2 + 2*f34*f43*v2 + 3*f13*f44*v2 - 3*f33*f44*v2 - f1*f46*v2 + f3*f46*v2 + 2*f14*f43*v3 - 3*f13*f44*v3 + f1*f46*v3 +
+      f2*f42*(f44*v1mv3 + 3*f34*v1mv4 - 4*f33*f4*v1mv4 - 3*f14*v3mv4 + 4*f13*f4*v3mv4) + f24*(2*f43*v1mv3 + f33*v1mv4 - 3*f3*f42*v1mv4 - f13*v3mv4 + 3*f1*f42*v3mv4) +
+      f23*(-3*f44*v1mv3 - f34*v1mv4 + 4*f3*f43*v1mv4 + f14*v3mv4 - 4*f1*f43*v3mv4) + f14*f33*v4 - f13*f34*v4 - 3*f14*f3*f42*v4 + 3*f1*f34*f42*v4 + 4*f13*f3*f43*v4 - 4*f1*f33*f43*v4)/
+      (f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+      break;
+    }
+    case 104:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((-(d4*f1mf22*f1mf4*f2mf4*(f12 + f2*f4 + 2*f1*(f2 + f4))) + d1*f1mf2*f1mf4*f2mf42*(f1*f2 + 2*(f1 + f2)*f4 + f42)
+      - 4*f12*f23*v1 + 3*f1*f24*v1 - 4*f1*f23*f4*v1 + 3*f24*f4*v1 + 12*f12*f2*f42*v1 -
+     4*f23*f42*v1 - 8*f12*f43*v1 + f1*f44*v1 + f45*v1 + f15*v2 + f14*f4*v2 - 8*f13*f42*v2 + 8*f12*f43*v2 - f1*f44*v2 - f45*v2 -
+     f1mf22*(f13 + f2*(3*f2 - 4*f4)*f4 + f12*(2*f2 + f4) + f1*(3*f2 - 4*f4)*(f2 + 2*f4))*v4)/(f1mf22*f1mf43*f2mf42));
+
+      break;
+    }
+    case 105:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (-(d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f2*f3*f4 + f12*(f2 + f3 + f4) + 2*f1*(f2*f3 + (f2 + f3)*f4))) -
+        d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1*f2*f3 + 2*(f2*f3 + f1*(f2 + f3))*f4 + (f1 + f2 + f3)*f42) + 5*f13*f24*f33*v1 - 4*f12*f25*f33*v1 - 5*f13*f23*f34*v1 + 3*f1*f25*f34*v1 +
+        4*f12*f23*f35*v1 - 3*f1*f24*f35*v1 + 5*f12*f24*f33*f4*v1 - 4*f1*f25*f33*f4*v1 - 5*f12*f23*f34*f4*v1 + 3*f25*f34*f4*v1 + 4*f1*f23*f35*f4*v1 - 3*f24*f35*f4*v1 - 15*f13*f24*f3*f42*v1 +
+        12*f12*f25*f3*f42*v1 + 5*f1*f24*f33*f42*v1 - 4*f25*f33*f42*v1 + 15*f13*f2*f34*f42*v1 - 5*f1*f23*f34*f42*v1 - 12*f12*f2*f35*f42*v1 + 4*f23*f35*f42*v1 + 10*f13*f24*f43*v1 - 8*f12*f25*f43*v1 +
+        20*f13*f23*f3*f43*v1 - 15*f12*f24*f3*f43*v1 - 20*f13*f2*f33*f43*v1 + 5*f24*f33*f43*v1 - 10*f13*f34*f43*v1 + 15*f12*f2*f34*f43*v1 - 5*f23*f34*f43*v1 + 8*f12*f35*f43*v1 - 15*f13*f23*f44*v1 +
+        10*f12*f24*f44*v1 + f1*f25*f44*v1 + 15*f13*f33*f44*v1 - 10*f12*f34*f44*v1 - f1*f35*f44*v1 + f12*f23*f45*v1 - 2*f1*f24*f45*v1 + f25*f45*v1 - f12*f33*f45*v1 + 2*f1*f34*f45*v1 - f35*f45*v1 +
+        5*f13*f2*f46*v1 + f1*f23*f46*v1 - 2*f24*f46*v1 - 5*f13*f3*f46*v1 - f1*f33*f46*v1 + 2*f34*f46*v1 - 3*f12*f2*f47*v1 + f23*f47*v1 + 3*f12*f3*f47*v1 - f33*f47*v1 - f17*f33*v2 + 2*f16*f34*v2 -
+        f15*f35*v2 - f16*f33*f4*v2 + 2*f15*f34*f4*v2 - f14*f35*f4*v2 + 3*f17*f3*f42*v2 - f15*f33*f42*v2 - 10*f14*f34*f42*v2 + 8*f13*f35*f42*v2 - 2*f17*f43*v2 - 5*f16*f3*f43*v2 + 15*f14*f33*f43*v2 -
+        8*f12*f35*f43*v2 + 4*f16*f44*v2 - 15*f13*f33*f44*v2 + 10*f12*f34*f44*v2 + f1*f35*f44*v2 + f12*f33*f45*v2 - 2*f1*f34*f45*v2 + f35*f45*v2 - 4*f14*f46*v2 + 5*f13*f3*f46*v2 + f1*f33*f46*v2 -
+        2*f34*f46*v2 + 2*f13*f47*v2 - 3*f12*f3*f47*v2 + f33*f47*v2 + f17*f23*v3 - 2*f16*f24*v3 + f15*f25*v3 + f16*f23*f4*v3 - 2*f15*f24*f4*v3 + f14*f25*f4*v3 - 3*f17*f2*f42*v3 + f15*f23*f42*v3 +
+        10*f14*f24*f42*v3 - 8*f13*f25*f42*v3 + 2*f17*f43*v3 + 5*f16*f2*f43*v3 - 15*f14*f23*f43*v3 + 8*f12*f25*f43*v3 - 4*f16*f44*v3 + 15*f13*f23*f44*v3 - 10*f12*f24*f44*v3 - f1*f25*f44*v3 -
+        f12*f23*f45*v3 + 2*f1*f24*f45*v3 - f25*f45*v3 + 4*f14*f46*v3 - 5*f13*f2*f46*v3 - f1*f23*f46*v3 + 2*f24*f46*v3 - 2*f13*f47*v3 + 3*f12*f2*f47*v3 - f23*f47*v3 -
+        f1mf22*f1mf32*f2mf3*(f13*(f22 + f2*f3 + f32 - 3*f42) + f2*f3*f4*(3*f2*f3 - 4*(f2 + f3)*f4 + 5*f42) + f1*(f2*f3 + 2*(f2 + f3)*f4)*(3*f2*f3 - 4*(f2 + f3)*f4 + 5*f42) +
+        f12*(2*f2*f3*(f2 + f3) + (f22 + f2*f3 + f32)*f4 - 6*(f2 + f3)*f42 + 5*f43))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+    }
+  }
+
+return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta3(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+  {
+    case 1043:  //no left derivative: v1, v2, v3, v4, d4; 1043 is used in IMRPhenomXHM
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f34 = f32*f32;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double v1mv2 = v1-v2;
+      UNUSED double v2mv3 = v2-v3;
+      UNUSED double v2mv4 = v2-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal = (d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4*(f1 + f2 + f3 + f4) + f34*f42*v1 - 3*f32*f44*v1 + 2*f3*f45*v1 + f14*f32*v2 - f12*f34*v2 - 2*f14*f3*f4*v2 + 2*f1*f34*f4*v2 + f14*f42*v2 - f34*f42*v2 +
+      4*f12*f3*f43*v2 - 4*f1*f32*f43*v2 - 3*f12*f44*v2 + 3*f32*f44*v2 + 2*f1*f45*v2 - 2*f3*f45*v2 - f14*f42*v3 + 3*f12*f44*v3 - 2*f1*f45*v3 +
+      f24*(-(f42*v1mv3) - f32*v1mv4 + 2*f3*f4*v1mv4 + f12*v3mv4 - 2*f1*f4*v3mv4) - 2*f2*f4*(f44*v1mv3 + f34*v1mv4 - 2*f32*f42*v1mv4 - f14*v3mv4 + 2*f12*f42*v3mv4) +
+      f22*(3*f44*v1mv3 + f34*v1mv4 - 4*f3*f43*v1mv4 - f14*v3mv4 + 4*f1*f43*v3mv4) - f14*f32*v4 + f12*f34*v4 + 2*f14*f3*f4*v4 - 2*f1*f34*f4*v4 - 4*f12*f3*f43*v4 + 4*f1*f32*f43*v4)/
+      (f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+      break;
+    }
+    case 104:
+    {
+
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((d4*f1mf22*f1mf4*f2mf4*(2*f1 + f2 + f4) - d1*f1mf2*f1mf4*f2mf42*(f1 + f2 + 2*f4)
+                + 2*(f44*(-v1 + v2) + 2*f12*f2mf42*(v1 - v4) + 2*f22*f42*(v1 - v4)
+                + 2*f13*f4*(v2 - v4) + f24*(-v1 + v4) + f14*(-v2 + v4) + 2*f1*f4*(f42*(v1 - v2) + f22*(v1 - v4) + 2*f2*f4*(-v1 + v4)))) / (f1mf22*f1mf43*f2mf42));
+
+
+      break;
+    }
+    case 105:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(f12 + f2*f3 + (f2 + f3)*f4 + 2*f1*(f2 + f3 + f4)) + d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1*f2 + f1*f3 + f2*f3 + 2*(f1 + f2 + f3)*f4 + f42) -
+        5*f13*f24*f32*v1 + 4*f12*f25*f32*v1 + 5*f13*f22*f34*v1 - 2*f25*f34*v1 - 4*f12*f22*f35*v1 + 2*f24*f35*v1 + 10*f13*f24*f3*f4*v1 - 8*f12*f25*f3*f4*v1 - 5*f12*f24*f32*f4*v1 + 4*f1*f25*f32*f4*v1 -
+        10*f13*f2*f34*f4*v1 + 5*f12*f22*f34*f4*v1 + 8*f12*f2*f35*f4*v1 - 4*f1*f22*f35*f4*v1 - 5*f13*f24*f42*v1 + 4*f12*f25*f42*v1 + 10*f12*f24*f3*f42*v1 - 8*f1*f25*f3*f42*v1 - 5*f1*f24*f32*f42*v1 +
+        4*f25*f32*f42*v1 + 5*f13*f34*f42*v1 - 10*f12*f2*f34*f42*v1 + 5*f1*f22*f34*f42*v1 - 4*f12*f35*f42*v1 + 8*f1*f2*f35*f42*v1 - 4*f22*f35*f42*v1 - 5*f12*f24*f43*v1 + 4*f1*f25*f43*v1 -
+        20*f13*f22*f3*f43*v1 + 10*f1*f24*f3*f43*v1 + 20*f13*f2*f32*f43*v1 - 5*f24*f32*f43*v1 + 5*f12*f34*f43*v1 - 10*f1*f2*f34*f43*v1 + 5*f22*f34*f43*v1 - 4*f1*f35*f43*v1 + 15*f13*f22*f44*v1 -
+        5*f1*f24*f44*v1 - 2*f25*f44*v1 - 15*f13*f32*f44*v1 + 5*f1*f34*f44*v1 + 2*f35*f44*v1 - 10*f13*f2*f45*v1 - f12*f22*f45*v1 + 3*f24*f45*v1 + 10*f13*f3*f45*v1 + f12*f32*f45*v1 - 3*f34*f45*v1 +
+        2*f12*f2*f46*v1 - f1*f22*f46*v1 - 2*f12*f3*f46*v1 + f1*f32*f46*v1 + 2*f1*f2*f47*v1 - f22*f47*v1 - 2*f1*f3*f47*v1 + f32*f47*v1 + f17*f32*v2 - 3*f15*f34*v2 + 2*f14*f35*v2 - 2*f17*f3*f4*v2 +
+        f16*f32*f4*v2 + 5*f14*f34*f4*v2 - 4*f13*f35*f4*v2 + f17*f42*v2 - 2*f16*f3*f42*v2 + f15*f32*f42*v2 + f16*f43*v2 + 10*f15*f3*f43*v2 - 15*f14*f32*f43*v2 + 4*f1*f35*f43*v2 - 8*f15*f44*v2 +
+        15*f13*f32*f44*v2 - 5*f1*f34*f44*v2 - 2*f35*f44*v2 + 8*f14*f45*v2 - 10*f13*f3*f45*v2 - f12*f32*f45*v2 + 3*f34*f45*v2 - f13*f46*v2 + 2*f12*f3*f46*v2 - f1*f32*f46*v2 - f12*f47*v2 +
+        2*f1*f3*f47*v2 - f32*f47*v2 - f17*f22*v3 + 3*f15*f24*v3 - 2*f14*f25*v3 + 2*f17*f2*f4*v3 - f16*f22*f4*v3 - 5*f14*f24*f4*v3 + 4*f13*f25*f4*v3 - f17*f42*v3 + 2*f16*f2*f42*v3 - f15*f22*f42*v3 -
+        f16*f43*v3 - 10*f15*f2*f43*v3 + 15*f14*f22*f43*v3 - 4*f1*f25*f43*v3 + 8*f15*f44*v3 - 15*f13*f22*f44*v3 + 5*f1*f24*f44*v3 + 2*f25*f44*v3 - 8*f14*f45*v3 + 10*f13*f2*f45*v3 + f12*f22*f45*v3 -
+        3*f24*f45*v3 + f13*f46*v3 - 2*f12*f2*f46*v3 + f1*f22*f46*v3 + f12*f47*v3 - 2*f1*f2*f47*v3 + f22*f47*v3 +
+        f1mf22*f1mf32*f2mf3*(2*f22*f32 + f13*(f2 + f3 - 2*f4) + f12*(f2 + f3 - 2*f4)*(2*(f2 + f3) + f4) - 4*(f22 + f2*f3 + f32)*f42 + 5*(f2 + f3)*f43 +
+        f1*(4*f2*f3*(f2 + f3) - 4*(f22 + f2*f3 + f32)*f4 - 3*(f2 + f3)*f42 + 10*f43))*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+    }
+  }
+
+  return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta4(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+  {
+    case 1043:  //no left derivative: v1, v2, v3, v4, d4; 1043 is used in IMRPhenomXHM
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+
+      UNUSED double v1mv2 = v1-v2;
+      UNUSED double v2mv3 = v2-v3;
+      UNUSED double v2mv4 = v2-v4;
+      UNUSED double v1mv3 = v1-v3;
+      UNUSED double v1mv4 = v1-v4;
+      UNUSED double v3mv4 = v3-v4;
+
+      retVal = (-(d4*f1mf2*f1mf3*f1mf4*f2mf3*f2mf4*f3mf4) - f33*f42*v1 + 2*f32*f43*v1 - f3*f44*v1 - f13*f32*v2 + f12*f33*v2 + 2*f13*f3*f4*v2 - 2*f1*f33*f4*v2 - f13*f42*v2 - 3*f12*f3*f42*v2 + 3*f1*f32*f42*v2 +
+      f33*f42*v2 + 2*f12*f43*v2 - 2*f32*f43*v2 - f1*f44*v2 + f3*f44*v2 + f13*f42*v3 - 2*f12*f43*v3 + f1*f44*v3 + f23*(f42*v1mv3 + f32*v1mv4 - 2*f3*f4*v1mv4 - f12*v3mv4 + 2*f1*f4*v3mv4) +
+      f2*f4*(f43*v1mv3 + 2*f33*v1mv4 - 3*f32*f4*v1mv4 - 2*f13*v3mv4 + 3*f12*f4*v3mv4) + f22*(-2*f43*v1mv3 - f33*v1mv4 + 3*f3*f42*v1mv4 + f13*v3mv4 - 3*f1*f42*v3mv4) + f13*f32*v4 - f12*f33*v4 -
+      2*f13*f3*f4*v4 + 2*f1*f33*f4*v4 + 3*f12*f3*f42*v4 - 3*f1*f32*f42*v4)/(f1mf2*f1mf3*f1mf42*f2mf3*f2mf42*f3mf42);
+      break;
+    }
+    case 104:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = ((-(d4*f1mf22*f1mf4*f2mf4) + d1*f1mf2*f1mf4*f2mf42 - 3*f1*f22*v1 + 2*f23*v1 + 6*f1*f2*f4*v1 - 3*f22*f4*v1
+              - 3*f1*f42*v1 + f43*v1 + f13*v2 - 3*f12*f4*v2 + 3*f1*f42*v2 - f43*v2 - f1mf22*(f1 + 2*f2 - 3*f4)*v4)/(f1mf22*f1mf43*f2mf42));
+
+      break;
+    }
+    case 105:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (-(d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4*(2*f1 + f2 + f3 + f4)) - d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42*(f1 + f2 + f3 + 2*f4) + 5*f13*f23*f32*v1 - 3*f1*f25*f32*v1 - 5*f13*f22*f33*v1 +
+        2*f25*f33*v1 + 3*f1*f22*f35*v1 - 2*f23*f35*v1 - 10*f13*f23*f3*f4*v1 + 6*f1*f25*f3*f4*v1 + 5*f12*f23*f32*f4*v1 - 3*f25*f32*f4*v1 + 10*f13*f2*f33*f4*v1 - 5*f12*f22*f33*f4*v1 -
+        6*f1*f2*f35*f4*v1 + 3*f22*f35*f4*v1 + 5*f13*f23*f42*v1 - 3*f1*f25*f42*v1 + 15*f13*f22*f3*f42*v1 - 10*f12*f23*f3*f42*v1 - 15*f13*f2*f32*f42*v1 + 5*f1*f23*f32*f42*v1 - 5*f13*f33*f42*v1 +
+        10*f12*f2*f33*f42*v1 - 5*f1*f22*f33*f42*v1 + 3*f1*f35*f42*v1 - 10*f13*f22*f43*v1 + 5*f12*f23*f43*v1 + f25*f43*v1 + 15*f12*f22*f3*f43*v1 - 10*f1*f23*f3*f43*v1 + 10*f13*f32*f43*v1 -
+        15*f12*f2*f32*f43*v1 + 5*f23*f32*f43*v1 - 5*f12*f33*f43*v1 + 10*f1*f2*f33*f43*v1 - 5*f22*f33*f43*v1 - f35*f43*v1 + 5*f13*f2*f44*v1 - 10*f12*f22*f44*v1 + 5*f1*f23*f44*v1 - 5*f13*f3*f44*v1 +
+        10*f12*f32*f44*v1 - 5*f1*f33*f44*v1 + 5*f12*f2*f45*v1 + 2*f1*f22*f45*v1 - 3*f23*f45*v1 - 5*f12*f3*f45*v1 - 2*f1*f32*f45*v1 + 3*f33*f45*v1 - 4*f1*f2*f46*v1 + 2*f22*f46*v1 + 4*f1*f3*f46*v1 -
+        2*f32*f46*v1 - 2*f16*f32*v2 + 3*f15*f33*v2 - f13*f35*v2 + 4*f16*f3*f4*v2 - 2*f15*f32*f4*v2 - 5*f14*f33*f4*v2 + 3*f12*f35*f4*v2 - 2*f16*f42*v2 - 5*f15*f3*f42*v2 + 10*f14*f32*f42*v2 -
+        3*f1*f35*f42*v2 + 4*f15*f43*v2 - 5*f14*f3*f43*v2 + f35*f43*v2 + 5*f13*f3*f44*v2 - 10*f12*f32*f44*v2 + 5*f1*f33*f44*v2 - 4*f13*f45*v2 + 5*f12*f3*f45*v2 + 2*f1*f32*f45*v2 - 3*f33*f45*v2 +
+        2*f12*f46*v2 - 4*f1*f3*f46*v2 + 2*f32*f46*v2 + 2*f16*f22*v3 - 3*f15*f23*v3 + f13*f25*v3 - 4*f16*f2*f4*v3 + 2*f15*f22*f4*v3 + 5*f14*f23*f4*v3 - 3*f12*f25*f4*v3 + 2*f16*f42*v3 +
+        5*f15*f2*f42*v3 - 10*f14*f22*f42*v3 + 3*f1*f25*f42*v3 - 4*f15*f43*v3 + 5*f14*f2*f43*v3 - f25*f43*v3 - 5*f13*f2*f44*v3 + 10*f12*f22*f44*v3 - 5*f1*f23*f44*v3 + 4*f13*f45*v3 - 5*f12*f2*f45*v3 -
+        2*f1*f22*f45*v3 + 3*f23*f45*v3 - 2*f12*f46*v3 + 4*f1*f2*f46*v3 - 2*f22*f46*v3 -
+        f1mf22*f1mf32*f2mf3*(2*f2*f3*(f2 + f3) + 2*f12*(f2 + f3 - 2*f4) - 3*(f22 + f2*f3 + f32)*f4 + f1*(f22 + 5*f2*f3 + f32 - 6*(f2 + f3)*f4 + 5*f42) + 5*f43)*v4)/
+        (f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+      );
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+    }
+  }
+
+  return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_delta5(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag)
+{
+  double retVal;
+
+  switch ( IntAmpFlag )
+  {
+    case 1043:  //no left derivative: v1, v2, v3, v4, d4; 1043 is used in IMRPhenomXHM
+    {
+      retVal = 0.;
+      break;
+    }
+    case 104:
+    {
+      retVal = 0.0;
+      break;
+    }
+    case 105:
+    {
+      UNUSED double f12 = f1*f1;
+      UNUSED double f13 = f12*f1;
+      UNUSED double f14 = f13*f1;
+      UNUSED double f15 = f14*f1;
+      UNUSED double f16 = f15*f1;
+      UNUSED double f17 = f16*f1;
+
+      UNUSED double f22 = f2*f2;
+      UNUSED double f23 = f22*f2;
+      UNUSED double f24 = f23*f2;
+      UNUSED double f25 = f24*f2;
+      UNUSED double f26 = f25*f2;
+      UNUSED double f27 = f26*f2;
+
+      UNUSED double f32 = f3*f3;
+      UNUSED double f33 = f32*f3;
+      UNUSED double f34 = f33*f3;
+      UNUSED double f35 = f34*f3;
+      UNUSED double f36 = f35*f3;
+      UNUSED double f37 = f36*f3;
+
+      UNUSED double f42 = f4*f4;
+      UNUSED double f43 = f42*f4;
+      UNUSED double f44 = f43*f4;
+      UNUSED double f45 = f44*f4;
+      UNUSED double f46 = f45*f4;
+      UNUSED double f47 = f46*f4;
+
+      UNUSED double f1mf2 = f1-f2;
+      UNUSED double f1mf3 = f1-f3;
+      UNUSED double f1mf4 = f1-f4;
+      UNUSED double f2mf3 = f2-f3;
+      UNUSED double f2mf4 = f2-f4;
+      UNUSED double f3mf4 = f3-f4;
+
+      UNUSED double f1mf22 = f1mf2*f1mf2;
+      UNUSED double f1mf32 = f1mf3*f1mf3;
+      UNUSED double f1mf42 = f1mf4*f1mf4;
+      UNUSED double f2mf32 = f2mf3*f2mf3;
+      UNUSED double f2mf42 = f2mf4*f2mf4;
+      UNUSED double f3mf42 = f3mf4*f3mf4;
+      UNUSED double f1mf43 = f1mf4*f1mf4*f1mf4;
+
+      retVal = (
+        (d4*f1mf22*f1mf32*f1mf4*f2mf3*f2mf4*f3mf4 + d1*f1mf2*f1mf3*f1mf4*f2mf3*f2mf42*f3mf42 - 4*f12*f23*f32*v1 + 3*f1*f24*f32*v1 + 4*f12*f22*f33*v1 - 2*f24*f33*v1 - 3*f1*f22*f34*v1 + 2*f23*f34*v1 +
+          8*f12*f23*f3*f4*v1 - 6*f1*f24*f3*f4*v1 - 4*f1*f23*f32*f4*v1 + 3*f24*f32*f4*v1 - 8*f12*f2*f33*f4*v1 + 4*f1*f22*f33*f4*v1 + 6*f1*f2*f34*f4*v1 - 3*f22*f34*f4*v1 - 4*f12*f23*f42*v1 +
+          3*f1*f24*f42*v1 - 12*f12*f22*f3*f42*v1 + 8*f1*f23*f3*f42*v1 + 12*f12*f2*f32*f42*v1 - 4*f23*f32*f42*v1 + 4*f12*f33*f42*v1 - 8*f1*f2*f33*f42*v1 + 4*f22*f33*f42*v1 - 3*f1*f34*f42*v1 +
+          8*f12*f22*f43*v1 - 4*f1*f23*f43*v1 - f24*f43*v1 - 8*f12*f32*f43*v1 + 4*f1*f33*f43*v1 + f34*f43*v1 - 4*f12*f2*f44*v1 - f1*f22*f44*v1 + 2*f23*f44*v1 + 4*f12*f3*f44*v1 + f1*f32*f44*v1 -
+          2*f33*f44*v1 + 2*f1*f2*f45*v1 - f22*f45*v1 - 2*f1*f3*f45*v1 + f32*f45*v1 + f15*f32*v2 - 2*f14*f33*v2 + f13*f34*v2 - 2*f15*f3*f4*v2 + f14*f32*f4*v2 + 4*f13*f33*f4*v2 - 3*f12*f34*f4*v2 +
+          f15*f42*v2 + 4*f14*f3*f42*v2 - 8*f13*f32*f42*v2 + 3*f1*f34*f42*v2 - 3*f14*f43*v2 + 8*f12*f32*f43*v2 - 4*f1*f33*f43*v2 - f34*f43*v2 + 3*f13*f44*v2 - 4*f12*f3*f44*v2 - f1*f32*f44*v2 +
+          2*f33*f44*v2 - f12*f45*v2 + 2*f1*f3*f45*v2 - f32*f45*v2 - f15*f22*v3 + 2*f14*f23*v3 - f13*f24*v3 + 2*f15*f2*f4*v3 - f14*f22*f4*v3 - 4*f13*f23*f4*v3 + 3*f12*f24*f4*v3 - f15*f42*v3 -
+          4*f14*f2*f42*v3 + 8*f13*f22*f42*v3 - 3*f1*f24*f42*v3 + 3*f14*f43*v3 - 8*f12*f22*f43*v3 + 4*f1*f23*f43*v3 + f24*f43*v3 - 3*f13*f44*v3 + 4*f12*f2*f44*v3 + f1*f22*f44*v3 - 2*f23*f44*v3 +
+          f12*f45*v3 - 2*f1*f2*f45*v3 + f22*f45*v3 + f1mf22*f1mf32*f2mf3*(2*f2*f3 + f1*(f2 + f3 - 2*f4) - 3*(f2 + f3)*f4 + 4*f42)*v4)/(f1mf22*f1mf32*f1mf43*f2mf3*f2mf42*f3mf42)
+        );
+
+        break ;
+      }
+      default:
+      {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_v3: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+      }
+    }
+
+    return retVal;
+}
+
+/* Solves system of equations for 5th order polynomial ansatz. Section VI.B, Eq. 6.5 of arXiv:2001.11412. Note that \alpha in paper are \delta in code here. */
+static double IMRPhenomX_Intermediate_Amp_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp)
+{
+	double a0         = pAmp->delta0;
+    double a1         = pAmp->delta1;
+    double a2         = pAmp->delta2;
+    double a3         = pAmp->delta3;
+    double a4         = pAmp->delta4;
+    double a5         = pAmp->delta5;
+
+    double ff7o6      = powers_of_f->seven_sixths;
+
+    int IntAmpFlag    = pWF->IMRPhenomXIntermediateAmpVersion;
+
+    double polynomial;
+
+    switch ( IntAmpFlag )
+  	{
+      case 1043: //1043 is used in IMRPhenomXHM
+      case 104:
+  		{
+        //polynomial        = a0 + a1*ff + a2*ff2 + a3*ff3 + a4*ff4;
+        polynomial = a0 + ff*(a1 + ff*(a2 + ff*(a3 + ff*a4)));
+
+    		break;
+  		}
+  		case 105:
+  		{
+        //polynomial        = a0 + a1*ff + a2*ff2 + a3*ff3 + a4*ff4 + a5*ff5;
+        polynomial = a0 + ff*(a1 + ff*(a2 + ff*(a3 + ff*(a4 + ff*a5))));
+
+    		break;
+  		}
+      default:
+      {
+        XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Amp_22_Ansatz: IMRPhenomXIntermediateAmpVersion is not valid. Recommended flag is 104.\n");
+
+        ff7o6      = 0.0;
+        polynomial = 1.0;
+
+        break;
+      }
+  	}
+
+		/* Return a polynomial embedded in the background from the merger */
+		return ff7o6 / polynomial;
+}
+
+/******************************* Phase Functions: Merger   *******************************/
+
+/* Intermediate phase collocation point v3. See Section VII.B of arXiv:2001.11412.  */
+UNUSED static double IMRPhenomX_Intermediate_Phase_22_v3(double eta, double S, double dchi, double delta, int IntPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+  double eta4  = eta3*eta;
+
+	double S2    = S*S;
+	double S3    = S2*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( IntPhaseFlag )
+	{
+		case 104: 			/* Canonical, 4 coefficients */
+		{
+      noSpin = (-85.65000000000003 - 413.9060603156141*eta - 4784.537141069749*eta2 + 1490.1208098409852*eta3 + 10040.191767983953*eta4)/(1. + 5.779247659216663*eta + 69.57046710291102*eta2);
+
+      eqSpin = (S*(4.692726457075735 - 7.038980703663575*S + eta2*(87.92695072054693 - 53.72849910673372*S - 40.89299875429382*S2) + 1.809693754991601*S2 + eta*(-13.873355143236994 + 11.141463520702901*S + 6.450651190707574*S2) + eta3*(-214.15302815157358 + 165.87430354875272*S + 53.19430999626736*S2 - 2.8784864337832756*S3) + 0.18008416467045393*S3))/(-0.19174821584528354 + 0.22339091810747033*S + 1.*eta3*S - 0.06756256922190347*S2);
+
+      uneqSpin = dchi*delta*eta3*(2989.296934478898 - 8693.785422139264*eta + 230.93311202289289*S);
+
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 coefficients */
+		{
+      noSpin = (-85.31300000000003 - 10937.096332153926*eta + 24894.22839497624*eta2 - 41966.01695284205*eta3 + 67157.48707167112*eta4)/(1. + 132.44486857622041*eta);
+
+      eqSpin = (S*(-50.47357379240076 + 73.09727082201734*S + eta3*(3596.7780512820414 - 2213.251793086697*S - 2751.2131780622212*S2) + eta*(156.5226913355741 - 58.19427796874254*S - 243.59756424149438*S2) - 14.822551015459917*S2 + eta2*(-1399.6118302073216 + 505.3549556613735*S + 1522.6588404541071*S2)))/(1.9694717754728777 - 2.272396692525365*S + 1.*S2);
+
+      uneqSpin = dchi*delta*eta3*(3453.778014556621 + eta*(-10048.103462582065 + 1757.9089741373239*S));
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_v3: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/* Intermediate phase collocation point v2. See Section VII.B of arXiv:2001.11412.  */
+static double IMRPhenomX_Intermediate_Phase_22_v2(double eta, double S, double dchi, double delta, int IntPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+
+	double S2    = S*S;
+	double S3    = S2*S;
+	double S4    = S3*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( IntPhaseFlag )
+	{
+		case 104: 			/* Canonical, 4 coefficients */
+		{
+      noSpin = (-84.09400000000004 - 1782.8025405571802*eta + 5384.38721936653*eta2)/(1. + 28.515617312596103*eta + 12.404097877099353*eta2);
+
+      eqSpin = (S*(22.5665046165141 - 39.94907120140026*S + 4.668251961072*S2 + 12.648584361431245*S3 + eta2*(-298.7528127869681 + 14.228745354543983*S + 398.1736953382448*S2 + 506.94924905801673*S3 - 626.3693674479357*S4) - 5.360554789680035*S4 + eta*(152.07900889608595 - 121.70617732909962*S2 - 169.36311036967322*S3 + 182.40064586992762*S4)))/(-1.1571201220629341 + 1.*S);
+
+      uneqSpin = dchi*delta*eta3*(5357.695021063607 - 15642.019339339662*eta + 674.8698102366333*S);
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 coefficients */
+		{
+      noSpin = (-82.54500000000004 - 5.58197349185435e6*eta - 3.5225742421184325e8*eta2 + 1.4667258334378073e9*eta3)/(1. + 66757.12830903867*eta + 5.385164380400193e6*eta2 + 2.5176585751772933e6*eta3);
+
+      eqSpin = (S*(19.416719811164853 - 36.066611959079935*S - 0.8612656616290079*S2 + eta2*(170.97203068800542 - 107.41099349364234*S - 647.8103976942541*S3) + 5.95010003393006*S3 + eta3*(-1365.1499998427248 + 1152.425940764218*S + 415.7134909564443*S2 + 1897.5444343138167*S3 - 866.283566780576*S4) + 4.984750041013893*S4 + eta*(207.69898051583655 - 132.88417400679026*S - 17.671713040498304*S2 + 29.071788188638315*S3 + 37.462217031512786*S4)))/(-1.1492259468169692 + 1.*S);
+
+      uneqSpin = dchi*delta*eta3*(7343.130973149263 - 20486.813161100774*eta + 515.9898508588834*S);
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_v3: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/* v2mRDv4 = vIM2 - vRD4. See Section VII.B of arXiv:2001.11412.  */
+static double IMRPhenomX_Intermediate_Phase_22_v2mRDv4(double eta, double S, double dchi, double delta, int IntPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+
+	double S2    = S*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( IntPhaseFlag )
+	{
+		case 104: 			/* Canonical, 4 coefficients */
+		{
+      noSpin = (eta*(-8.244230124407343 - 182.80239160435949*eta + 638.2046409916306*eta2 - 578.878727101827*eta3))/(-0.004863669418916522 - 0.5095088831841608*eta + 1.*eta2);
+
+      eqSpin = (S*(0.1344136125169328 + 0.0751872427147183*S + eta2*(7.158823192173721 + 25.489598292111104*S - 7.982299108059922*S2) + eta*(-5.792368563647471 + 1.0190164430971749*S + 0.29150399620268874*S2) + 0.033627267594199865*S2 + eta3*(17.426503081351534 - 90.69790378048448*S + 20.080325133405847*S2)))/(0.03449545664201546 - 0.027941977370442107*S + (0.005274757661661763 + 0.0455523144123269*eta - 0.3880379911692037*eta2 + 1.*eta3)*S2);
+
+      uneqSpin = 160.2975913661124*dchi*delta*eta2;
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 coefficients */
+		{
+      noSpin = (eta*(0.9951733419499662 + 101.21991715215253*eta + 632.4731389009143*eta2))/(0.00016803066316882238 + 0.11412314719189287*eta + 1.8413983770369362*eta2 + 1.*eta3);
+
+      eqSpin = (S*(18.694178521101332 + 16.89845522539974*S + 4941.31613710257*eta2*S + eta*(-697.6773920613674 - 147.53381808989846*S2) + 0.3612417066833153*S2 + eta3*(3531.552143264721 - 14302.70838220423*S + 178.85850322465944*S2)))/(2.965640445745779 - 2.7706595614504725*S + 1.*S2);
+
+      uneqSpin = dchi*delta*eta2*(356.74395864902294 + 1693.326644293169*eta2*S);
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_d23: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/* v3mRDv4 = vIM3 - vRD4. See Section VII.B of arXiv:2001.11412.  */
+static double IMRPhenomX_Intermediate_Phase_22_v3mRDv4(double eta, double S, double dchi, double delta, int IntPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+	double eta4  = eta3*eta;
+	double eta6  = eta3*eta3;
+
+	double S2    = S*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( IntPhaseFlag )
+	{
+		case 104: 			/* Canonical, 4 coefficients */
+		{
+      noSpin = (0.3145740304678042 + 299.79825045000655*eta - 605.8886581267144*eta2 - 1302.0954503758007*eta3)/(1. + 2.3903703875353255*eta - 19.03836730923657*eta2);
+
+      eqSpin = (S*(1.150925084789774 - 0.3072381261655531*S + eta4*(12160.22339193134 - 1459.725263347619*S - 9581.694749116636*S2) + eta2*(1240.3900459406875 - 289.48392062629966*S - 1218.1320231846412*S2) - 1.6191217310064605*S2 + eta*(-41.38762957457647 + 60.47477582076457*S2) + eta3*(-7540.259952257055 + 1379.3429194626635*S + 6372.99271204178*S2)))/(-1.4325421225106187 + 1.*S);
+
+      uneqSpin = dchi*delta*eta3*(-444.797248674011 + 1448.47758082697*eta + 152.49290092435044*S);
+
+  		break;
+		}
+		case 105:				/* Canonical, 5 coefficients */
+		{
+      noSpin = (eta*(-5.126358906504587 - 227.46830225846668*eta + 688.3609087244353*eta2 - 751.4184178636324*eta3))/(-0.004551938711031158 - 0.7811680872741462*eta + 1.*eta2);
+
+      eqSpin = (S*(0.1549280856660919 - 0.9539250460041732*S - 539.4071941841604*eta2*S + eta*(73.79645135116367 - 8.13494176717772*S2) - 2.84311102369862*S2 + eta3*(-936.3740515136005 + 1862.9097047992134*S + 224.77581754671272*S2)))/(-1.5308507364054487 + 1.*S);
+
+      uneqSpin = 2993.3598520496153*dchi*delta*eta6;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_d23: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/* d43 = v4 - v3. See Section VII.B of arXiv:2001.11412.  */
+static double IMRPhenomX_Intermediate_Phase_22_d43(double eta, double S, double dchi, double delta, int IntPhaseFlag){
+
+	double eta2  = eta*eta;
+	double eta3  = eta2*eta;
+	double eta4  = eta3*eta;
+
+	double S2    = S*S;
+
+	double noSpin, eqSpin, uneqSpin;
+
+	switch ( IntPhaseFlag )
+	{
+		case 104:
+		{
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_d43: Point d43 should not be called when using IMRPhenomXIntermediatePhaseVersion == 104.\n");
+      break;
+		}
+		case 105:				/* Canonical, 5 coefficients */
+		{
+      noSpin = (0.4248820426833804 - 906.746595921514*eta - 282820.39946006844*eta2 - 967049.2793750163*eta3 + 670077.5414916876*eta4)/(1. + 1670.9440812294847*eta + 19783.077247023448*eta2);
+
+      eqSpin = (S*(0.22814271667259703 + 1.1366593671801855*S + eta3*(3499.432393555856 - 877.8811492839261*S - 4974.189172654984*S2) + eta*(12.840649528989287 - 61.17248283184154*S2) + 0.4818323187946999*S2 + eta2*(-711.8532052499075 + 269.9234918621958*S + 941.6974723887743*S2) + eta4*(-4939.642457025497 - 227.7672020783411*S + 8745.201037897836*S2)))/(-1.2442293719740283 + 1.*S);
+
+      uneqSpin = dchi*delta*(-514.8494071830514 + 1493.3851099678195*eta)*eta3;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_d43: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+	}
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+
+/*	
+	See section VII. B of arXiv:2001.11412. 
+
+	Phase derivative ansatz for intermediate region, Eq. 7.6 of arXiv:2001.11412.
+
+	This is the canonical intermediate ansatz:
+
+	a_0 + a_1 ft^(-1) + a_2 ft^(-2) + a_3 ft^(-3) + a4 ft^(-4) + (4 * a_RD) / ( (2 * f_fdamp)^2 + (f - f_ring)^2 )
+
+	ft = (f / f_ring)
+*/
+static double IMRPhenomX_Intermediate_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
+{
+  double invff1 = powers_of_f->m_one;
+  double invff2 = powers_of_f->m_two;
+  double invff3 = powers_of_f->m_three;
+  double invff4 = powers_of_f->m_four;
+
+  double fda    = pWF->fDAMP;
+  double frd    = pWF->fRING;
+
+  double LorentzianTerm;
+  double phaseOut = 0;
+
+  int IntPhaseVersion = pWF->IMRPhenomXIntermediatePhaseVersion;
+
+  switch ( IntPhaseVersion )
+  {
+    case 104: 			/* Canonical, 4 coefficients */
+    {
+
+      /* This is the Lorentzian term where cL = - a_{RD} dphase0 */
+      LorentzianTerm = (4.0 * pPhase->cL) / ( (4.0*fda*fda) + (ff - frd)*(ff - frd) );
+
+      /* Return a polynomial embedded in the background from the merger */
+      phaseOut       = pPhase->b0 + pPhase->b1*invff1 + pPhase->b2*invff2 + pPhase->b4*invff4 + LorentzianTerm;
+
+      break;
+    }
+    case 105:				/* Canonical, 5 coefficients */
+    {
+
+      /* This is the Lorentzian term where cL = - a_{RD} dphase0 */
+      LorentzianTerm = (4.0 * pPhase->cL) / ( (4.0*fda*fda) + (ff - frd)*(ff - frd) );
+
+      /* Return a polynomial embedded in the background from the merger */
+      phaseOut       = (pPhase->b0) + (pPhase->b1)*invff1 + (pPhase->b2)*invff2 + (pPhase->b3)*invff3 + (pPhase->b4)*invff4 + LorentzianTerm;
+
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_Ansatz: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+    }
+  }
+
+  return phaseOut;
+}
+
+/*	
+	See section VII. B of arXiv:2001.11412. 
+
+	Integrated phase ansatz for intermediate region, Eq. 7.6 of arXiv:2001.11412.
+
+    Effective spin parameterization used = StotR
+*/
+static double IMRPhenomX_Intermediate_Phase_22_AnsatzInt(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
+{
+  double invff1 = powers_of_f->m_one;
+  double invff2 = powers_of_f->m_two;
+  double invff3 = powers_of_f->m_three;
+  double logfv   = powers_of_f->log;
+
+  double frd = pWF->fRING;
+  double fda = pWF->fDAMP;
+
+  double b0  = pPhase->b0;
+  double b1  = pPhase->b1;
+  double b2  = pPhase->b2;
+  double b3  = pPhase->b3;
+  double b4  = pPhase->b4;
+  double cL  = pPhase->cL;
+
+  double phaseOut;
+
+  int IntPhaseVersion = pWF->IMRPhenomXIntermediatePhaseVersion;
+
+  switch ( IntPhaseVersion )
+  {
+    case 104: 			/* Canonical, 4 coefficients */
+    {
+      //phaseOut = pPhase->b0*f + pPhase->b1*logfv - pPhase->b2*invff1 - pPhase->b4*invff3/3.0 + ( 2.0*pPhase->cL*atan( (f - frd) / (2.0 * fda) ) ) / fda ;
+      phaseOut = b0*f + b1*logfv - b2*invff1 - (b4*invff3/3.0) + ( 2.0*cL*atan( (f - frd) / (2.0 * fda) ) ) / fda ;
+      break;
+    }
+    case 105:				/* Canonical, 5 coefficients */
+    {
+      phaseOut = b0*f + b1*logfv - b2*invff1 - b3*invff2/2.0 - (b4*invff3/3.0) + ( 2.0 * cL * atan( (f - frd) / (2.0 * fda) ) ) / fda ;
+      break;
+    }
+    default:
+    {
+		XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Intermediate_Phase_22_AnsatzInt: IMRPhenomXIntermediatePhaseVersion is not valid. Recommended flag is 104.\n");
+      break;
+    }
+  }
+
+  return phaseOut;
+
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_intermediate.h b/lalsimulation/lib/LALSimIMRPhenomX_intermediate.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9af787c3996a5617a018b8b583eef6191ba49a3
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_intermediate.h
@@ -0,0 +1,72 @@
+#ifndef _LALSIM_IMR_PHENOMX_INTERMEDIATE_H
+#define _LALSIM_IMR_PHENOMX_INTERMEDIATE_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+#include "LALSimIMRPhenomX.h"
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+
+/********************************* IMRPhenomX: Amplitude Functions *********************************/
+static double IMRPhenomX_Intermediate_Amp_22_vA(double eta, double S, double dchi, double delta, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_v2(double eta, double S, double dchi, double delta, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_v3(double eta, double S, double dchi, double delta, int IntAmpFlag);
+
+static double IMRPhenomX_Intermediate_Amp_22_delta0(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_delta1(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_delta2(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_delta3(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_delta4(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+static double IMRPhenomX_Intermediate_Amp_22_delta5(double d1, double d4, double v1, double v2, double v3, double v4, double f1, double f2, double f3, double f4, int IntAmpFlag);
+
+static double IMRPhenomX_Intermediate_Amp_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+
+/********************************* IMRPhenomX: Phase Functions *********************************/
+static double IMRPhenomX_Intermediate_Phase_22_v2( double eta, double S, double dchi, double delta, int IntPhaseFlag);
+UNUSED static double IMRPhenomX_Intermediate_Phase_22_v3( double eta, double S, double dchi, double delta, int IntPhaseFlag);
+static double IMRPhenomX_Intermediate_Phase_22_v2mRDv4(double eta, double S, double dchi, double delta, int IntPhaseFlag);
+static double IMRPhenomX_Intermediate_Phase_22_v3mRDv4(double eta, double S, double dchi, double delta, int IntPhaseFlag);
+static double IMRPhenomX_Intermediate_Phase_22_d43(double eta, double S, double dchi, double delta, int IntPhaseFlag);
+
+static double IMRPhenomX_Intermediate_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+static double IMRPhenomX_Intermediate_Phase_22_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// of #ifndef _LALSIM_IMR_PHENOMX_INTERMEDIATE_H
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_internals.c b/lalsimulation/lib/LALSimIMRPhenomX_internals.c
new file mode 100644
index 0000000000000000000000000000000000000000..88f09132b576990f3658a1568b4e265020ca7ddc
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_internals.c
@@ -0,0 +1,2420 @@
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ * 	This code builds on:
+ * 		LALSimIMRPhenomD_internals.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ * Internal functions for IMRPhenomX, arXiv:2001.11412
+ */
+
+/* IMRPhenomX Header Files */
+#include "LALSimIMRPhenomX_utilities.h"
+#include "LALSimIMRPhenomX_internals.h"
+
+#include "LALSimIMRPhenomX_inspiral.c"
+#include "LALSimIMRPhenomX_intermediate.c"
+#include "LALSimIMRPhenomX_ringdown.c"
+#include "LALSimIMRPhenomX_qnm.c"
+//#include "LALSimIMRPhenomX_tidal.c"
+//#include "LALSimIMRPhenomX_precessing.c"
+
+/* LAL Header Files */
+#include <lal/LALSimIMR.h>
+#include <lal/LALConstants.h>
+#include <lal/Date.h>
+#include <lal/FrequencySeries.h>
+#include <lal/Units.h>
+
+/* GSL Header Files */
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+
+
+/* This struct is used to pre-cache useful powers of frequency, avoiding numerous expensive operations */
+int IMRPhenomX_Initialize_Powers(IMRPhenomX_UsefulPowers *p, REAL8 number)
+{
+	XLAL_CHECK(0 != p, XLAL_EFAULT, "p is NULL");
+	XLAL_CHECK(number >= 0, XLAL_EDOM, "number must be non-negative");
+
+	double sixth      = pow(number, 1.0 / 6.0);
+	double m_sixth    = 1.0 / sixth;
+
+	p->one_sixth      = sixth;
+	p->m_one_sixth    = m_sixth;
+
+	p->m_one          = 1.0 / number;
+	p->itself         = number;
+
+	p->one_third      = sixth * sixth;
+	p->m_one_third    = 1.0 / (p->one_third);
+
+	p->two_thirds     = p->one_third * p->one_third;
+	p->m_two_thirds   = 1.0 / p->two_thirds;
+
+	p->four_thirds    = p->two_thirds * p->two_thirds;
+	p->m_four_thirds  = 1.0 / p->four_thirds;
+
+	p->five_thirds    = p->four_thirds * p->one_third;
+	p->m_five_thirds  = 1.0 / p->five_thirds;
+
+	p->seven_thirds   = p->four_thirds * number;
+	p->m_seven_thirds = 1.0 / p->seven_thirds;
+
+	p->eight_thirds   = p->seven_thirds * p->one_third;
+	p->m_eight_thirds = 1.0 / p->eight_thirds;
+
+	p->two            = number   * number;
+	p->three          = p->two   * number;
+	p->four           = p->three * number;
+	p->five           = p->four  * number;
+
+	p->m_two          = 1.0 / p->two;
+	p->m_three        = 1.0 / p->three;
+	p->m_four         = 1.0 / p->four;
+
+	p->seven_sixths   = p->one_sixth   * p->itself;
+	p->m_seven_sixths = p->m_one_sixth * p->m_one;
+
+	p->log            = log(number);
+	p->sqrt           = p->one_sixth*p->one_sixth*p->one_sixth;
+
+	return XLAL_SUCCESS;
+}
+
+/* A stripped down version of IMRPhenomX_Initialize_Powers for main production loop */
+int IMRPhenomX_Initialize_Powers_Light(IMRPhenomX_UsefulPowers *p, REAL8 number)
+{
+	XLAL_CHECK(0 != p, XLAL_EFAULT, "p is NULL");
+	XLAL_CHECK(number >= 0, XLAL_EDOM, "number must be non-negative");
+
+	double sixth      = pow(number, 1.0 / 6.0);
+	double m_sixth    = 1.0 / sixth;
+
+	p->one_sixth      = sixth;
+	p->m_one_sixth    = m_sixth;
+
+	p->m_one          = 1.0 / number;
+	p->itself         = number;
+
+	p->one_third      = sixth * sixth;
+	p->two_thirds     = p->one_third * p->one_third;
+
+	p->m_two          = p->m_one   * p->m_one;
+	p->m_three        = p->m_two   * p->m_one;
+
+	p->seven_sixths   = p->one_sixth   * p->itself;
+	p->m_seven_sixths = p->m_one_sixth * p->m_one;
+
+	p->log            = log(number);
+
+	return XLAL_SUCCESS;
+}
+
+/* Leading order amplitude pre-factor, see Eq. 6.2 of arXiv:2001.11412 */
+REAL8 XLALSimIMRPhenomXAmp22Prefactor(REAL8 eta)
+{
+	REAL8 ampOut;
+	ampOut = sqrt(2.0/3.0) * sqrt(eta)  / pow(LAL_PI,1.0/6.0);
+	return ampOut;
+}
+
+int IMRPhenomXSetWaveformVariables(
+	IMRPhenomXWaveformStruct *wf,
+  const REAL8 m1_SI,
+  const REAL8 m2_SI,
+  const REAL8 chi1L_In,
+  const REAL8 chi2L_In,
+  const REAL8 deltaF,
+  const REAL8 fRef,
+  const REAL8 phi0,
+  const REAL8 f_min,
+  const REAL8 f_max,
+  const REAL8 distance,
+  const REAL8 inclination,
+  LALDict *LALParams,
+	UNUSED const UINT4 debug
+)
+{
+
+	/* Copy model version to struct */
+	wf->IMRPhenomXInspiralPhaseVersion      = XLALSimInspiralWaveformParamsLookupPhenomXInspiralPhaseVersion(LALParams);
+	wf->IMRPhenomXIntermediatePhaseVersion  = XLALSimInspiralWaveformParamsLookupPhenomXIntermediatePhaseVersion(LALParams);
+	wf->IMRPhenomXRingdownPhaseVersion      = XLALSimInspiralWaveformParamsLookupPhenomXRingdownPhaseVersion(LALParams);
+
+	wf->IMRPhenomXInspiralAmpVersion        = XLALSimInspiralWaveformParamsLookupPhenomXInspiralAmpVersion(LALParams);
+	wf->IMRPhenomXIntermediateAmpVersion    = XLALSimInspiralWaveformParamsLookupPhenomXIntermediateAmpVersion(LALParams);
+	wf->IMRPhenomXRingdownAmpVersion        = XLALSimInspiralWaveformParamsLookupPhenomXRingdownAmpVersion(LALParams);
+
+	wf->debug = PHENOMXDEBUG;
+
+	if(PHENOMXDEBUG)
+	{
+		printf("\n");
+		printf("Inspiral Amp Version		: %d\n",wf->IMRPhenomXInspiralAmpVersion);
+		printf("Intermediate Amp Version	: %d\n",wf->IMRPhenomXIntermediateAmpVersion);
+		printf("Ringdown Amp Version		: %d\n",wf->IMRPhenomXRingdownAmpVersion);
+		printf("\n");
+		printf("Inspiral Phase Version		: %d\n",wf->IMRPhenomXInspiralPhaseVersion);
+		printf("Intermediate Phase Version	: %d\n",wf->IMRPhenomXIntermediatePhaseVersion);
+		printf("Ringdown Phase Version		: %d\n",wf->IMRPhenomXRingdownPhaseVersion);
+		printf("\n");
+	}
+
+	/*
+	First perform a sanity check to make sure that a legitimate waveform version has been called. If not, fail immediately.
+	Every time a new version for one of the regions is added, user must add case below.
+	*/
+	int InspPhaseFlag = wf->IMRPhenomXInspiralPhaseVersion;
+
+	/* Phase : Inspiral */
+	switch( InspPhaseFlag )
+	{
+		// Canonical TaylorF2 up to 3.5PN with 4 pseudo-PN coefficients
+		case 104:
+		{
+			break;
+		}
+		// Canonical TaylorF2 up to 3.5PN with 5 pseudo-PN coefficients
+		case 105:
+		{
+			break;
+		}
+		// Extended TaylorF2 up to 4.5PN with 4 pseudo-PN coefficients
+		case 114:
+		{
+			break;
+		}
+		// Extended TaylorF2 up to 4.5PN with 5 pseudo-PN coefficients
+		case 115:
+		{
+			break;
+		}
+		// We must pass a recognised inspiral phase version. Otherwise fail.
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL, "Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXInspiralPhaseVersion not recognized. Recommended flag is 104.\n");
+		}
+	}
+
+	int IntPhaseFlag = wf->IMRPhenomXIntermediatePhaseVersion;
+	/* Phase : Intermediate */
+	switch( IntPhaseFlag )
+	{
+		// 4 intermediate coefficients
+		case 104:
+		{
+			break;
+		}
+		// 5 intermediate coefficients
+		case 105:
+		{
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL,"Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXIntermediatePhaseVersion not recognized. Recommended flag is 105.\n");
+		}
+	}
+
+	int RDPhaseFlag = wf->IMRPhenomXRingdownPhaseVersion;
+	/* Phase : Ringdown */
+	switch( RDPhaseFlag )
+	{
+		// 5 ringdown coefficients
+		case 105:
+		{
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL,"Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXRingdownPhaseVersion not recognized. Recommended flag is 105.\n");
+		}
+	}
+
+	int InsAmpFlag = wf->IMRPhenomXInspiralAmpVersion;
+	/* Amplitude : Inspiral */
+	switch( InsAmpFlag )
+	{
+		// Canonical TaylorF2 with 4 pseudo-PN coefficients
+		case 103:
+		{
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL,"Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXInspiralAmpVersion not recognized. Recommended flag is 103.\n");
+		}
+	}
+
+	int IntAmpFlag = wf->IMRPhenomXIntermediateAmpVersion;
+	/* Amplitude : Intermediate */
+	switch( IntAmpFlag )
+	{
+		// Intermediate region constructed from 4th order polynomial
+		case 1043:
+		{
+			break;
+		}
+		// Intermediate region constructed from a 4th order polynomial
+		case 104:
+		{
+			break;
+		}
+		// Intermediate region constructed from a 5th order polynomial
+		case 105:
+		{
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL,"Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXIntermediateAmpVersion not recognized. Recommended flag is 104.\n");
+		}
+	}
+
+	int RDAmpFlag = wf->IMRPhenomXRingdownAmpVersion;
+	/* Amplitude : Ringdown */
+	switch( RDAmpFlag )
+	{
+		case 103:
+		{
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL,"Error in IMRPhenomX_SetWaveformVariables: IMRPhenomXRingdownAmpVersion not recognized. Recommended flag is 103.\n");
+		}
+	}
+
+	/* Rescale to mass in solar masses */
+	REAL8 m1_In      = m1_SI / LAL_MSUN_SI; // Mass 1 in solar masses
+	REAL8 m2_In      = m2_SI / LAL_MSUN_SI; // Mass 2 in solar masses
+
+	REAL8 m1, m2, chi1L, chi2L;
+
+	/* Check if m1 >= m2, if not then swap masses/spins */
+	if(m1_In >= m2_In)
+	{
+		chi1L = chi1L_In;
+		chi2L = chi2L_In;
+		m1    = m1_In;
+		m2    = m2_In;
+	}
+	else
+	{
+		XLAL_PRINT_WARNING("Warning: m1 < m2, swapping the masses and spins.\n");
+		chi1L = chi2L_In;
+		chi2L = chi1L_In;
+		m1    = m2_In;
+		m2    = m1_In;
+	}
+
+	/* Check that physical spins have been called. Perform internal nudge to check for numerical round-off issues. */
+	if(chi1L > 1.0)
+	{
+		IMRPhenomX_InternalNudge(chi1L,1.0,1e-6);
+	}
+	if(chi2L > 1.0)
+	{
+		IMRPhenomX_InternalNudge(chi2L,1.0,1e-6);
+	}
+	if(chi1L < -1.0)
+	{
+		IMRPhenomX_InternalNudge(chi1L,-1.0,1e-6);
+	}
+	if(chi2L < -1.0)
+	{
+		IMRPhenomX_InternalNudge(chi2L,-1.0,1e-6);
+	}
+	/* If spins are still unphysical after checking for small round-off errors, fail. */
+	if( chi1L > 1.0 || chi1L < -1.0 || chi2L > 1.0 || chi2L < -1.0)
+	{
+		//XLALPrintError("Unphyiscal spins: must be in the range [-1,1].\n");
+		XLAL_ERROR(XLAL_EDOM, "Unphysical spins requested: must obey the Kerr bound [-1,1].\n");
+	}
+
+	// Symmetric mass ratio
+	REAL8 delta = fabs((m1 - m2) / (m1+m2));
+	REAL8 eta   = fabs(0.25 * (1.0 - delta*delta) ); // use fabs to prevent negative sign due to roundoff
+
+	/* Perform some sanity checks on eta - FIXME_SH this should not be necessary anymore */
+	if(eta > 0.25)
+	{
+		IMRPhenomX_InternalNudge(eta,0.25,1e-6);
+	}
+	if(eta > 0.25 || eta < 0.0)
+	{
+		//XLALPrintError("Unphyiscal eta: must be between 0 and 0.25\n");
+		XLAL_ERROR(XLAL_EDOM,"Unphysical eta: must be between 0 and 0.25\n");
+	}
+	//if(eta < MAX_ALLOWED_ETA)
+	//{
+	//	XLAL_PRINT_WARNING("Warning: The model is not calibrated against numerical-relativity mass-ratios greater than 18.\n");
+	//}
+
+	/* Check that masses are correctly ordered. Swap if necessary.
+	return_code = IMRPhenomX_CheckMassOrdering(m1,m2,chi1L,chi2L);
+	XLAL_CHECK(XLAL_SUCCESS == return_code, XLAL_EFUNC, "Failure: IMRPhenomX_CheckMassOrdering");
+	*/
+
+	REAL8 q   = ((m1 > m2) ? (m1 / m2) : (m2 / m1));
+
+	/* Masses definitions. Note that m1 and m2 are the component masses in solar masses. */
+	wf->m1_SI     = m1 * LAL_MSUN_SI;																						// Mass 1 (larger) in SI units
+	wf->m2_SI     = m2 * LAL_MSUN_SI;																						// Mass 2 (smaller) in SI units
+	wf->q         = q;																								    			// Mass ratio >= 1
+	wf->eta       = eta;                                                        // Symmetric mass ratio
+	wf->Mtot_SI   = wf->m1_SI + wf->m2_SI;                                      // Total mass in SI units
+	wf->Mtot      = m1 + m2;																										// Total mass in solar masss
+	wf->m1        = m1 / (wf->Mtot);                         						        // Mass 1 (larger), dimensionless (i.e. m1 \in [0,1])
+	wf->m2        = m2 / (wf->Mtot);						                                // Mass 2 (smaller), dimensionless
+	wf->M_sec     = wf->Mtot * LAL_MTSUN_SI;                                    // Conversion factor Hz to geometric frequency, total mass in seconds
+	wf->delta     = delta;                                                      // PN symmetry coefficient
+
+	wf->eta2 = eta * eta;
+	wf->eta3 = eta * wf->eta2;
+
+	if(wf->debug)
+	{
+		printf("m1 (Msun) = %.6f\n",m1);
+		printf("m2 (Msun) = %.6f\n",m2);
+		printf("m1_SI     = %.6f\n",wf->m1_SI);
+		printf("m2_SI     = %.6f\n",wf->m2_SI);
+		printf("m1        = %.6f\n",wf->m1);
+		printf("m2        = %.6f\n",wf->m2);
+	}
+
+	if(wf->q > MAX_ALLOWED_MASS_RATIO)
+	{
+		XLAL_PRINT_WARNING("Warning: The model is not supported at such high mass ratios, see MAX_ALLOWED_MASS_RATIO.\n");
+	}
+
+	/* Spins */
+	wf->chi1L     = chi1L;
+	wf->chi2L     = chi2L;
+
+	wf->chi1L2L   = chi1L * chi2L;
+
+	/* Useful powers of spin */
+	wf->chi1L2    = chi1L*chi1L;
+	wf->chi1L3    = chi1L*chi1L*chi1L;
+
+	wf->chi2L2    = chi2L*chi2L;
+	wf->chi2L3    = chi2L*chi2L*chi2L;
+
+	/* Spin parameterisations */
+	wf->chiEff    = XLALSimIMRPhenomXchiEff(eta,chi1L,chi2L);
+	wf->chiPNHat  = XLALSimIMRPhenomXchiPNHat(eta,chi1L,chi2L);
+	wf->STotR     = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
+	wf->dchi      = XLALSimIMRPhenomXdchi(chi1L,chi2L);
+
+	wf->SigmaL    = (wf->chi2L * wf->m2) - (wf->chi1L * wf->m1); 										// SigmaL = (M/m2)*(S2.L) - (M/m2)*(S1.L)
+	wf->SL        = wf->chi1L * (wf->m1 * wf->m1) + wf->chi2L * (wf->m2 * wf->m2);  // SL = S1.L + S2.L
+
+	if(wf->debug)
+	{
+		printf("eta     : %.6f\n",wf->eta);
+		printf("q       : %.6f\n",wf->q);
+		printf("chi1L   : %.6f\n",wf->chi1L);
+		printf("chi2L   : %.6f\n",wf->chi2L);
+		printf("chi_eff : %.6f\n",wf->chiEff);
+		printf("chi_hat : %.6f\n",wf->chiPNHat);
+		printf("STotR   : %.6f\n",wf->STotR);
+	}
+
+	/* If no reference frequency is passed, set it to the starting GW frequency */
+	wf->fRef      = (fRef == 0.0) ? f_min : fRef;
+	wf->phiRef_In = phi0;
+	wf->phi0      = phi0;							// Orbital phase at reference frequency (as passed from lalsimulation)
+	wf->beta      = LAL_PI*0.5 - phi0; 				// Azimuthal angle of binary at reference frequency
+	wf->phifRef   = 0.0;							// This is calculated later
+
+	/* Geometric reference frequency */
+	wf->MfRef     = XLALSimIMRPhenomXUtilsHztoMf(wf->fRef,wf->Mtot);
+	wf->piM       = LAL_PI * wf->M_sec;
+	wf->v_ref     = cbrt(wf->piM * wf->fRef);
+
+	wf->deltaF    = deltaF;
+
+	/* Define the default end of the waveform as: 0.3 Mf. This value is chosen such that the 44 mode also shows the ringdown part. */
+	wf->fCutDef   = 0.3;
+	// If chieff is very high the ringdown of the 44 is almost cut it out when using 0.3, so we increase a little bit the cut of freq up 0.33.
+	if(wf->chiEff > 0.99) wf->fCutDef = 0.33;
+
+	/* Minimum and maximum frequency */
+	wf->fMin      = f_min;
+	wf->fMax      = f_max;
+
+	/* Convert fCut to physical cut-off frequency */
+	wf->fCut      = wf->fCutDef / wf->M_sec;
+
+	/* Sanity check that minimum start frequency is less than cut-off frequency */
+	if (wf->fCut <= wf->fMin)
+	{
+		XLALPrintError("(fCut = %g Hz) <= f_min = %g\n", wf->fCut, wf->fMin);
+	}
+
+	if(wf->debug)
+	{
+		printf("fRef : %.6f\n",wf->fRef);
+		printf("phi0 : %.6f\n",wf->phi0);
+		printf("fCut : %.6f\n",wf->fCut);
+		printf("fMin : %.6f\n",wf->fMin);
+		printf("fMax : %.6f\n",wf->fMax);
+	}
+
+	/* By default f_max_prime is f_max. If fCut < fMax, then use fCut, i.e. waveform up to fMax will be zeros */
+	wf->f_max_prime   = wf->fMax;
+	wf->f_max_prime   = wf->fMax ? wf->fMax : wf->fCut;
+	wf->f_max_prime   = (wf->f_max_prime > wf->fCut) ? wf->fCut : wf->f_max_prime;
+
+	if (wf->f_max_prime <= wf->fMin)
+	{
+		XLALPrintError("f_max <= f_min\n");
+	}
+
+	if(wf->debug)
+	{
+		printf("fMin        = %.6f\n",wf->fMin);
+		printf("fMax        = %.6f\n",wf->fMax);
+		printf("f_max_prime = %.6f\n",wf->f_max_prime);
+	}
+
+	/* Final Mass and Spin */
+	wf->Mfinal    = XLALSimIMRPhenomXFinalMass2017(wf->eta,wf->chi1L,wf->chi2L);
+	wf->afinal    = XLALSimIMRPhenomXFinalSpin2017(wf->eta,wf->chi1L,wf->chi2L);
+
+	/* Ringdown and damping frequency of final BH */
+#if QNMfits == 1
+	wf->fRING     = evaluate_QNMfit_fring22(wf->afinal) / (wf->Mfinal);
+	wf->fDAMP     = evaluate_QNMfit_fdamp22(wf->afinal) / (wf->Mfinal);
+#else
+	wf->fRING     = interpolateQNMData_fring_22(wf->afinal) / (wf->Mfinal);
+	wf->fDAMP     = interpolateQNMData_fdamp_22(wf->afinal) / (wf->Mfinal);
+#endif
+
+
+	if(wf->debug)
+	{
+		printf("Mf  = %.6f\n",wf->Mfinal);
+		printf("af  = %.6f\n",wf->afinal);
+		printf("frd = %.6f\n",wf->fRING);
+		printf("fda = %.6f\n",wf->fDAMP);
+	}
+
+	if(wf->Mfinal > 1.0)
+	{
+		XLAL_ERROR(XLAL_EDOM, "IMRPhenomX_FinalMass2018: Final mass > 1.0 not physical.");
+	}
+	if(fabs(wf->afinal) > 1.0)
+	{
+		XLAL_ERROR(XLAL_EDOM, "IMRPhenomX_FinalSpin2018: Final spin > 1.0 is not physical.");
+	}
+
+	/* Fit to the hybrid minimum energy circular orbit (MECO), Cabero et al, Phys.Rev. D95 (2017) */
+	wf->fMECO       = XLALSimIMRPhenomXfMECO(wf->eta,wf->chi1L,wf->chi2L);
+
+	/* Innermost stable circular orbit (ISCO), e.g. Ori et al, Phys.Rev. D62 (2000) 124022 */
+	wf->fISCO       = XLALSimIMRPhenomXfISCO(wf->afinal);
+
+	if(wf->debug)
+	{
+		printf("fMECO = %.6f\n",wf->fMECO);
+		printf("fISCO = %.6f\n",wf->fISCO);
+	}
+
+	if(wf->fMECO > wf->fISCO)
+	{
+		/* If MECO > fISCO, throw an error - this may be the case for very corner cases in the parameter space (e.g. q ~ 1000, chi ~ 0.999) */
+		XLAL_ERROR(XLAL_EDOM, "Error: f_MECO cannot be greater than f_ISCO.");
+	}
+
+	/* Distance and inclination */
+	wf->distance    = distance;
+	wf->inclination = inclination;
+
+	/* Amplitude normalization */
+	wf->amp0        = wf->Mtot * LAL_MRSUN_SI * wf->Mtot * LAL_MTSUN_SI / wf->distance;
+	wf->ampNorm     = sqrt(2.0/3.0) * sqrt(wf->eta) * powers_of_lalpi.m_one_sixth;
+
+	if(wf->debug)
+	{
+		printf("\n\neta     = %.6f\n",wf->eta);
+		printf("\nampNorm = %e\n",wf->ampNorm);
+		printf("amp0 : %e",wf->amp0);
+	}
+
+	/* Phase normalization */
+	wf->dphase0     = 5.0 / (128.0 * pow(LAL_PI,5.0/3.0));
+
+	if(wf->debug)
+	{
+		printf("\n\n **** Sanity checks complete. Waveform struct has been initialized. **** \n\n");
+	}
+
+	return XLAL_SUCCESS;
+}
+
+int IMRPhenomXGetAmplitudeCoefficients(
+	IMRPhenomXWaveformStruct *pWF,
+	IMRPhenomXAmpCoefficients *pAmp
+)
+{
+	INT4 debug = PHENOMXDEBUG;
+
+	REAL8 V1, V2, V3, V4;
+	REAL8 F1, F2, F3, F4;
+	REAL8 d1, d4;
+
+	/* Declare local spin variables for convenience */
+	REAL8 chi1L         = pWF->chi1L;
+	REAL8 chi2L         = pWF->chi2L;
+	REAL8 chi1L2        = pWF->chi1L2;
+	REAL8 chi1L3        = pWF->chi1L3;
+	REAL8 chi2L2        = pWF->chi2L2;
+
+	// Local PN symmetry parameter
+	REAL8 delta         = pWF->delta;
+
+	// Local powers of the symmetric mass ratio
+	REAL8 eta           = pWF->eta;
+	REAL8 eta2          = pWF->eta2;
+	REAL8 eta3          = pWF->eta3;
+
+	if(debug)
+	{
+		printf("chi1L  = %.6f\n",chi1L);
+		printf("chi1L2 = %.6f\n",chi1L2);
+		printf("chi1L3 = %.6f\n",chi1L3);
+		printf("chi2L2 = %.6f\n",chi2L2);
+		printf("delta  = %.6f\n",delta);
+		printf("eta2   = %.6f\n",eta2);
+		printf("eta3   = %.6f\n",eta3);
+	}
+
+	// Phenomenological ringdown coefficients: note that \gamma2 = \lambda in arXiv:2001.11412 and \gamma3 = \sigma in arXiv:2001.11412 
+	pAmp->gamma2        = IMRPhenomX_Ringdown_Amp_22_gamma2(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownAmpVersion);
+	pAmp->gamma3        = IMRPhenomX_Ringdown_Amp_22_gamma3(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownAmpVersion);
+
+	/* Get peak ringdown frequency, Eq. 5.14 in arXiv:2001.11412: Abs[fring + fdamp * gamma3 * (Sqrt[1 - gamma2^2] - 1)/gamma2 ] */
+	pAmp->fAmpRDMin     = IMRPhenomX_Ringdown_Amp_22_PeakFrequency(pAmp->gamma2,pAmp->gamma3,pWF->fRING,pWF->fDAMP,pWF->IMRPhenomXRingdownAmpVersion);
+
+	// Value of v1RD at fAmpRDMin is used to calcualte gamma1 \propto the amplitude of the deformed Lorentzian
+	pAmp->v1RD          = IMRPhenomX_Ringdown_Amp_22_v1(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownAmpVersion);
+	F1                  = pAmp->fAmpRDMin;
+
+	// Solving linear equation: ansatzRD(F1) == v1
+	pAmp->gamma1 = ( pAmp->v1RD / (pWF->fDAMP * pAmp->gamma3) ) * (F1*F1 - 2.0*F1*pWF->fRING + pWF->fRING*pWF->fRING + pWF->fDAMP*pWF->fDAMP*pAmp->gamma3*pAmp->gamma3)
+													* exp( ( (F1 - pWF->fRING) * pAmp->gamma2 ) / (pWF->fDAMP * pAmp->gamma3) );
+
+	/* Pre-cache these constants for the ringdown amplitude */
+	pAmp->gammaR   = pAmp->gamma2 / (pWF->fDAMP * pAmp->gamma3);
+	pAmp->gammaD2  = (pAmp->gamma3 * pWF->fDAMP) * (pAmp->gamma3 * pWF->fDAMP);
+	pAmp->gammaD13 = pWF->fDAMP * pAmp->gamma1 * pAmp->gamma3;
+
+	if(debug)
+	{
+		printf("V1     = %.6f\n",pAmp->v1RD);
+		printf("gamma1 = %.6f\n",pAmp->gamma1);
+		printf("gamma2 = %.6f\n",pAmp->gamma2);
+		printf("gamma3 = %.6f\n",pAmp->gamma3);
+		printf("fmax   = %.6f\n",pAmp->fAmpRDMin);
+	}
+
+	/* Inspiral-Intermediate transition frequencies, see Eq. 5.7 in arXiv:2001.11412 */
+	pAmp->fAmpInsMin    = 0.0026;
+	pAmp->fAmpInsMax    = pWF->fMECO + 0.25*(pWF->fISCO - pWF->fMECO);
+
+	/* Inspiral-Intermediate matching frequency, Eq. 5.16 in arXiv:2001.11412 */
+	pAmp->fAmpMatchIN   = pAmp->fAmpInsMax;
+
+	/* Intermediate-Ringdown matching frequency */
+	//pAmp->fAmpMatchIM   = pAmp->fAmpRDMin;
+
+	/* End of intermerdiate region, Eq. 5.16 in arXiv:2001.11412 */
+	pAmp->fAmpIntMax    = pAmp->fAmpRDMin;
+
+	/* TaylorF2 PN Amplitude Coefficients from usual PN re-expansion of Hlm's */
+	pAmp->pnInitial     = 1.0;
+	pAmp->pnOneThird    = 0.0;
+	pAmp->pnTwoThirds   = ( (-969 + 1804*eta)/672. ) * powers_of_lalpi.two_thirds;
+	pAmp->pnThreeThirds = ( (81*(chi1L + chi2L) + 81*chi1L*delta - 81*chi2L*delta - 44*(chi1L + chi2L)*eta)/48. ) * powers_of_lalpi.itself;
+	pAmp->pnFourThirds  = ( (-27312085 - 10287648*chi1L2*(1 + delta)
+													+ 24*(428652*chi2L2*(-1 + delta) + (-1975055 + 10584*(81*chi1L2 - 94*chi1L*chi2L + 81*chi2L2))*eta
+													+ 1473794*eta2))/8.128512e6 ) * powers_of_lalpi.one_third * powers_of_lalpi.itself;
+	pAmp->pnFiveThirds  = ( (-6048*chi1L3*(-1 - delta + (3 + delta)*eta) + chi2L*(-((287213 + 6048*chi2L2)*(-1 + delta))
+													+ 4*(-93414 + 1512*chi2L2*(-3 + delta) + 2083*delta)*eta - 35632*eta2)
+													+ chi1L*(287213*(1 + delta) - 4*eta*(93414 + 2083*delta + 8908*eta))
+													+ 42840*(-1 + 4*eta)*LAL_PI)/32256. ) * powers_of_lalpi.five_thirds;
+	pAmp->pnSixThirds   = ( (-1242641879927 + 12.0*(28.0*(-3248849057.0
+													+ 11088*(163199*chi1L2 - 266498*chi1L*chi2L + 163199*chi2L2))*eta2
+													+ 27026893936*eta3 - 116424*(147117*(-(chi2L2*(-1.0 + delta)) + chi1L2*(1.0 + delta))
+													+ 60928*(chi1L + chi2L + chi1L*delta - chi2L*delta)*LAL_PI)
+													+ eta*(545384828789.0 - 77616*(638642*chi1L*chi2L + chi1L2*(-158633 + 282718*delta)
+													- chi2L2*(158633.0 + 282718.0*delta) - 107520.0*(chi1L + chi2L)*LAL_PI
+													+ 275520*powers_of_lalpi.two))))/6.0085960704e10 ) * powers_of_lalpi.two;
+
+
+	/* These are the same order as the canonical pseudo-PN terms but we can add higher order PN information as and when available here */
+	pAmp->pnSevenThirds = 0.0;
+	pAmp->pnEightThirds = 0.0;
+	pAmp->pnNineThirds  = 0.0;
+
+	/* Generate Pseudo-PN Coefficients for Amplitude. */
+	switch( pWF->IMRPhenomXInspiralAmpVersion)
+	{
+		case 103:
+		{
+			pAmp->CollocationValuesAmpIns[0] = 0.0; // This is not currently used but may be invoked in future recalibration. Leave here, its harmless.
+			pAmp->CollocationValuesAmpIns[1] = IMRPhenomX_Inspiral_Amp_22_v2(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralAmpVersion);
+			pAmp->CollocationValuesAmpIns[2] = IMRPhenomX_Inspiral_Amp_22_v3(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralAmpVersion);
+			pAmp->CollocationValuesAmpIns[3] = IMRPhenomX_Inspiral_Amp_22_v4(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralAmpVersion);
+
+			pAmp->CollocationPointsAmpIns[0] = 0.25 * pAmp->fAmpMatchIN;
+			pAmp->CollocationPointsAmpIns[1] = 0.50 * pAmp->fAmpMatchIN;
+			pAmp->CollocationPointsAmpIns[2] = 0.75 * pAmp->fAmpMatchIN;
+			pAmp->CollocationPointsAmpIns[3] = 1.00 * pAmp->fAmpMatchIN;
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL, "Error in IMRPhenomXGetAmplitudeCoefficients: IMRPhenomXInspiralAmpVersion is not valid.\n");
+		}
+	}
+
+	// Set collocation points and values
+	V1 = pAmp->CollocationValuesAmpIns[1];
+	V2 = pAmp->CollocationValuesAmpIns[2];
+	V3 = pAmp->CollocationValuesAmpIns[3];
+	F1 = pAmp->CollocationPointsAmpIns[1];
+	F2 = pAmp->CollocationPointsAmpIns[2];
+	F3 = pAmp->CollocationPointsAmpIns[3];
+
+	if(debug)
+	{
+		printf("\nAmplitude pseudo PN coeffcients\n");
+		printf("fAmpMatchIN = %.6f\n",pAmp->fAmpMatchIN);
+		printf("V1   = %.6f\n",V1);
+		printf("V2   = %.6f\n",V2);
+		printf("V3   = %.6f\n",V3);
+		printf("F1   = %e\n",F1);
+		printf("F2   = %e\n",F2);
+		printf("F3   = %e\n",F3);
+	}
+
+	/* Using the collocation points and their values, we solve a linear system of equations to recover the pseudo-PN coefficients */
+	pAmp->rho1 = IMRPhenomX_Inspiral_Amp_22_rho1(V1,V2,V3,F1,F2,F3,pWF->IMRPhenomXInspiralAmpVersion);
+	pAmp->rho2 = IMRPhenomX_Inspiral_Amp_22_rho2(V1,V2,V3,F1,F2,F3,pWF->IMRPhenomXInspiralAmpVersion);
+	pAmp->rho3 = IMRPhenomX_Inspiral_Amp_22_rho3(V1,V2,V3,F1,F2,F3,pWF->IMRPhenomXInspiralAmpVersion);
+
+	/* Set TaylorF2 pseudo-PN coefficients */
+	pAmp->pnSevenThirds = pAmp->rho1;
+	pAmp->pnEightThirds = pAmp->rho2;
+	pAmp->pnNineThirds  = pAmp->rho3;
+
+	if(debug)
+	{
+		printf("\nTaylorF2 PN Amplitude Coefficients\n");
+		printf("pnTwoThirds   = %.6f\n",pAmp->pnTwoThirds);
+		printf("pnThreeThirds = %.6f\n",pAmp->pnThreeThirds);
+		printf("pnFourThirds  = %.6f\n",pAmp->pnFourThirds);
+		printf("pnFiveThirds  = %.6f\n",pAmp->pnFiveThirds);
+		printf("pnSixThirds   = %.6f\n",pAmp->pnSixThirds);
+		printf("\n");
+		printf("powers_of_lalpi.itself = %.6f\n",powers_of_lalpi.itself);
+		printf("powers_of_lalpi.four_thirds = %.6f\n",powers_of_lalpi.four_thirds);
+		printf("powers_of_lalpi.five_thirds = %.6f\n",powers_of_lalpi.five_thirds);
+		printf("\n");
+		printf("Pseudo-PN Amplitude Coefficients (Agrees with MMA).\n");
+		printf("alpha1 = %.6f\n",pAmp->pnSevenThirds);
+		printf("alpha2 = %.6f\n",pAmp->pnEightThirds);
+		printf("alpha3  = %.6f\n",pAmp->pnNineThirds);
+	}
+
+	/* Now we can reconstruct the intermediate region, which depends on the derivative of the inspiral and ringdown fits at the boundaries */
+	F1     = pAmp->fAmpMatchIN;
+	F4     = pAmp->fAmpRDMin;
+
+	// Initialise useful powers for the boundary points
+	IMRPhenomX_UsefulPowers powers_of_F1;
+	IMRPhenomX_Initialize_Powers(&powers_of_F1,F1);
+
+	IMRPhenomX_UsefulPowers powers_of_F4;
+	IMRPhenomX_Initialize_Powers(&powers_of_F4,F4);
+
+	/* Calculate derivative of amplitude on boundary points */
+	d1     = IMRPhenomX_Inspiral_Amp_22_DAnsatz(F1,pWF,pAmp);
+	d4     = IMRPhenomX_Ringdown_Amp_22_DAnsatz(F4,pWF,pAmp);
+
+	double inspF1 = IMRPhenomX_Inspiral_Amp_22_Ansatz(F1,&powers_of_F1,pWF,pAmp);
+	double rdF4   = IMRPhenomX_Ringdown_Amp_22_Ansatz(F4,pWF,pAmp);
+
+	/* 
+		Use d1 and d4 calculated above to get the derivative of the amplitude on the boundaries:
+	
+		D[ f^{7/6} Ah^{-1}[f] , f] = ( (7/6) * f^{1/6} / Ah[f] ) - ( f^{7/6} Ah'[f] ) / (Ah[f]^2)
+	
+		where d1 = Ah'[F1], inspF1 = Ah[F1] etc.
+	
+	*/
+	d1     = ((7.0/6.0) * powers_of_F1.one_sixth / inspF1) - ( powers_of_F1.seven_sixths * d1 / (inspF1*inspF1) );
+	d4     = ((7.0/6.0) * powers_of_F4.one_sixth / rdF4)   - ( powers_of_F4.seven_sixths * d4 / (rdF4*rdF4) );
+
+	if(debug)
+	{
+		printf("d1 = %.6f\n",d1);
+		printf("d4 = %.6f\n",d4);
+	}
+
+	/* Pass inverse of points to reconstruction function... */
+	switch ( pWF->IMRPhenomXIntermediateAmpVersion )
+	{
+		case 1043:
+		{
+			// Use a 5th order polynomial in intermediate - great agreement to calibration points but poor extrapolation
+			F2     = F1 + (1.0/3.0) * (F4-F1);
+			F3     = F1 + (2.0/3.0) * (F4-F1);
+
+			V1     = powers_of_F1.m_seven_sixths * inspF1;
+			V2     = IMRPhenomX_Intermediate_Amp_22_v2(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediateAmpVersion);
+			V3     = IMRPhenomX_Intermediate_Amp_22_v3(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediateAmpVersion);
+			V4     = powers_of_F4.m_seven_sixths * rdF4;
+
+			V1 		 = 1.0 / V1;
+			V2 		 = 1.0 / V2;
+			V3 		 = 1.0 / V3;
+			V4 		 = 1.0 / V4;
+			break;
+		}
+		case 104:
+		{
+			// Use a 4th order polynomial in intermediate - good extrapolation, recommended default fit
+			F2     = F1 + (1.0/2.0) * (F4-F1);
+			F3     = 0.0;
+
+			V1     = powers_of_F1.m_seven_sixths * inspF1;
+			V2     = IMRPhenomX_Intermediate_Amp_22_vA(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediateAmpVersion);
+			V4     = powers_of_F4.m_seven_sixths * rdF4;
+
+			V1 		 = 1.0 / V1;
+			V2 		 = 1.0 / V2;
+			V3 		 = 0.0;
+			V4 		 = 1.0 / V4;
+
+			break;
+		}
+		case 105:
+		{
+			// Use a 5th order polynomial in intermediate - great agreement to calibration points but poor extrapolation
+			F2     = F1 + (1.0/3.0) * (F4-F1);
+			F3     = F1 + (2.0/3.0) * (F4-F1);
+
+			V1     = powers_of_F1.m_seven_sixths * inspF1;
+			V2     = IMRPhenomX_Intermediate_Amp_22_v2(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediateAmpVersion);
+			V3     = IMRPhenomX_Intermediate_Amp_22_v3(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediateAmpVersion);
+			V4     = powers_of_F4.m_seven_sixths * rdF4;
+
+			V1 		 = 1.0 / V1;
+			V2 		 = 1.0 / V2;
+			V3 		 = 1.0 / V3;
+			V4 		 = 1.0 / V4;
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL, "Error: IMRPhenomXIntermediateAmpVersion is not valid.\n");
+		}
+	}
+
+	if(debug)
+	{
+		printf("\nIntermediate Region: \n");
+		printf("F1 = %.6f\n",F1);
+		printf("F2 = %.6f\n",F2);
+		printf("F3 = %.6f\n",F3);
+		printf("F4 = %.6f\n",F4);
+		printf("\n");
+		printf("Insp@F1 = %.6f\n",IMRPhenomX_Inspiral_Amp_22_Ansatz(F1,&powers_of_F1,pWF,pAmp));
+		printf("d1 = %.6f\n",d1);
+		printf("d4 = %.6f\n",d4);
+		printf("V1 = %.6f\n",V1);
+		printf("V2 = %.6f\n",V2);
+		printf("V3 = %.6f\n",V3);
+		printf("V4 = %.6f\n",V4);
+	}
+
+	/*
+	Reconstruct the phenomenological coefficients for the intermediate ansatz:
+	*/
+	pAmp->delta0 = IMRPhenomX_Intermediate_Amp_22_delta0(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+	pAmp->delta1 = IMRPhenomX_Intermediate_Amp_22_delta1(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+	pAmp->delta2 = IMRPhenomX_Intermediate_Amp_22_delta2(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+	pAmp->delta3 = IMRPhenomX_Intermediate_Amp_22_delta3(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+	pAmp->delta4 = IMRPhenomX_Intermediate_Amp_22_delta4(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+	pAmp->delta5 = IMRPhenomX_Intermediate_Amp_22_delta5(d1,d4,V1,V2,V3,V4,F1,F2,F3,F4,pWF->IMRPhenomXIntermediateAmpVersion);
+
+	if(debug)
+	{
+  	    printf("delta0 = %.6f\n",pAmp->delta0);
+		printf("delta1 = %.6f\n",pAmp->delta1);
+		printf("delta2 = %.6f\n",pAmp->delta2);
+		printf("delta3 = %.6f\n",pAmp->delta3);
+		printf("delta4 = %.6f\n",pAmp->delta4);
+		printf("delta5 = %.6f\n",pAmp->delta5);
+	}
+
+	return XLAL_SUCCESS;
+}
+
+/*
+ * Function to populate the IMRPhenomXPhaseCoefficients struct:
+*/
+int IMRPhenomXGetPhaseCoefficients(
+	IMRPhenomXWaveformStruct *pWF,
+	IMRPhenomXPhaseCoefficients *pPhase
+)
+{
+	//IMRPhenomXPhaseCoefficients *pPhase = (IMRPhenomXPhaseCoefficients *) XLALMalloc(sizeof(IMRPhenomXPhaseCoefficients));
+
+	const INT4 debug = PHENOMXDEBUG; // pWF->debug;
+
+	/* GSL objects for solving system of equations via LU decomposition */
+	gsl_vector *b, *x;
+	gsl_matrix *A;
+	gsl_permutation *p;
+	int s;
+
+	REAL8 deltax;
+	REAL8 xmin;
+	REAL8 fi;
+	//REAL8 gpoints4[4]     = {1.0, 3.0/4, 1.0/4, 0.0};
+	//REAL8 gpoints5[5]     = {1.0, 1.0/2 + 1.0/(2.0*sqrt(2.0)), 1.0/2, 1.0/2 - 1.0/(2*sqrt(2.0)), 0.};
+
+	REAL8 gpoints4[4]     = {0.0, 1.0/4.0, 3.0/4.0, 1.0};
+	REAL8 gpoints5[5]     = {0.0, 1.0/2 - 1.0/(2*sqrt(2.0)), 1.0/2.0, 1.0/2 + 1.0/(2.0*sqrt(2.0)), 1.0};
+
+	//pPhase->fPhaseMatchIN = pWF->fMECO;
+	//pPhase->fPhaseMatchIM = 0.6 * (0.5 * pWF->fRING + pWF->fISCO);
+
+	// Matching regions
+	
+	/* This is Eq. 5.11 in the paper */
+	double fIMmatch = 0.6 * (0.5 * pWF->fRING + pWF->fISCO);
+	
+	/* This is the MECO frequency */
+	double fINmatch = pWF->fMECO;
+	
+	/* This is Eq. 5.10 in the paper */
+	double deltaf   = (fIMmatch - fINmatch) * 0.03;
+
+	// Transition frequency is just below the MECO frequency and just above the RD fitting region
+	
+	/* These are defined in Eq. 7.7 and the text just below, f_H = fPhaseMatchIM and f_L = fPhaseMatchIN */
+	pPhase->fPhaseMatchIN  = fINmatch - 1.0*deltaf;
+	pPhase->fPhaseMatchIM  = fIMmatch + 0.5*deltaf;
+
+	/* Defined in Eq. 7.4, this is f_L */
+	pPhase->fPhaseInsMin  = 0.0026;
+	
+	/* Defined in Eq. 7.4, this is f_H */
+	pPhase->fPhaseInsMax  = 1.020 * pWF->fMECO;
+
+	/* Defined in Eq. 7.12, this is f_L */
+	pPhase->fPhaseRDMin   = fIMmatch;
+	
+	/* Defined in Eq. 7.12, this is f_L */
+	pPhase->fPhaseRDMax   = pWF->fRING + 1.25*pWF->fDAMP;
+
+	pPhase->phiNorm    		= -(3.0 * powers_of_lalpi.m_five_thirds) / (128.0);
+
+	/* For convenience, define some variables here */
+	REAL8 chi1L           = pWF->chi1L;
+	REAL8 chi2L           = pWF->chi2L;
+
+	REAL8 chi1L2L         = chi1L * chi2L;
+
+	REAL8 chi1L2          = pWF->chi1L * pWF->chi1L;
+	REAL8 chi1L3          = pWF->chi1L * chi1L2;
+
+	REAL8 chi2L2          = pWF->chi2L * pWF->chi2L;
+	REAL8 chi2L3          = pWF->chi2L * chi2L2;
+
+	REAL8 eta             = pWF->eta;
+	REAL8 eta2            = eta*eta;
+	REAL8 eta3            = eta*eta2;
+
+	REAL8 delta           = pWF->delta;
+
+	/* Pre-initialize all phenomenological coefficients */
+	pPhase->a0 = 0.0;
+	pPhase->a1 = 0.0;
+	pPhase->a2 = 0.0;
+	pPhase->a3 = 0.0;
+	pPhase->a4 = 0.0;
+
+	pPhase->b0 = 0.0;
+	pPhase->b1 = 0.0;
+	pPhase->b2 = 0.0;
+	pPhase->b3 = 0.0;
+	pPhase->b4 = 0.0;
+
+	pPhase->c0 = 0.0;
+	pPhase->c1 = 0.0;
+	pPhase->c2 = 0.0;
+	pPhase->c3 = 0.0;
+	pPhase->c4 = 0.0;
+	pPhase->cL = 0.0;
+
+	pPhase->sigma0 = 0.0;
+	pPhase->sigma1 = 0.0;
+	pPhase->sigma2 = 0.0;
+	pPhase->sigma3 = 0.0;
+	pPhase->sigma4 = 0.0;
+	pPhase->sigma5 = 0.0;
+	
+	/*
+		The general strategy is to initialize a linear system of equations:
+	
+		A.x = b
+
+		- A is a matrix with the coefficients of the ansatz evaluated at the collocation nodes. 
+		- b is a vector of the value of the collocation points
+		- x is the solution vector (i.e. the coefficients) that we must solve for. 
+
+		We choose to do this using a standard LU decomposition. 
+	*/
+
+	/* Generate list of collocation points */
+	/*
+	The Gauss-Chebyshev Points are given by:
+	GCPoints[n] = Table[Cos[i * pi/n] , {i, 0, n}]
+
+	SamplePoints[xmin,xmax,n] = {
+		pWF->delta = xmax - xmin;
+		gpoints = 0.5 * (1 + GCPoints[n-1]);
+
+		return {xmin + pWF->delta * gpoints}
+	}
+
+	gpoints4 = [1.0, 3.0/4, 1.0/4, 0.0];
+	gpoints5 = [1.0, 1.0/2 + 1.0/(2.0*sqrt(2.0)), 1.0/2, 1.0/2 - 1.0/(2*sqrt(2.0)), 0.]
+	
+	*/
+
+	/*
+	Ringdown phase collocation points:
+	Here we only use the first N+1 points in the array where N = the
+	number of pseudo PN terms.
+
+	The size of the array is controlled by: N_MAX_COLLOCATION_POINTS_PHASE_RD
+
+	Default is to use 5 collocation points.
+	*/
+	deltax = pPhase->fPhaseRDMax - pPhase->fPhaseRDMin;
+	xmin   = pPhase->fPhaseRDMin;
+	int i;
+
+	double phaseRD; // This is used in intermediate phase reconstruction.
+
+	if(debug)
+	{
+		printf("\n");
+		printf("Solving system of equations for RD phase...\n");
+	}
+
+	// Initialize collocation points
+	for(i = 0; i < 5; i++)
+	{
+		pPhase->CollocationPointsPhaseRD[i] = gpoints5[i] * deltax + xmin;
+	}
+	// Collocation point 4 is set to the ringdown frequency ~ dip in Lorentzian
+	pPhase->CollocationPointsPhaseRD[3] = pWF->fRING;
+
+	if(debug)
+	{
+		printf("Rigndown collocation points : \n");
+		printf("F1 : %.6f\n",pPhase->CollocationPointsPhaseRD[0]);
+		printf("F2 : %.6f\n",pPhase->CollocationPointsPhaseRD[1]);
+		printf("F3 : %.6f\n",pPhase->CollocationPointsPhaseRD[2]);
+		printf("F4 : %.6f\n",pPhase->CollocationPointsPhaseRD[3]);
+		printf("F5 : %.6f\n",pPhase->CollocationPointsPhaseRD[4]);
+	}
+
+	switch(pWF->IMRPhenomXRingdownPhaseVersion)
+	{
+		case 105:
+		{
+			pPhase->NCollocationPointsRD = 5;
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL, "Error: IMRPhenomXRingdownPhaseVersion is not valid.\n");
+		}
+	}
+
+	if(debug)
+	{
+		printf("NCollRD = %d\n",pPhase->NCollocationPointsRD);
+	}
+
+	// Eq. 7.13 in arXiv:2001.11412
+	double RDv4 = IMRPhenomX_Ringdown_Phase_22_v4(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownPhaseVersion);
+
+	/* These are the calibrated collocation points, as per Eq. 7.13 */
+	pPhase->CollocationValuesPhaseRD[0] = IMRPhenomX_Ringdown_Phase_22_d12(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownPhaseVersion);
+	pPhase->CollocationValuesPhaseRD[1] = IMRPhenomX_Ringdown_Phase_22_d24(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownPhaseVersion);
+	pPhase->CollocationValuesPhaseRD[2] = IMRPhenomX_Ringdown_Phase_22_d34( pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownPhaseVersion);
+	pPhase->CollocationValuesPhaseRD[3] = RDv4;
+	pPhase->CollocationValuesPhaseRD[4] = IMRPhenomX_Ringdown_Phase_22_d54(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXRingdownPhaseVersion);
+
+	/* v_j = d_{j4} + v4 */
+	pPhase->CollocationValuesPhaseRD[4] = pPhase->CollocationValuesPhaseRD[4] + pPhase->CollocationValuesPhaseRD[3]; // v5 = d54  + v4
+	pPhase->CollocationValuesPhaseRD[2] = pPhase->CollocationValuesPhaseRD[2] + pPhase->CollocationValuesPhaseRD[3]; // v3 = d34  + v4
+	pPhase->CollocationValuesPhaseRD[1] = pPhase->CollocationValuesPhaseRD[1] + pPhase->CollocationValuesPhaseRD[3]; // v2 = d24  + v4
+	pPhase->CollocationValuesPhaseRD[0] = pPhase->CollocationValuesPhaseRD[0] + pPhase->CollocationValuesPhaseRD[1]; // v1 = d12  + v2
+
+	// Debugging information. Leave for convenience later on.
+	if(debug)
+	{
+		printf("\n");
+		printf("Ringdown Collocation Points: \n");
+		printf("v1 : %.6f\n",pPhase->CollocationValuesPhaseRD[0]);
+		printf("v2 : %.6f\n",pPhase->CollocationValuesPhaseRD[1]);
+		printf("v3 : %.6f\n",pPhase->CollocationValuesPhaseRD[2]);
+		printf("v4 : %.6f\n",pPhase->CollocationValuesPhaseRD[3]);
+		printf("v5 : %.6f\n",pPhase->CollocationValuesPhaseRD[4]);
+		printf("\n");
+	}
+
+	phaseRD = pPhase->CollocationValuesPhaseRD[0];
+
+	p = gsl_permutation_alloc(pPhase->NCollocationPointsRD);
+	b = gsl_vector_alloc(pPhase->NCollocationPointsRD);
+	x = gsl_vector_alloc(pPhase->NCollocationPointsRD);
+	A = gsl_matrix_alloc(pPhase->NCollocationPointsRD,pPhase->NCollocationPointsRD);
+
+	/*
+	Populate the b vector
+	*/
+	gsl_vector_set(b,0,pPhase->CollocationValuesPhaseRD[0]);
+	gsl_vector_set(b,1,pPhase->CollocationValuesPhaseRD[1]);
+	gsl_vector_set(b,2,pPhase->CollocationValuesPhaseRD[2]);
+	gsl_vector_set(b,3,pPhase->CollocationValuesPhaseRD[3]);
+	gsl_vector_set(b,4,pPhase->CollocationValuesPhaseRD[4]);
+
+	/*
+			Eq. 7.12 in arXiv:2001.11412
+	
+			ansatzRD(f) = a_0 + a_1 f^(-1/3) + a_2 f^(-2) + a_3 f^(-3) + a_4 f^(-4) + ( aRD ) / ( (f_damp^2 + (f - f_ring)^2 ) )
+
+			Canonical ansatz sets a_3 to 0.
+	*/
+
+	/*
+		We now set up and solve a linear system of equations.
+		First we populate the matrix A_{ij}
+	*/
+
+	/* Note that ff0 is always 1 */
+	REAL8 ff, invff, ff0, ff1, ff2, ff3, ff4;
+
+	/* A_{0,i} */
+	ff    = pPhase->CollocationPointsPhaseRD[0];
+	invff = 1.0 / ff;
+	ff1   = cbrt(invff);   // f^{-1/3}
+	ff2   = invff * invff; // f^{-2}
+	ff3   = ff2 * ff2;		 // f^{-4}
+	ff4   = -(pWF->dphase0) / (pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+	gsl_matrix_set(A,0,0,1.0); // Constant
+	gsl_matrix_set(A,0,1,ff1); // f^(-1/3) term
+	gsl_matrix_set(A,0,2,ff2); // f^(-2) term
+	gsl_matrix_set(A,0,3,ff3); // f^(-4) term
+	gsl_matrix_set(A,0,4,ff4); // Lorentzian term
+
+	if(debug)
+	{
+		printf("For row 0: a0 + a1 %.6f + a2 %.6f + a4 %.6f + aRD %.6f\n",ff1,ff2,ff3,ff4);
+	}
+
+	/* A_{1,i} */
+	ff    = pPhase->CollocationPointsPhaseRD[1];
+	invff = 1.0 / ff;
+	ff1   = cbrt(invff);
+	ff2   = invff * invff;
+	ff3   = ff2 * ff2;
+	ff4   = -(pWF->dphase0) / (pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+	gsl_matrix_set(A,1,0,1.0);
+	gsl_matrix_set(A,1,1,ff1);
+	gsl_matrix_set(A,1,2,ff2);
+	gsl_matrix_set(A,1,3,ff3);
+	gsl_matrix_set(A,1,4,ff4);
+
+	/* A_{2,i} */
+	ff    =  pPhase->CollocationPointsPhaseRD[2];
+	invff = 1.0 / ff;
+	ff1   = cbrt(invff);
+	ff2   = invff * invff;
+	ff3   = ff2 * ff2;
+	ff4   = -(pWF->dphase0) / (pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+	gsl_matrix_set(A,2,0,1.0);
+	gsl_matrix_set(A,2,1,ff1);
+	gsl_matrix_set(A,2,2,ff2);
+	gsl_matrix_set(A,2,3,ff3);
+	gsl_matrix_set(A,2,4,ff4);
+
+	/* A_{3,i} */
+	ff    = pPhase->CollocationPointsPhaseRD[3];
+	invff = 1.0 / ff;
+	ff1   = cbrt(invff);
+	ff2   = invff * invff;
+	ff3   = ff2 * ff2;
+	ff4   = -(pWF->dphase0) / (pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+	gsl_matrix_set(A,3,0,1.0);
+	gsl_matrix_set(A,3,1,ff1);
+	gsl_matrix_set(A,3,2,ff2);
+	gsl_matrix_set(A,3,3,ff3);
+	gsl_matrix_set(A,3,4,ff4);
+
+	/* A_{4,i} */
+	ff    = pPhase->CollocationPointsPhaseRD[4];
+	invff = 1.0 / ff;
+	ff1   = cbrt(invff);
+	ff2   = invff * invff;
+	ff3   = ff2 * ff2;
+	ff4   = -(pWF->dphase0) / (pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+	gsl_matrix_set(A,4,0,1.0);
+	gsl_matrix_set(A,4,1,ff1);
+	gsl_matrix_set(A,4,2,ff2);
+	gsl_matrix_set(A,4,3,ff3);
+	gsl_matrix_set(A,4,4,ff4);
+
+	/* We now solve the system A x = b via an LU decomposition */
+	gsl_linalg_LU_decomp(A,p,&s);
+	gsl_linalg_LU_solve(A,p,b,x);
+
+	pPhase->c0  = gsl_vector_get(x,0); // x[0]; 	// a0
+	pPhase->c1  = gsl_vector_get(x,1); // x[1];		// a1
+	pPhase->c2  = gsl_vector_get(x,2); // x[2]; 	// a2
+	pPhase->c4  = gsl_vector_get(x,3); // x[3]; 	// a4
+	pPhase->cRD = gsl_vector_get(x,4);
+	pPhase->cL  = -(pWF->dphase0 * pPhase->cRD); // ~ x[4] // cL = - a_{RD} * dphase0
+
+	if(debug)
+	{
+		printf("\n");
+		printf("Ringdown Coefficients: \n");
+		printf("c0  : %.6f\n",pPhase->c0);
+		printf("c1  : %.6f\n",pPhase->c1);
+		printf("c2  : %.6f\n",pPhase->c2);
+		printf("c4  : %e\n",pPhase->c4);
+		printf("cRD : %.6f\n",gsl_vector_get(x,4));
+		printf("d0  : %.6f\n",pWF->dphase0);
+		printf("cL  : %e\n",pPhase->cL);
+		printf("\n");
+
+		printf("Freeing arrays...\n");
+	}
+
+	/* Tidy up in preparation for next GSL solve ... */
+	gsl_vector_free(b);
+	gsl_vector_free(x);
+	gsl_matrix_free(A);
+	gsl_permutation_free(p);
+
+	/*
+	Inspiral phase collocation points:
+	Here we only use the first N+1 points in the array where N = the
+	number of pseudo PN terms. E.g. for 4 pseudo-PN terms, we will
+	need 4 collocation points. An ansatz with n free coefficients
+	needs n pieces of information in order to constrain the ansatz.
+
+	The size of the array is controlled by: N_MAX_COLLOCATION_POINTS_PHASE_INS
+
+	Default is to use 4 pseudo-PN coefficients and hence 4 collocation points.
+	
+	GC points as per Eq. 7.4 and 7.5, where f_L = pPhase->fPhaseInsMin and f_H = pPhase->fPhaseInsMax
+	*/
+	deltax      = pPhase->fPhaseInsMax - pPhase->fPhaseInsMin;
+	xmin        = pPhase->fPhaseInsMin;
+
+	/*
+			Set number of pseudo-PN coefficients:
+				- If you add a new PN inspiral approximant, update with new version here.
+	*/
+	switch(pWF->IMRPhenomXInspiralPhaseVersion)
+	{
+		case 104:
+		{
+			pPhase->NPseudoPN = 4;
+			pPhase->NCollocationPointsPhaseIns = 4;
+			break;
+		}
+		case 105:
+		{
+			pPhase->NPseudoPN = 5;
+			pPhase->NCollocationPointsPhaseIns = 5;
+			break;
+		}
+		case 114:
+		{
+			pPhase->NPseudoPN = 4;
+			pPhase->NCollocationPointsPhaseIns = 4;
+			break;
+		}
+		case 115:
+		{
+			pPhase->NPseudoPN = 5;
+			pPhase->NCollocationPointsPhaseIns = 5;
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR_REAL8(XLAL_EINVAL, "Error: IMRPhenomXInspiralPhaseVersion is not valid.\n");
+		}
+	}
+
+	if(debug)
+	{
+		printf("\n");
+		printf("NPseudoPN : %d\n",pPhase->NPseudoPN);
+		printf("NColl : %d\n",pPhase->NCollocationPointsPhaseIns);
+		printf("\n");
+	}
+
+	p = gsl_permutation_alloc(pPhase->NCollocationPointsPhaseIns);
+	b = gsl_vector_alloc(pPhase->NCollocationPointsPhaseIns);
+	x = gsl_vector_alloc(pPhase->NCollocationPointsPhaseIns);
+	A = gsl_matrix_alloc(pPhase->NCollocationPointsPhaseIns,pPhase->NCollocationPointsPhaseIns);
+
+	/*
+	If we are using 4 pseudo-PN coefficients, call the routines below.
+	The inspiral phase version is still passed to the individual functions.
+	*/
+	if(pPhase->NPseudoPN == 4)
+	{
+		// By default all models implemented use the following GC points.
+		// If a new model is calibrated with different choice of collocation points, edit this.
+		for(i = 0; i < pPhase->NCollocationPointsPhaseIns; i++)
+		{
+			fi = gpoints4[i] * deltax + xmin;
+			pPhase->CollocationPointsPhaseIns[i] = fi;
+		}
+
+		// Calculate the value of the differences between the ith and 3rd collocation points at the GC nodes
+		pPhase->CollocationValuesPhaseIns[0] = IMRPhenomX_Inspiral_Phase_22_d13(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[1] = IMRPhenomX_Inspiral_Phase_22_d23(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[2] = IMRPhenomX_Inspiral_Phase_22_v3( pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[3] = IMRPhenomX_Inspiral_Phase_22_d43(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+
+		// Calculate the value of the collocation points at GC nodes via: v_i = d_i3 + v3
+		pPhase->CollocationValuesPhaseIns[0] = pPhase->CollocationValuesPhaseIns[0] + pPhase->CollocationValuesPhaseIns[2];
+		pPhase->CollocationValuesPhaseIns[1] = pPhase->CollocationValuesPhaseIns[1] + pPhase->CollocationValuesPhaseIns[2];
+		pPhase->CollocationValuesPhaseIns[3] = pPhase->CollocationValuesPhaseIns[3] + pPhase->CollocationValuesPhaseIns[2];
+
+		if(debug)
+		{
+			printf("\n");
+			printf("Inspiral Collocation Points and Values:\n");
+			printf("F1 : %.6f\n",pPhase->CollocationPointsPhaseIns[0]);
+			printf("F2 : %.6f\n",pPhase->CollocationPointsPhaseIns[1]);
+			printf("F3 : %.6f\n",pPhase->CollocationPointsPhaseIns[2]);
+			printf("F4 : %.6f\n",pPhase->CollocationPointsPhaseIns[3]);
+			printf("\n");
+			printf("V1 : %.6f\n",pPhase->CollocationValuesPhaseIns[0]);
+			printf("V2 : %.6f\n",pPhase->CollocationValuesPhaseIns[1]);
+			printf("V3 : %.6f\n",pPhase->CollocationValuesPhaseIns[2]);
+			printf("V4 : %.6f\n",pPhase->CollocationValuesPhaseIns[3]);
+			printf("\n");
+		}
+
+		gsl_vector_set(b,0,pPhase->CollocationValuesPhaseIns[0]);
+		gsl_vector_set(b,1,pPhase->CollocationValuesPhaseIns[1]);
+		gsl_vector_set(b,2,pPhase->CollocationValuesPhaseIns[2]);
+		gsl_vector_set(b,3,pPhase->CollocationValuesPhaseIns[3]);
+
+		/* A_{0,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[0];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff0 = 1.0;
+		gsl_matrix_set(A,0,0,1.0);
+		gsl_matrix_set(A,0,1,ff1);
+		gsl_matrix_set(A,0,2,ff2);
+		gsl_matrix_set(A,0,3,ff3);
+
+		/* A_{1,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[1];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff0 = 1.0;
+		gsl_matrix_set(A,1,0,1.0);
+		gsl_matrix_set(A,1,1,ff1);
+		gsl_matrix_set(A,1,2,ff2);
+		gsl_matrix_set(A,1,3,ff3);
+
+		/* A_{2,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[2];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff0 = 1.0;
+		gsl_matrix_set(A,2,0,1.0);
+		gsl_matrix_set(A,2,1,ff1);
+		gsl_matrix_set(A,2,2,ff2);
+		gsl_matrix_set(A,2,3,ff3);
+
+		/* A_{3,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[3];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff0 = 1.0;
+		gsl_matrix_set(A,3,0,1.0);
+		gsl_matrix_set(A,3,1,ff1);
+		gsl_matrix_set(A,3,2,ff2);
+		gsl_matrix_set(A,3,3,ff3);
+
+		/* We now solve the system A x = b via an LU decomposition */
+		gsl_linalg_LU_decomp(A,p,&s);
+		gsl_linalg_LU_solve(A,p,b,x);
+
+		/* Set inspiral phenomenological coefficients from solution to A x = b */
+		pPhase->a0 = gsl_vector_get(x,0); // x[0]; // alpha_0
+		pPhase->a1 = gsl_vector_get(x,1); // x[1]; // alpha_1
+		pPhase->a2 = gsl_vector_get(x,2); // x[2]; // alpha_2
+		pPhase->a3 = gsl_vector_get(x,3); // x[3]; // alpha_3
+		pPhase->a4 = 0.0;
+
+		/*
+				PSEUDO PN TERMS WORK:
+					- 104 works.
+					- 105 not tested.
+					- 114 not tested.
+					- 115 not tested.
+		*/
+		if(debug)
+		{
+			printf("\n");
+			printf("3pPN\n");
+			printf("Inspiral Pseudo-PN Coefficients:\n");
+			printf("a0 : %.6f\n",pPhase->a0);
+			printf("a1 : %.6f\n",pPhase->a1);
+			printf("a2 : %.6f\n",pPhase->a2);
+			printf("a3 : %.6f\n",pPhase->a3);
+			printf("a4 : %.6f\n",pPhase->a4);
+			printf("\n");
+		}
+
+		/* Tidy up in preparation for next GSL solve ... */
+		gsl_vector_free(b);
+		gsl_vector_free(x);
+		gsl_matrix_free(A);
+		gsl_permutation_free(p);
+
+	}
+	else if(pPhase->NPseudoPN == 5)
+	{
+		// Using 5 pseudo-PN coefficients so set 5 collocation points
+		for(i = 0; i < 5; i++)
+		{
+			fi = gpoints5[i] * deltax + xmin;
+			pPhase->CollocationPointsPhaseIns[i] = fi;
+		}
+		pPhase->CollocationValuesPhaseIns[0] = IMRPhenomX_Inspiral_Phase_22_d13(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[1] = IMRPhenomX_Inspiral_Phase_22_d23(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[2] = IMRPhenomX_Inspiral_Phase_22_v3( pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[3] = IMRPhenomX_Inspiral_Phase_22_d43(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+		pPhase->CollocationValuesPhaseIns[4] = IMRPhenomX_Inspiral_Phase_22_d53(pWF->eta,pWF->chiPNHat,pWF->dchi,pWF->delta,pWF->IMRPhenomXInspiralPhaseVersion);
+
+		/* v_j = d_j3 + v_3 */
+		pPhase->CollocationValuesPhaseIns[0] = pPhase->CollocationValuesPhaseIns[0] + pPhase->CollocationValuesPhaseIns[2];
+		pPhase->CollocationValuesPhaseIns[1] = pPhase->CollocationValuesPhaseIns[1] + pPhase->CollocationValuesPhaseIns[2];
+		pPhase->CollocationValuesPhaseIns[3] = pPhase->CollocationValuesPhaseIns[3] + pPhase->CollocationValuesPhaseIns[2];
+		pPhase->CollocationValuesPhaseIns[4] = pPhase->CollocationValuesPhaseIns[4] + pPhase->CollocationValuesPhaseIns[2];
+
+		if(debug)
+		{
+			printf("\n");
+			printf("Inspiral Collocation Points and Values:\n");
+			printf("F1 : %.6f\n",pPhase->CollocationPointsPhaseIns[0]);
+			printf("F2 : %.6f\n",pPhase->CollocationPointsPhaseIns[1]);
+			printf("F3 : %.6f\n",pPhase->CollocationPointsPhaseIns[2]);
+			printf("F4 : %.6f\n",pPhase->CollocationPointsPhaseIns[3]);
+			printf("F5 : %.6f\n",pPhase->CollocationPointsPhaseIns[4]);
+			printf("\n");
+			printf("V1 : %.6f\n",pPhase->CollocationValuesPhaseIns[0]);
+			printf("V2 : %.6f\n",pPhase->CollocationValuesPhaseIns[1]);
+			printf("V3 : %.6f\n",pPhase->CollocationValuesPhaseIns[2]);
+			printf("V4 : %.6f\n",pPhase->CollocationValuesPhaseIns[3]);
+			printf("V5 : %.6f\n",pPhase->CollocationValuesPhaseIns[4]);
+			printf("\n");
+		}
+
+		gsl_vector_set(b,0,pPhase->CollocationValuesPhaseIns[0]);
+		gsl_vector_set(b,1,pPhase->CollocationValuesPhaseIns[1]);
+		gsl_vector_set(b,2,pPhase->CollocationValuesPhaseIns[2]);
+		gsl_vector_set(b,3,pPhase->CollocationValuesPhaseIns[3]);
+		gsl_vector_set(b,4,pPhase->CollocationValuesPhaseIns[4]);
+
+		/* A_{0,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[0];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff4 = ff * ff1;
+		gsl_matrix_set(A,0,0,1.0);
+		gsl_matrix_set(A,0,1,ff1);
+		gsl_matrix_set(A,0,2,ff2);
+		gsl_matrix_set(A,0,3,ff3);
+		gsl_matrix_set(A,0,4,ff4);
+
+		/* A_{1,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[1];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff4 = ff * ff1;
+		gsl_matrix_set(A,1,0,1.0);
+		gsl_matrix_set(A,1,1,ff1);
+		gsl_matrix_set(A,1,2,ff2);
+		gsl_matrix_set(A,1,3,ff3);
+		gsl_matrix_set(A,1,4,ff4);
+
+		/* A_{2,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[2];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff4 = ff * ff1;
+		gsl_matrix_set(A,2,0,1.0);
+		gsl_matrix_set(A,2,1,ff1);
+		gsl_matrix_set(A,2,2,ff2);
+		gsl_matrix_set(A,2,3,ff3);
+		gsl_matrix_set(A,2,4,ff4);
+
+		/* A_{3,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[3];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff4 = ff * ff1;
+		gsl_matrix_set(A,3,0,1.0);
+		gsl_matrix_set(A,3,1,ff1);
+		gsl_matrix_set(A,3,2,ff2);
+		gsl_matrix_set(A,3,3,ff3);
+		gsl_matrix_set(A,3,4,ff4);
+
+		/* A_{4,i} */
+		ff  = pPhase->CollocationPointsPhaseIns[4];
+		ff1 = cbrt(ff);
+		ff2 = ff1 * ff1;
+		ff3 = ff;
+		ff4 = ff * ff1;
+		gsl_matrix_set(A,4,0,1.0);
+		gsl_matrix_set(A,4,1,ff1);
+		gsl_matrix_set(A,4,2,ff2);
+		gsl_matrix_set(A,4,3,ff3);
+		gsl_matrix_set(A,4,4,ff4);
+
+		/* We now solve the system A x = b via an LU decomposition */
+		gsl_linalg_LU_decomp(A,p,&s);
+		gsl_linalg_LU_solve(A,p,b,x);
+
+		/* Set inspiral phenomenological coefficients from solution to A x = b */
+		pPhase->a0 = gsl_vector_get(x,0); // x[0];
+		pPhase->a1 = gsl_vector_get(x,1); // x[1];
+		pPhase->a2 = gsl_vector_get(x,2); // x[2];
+		pPhase->a3 = gsl_vector_get(x,3); // x[3];
+		pPhase->a4 = gsl_vector_get(x,4); // x[4];
+
+		if(debug)
+		{
+			printf("\n");
+			printf("4pPN\n");
+			printf("Inspiral Pseudo-PN Coefficients:\n");
+			printf("a0 : %.6f\n",pPhase->a0);
+			printf("a1 : %.6f\n",pPhase->a1);
+			printf("a2 : %.6f\n",pPhase->a2);
+			printf("a3 : %.6f\n",pPhase->a3);
+			printf("a4 : %.6f\n",pPhase->a4);
+			printf("\n");
+		}
+
+		/* Tidy up in preparation for next GSL solve ... */
+		gsl_vector_free(b);
+		gsl_vector_free(x);
+		gsl_matrix_free(A);
+		gsl_permutation_free(p);
+	}
+	else
+	{
+		XLALPrintError("Error in ComputeIMRPhenomXWaveformVariables: NPseudoPN requested is not valid.\n");
+	}
+
+	/* The pseudo-PN coefficients are normalized such that: (dphase0 / eta) * f^{8/3} * a_j */
+	/* So we must re-scale these terms by an extra factor of f^{-8/3} in the PN phasing */
+	pPhase->sigma1 = (-5.0/3.0) * pPhase->a0;
+	pPhase->sigma2 = (-5.0/4.0) * pPhase->a1;
+	pPhase->sigma3 = (-5.0/5.0) * pPhase->a2;
+	pPhase->sigma4 = (-5.0/6.0) * pPhase->a3;
+	pPhase->sigma5 = (-5.0/7.0) * pPhase->a4;
+
+	/* Initialize TaylorF2 PN coefficients  */
+	pPhase->dphi0  = 0.0;
+	pPhase->dphi1  = 0.0;
+	pPhase->dphi2  = 0.0;
+	pPhase->dphi3  = 0.0;
+	pPhase->dphi4  = 0.0;
+	pPhase->dphi5  = 0.0;
+	pPhase->dphi6  = 0.0;
+	pPhase->dphi7  = 0.0;
+	pPhase->dphi8  = 0.0;
+	pPhase->dphi9  = 0.0;
+	pPhase->dphi10 = 0.0;
+	pPhase->dphi11 = 0.0;
+	pPhase->dphi12 = 0.0;
+
+	pPhase->dphi5L = 0.0;
+	pPhase->dphi6L = 0.0;
+	pPhase->dphi8L = 0.0;
+	pPhase->dphi9L = 0.0;
+
+	pPhase->phi0   = 0.0;
+	pPhase->phi1   = 0.0;
+	pPhase->phi2   = 0.0;
+	pPhase->phi3   = 0.0;
+	pPhase->phi4   = 0.0;
+	pPhase->phi5   = 0.0;
+	pPhase->phi6   = 0.0;
+	pPhase->phi7   = 0.0;
+	pPhase->phi8   = 0.0;
+	pPhase->phi9   = 0.0;
+	pPhase->phi10  = 0.0;
+	pPhase->phi11  = 0.0;
+	pPhase->phi12  = 0.0;
+
+	pPhase->phi5L  = 0.0;
+	pPhase->phi6L  = 0.0;
+	pPhase->phi8L  = 0.0;
+	pPhase->phi9L  = 0.0;
+
+	/* **** TaylorF2 PN Coefficients: Phase **** */
+
+	/*
+			- These are the PN coefficients normalised by: 3 / (128 * eta * [pi M f]^{5/3} ).
+			- We add in powers of (M f)^{N/3} later but add powers of pi^{N/3} here
+			- The log terms are *always* in terms of log(v), so we multiply by log(v) when summing PN phasing series.
+			- We *do not* overwrite the PN phasing series with pseudo-PN terms. These are added separately.
+	
+			PN terms can be found in:
+				- Marsat et al, CQG, 32, 085008, (2015)
+				- Bohe et al, CQG, 32, 195010, (2015)
+				- Bernard et al, PRD, 95, 044026, (2017)
+				- Bernard et al, PRD, 93, 084037, (2016)
+				- Damour et al, PRD, 89, 064058, (2014)
+				- Damour et al, PRD, 95, 084005, (2017)
+				- Bernard et al, PRD, 96, 104043, (2017)
+				- Marchand et al, PRD, 97, 044023, (2018)
+				- Marchand et al, CQG, 33, 244003, (2016)
+				- Nagar et al, PRD, 99, 044007, (2019)
+				- Messina et al, PRD, 97, 084016, (2018)	
+	*/
+
+	/* Analytically known PN coefficients */
+	/* Newtonian */
+	pPhase->phi0   = 1.0 ;
+
+	/* 0.5 PN */
+	pPhase->phi1   = 0.0;
+
+	/* 1.0 PN, Non-Spinning */
+	pPhase->phi2   = (3715/756. + (55*eta)/9.) * powers_of_lalpi.two_thirds;
+
+	/* 1.5 PN, Non-Spinning */
+	pPhase->phi3   = - 16.0 * powers_of_lalpi.two;
+
+	/* 1.5 PN, Spin-Orbit */
+	pPhase->phi3 += ( (113*(chi1L + chi2L + chi1L*delta - chi2L*delta) - 76*(chi1L + chi2L)*eta)/6. ) * powers_of_lalpi.itself;
+
+	/* 2.0 PN, Non-Spinning */
+	pPhase->phi4  = ( 15293365/508032. + (27145*eta)/504. + (3085*eta2)/72. ) * powers_of_lalpi.four_thirds ;
+
+	/* 2.0 PN, Spin-Spin */
+	pPhase->phi4 +=  ( (-5*(81*chi1L2*(1 + delta - 2*eta) + 316*chi1L2L*eta - 81*chi2L2*(-1 + delta + 2*eta)))/16. ) * powers_of_lalpi.four_thirds;
+
+	/* 2.5PN, Non-Spinning */
+	pPhase->phi5L  = ( (5*(46374 - 6552*eta)*LAL_PI)/4536. ) * powers_of_lalpi.five_thirds;
+
+	/* 2.5PN, Spin-Orbit */
+	pPhase->phi5L += ( (-732985*(chi1L + chi2L + chi1L*delta - chi2L*delta) - 560*(-1213*(chi1L + chi2L) + 63*(chi1L - chi2L)*delta)*eta +
+     85680*(chi1L + chi2L)*eta2)/4536. ) * powers_of_lalpi.five_thirds;
+
+	pPhase->phi5   = 0.0;
+
+	/* 3.0 PN, Non-Spinning */
+	pPhase->phi6   = ( 11583231236531/4.69421568e9 - (5*eta*(3147553127 + 588*eta*(-45633 + 102260*eta)))/3.048192e6 - (6848*LAL_GAMMA)/21. -
+   (640*powers_of_lalpi.two)/3. + (2255*eta*powers_of_lalpi.two)/12. - (13696*log(2))/21. - (6848*powers_of_lalpi.log)/63. )  * powers_of_lalpi.two;
+
+	/* 3.0 PN, Spin-Orbit */
+	pPhase->phi6  += ( (5*(227*(chi1L + chi2L + chi1L*delta - chi2L*delta) - 156*(chi1L + chi2L)*eta)*LAL_PI)/3. ) * powers_of_lalpi.two;
+
+	/* 3.0 PN, Spin-Spin  */
+	pPhase->phi6  += ( (5*(20*chi1L2L*eta*(11763 + 12488*eta) + 7*chi2L2*(-15103*(-1 + delta) + 2*(-21683 + 6580*delta)*eta - 9808*eta2) -
+       7*chi1L2*(-15103*(1 + delta) + 2*(21683 + 6580*delta)*eta + 9808*eta2)))/4032. ) * powers_of_lalpi.two;
+
+	/* 3.0 PN, Log Term */
+	pPhase->phi6L  = (-6848/63.) * powers_of_lalpi.two;
+
+	/* 3.5PN, Non-Spinning */
+	pPhase->phi7   = ( (5*(15419335 + 168*(75703 - 29618*eta)*eta)*LAL_PI)/254016. ) * powers_of_lalpi.seven_thirds;
+
+	/* 3.5PN, Spin-Orbit */
+	pPhase->phi7  += ( (5*(-5030016755*(chi1L + chi2L + chi1L*delta - chi2L*delta) + 4*(2113331119*(chi1L + chi2L) + 675484362*(chi1L - chi2L)*delta)*eta -
+       1008*(208433*(chi1L + chi2L) + 25011*(chi1L - chi2L)*delta)*eta2 + 90514368*(chi1L + chi2L)*eta3))/6.096384e6 ) * powers_of_lalpi.seven_thirds;
+
+	/* 3.5PN, Spin-Spin */
+	pPhase->phi7  += ( -5*(57*chi1L2*(1 + delta - 2*eta) + 220*chi1L2L*eta - 57*chi2L2*(-1 + delta + 2*eta))*LAL_PI ) * powers_of_lalpi.seven_thirds;
+
+	/* 3.5PN, Cubic-in-Spin */
+	pPhase->phi7  += ( (14585*(-(chi2L3*(-1 + delta)) + chi1L3*(1 + delta)) -
+     5*(chi2L3*(8819 - 2985*delta) + 8439*chi1L*chi2L2*(-1 + delta) - 8439*chi1L2*chi2L*(1 + delta) + chi1L3*(8819 + 2985*delta))*
+      eta + 40*(chi1L + chi2L)*(17*chi1L2 - 14*chi1L2L + 17*chi2L2)*eta2)/48. ) * powers_of_lalpi.seven_thirds;
+
+	/* 4.0PN, Non-Spinning */
+	pPhase->phi8   = 0.0;
+
+	/* 4.0PN, Spin-Orbit */
+	pPhase->phi8   = ( (-5*(1263141*(chi1L + chi2L + chi1L*delta - chi2L*delta) - 2*(794075*(chi1L + chi2L) + 178533*(chi1L - chi2L)*delta)*eta +
+       94344*(chi1L + chi2L)*eta2)*LAL_PI*(-1 + powers_of_lalpi.log))/9072. ) * powers_of_lalpi.eight_thirds;
+
+	/* 4.0PN Log Terms */
+	pPhase->phi8L  = ((-5*(1263141*(chi1L + chi2L + chi1L*delta - chi2L*delta) - 2*(794075*(chi1L + chi2L) + 178533*(chi1L - chi2L)*delta)*eta +
+       94344*(chi1L + chi2L)*eta2)*LAL_PI)/9072.) * powers_of_lalpi.eight_thirds ;
+
+	if(debug)
+	{
+		printf("TaylorF2 PN Coefficients: \n");
+		printf("phi0 : %.6f\n",pPhase->phi0);
+		printf("phi1 : %.6f\n",pPhase->phi1);
+		printf("phi2 : %.6f\n",pPhase->phi2);
+		printf("phi3 : %.6f\n",pPhase->phi3);
+		printf("phi4 : %.6f\n",pPhase->phi4);
+		printf("phi5 : %.6f\n",pPhase->phi5);
+		printf("phi6 : %.6f\n",pPhase->phi6);
+		printf("phi7 : %.6f\n",pPhase->phi7);
+		printf("phi8 : %.6f\n",pPhase->phi8);
+
+		printf("phi5L : %.6f\n",pPhase->phi5L);
+		printf("phi6L : %.6f\n",pPhase->phi6L);
+		printf("phi8L : %.6f\n",pPhase->phi8L);
+	}
+
+	/* This version of TaylorF2 contains an additional 4.5PN tail term and a LO-SS tail term at 3.5PN */
+	if(pWF->IMRPhenomXInspiralPhaseVersion == 114 || pWF->IMRPhenomXInspiralPhaseVersion == 115)
+	{
+		/* 3.5PN, Leading Order Spin-Spin Tail Term */
+		pPhase->phi7  += ( (5*(65*chi1L2*(1 + delta - 2*eta) + 252*chi1L2L*eta - 65*chi2L2*(-1 + delta + 2*eta))*LAL_PI)/4. ) * powers_of_lalpi.seven_thirds;
+
+		/* 4.5PN, Tail Term */
+		pPhase->phi9  += ( (5*(-256 + 451*eta)*powers_of_lalpi.three)/6. + (LAL_PI*(105344279473163 + 700*eta*(-298583452147 + 96*eta*(99645337 + 14453257*eta)) -
+        12246091038720*LAL_GAMMA - 24492182077440*log(2.0)))/1.877686272e10 - (13696*LAL_PI*powers_of_lalpi.log)/63. ) * powers_of_lalpi.three;
+
+		/* 4.5PN, Log Term */
+		pPhase->phi9L  = (  (-13696*LAL_PI)/63.0  ) * powers_of_lalpi.three;
+	}
+
+	/* Calibrated pseudo-PN coefficients: Note that these implicitly contain powers_of_lalpi in the calibration */
+	//pPhase->phi8  += pPhase->sigma1;     /* 4.5 PN */
+	//pPhase->phi9  += pPhase->sigma2;     /* 5.0 PN */
+	//pPhase->phi10 += pPhase->sigma3;     /* 5.5 PN */
+	//pPhase->phi11 += pPhase->sigma4;     /* 6.0 PN */
+	//pPhase->phi12 += pPhase->sigma5;     /* 6.5 PN */
+
+	if(debug)
+	{
+		printf("phi8P  : %.6f\n",pPhase->sigma1);
+		printf("phi9P  : %.6f\n",pPhase->sigma2);
+		printf("phi10P : %.6f\n",pPhase->sigma3);
+		printf("phi11P : %.6f\n",pPhase->sigma4);
+		printf("phi12P : %.6f\n",pPhase->sigma5);
+	}
+
+	pPhase->phi_initial = - LAL_PI_4;
+
+	/* **** TaylorF2 PN Coefficients: Normalized Phase Derivative **** */
+	pPhase->dphi0  = 1.0;
+	pPhase->dphi1  = 0.0;
+	pPhase->dphi2  = ( 743/252. + (11*eta)/3. )*powers_of_lalpi.two_thirds;
+	pPhase->dphi3  = ( (chi2L*(113 - 113*delta - 76*eta) + chi1L*(113*(1 + delta) - 76*eta) - 96*LAL_PI)/15. ) * powers_of_lalpi.itself;
+	pPhase->dphi4  = (  3058673/508032. - (81*chi1L2*(1 + delta))/16. - (79*chi1L2L*eta)/4. +
+   (81*chi2L2*(-1 + delta + 2*eta))/16. + (eta*(5429 + 5103*chi1L2 + 4319*eta))/504.  ) * powers_of_lalpi.four_thirds;
+	pPhase->dphi5  = ( (-146597*chi2L*delta + 146597*(chi1L + chi2L + chi1L*delta) +
+     112*(chi1L*(-1213 + 63*delta) - chi2L*(1213 + 63*delta))*eta -
+     17136*(chi1L + chi2L)*eta2 + 6*(-7729 + 1092*eta)*LAL_PI)/1512. ) * powers_of_lalpi.five_thirds;
+	pPhase->dphi6  = ( (-10052469856691 + 24236159077900*eta)/2.34710784e10 + (6848*LAL_GAMMA)/105. +
+   (-951489*chi1L2*(1 + delta) - 180*chi1L2L*eta*(11763 + 12488*eta) +
+      63*chi2L2*(15103*(-1 + delta) + 2*(21683 - 6580*delta)*eta + 9808*eta2) +
+      7*eta*(18*chi1L2*(21683 + 6580*delta + 4904*eta) + eta*(-45633 + 102260*eta)) -
+      12096*(chi2L*(227 - 227*delta - 156*eta) + chi1L*(227*(1 + delta) - 156*eta))*LAL_PI -
+      3024*(-512 + 451*eta)*powers_of_lalpi.two)/36288. + (13696*log(2))/105. + (6848*powers_of_lalpi.log)/315.0   ) * powers_of_lalpi.two;
+
+	// Log[f] term
+	pPhase->dphi6L = (  6848 / 315. ) * powers_of_lalpi.two;
+
+	pPhase->dphi7  = (-(chi1L2*chi2L*eta*(2813*(1 + delta) + 8*eta))/8. +
+   (chi1L3*(-2917*(1 + delta) + (8819 + 2985*delta)*eta - 136*eta2))/24. +
+   (chi2L*(-5030016755*(-1 + delta) + 4*(-2113331119 + 675484362*delta)*eta +
+        1008*(208433 - 25011*delta)*eta2 - 90514368*eta3))/3.048192e6 -
+   (chi2L3*(2917 + eta*(-8819 + 136*eta) + delta*(-2917 + 2985*eta)))/24. +
+   (chi1L*(5030016755 - 8453324476*eta +
+        1008*eta*((208433 - 89796*eta)*eta - 378*chi2L2*(2813 + 8*eta)) +
+        delta*(5030016755 + 504*eta*(-5360987 + 2126628*chi2L2 + 50022*eta))))/3.048192e6 +
+   (-15419335/127008. + 114*chi1L2*(1 + delta - 2*eta) - (75703*eta)/756. +
+      440*chi1L2L*eta + (14809*eta2)/378. - 114*chi2L2*(-1 + delta + 2*eta))*LAL_PI ) * powers_of_lalpi.seven_thirds;
+
+	pPhase->dphi8  = ( ((chi1L*(1263141 - 1588150*eta + 94344*eta2 - 9*delta*(-140349 + 39674*eta)) +
+       chi2L*(1263141 - 1588150*eta + 94344*eta2 + 9*delta*(-140349 + 39674*eta)))*LAL_PI)/3024. ) * powers_of_lalpi.eight_thirds * powers_of_lalpi.log;
+
+	// Log[f] term
+	pPhase->dphi8L  = ( ((chi1L*(1263141 - 1588150*eta + 94344*eta2 - 9*delta*(-140349 + 39674*eta)) +
+       chi2L*(1263141 - 1588150*eta + 94344*eta2 + 9*delta*(-140349 + 39674*eta)))*LAL_PI)/3024. ) * powers_of_lalpi.eight_thirds;
+
+	if(pWF->IMRPhenomXInspiralPhaseVersion == 114 || pWF->IMRPhenomXInspiralPhaseVersion == 115)
+	{
+		/* This version of TaylorF2 contains an additional 4.5PN tail term and a LO-SS tail term at 3.5PN */
+		pPhase->dphi7 += ( ((-65*chi1L2*(1 + delta - 2*eta) - 252*chi1L2L*eta + 65*chi2L2*(-1 + delta + 2*eta))*
+     LAL_PI)/2. ) * powers_of_lalpi.seven_thirds;
+
+		pPhase->dphi9 += ( (512/3. - (902*eta)/3.)*powers_of_lalpi.three + LAL_PI *
+    (-102282756713483/2.34710784e10 + (298583452147*eta)/3.3530112e7 - (9058667*eta2)/31752. -
+      (2064751*eta3)/49896. + (54784*LAL_GAMMA)/105. + (109568*log(2))/105. +
+      (54784*log(LAL_PI))/315.) ) * powers_of_lalpi.three;
+
+		pPhase->dphi9L = ( (54784*LAL_PI)/315. ) * powers_of_lalpi.three;
+	}
+
+	if(debug)
+	{
+		printf("\nTaylorF2 PN Derivative Coefficients\n");
+		printf("dphi0  : %.6f\n",pPhase->dphi0);
+		printf("dphi1  : %.6f\n",pPhase->dphi1);
+		printf("dphi2  : %.6f\n",pPhase->dphi2);
+		printf("dphi3  : %.6f\n",pPhase->dphi3);
+		printf("dphi4  : %.6f\n",pPhase->dphi4);
+		printf("dphi5  : %.6f\n",pPhase->dphi5);
+		printf("dphi6  : %.6f\n",pPhase->dphi6);
+		printf("dphi7  : %.6f\n",pPhase->dphi7);
+		printf("dphi8  : %.6f\n",pPhase->dphi8);
+		printf("dphi9  : %.6f\n",pPhase->dphi9);
+		printf("\n");
+		printf("dphi6L : %.6f\n",pPhase->dphi6L);
+		printf("dphi8L : %.6f\n",pPhase->dphi8L);
+		printf("dphi9L : %.6f\n",pPhase->dphi9L);
+	}
+
+	/*
+			Calculate phase at fmatchIN. This will be used as the collocation point for the intermediate fit.
+			In practice, the transition point is just below the MECO frequency.
+	*/
+	if(debug)
+	{
+		printf("\nTransition frequency for ins to int : %.6f\n",pPhase->fPhaseMatchIN);
+	}
+
+	IMRPhenomX_UsefulPowers powers_of_fmatchIN;
+	IMRPhenomX_Initialize_Powers(&powers_of_fmatchIN,pPhase->fPhaseMatchIN);
+
+	double phaseIN;
+	phaseIN  = pPhase->dphi0; 																														// f^{0/3}
+	phaseIN += pPhase->dphi1 	* powers_of_fmatchIN.one_third; 														// f^{1/3}
+	phaseIN += pPhase->dphi2 	* powers_of_fmatchIN.two_thirds; 														// f^{2/3}
+	phaseIN += pPhase->dphi3 	* powers_of_fmatchIN.itself; 																// f^{3/3}
+	phaseIN += pPhase->dphi4 	* powers_of_fmatchIN.four_thirds; 													// f^{4/3}
+	phaseIN += pPhase->dphi5 	* powers_of_fmatchIN.five_thirds; 													// f^{5/3}
+	phaseIN += pPhase->dphi6  * powers_of_fmatchIN.two;																		// f^{6/3}
+	phaseIN += pPhase->dphi6L * powers_of_fmatchIN.two * powers_of_fmatchIN.log;					// f^{6/3}, Log[f]
+	phaseIN += pPhase->dphi7  * powers_of_fmatchIN.seven_thirds;													// f^{7/3}
+	phaseIN += pPhase->dphi8  * powers_of_fmatchIN.eight_thirds;													// f^{8/3}
+	phaseIN += pPhase->dphi8L * powers_of_fmatchIN.eight_thirds * powers_of_fmatchIN.log;	// f^{8/3}
+	phaseIN += pPhase->dphi9  * powers_of_fmatchIN.three;																	// f^{9/3}
+	phaseIN += pPhase->dphi9L * powers_of_fmatchIN.three * powers_of_fmatchIN.log;				// f^{9/3}
+
+	// Add pseudo-PN Coefficient
+	phaseIN += ( 		pPhase->a0 * powers_of_fmatchIN.eight_thirds
+								+ pPhase->a1 * powers_of_fmatchIN.three
+								+ pPhase->a2 * powers_of_fmatchIN.eight_thirds * powers_of_fmatchIN.two_thirds
+								+ pPhase->a3 * powers_of_fmatchIN.eight_thirds * powers_of_fmatchIN.itself
+								+ pPhase->a4 * powers_of_fmatchIN.eight_thirds * powers_of_fmatchIN.four_thirds
+							);
+
+	phaseIN  = phaseIN * powers_of_fmatchIN.m_eight_thirds * pWF->dphase0;
+
+	/*
+	Intermediate phase collocation points:
+	Here we only use the first N points in the array where N = the
+	number of intermediate collocation points.
+
+	The size of the array is controlled by: N_MAX_COLLOCATION_POINTS_PHASE_INT
+
+	Default is to use 5 collocation points.
+	
+	See. Eq. 7.7 and 7.8 where f_H = pPhase->fPhaseMatchIM and f_L = pPhase->fPhaseMatchIN
+	*/
+	deltax      = pPhase->fPhaseMatchIM - pPhase->fPhaseMatchIN;
+	xmin        = pPhase->fPhaseMatchIN;
+
+	switch(pWF->IMRPhenomXIntermediatePhaseVersion)
+	{
+		case 104:
+		{
+			// Fourth order polynomial ansatz
+			pPhase->NCollocationPointsInt = 4;
+			break;
+		}
+		case 105:
+		{
+			// Fifth order polynomial ansatz
+			pPhase->NCollocationPointsInt = 5;
+			break;
+		}
+		default:
+		{
+			XLAL_ERROR(XLAL_EINVAL, "Error: IMRPhenomXIntermediatePhaseVersion is not valid.\n");
+		}
+	}
+
+	if(debug)
+	{
+	printf("\nNColPointsInt : %d\n",pPhase->NCollocationPointsInt);
+	}
+
+	p = gsl_permutation_alloc(pPhase->NCollocationPointsInt);
+	b = gsl_vector_alloc(pPhase->NCollocationPointsInt);
+	x = gsl_vector_alloc(pPhase->NCollocationPointsInt);
+	A = gsl_matrix_alloc(pPhase->NCollocationPointsInt,pPhase->NCollocationPointsInt);
+
+	// Canonical intermediate model using 4 collocation points
+	if(pWF->IMRPhenomXIntermediatePhaseVersion == 104)
+	{
+		// Using 4 collocation points in intermediate region
+		for(i = 0; i < 4; i++)
+		{
+			fi = gpoints4[i] * deltax + xmin;
+
+			pPhase->CollocationPointsPhaseInt[i] = fi;
+		}
+
+		// v2IM - v4RD. Using v4RD helps condition the fits with v4RD being very a robust fit.
+		double v2IMmRDv4 = IMRPhenomX_Intermediate_Phase_22_v2mRDv4(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		// v3IM - v4RD. Using v4RD helps condition the fits with v4RD being very a robust fit.
+		double v3IMmRDv4 = IMRPhenomX_Intermediate_Phase_22_v3mRDv4(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		// Direct fit to the collocation point at F2. We will take a weighted average of the direct and conditioned fit.
+		double v2IM      = IMRPhenomX_Intermediate_Phase_22_v2(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		/* Evaluate collocation points */
+		pPhase->CollocationValuesPhaseInt[0] = phaseIN;
+
+		// Take a weighted average for these points? Can help condition the fit.
+		pPhase->CollocationValuesPhaseInt[1] = 0.75*(v2IMmRDv4 + RDv4) + 0.25*v2IM;
+		
+		// Use just v2 - v4RD to reconstruct the fit?
+		//pPhase->CollocationValuesPhaseInt[1] = v2IMmRDv4 + RDv4);
+
+		pPhase->CollocationValuesPhaseInt[2] = v3IMmRDv4 + RDv4;
+
+		pPhase->CollocationValuesPhaseInt[3] = phaseRD;
+
+		/* A_{0,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[0];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,0,0,1.0);
+		gsl_matrix_set(A,0,1,ff1);
+		gsl_matrix_set(A,0,2,ff2);
+		gsl_matrix_set(A,0,3,ff3);
+		gsl_vector_set(b,0,pPhase->CollocationValuesPhaseInt[0] - ff0);
+
+		/* A_{1,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[1];
+		ff1 = 1.0 / (ff / pWF->fRING);
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,1,0,1);
+		gsl_matrix_set(A,1,1,ff1);
+		gsl_matrix_set(A,1,2,ff2);
+		gsl_matrix_set(A,1,3,ff3);
+		gsl_vector_set(b,1,pPhase->CollocationValuesPhaseInt[1] - ff0);
+
+		/* A_{2,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[2];
+		ff1 = 1.0 / (ff / pWF->fRING);
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,2,0,1);
+		gsl_matrix_set(A,2,1,ff1);
+		gsl_matrix_set(A,2,2,ff2);
+		gsl_matrix_set(A,2,3,ff3);
+		gsl_vector_set(b,2,pPhase->CollocationValuesPhaseInt[2] - ff0);
+
+		/* A_{3,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[3];
+		ff1 = 1.0 / (ff / pWF->fRING);
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,3,0,1);
+		gsl_matrix_set(A,3,1,ff1);
+		gsl_matrix_set(A,3,2,ff2);
+		gsl_matrix_set(A,3,3,ff3);
+		gsl_vector_set(b,3,pPhase->CollocationValuesPhaseInt[3] - ff0);
+
+		/* We now solve the system A x = b via an LU decomposition */
+		gsl_linalg_LU_decomp(A,p,&s);
+		gsl_linalg_LU_solve(A,p,b,x);
+
+		/* Set intermediate phenomenological coefficients from solution to A x = b */
+		pPhase->b0 = gsl_vector_get(x,0);                                                        // x[0] // Constant
+		pPhase->b1 = gsl_vector_get(x,1) * pWF->fRING;                                           // x[1] // f^{-1}
+		pPhase->b2 = gsl_vector_get(x,2) * pWF->fRING * pWF->fRING;                              // x[2] // f^{-2}
+		//pPhase->b3 = 0.0;
+		pPhase->b4 = gsl_vector_get(x,3) * pWF->fRING * pWF->fRING * pWF->fRING * pWF->fRING;    // x[3] // f^{-4}
+
+		/* Tidy up in preparation for next GSL solve ... */
+		gsl_vector_free(b);
+		gsl_vector_free(x);
+		gsl_matrix_free(A);
+		gsl_permutation_free(p);
+	}
+	// Canonical intermediate model using 5 collocation points
+	else if(pWF->IMRPhenomXIntermediatePhaseVersion == 105)
+	{
+		// Using 5 collocation points in intermediate region
+		for(i = 0; i < 5; i++)
+		{
+			fi = gpoints5[i] * deltax + xmin;
+
+			pPhase->CollocationPointsPhaseInt[i] = fi;
+		}
+
+		/* Evaluate collocation points */
+
+		/* The first and last collocation points for the intermediate region are set from the inspiral fit and ringdown respectively */
+		pPhase->CollocationValuesPhaseInt[0] = phaseIN;
+		pPhase->CollocationValuesPhaseInt[4] = phaseRD;
+
+		// v2IM - v4RD. Using v4RD helps condition the fits with v4RD being very a robust fit.
+		double v2IMmRDv4 = IMRPhenomX_Intermediate_Phase_22_v2mRDv4(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		// v3IM - v4RD. Using v4RD helps condition the fits with v4RD being very a robust fit.
+		double v3IMmRDv4 = IMRPhenomX_Intermediate_Phase_22_v3mRDv4(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		// Direct fit to the collocation point at F2. We will take a weighted average of the direct and conditioned fit.
+		double v2IM      = IMRPhenomX_Intermediate_Phase_22_v2(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+		// Take a weighted average for these points. Helps condition the fit.
+		pPhase->CollocationValuesPhaseInt[1] = 0.75*(v2IMmRDv4 + RDv4) + 0.25*v2IM;
+
+		pPhase->CollocationValuesPhaseInt[2] = v3IMmRDv4 + RDv4;
+		pPhase->CollocationValuesPhaseInt[3] = IMRPhenomX_Intermediate_Phase_22_d43(pWF->eta,pWF->STotR,pWF->dchi,pWF->delta,pWF->IMRPhenomXIntermediatePhaseVersion);
+
+
+		// Collocation points: v4 = d43 + v3
+		pPhase->CollocationValuesPhaseInt[3] = pPhase->CollocationValuesPhaseInt[3] + pPhase->CollocationValuesPhaseInt[2];
+
+		/* A_{0,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[0];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff4 = ff2 * ff2;
+		ff0 = (4.0 * pPhase->cL) / ((2.0*pWF->fDAMP)*(2.0*pWF->fDAMP) + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,0,0,1.0);
+		gsl_matrix_set(A,0,1,ff1);
+		gsl_matrix_set(A,0,2,ff2);
+		gsl_matrix_set(A,0,3,ff3);
+		gsl_matrix_set(A,0,4,ff4);
+		gsl_vector_set(b,0,pPhase->CollocationValuesPhaseInt[0] - ff0);
+
+		if(debug)
+		{
+		printf("For row 0: a0 + a1 %.6f + a2 %.6f + a3 %.6f + a4 %.6f = %.6f , ff0 = %.6f, ff = %.6f\n",ff1,ff2,ff3,ff4,pPhase->CollocationValuesPhaseInt[0] - ff0,ff0,ff);
+		}
+
+		/* A_{1,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[1];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff4 = ff2 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,1,0,1.0);
+		gsl_matrix_set(A,1,1,ff1);
+		gsl_matrix_set(A,1,2,ff2);
+		gsl_matrix_set(A,1,3,ff3);
+		gsl_matrix_set(A,1,4,ff4);
+		gsl_vector_set(b,1,pPhase->CollocationValuesPhaseInt[1] - ff0);
+
+		if(debug)
+		{
+		printf("For row 1: a0 + a1 %.6f + a2 %.6f + a3 %.6f + a4 %.6f = %.6f\n",ff1,ff2,ff3,ff4,pPhase->CollocationValuesPhaseInt[1] - ff0);
+		}
+
+		/* A_{2,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[2];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff4 = ff2 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,2,0,1.0);
+		gsl_matrix_set(A,2,1,ff1);
+		gsl_matrix_set(A,2,2,ff2);
+		gsl_matrix_set(A,2,3,ff3);
+		gsl_matrix_set(A,2,4,ff4);
+		gsl_vector_set(b,2,pPhase->CollocationValuesPhaseInt[2] - ff0);
+
+		if(debug)
+		{
+		printf("For row 2: a0 + a1 %.6f + a2 %.6f + a3 %.6f + a4 %.6f = %.6f\n",ff1,ff2,ff3,ff4,pPhase->CollocationValuesPhaseInt[2] - ff0);
+		}
+
+		/* A_{3,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[3];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff4 = ff2 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,3,0,1.0);
+		gsl_matrix_set(A,3,1,ff1);
+		gsl_matrix_set(A,3,2,ff2);
+		gsl_matrix_set(A,3,3,ff3);
+		gsl_matrix_set(A,3,4,ff4);
+		gsl_vector_set(b,3,pPhase->CollocationValuesPhaseInt[3] - ff0);
+
+		if(debug)
+		{
+		printf("For row 3: a0 + a1 %.6f + a2 %.6f + a3 %.6f + a4 %.6f = %.6f\n",ff1,ff2,ff3,ff4,pPhase->CollocationValuesPhaseInt[3] - ff0);
+		}
+
+		/* A_{4,i} */
+		ff  = pPhase->CollocationPointsPhaseInt[4];
+		ff1 = pWF->fRING / ff;
+		ff2 = ff1 * ff1;
+		ff3 = ff1 * ff2;
+		ff4 = ff2 * ff2;
+		ff0 = (4 * pPhase->cL) / (4.0*pWF->fDAMP*pWF->fDAMP + (ff - pWF->fRING)*(ff - pWF->fRING));
+		gsl_matrix_set(A,4,0,1.0);
+		gsl_matrix_set(A,4,1,ff1);
+		gsl_matrix_set(A,4,2,ff2);
+		gsl_matrix_set(A,4,3,ff3);
+		gsl_matrix_set(A,4,4,ff4);
+		gsl_vector_set(b,4,pPhase->CollocationValuesPhaseInt[4] - ff0);
+
+		if(debug)
+		{
+		printf("For row 4: a0 + a1 %.6f + a2 %.6f + a3 %.6f + a4 %.6f = %.6f\n",ff1,ff2,ff3,ff4,pPhase->CollocationValuesPhaseInt[4] - ff0);
+		}
+
+		/* We now solve the system A x = b via an LU decomposition */
+		gsl_linalg_LU_decomp(A,p,&s);
+		gsl_linalg_LU_solve(A,p,b,x);
+
+		/* Set intermediate phenomenological coefficients from solution to A x = b */
+		pPhase->b0 = gsl_vector_get(x,0);                                                      // x[0] // Const.
+		pPhase->b1 = gsl_vector_get(x,1) * pWF->fRING;                                         // x[1] // f^{-1}
+		pPhase->b2 = gsl_vector_get(x,2) * pWF->fRING * pWF->fRING;                            // x[2] // f^{-2}
+		pPhase->b3 = gsl_vector_get(x,3) * pWF->fRING * pWF->fRING * pWF->fRING;               // x[3] // f^{-3}
+		pPhase->b4 = gsl_vector_get(x,4) * pWF->fRING * pWF->fRING * pWF->fRING * pWF->fRING;  // x[4] // f^{-4}
+
+		if(debug)
+		{
+		printf("\n");
+		printf("Intermediate Collocation Points and Values:\n");
+		printf("F1 : %.7f\n",pPhase->CollocationPointsPhaseInt[0]);
+		printf("F2 : %.7f\n",pPhase->CollocationPointsPhaseInt[1]);
+		printf("F3 : %.7f\n",pPhase->CollocationPointsPhaseInt[2]);
+		printf("F4 : %.7f\n",pPhase->CollocationPointsPhaseInt[3]);
+		printf("F5 : %.7f\n",pPhase->CollocationPointsPhaseInt[4]);
+		printf("\n");
+		printf("V's agree with Mathematica...\n");
+		printf("V1 : %.7f\n",pPhase->CollocationValuesPhaseInt[0]);
+		printf("V2 : %.7f\n",pPhase->CollocationValuesPhaseInt[1]);
+		printf("V3 : %.7f\n",pPhase->CollocationValuesPhaseInt[2]);
+		printf("V4 : %.7f\n",pPhase->CollocationValuesPhaseInt[3]);
+		printf("V5 : %.7f\n",pPhase->CollocationValuesPhaseInt[4]);
+		printf("\n");
+		printf("g0 : %.7f\n",gsl_vector_get(x,0));
+		printf("g1 : %.7f\n",gsl_vector_get(x,1));
+		printf("g2 : %.7f\n",gsl_vector_get(x,2));
+		printf("g3 : %.7f\n",gsl_vector_get(x,3));
+		printf("g4 : %.7f\n",gsl_vector_get(x,4));
+		printf("\n");
+		printf("b0 : %.7f\n",pPhase->b0);
+		printf("b1 : %.7f\n",pPhase->b1);
+		printf("b2 : %.7f\n",pPhase->b2);
+		printf("b3 : %.7f\n",pPhase->b3);
+		printf("b4 : %.7f\n",pPhase->b4);
+		printf("\n");
+		}
+
+		/* Tidy up */
+		gsl_vector_free(b);
+		gsl_vector_free(x);
+		gsl_matrix_free(A);
+		gsl_permutation_free(p);
+	}
+	else
+	{
+		XLALPrintError("Error in ComputeIMRPhenomXWaveformVariables: IMRPhenomXIntermediatePhaseVersion is not valid.\n");
+	}
+
+	/* Set pre-cached variables */
+	pPhase->c4ov3   = pPhase->c4 / 3.0;
+	pPhase->cLovfda = pPhase->cL / pWF->fDAMP;
+
+	/* Initialize connection coefficients */
+	pPhase->C1Int = 0;
+	pPhase->C2Int = 0;
+	pPhase->C1MRD = 0;
+	pPhase->C2MRD = 0;
+
+	/* END OF ROUTINE; RETURN STRUCT */
+	return XLAL_SUCCESS;
+}
+
+
+void IMRPhenomX_Phase_22_ConnectionCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase)
+{
+	int debug = pWF->debug;
+
+	double fIns = pPhase->fPhaseMatchIN;
+	double fInt = pPhase->fPhaseMatchIM;
+
+	/*
+			Assume an ansatz of the form:
+
+			phi_Inspiral (f) = phi_Intermediate (f) + C1 + C2 * f
+
+			where transition frequency is fIns
+
+			phi_Inspiral (fIns) = phi_Intermediate (fIns) + C1 + C2 * fIns
+			phi_Inspiral'(fIns) = phi_Intermediate'(fIns) + C2
+
+			Solving for C1 and C2
+
+			C2 = phi_Inspiral'(fIns) - phi_Intermediate'(fIns)
+			C1 = phi_Inspiral (fIns) - phi_Intermediate (fIns) - C2 * fIns
+
+	*/
+	IMRPhenomX_UsefulPowers powers_of_fIns;
+  IMRPhenomX_Initialize_Powers(&powers_of_fIns,fIns);
+
+  double DPhiIns = IMRPhenomX_Inspiral_Phase_22_Ansatz(fIns,&powers_of_fIns,pPhase);
+  double DPhiInt = IMRPhenomX_Intermediate_Phase_22_Ansatz(fIns,&powers_of_fIns,pWF,pPhase);
+
+  pPhase->C2Int = DPhiIns - DPhiInt;
+
+	double phiIN = IMRPhenomX_Inspiral_Phase_22_AnsatzInt(fIns,&powers_of_fIns,pPhase);
+	double phiIM = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(fIns,&powers_of_fIns,pWF,pPhase);
+
+	if(debug)
+	{
+	printf("\n");
+	printf("dphiIM = %.6f and dphiIN = %.6f\n",DPhiInt,DPhiIns);
+	printf("phiIN(fIns)  : %.7f\n",phiIN);
+	printf("phiIM(fIns)  : %.7f\n",phiIM);
+	printf("fIns         : %.7f\n",fIns);
+	printf("C2           : %.7f\n",pPhase->C2Int);
+	printf("\n");
+	}
+
+	pPhase->C1Int = phiIN - phiIM - (pPhase->C2Int * fIns);
+
+	/*
+			Assume an ansatz of the form:
+
+			phi_Intermediate (f)    = phi_Ringdown (f) + C1 + C2 * f
+
+			where transition frequency is fIM
+
+			phi_Intermediate (fIM) = phi_Ringdown (fRD) + C1 + C2 * fIM
+			phi_Intermediate'(fIM) = phi_Ringdown'(fRD) + C2
+
+			Solving for C1 and C2
+
+			C2 = phi_Inspiral'(fIM) - phi_Intermediate'(fIM)
+			C1 = phi_Inspiral (fIM) - phi_Intermediate (fIM) - C2 * fIM
+
+	*/
+	IMRPhenomX_UsefulPowers powers_of_fInt;
+  IMRPhenomX_Initialize_Powers(&powers_of_fInt,fInt);
+
+  double phiIMC         = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(fInt,&powers_of_fInt,pWF,pPhase) + pPhase->C1Int + pPhase->C2Int*fInt;
+	double phiRD          = IMRPhenomX_Ringdown_Phase_22_AnsatzInt(fInt,&powers_of_fInt,pWF,pPhase);
+  double DPhiIntC       = IMRPhenomX_Intermediate_Phase_22_Ansatz(fInt,&powers_of_fInt,pWF,pPhase) + pPhase->C2Int;
+  double DPhiRD         = IMRPhenomX_Ringdown_Phase_22_Ansatz(fInt,&powers_of_fInt,pWF,pPhase);
+
+	pPhase->C2MRD = DPhiIntC - DPhiRD;
+  pPhase->C1MRD = phiIMC - phiRD - pPhase->C2MRD*fInt;
+
+	if(debug)
+	{
+	printf("\n");
+	printf("phiIMC(fInt) : %.7f\n",phiIMC);
+	printf("phiRD(fInt)  : %.7f\n",phiRD);
+	printf("fInt         : %.7f\n",fInt);
+	printf("C2           : %.7f\n",pPhase->C2Int);
+	printf("\n");
+	}
+
+	if(debug)
+	{
+	printf("dphiIM = %.6f and dphiRD = %.6f\n",DPhiIntC,DPhiRD);
+	printf("\nContinuity Coefficients\n");
+	printf("C1Int : %.6f\n",pPhase->C1Int);
+	printf("C2Int : %.6f\n",pPhase->C2Int);
+	printf("C1MRD : %.6f\n",pPhase->C1MRD);
+	printf("C2MRD : %.6f\n",pPhase->C2MRD);
+	}
+
+  return;
+}
+
+double IMRPhenomX_TimeShift_22(IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF){
+
+    REAL8 linb, tshift, dphi22Ref,frefFit;
+
+    // here we align the model to the hybrids, for which psi4 peaks 500M before the end of the waveform
+    // linb is a parameter-space fit of dphi22(fring22-fdamp22), evaluated on the calibration dataset
+    linb = XLALSimIMRPhenomXLinb(pWF->eta, pWF->STotR, pWF->dchi, pWF->delta);
+    frefFit=pWF->fRING-pWF->fDAMP;
+    IMRPhenomX_UsefulPowers powers_of_frefFit;
+    IMRPhenomX_Initialize_Powers(&powers_of_frefFit,frefFit);
+    dphi22Ref=1./(pWF->eta)*IMRPhenomX_dPhase_22(frefFit, &powers_of_frefFit, pPhase, pWF);
+    // here we correct the time-alignment of the waveform by first aligning the peak of psi4, and then adding a correction to align the peak of strain instead
+    REAL8 psi4tostrain=XLALSimIMRPhenomXPsi4ToStrain(pWF->eta, pWF->STotR, pWF->dchi);
+    tshift=linb-dphi22Ref -2.*LAL_PI*(500+psi4tostrain);
+
+    //phX phase will read phi22=1/eta*IMRPhenomX_Phase_22+tshift f, modulo a residual phase-shift
+    return(tshift);
+
+}
+
+
+
+/*
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ * This function computes the IMRPhenomX phase given a phase coefficients struct pPhase.
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ */
+double IMRPhenomX_Phase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
+{
+	// Inspiral region, f < fPhaseInsMax
+  if (!IMRPhenomX_StepFuncBool(ff, pPhase->fPhaseMatchIN))
+  {
+	  double PhiIns = IMRPhenomX_Inspiral_Phase_22_AnsatzInt(ff, powers_of_f, pPhase);
+	  return PhiIns;
+  }
+
+	// Ringdown region, f > fPhaseIntMax
+  if (IMRPhenomX_StepFuncBool(ff, pPhase->fPhaseMatchIM))
+  {
+	  double PhiMRD = IMRPhenomX_Ringdown_Phase_22_AnsatzInt(ff, powers_of_f, pWF, pPhase)
+                            + pPhase->C1MRD + (pPhase->C2MRD * ff);
+	  return PhiMRD;
+  }
+
+  //	Intermediate region, fPhaseInsMax < f < fPhaseIntMax
+  double PhiInt = IMRPhenomX_Intermediate_Phase_22_AnsatzInt(ff, powers_of_f, pWF, pPhase)
+                            + pPhase->C1Int + (pPhase->C2Int * ff);
+
+  return PhiInt;
+}
+
+/*
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ * This function computes the IMRPhenomX phase derivative given a phase coefficients struct pPhase.
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ */
+double IMRPhenomX_dPhase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF)
+{
+	// Inspiral region, f < fPhaseInsMax
+  if (!IMRPhenomX_StepFuncBool(ff, pPhase->fPhaseMatchIN))
+  {
+	  double dPhiIns = IMRPhenomX_Inspiral_Phase_22_Ansatz(ff, powers_of_f, pPhase);
+	  return dPhiIns;
+  }
+
+	// Ringdown region, f > fPhaseIntMax
+  if (IMRPhenomX_StepFuncBool(ff, pPhase->fPhaseMatchIM))
+  {
+	  double dPhiMRD = IMRPhenomX_Ringdown_Phase_22_Ansatz(ff, powers_of_f, pWF, pPhase)
+                            + (pPhase->C2MRD);
+	  return dPhiMRD;
+  }
+
+  //	Intermediate region, fPhaseInsMax < f < fPhaseIntMax
+  double dPhiInt = IMRPhenomX_Intermediate_Phase_22_Ansatz(ff, powers_of_f, pWF, pPhase)
+                            + (pPhase->C2Int);
+
+  return dPhiInt;
+}
+
+/*
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ * This function computes the IMRPhenomX amplitude given an amplitude coefficients struct pAmp.
+ * ********** ********** ********** ********** ********** ********** ********** ********** ********** **********
+ */
+double IMRPhenomX_Amplitude_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp, IMRPhenomXWaveformStruct *pWF) {
+  //double f_seven_sixths = powers_of_f->seven_sixths;
+  //double AmpPreFac      = pWF->ampNorm / f_seven_sixths; // Use this if we want return normalized amplitudes
+	double AmpPreFac      = pWF->ampNorm / powers_of_f->seven_sixths;
+
+  // Inspiral region, f < fAmpMatchIN
+  if (!IMRPhenomX_StepFuncBool(ff, pAmp->fAmpMatchIN))
+  {
+    double AmpIns =  AmpPreFac * IMRPhenomX_Inspiral_Amp_22_Ansatz(ff, powers_of_f, pWF, pAmp);
+	  return AmpIns;
+  }
+
+	// Ringdown region, f > fAmpRDMin
+  if (IMRPhenomX_StepFuncBool(ff, pAmp->fAmpRDMin))
+  {
+    double AmpMRD = AmpPreFac * IMRPhenomX_Ringdown_Amp_22_Ansatz(ff, pWF, pAmp);
+    return AmpMRD;
+  }
+
+  // Intermediate region, fAmpMatchIN < f < fAmpRDMin
+  double AmpInt = AmpPreFac * IMRPhenomX_Intermediate_Amp_22_Ansatz(ff, powers_of_f, pWF, pAmp);
+  return AmpInt;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_internals.h b/lalsimulation/lib/LALSimIMRPhenomX_internals.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c2e89e8fa7c6234845230d0158f3ba669189a67
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_internals.h
@@ -0,0 +1,385 @@
+#ifndef _LALSIM_IMR_PHENOMX_INTERNALS_H
+#define _LALSIM_IMR_PHENOMX_INTERNALS_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/*
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+/* Inherited from IMRPhenomD */
+#define N_MAX_COLLOCATION_POINTS_PHASE_RD 5
+#define N_MAX_COLLOCATION_POINTS_PHASE_INT 5
+#define N_MAX_COLLOCATION_POINTS_PHASE_INS 6
+
+#define N_MAX_COLLOCATION_POINTS_AMP_RD 5
+#define N_MAX_COLLOCATION_POINTS_AMP_INT 5
+#define N_MAX_COLLOCATION_POINTS_AMP_INS 5
+
+/* Standard libraries */
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+  //#include <complex.h>
+
+/* GSL */
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_spline.h>
+
+/* LAL */
+#include <lal/LALStdlib.h>
+#include <lal/LALConstants.h>
+#include <lal/Date.h>
+#include <lal/FrequencySeries.h>
+#include <lal/Units.h>
+
+/* IMRPhenomX */
+#include <lal/LALSimInspiral.h>
+
+/* ********************** CACHED VARIABLES ********************* */
+/*
+	Cached, recurring coefficients that occur in IMRPhenomX.
+	Must be frequency independent.
+*/
+typedef struct tagIMRPhenomXWaveformStruct
+{
+	/* Debug flag */
+	INT4 debug;
+
+	/* Model Version Parameters */
+	INT4  IMRPhenomXInspiralPhaseVersion;
+	INT4  IMRPhenomXIntermediatePhaseVersion;
+	INT4  IMRPhenomXRingdownPhaseVersion;
+
+	INT4  IMRPhenomXInspiralAmpVersion;
+	INT4  IMRPhenomXIntermediateAmpVersion;
+	INT4  IMRPhenomXRingdownAmpVersion;
+
+	/* Mass Parameters */
+	REAL8 m1_SI; 		// Mass in SI units
+	REAL8 m2_SI;	 	// Mass in SI units
+	REAL8 Mtot_SI; 	// Total mass in SI units
+	REAL8 m1;		 		// Mass in solar masses
+	REAL8 m2;	   		// Mass in solar masses
+	REAL8 Mtot;  		// Total mass in solar masses
+	REAL8 Mc;				// Chirp mass in solar masses
+	REAL8 q;				// Mass ratio >= 1
+	REAL8 eta;			// Symmetric mass ratio
+	REAL8 delta;		// PN symmetry parameter: sqrt(1-4*eta)
+
+	/* Spin Parameters */
+	REAL8 chi1L;
+	REAL8 chi2L;
+	REAL8 chiEff;
+	REAL8 chiPNHat;
+	REAL8 STotR;
+	REAL8 dchi;
+	REAL8 SL;
+	REAL8 SigmaL;
+
+	/* Useful Powers (?) */
+	REAL8 eta2;
+	REAL8 eta3;
+	REAL8 eta4;
+	REAL8 chi1L2;
+	REAL8 chi1L3;
+	REAL8 chi2L2;
+	REAL8 chi2L3;
+	REAL8 chi1L2L; // chi1 * chi2;
+
+	/* Amplitude and Phase Normalisation */
+	REAL8 dphase0;
+	REAL8 amp0;
+	REAL8 ampNorm;
+
+	/* Frequencies */
+	REAL8 fMECO;
+	REAL8 fISCO;
+
+	/* Ringdown and Damping Frequencies for 22 Mode */
+	REAL8 fRING;
+	REAL8 fDAMP;
+
+	/* Ringdown and Damping Frequencies for 21 Mode */
+	REAL8 fRING21;
+	REAL8 fDAMP21;
+
+	/* Ringdown and Damping Frequencies for 33 Mode */
+	REAL8 fRING33;
+	REAL8 fDAMP33;
+
+	/* Ringdown and Damping Frequencies for 32 Mode */
+	REAL8 fRING32;
+	REAL8 fDAMP32;
+
+	/* Ringdown and Damping Frequencies for 44 Mode */
+	REAL8 fRING44;
+	REAL8 fDAMP44;
+
+	REAL8 fMin;
+	REAL8 fMax;
+	REAL8 f_max_prime;
+	REAL8 deltaF;
+	REAL8 fCut;
+
+	// Dimensionless frequency (Mf) defining the end of the waveform
+	REAL8 fCutDef;
+
+	REAL8 fRef;
+	REAL8 MfRef;
+	REAL8 M_sec;
+	REAL8 phiRef_In;
+	REAL8 phi0;
+	REAL8 phifRef;
+	REAL8 piM;
+	REAL8 v_ref;
+
+	/* Final mass and spin */
+	REAL8 Erad;
+	REAL8 afinal;
+	REAL8 Mfinal;
+
+	REAL8 distance;
+	REAL8 inclination;
+	REAL8 beta;
+
+} IMRPhenomXWaveformStruct;
+
+
+typedef struct tagIMRPhenomX_UsefulPowers
+{
+	REAL8 seven_sixths;
+	REAL8 one_sixth;
+	REAL8 eight_thirds;
+	REAL8 seven_thirds;
+	REAL8 five_thirds;
+	REAL8 four_thirds;
+	REAL8 two_thirds;
+	REAL8 one_third;
+	REAL8 five;
+	REAL8 four;
+	REAL8 three;
+	REAL8 two;
+	REAL8 sqrt;
+	REAL8 itself;
+	REAL8 m_sqrt;
+	REAL8 m_one;
+	REAL8 m_two;
+	REAL8 m_three;
+	REAL8 m_four;
+	REAL8 m_five;
+	REAL8 m_six;
+	REAL8 m_one_third;
+	REAL8 m_two_thirds;
+	REAL8 m_four_thirds;
+	REAL8 m_five_thirds;
+	REAL8 m_seven_thirds;
+	REAL8 m_eight_thirds;
+	REAL8 m_one_sixth;
+	REAL8 m_seven_sixths;
+
+	REAL8 log;
+
+} IMRPhenomX_UsefulPowers;
+
+/*
+ * useful powers of LAL_PI, calculated once and kept constant - to be initied with a call to
+ */
+extern IMRPhenomX_UsefulPowers powers_of_lalpi;
+
+typedef struct tagIMRPhenomXPhaseCoefficients
+{
+	/* PHASE */
+	/* Phase Transition Frequencies */
+	REAL8 fPhaseInsMin;
+	REAL8 fPhaseInsMax;
+	REAL8 fPhaseIntMin;
+	REAL8 fPhaseIntMax;
+	REAL8 fPhaseRDMin;
+	REAL8 fPhaseRDMax;
+
+	REAL8 fPhaseMatchIN;
+	REAL8 fPhaseMatchIM;
+
+	REAL8 C1Int, C2Int;
+	REAL8 C1MRD, C2MRD;
+
+  /* These are the RD phenomenological coefficients 					*/
+  REAL8 c0, c1, c2, c3, c4, cL, cRD;
+
+  /* These are the intermediate phenomenological coefficients */
+  REAL8 b0, b1, b2, b3, b4;
+
+  /* These are the inspiral phenomenological coefficients 		*/
+  REAL8 a0, a1, a2, a3, a4;
+
+	/* Pre-cached variables */
+	REAL8 c4ov3, cLovfda;
+
+	/* TaylorF2 PN Coefficients */
+	REAL8 phi0, phi1, phi2, phi3, phi4, phi5, phi6, phi7, phi8, phi9, phi10, phi11, phi12, phi13, phi5L, phi6L, phi8L, phi9L;
+	REAL8 phi_initial, phiNorm;
+	REAL8 dphi0, dphi1, dphi2, dphi3, dphi4, dphi5, dphi6, dphi7, dphi8, dphi9, dphi10, dphi11, dphi12, dphi13, dphi5L, dphi6L, dphi8L, dphi9L;
+
+	/* Pseudo-PN Coefficients */
+	REAL8 sigma0, sigma1, sigma2, sigma3, sigma4, sigma5;
+
+  /* Flag to set how many collocation points the RD region uses 	*/
+  INT4  NCollocationPointsRD;
+
+  /* Flag to set how many collocation points the INT region uses 	*/
+  INT4  NCollocationPointsInt;
+
+  /* Integer to tell us how many pseudo PN terms are used 											*/
+  INT4	NPseudoPN;
+	INT4  NCollocationPointsPhaseIns;
+
+	/* The canonical ringdown phase is constructed from 5 collocation points 			*/
+	REAL8 CollocationPointsPhaseRD[N_MAX_COLLOCATION_POINTS_PHASE_RD];
+	REAL8 CollocationValuesPhaseRD[N_MAX_COLLOCATION_POINTS_PHASE_RD];
+	REAL8 CoefficientsPhaseRD[N_MAX_COLLOCATION_POINTS_PHASE_RD];
+
+
+	/* The canonical intermediate phase is constructed from 4/5 collocation points  */
+	REAL8 CollocationPointsPhaseInt[N_MAX_COLLOCATION_POINTS_PHASE_INT];
+	REAL8 CollocationValuesPhaseInt[N_MAX_COLLOCATION_POINTS_PHASE_INT];
+	REAL8 CoefficientsPhaseInt[N_MAX_COLLOCATION_POINTS_PHASE_INT];
+
+	/*
+		 	For N pseudo-PN terms we need N+1 collocation points:
+		 	We have set N_MAX_COLLOCATION_POINTS_INS = 5 to allow
+		 	either 3 or 4 pseudo-PN coefficients to be used.
+	*/
+	REAL8 CollocationPointsPhaseIns[N_MAX_COLLOCATION_POINTS_PHASE_INS];
+	REAL8 CollocationValuesPhaseIns[N_MAX_COLLOCATION_POINTS_PHASE_INS];
+	REAL8 CoefficientsPhaseIns[N_MAX_COLLOCATION_POINTS_PHASE_INS];
+
+} IMRPhenomXPhaseCoefficients;
+
+typedef struct tagIMRPhenomXAmpCoefficients
+{
+	REAL8 fAmpInsMin;
+	REAL8 fAmpInsMax;
+	REAL8 fAmpIntMin;
+	REAL8 fAmpIntMax;
+	REAL8 fAmpRDMin;
+	REAL8 fAmpRDMax;
+
+	REAL8 fAmpMatchIN;
+	REAL8 fAmpMatchIM;
+
+  /* These are the RD phenomenological coefficients 					*/
+  REAL8 c0, c1, c2, c3, c4, cL;
+
+  /* These are the intermediate phenomenological coefficients */
+  REAL8 b0, b1, b2, b3, b4, b5;
+
+  /* These are the inspiral phenomenological coefficients 		*/
+  REAL8 a0, a1, a2, a3, a4, a5;
+
+	REAL8 v1RD, sigmaRD;
+
+	REAL8 rho1, rho2, rho3;																	/* Inspiral pseudo-PN coefficients 							*/
+	REAL8 delta0, delta1, delta2, delta3, delta4, delta5;		/* Intermediate phenomenological coefficients 	*/
+	REAL8 gamma1, gamma2, gamma3;														/* Ringdown phenomenological coefficients 			*/
+	REAL8 gammaR, gammaD13, gammaD2;
+
+	/* PN Amplitude Prefactors */
+	REAL8 pnInitial, pnOneThird, pnTwoThirds, pnThreeThirds, pnFourThirds, pnFiveThirds, pnSixThirds, pnSevenThirds, pnEightThirds, pnNineThirds;
+
+  /* Flags to set the ringdown amplitude version			*/
+	INT4  NCollocationPointsRD;
+	INT4  IMRPhenomXRingdownAmpVersion;
+
+	/* Flags to set the intermediate amplitude version	*/
+	INT4  NCollocationPointsInt;
+	INT4  IMRPhenomXIntermediateAmpVersion;
+
+  /* Flags to set the inspiral amplitude version 			*/
+	INT4	NPseudoPN;
+	INT4  IMRPhenomXInspiralAmpVersion;
+
+	/* The ringdown is constructed from 5 collocation points 						*/
+	REAL8 CollocationPointsAmpRD[N_MAX_COLLOCATION_POINTS_AMP_RD];
+	REAL8 CollocationValuesAmpRD[N_MAX_COLLOCATION_POINTS_AMP_RD];
+
+	REAL8 CollocationPointsAmpInt[N_MAX_COLLOCATION_POINTS_AMP_INT];
+	REAL8 CollocationValuesAmpInt[N_MAX_COLLOCATION_POINTS_AMP_INT];
+
+	/* For 3 pseudo-PN parameters we need 4 collocation points         	*/
+	/* For 4 pseudo-PN parameters we need 5 collocation points, etc... 	*/
+	REAL8 CollocationPointsAmpIns[N_MAX_COLLOCATION_POINTS_AMP_INS];
+	REAL8 CollocationValuesAmpIns[N_MAX_COLLOCATION_POINTS_AMP_INS];
+
+} IMRPhenomXAmpCoefficients;
+
+
+
+///////////////////////////// Useful Numerical Routines /////////////////////////////
+int IMRPhenomX_Initialize_Powers(IMRPhenomX_UsefulPowers *p, REAL8 number);
+int IMRPhenomX_Initialize_Powers_Light(IMRPhenomX_UsefulPowers *p, REAL8 number);
+
+int IMRPhenomXSetWaveformVariables(
+IMRPhenomXWaveformStruct *pWF,
+	const REAL8 m1_SI,
+	const REAL8 m2_SI,
+	const REAL8 chi1L_In,
+	const REAL8 chi2L_In,
+	const REAL8 deltaF,
+	const REAL8 fRef,
+	const REAL8 phiRef,
+	const REAL8 f_min,
+	const REAL8 f_max,
+	const REAL8 distance,
+	const REAL8 inclination,
+	LALDict *lalParams,
+	const UINT4 debug
+);
+
+double IMRPhenomX_Amplitude_22(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXAmpCoefficients *pAmp, IMRPhenomXWaveformStruct *pWF);
+double IMRPhenomX_Phase_22(double f, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *Phase, IMRPhenomXWaveformStruct *pWF);
+double IMRPhenomX_dPhase_22(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF);
+
+int IMRPhenomXGetAmplitudeCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+int IMRPhenomXGetPhaseCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+
+double IMRPhenomX_TimeShift_22(IMRPhenomXPhaseCoefficients *pPhase, IMRPhenomXWaveformStruct *pWF);
+    
+void IMRPhenomX_Phase_22_ConnectionCoefficients(IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+
+REAL8 XLALSimIMRPhenomXAmp22Prefactor(REAL8 eta);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// of #ifndef _LALSIM_IMR_PHENOMX_INTERNALS_H
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_qnm.c b/lalsimulation/lib/LALSimIMRPhenomX_qnm.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9c74f2778e635a698ffe86bbf6d53af171be698
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_qnm.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 Sascha Husa, Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/*
+ * \author Sascha Husa
+ * \author Geraint Pratten
+ *
+ */
+
+#include "LALSimIMRPhenomX_qnm.h"
+
+#if QNMfits == 1
+/**
+ *  evaluate fit QNMData_fring_22
+ */
+static double evaluate_QNMfit_fring22(double finalDimlessSpin){
+
+double return_val;
+
+if (fabs(finalDimlessSpin) > 1.0) {
+       XLAL_ERROR(XLAL_EDOM, "PhenomX evaluate_QNMfit_fring22 \
+function: |finalDimlessSpin| > 1.0 not supported");
+}
+
+double x2= finalDimlessSpin*finalDimlessSpin;
+double x3= x2*finalDimlessSpin;
+double x4= x2*x2;
+double x5= x3*x2;
+double x6= x3*x3;
+double x7= x4*x3;
+
+return_val = (0.05947169566573468 - \
+0.14989771215394762*finalDimlessSpin + 0.09535606290986028*x2 + \
+0.02260924869042963*x3 - 0.02501704155363241*x4 - \
+0.005852438240997211*x5 + 0.0027489038393367993*x6 + \
+0.0005821983163192694*x7)/(1 - 2.8570126619966296*finalDimlessSpin + \
+2.373335413978394*x2 - 0.6036964688511505*x4 + \
+0.0873798215084077*x6);
+return return_val;
+}
+
+
+/**
+ *  evaluate fit QNMData_fdamp_22
+ */
+static double evaluate_QNMfit_fdamp22(double finalDimlessSpin){
+
+double return_val;
+
+if (fabs(finalDimlessSpin) > 1.0) {
+       XLAL_ERROR(XLAL_EDOM, "PhenomX evaluate_QNMfit_fdamp22 \
+function: |finalDimlessSpin| > 1.0 not supported");
+}
+
+double x2= finalDimlessSpin*finalDimlessSpin;
+double x3= x2*finalDimlessSpin;
+double x4= x2*x2;
+double x5= x3*x2;
+double x6= x3*x3;
+
+return_val = (0.014158792290965177 - \
+0.036989395871554566*finalDimlessSpin + 0.026822526296575368*x2 + \
+0.0008490933750566702*x3 - 0.004843996907020524*x4 - \
+0.00014745235759327472*x5 + 0.0001504546201236794*x6)/(1 - \
+2.5900842798681376*finalDimlessSpin + 1.8952576220623967*x2 - \
+0.31416610693042507*x4 + 0.009002719412204133*x6);
+return return_val;
+}
+
+
+#else
+ /**
+  *  evaluate interpolated data set QNMData_fring_22, see Berti et al, CQG, 26, 163001, (2009)
+  */
+static double interpolateQNMData_fring_22(double finalDimlessSpin) {
+   double return_val;
+
+   if (fabs(finalDimlessSpin) > 1.0) {
+ 	   XLAL_ERROR(XLAL_EDOM, "PhenomX interpolateQNMData_fring_22 function: |finalDimlessSpin| > 1.0 not supported");
+   }
+   gsl_interp_accel *acc = gsl_interp_accel_alloc();
+   gsl_spline *iData = gsl_spline_alloc(gsl_interp_cspline, QNMData_fring_22_length);
+   gsl_spline_init(iData, QNMData_a, QNMData_fring_22, QNMData_fring_22_length);
+
+   return_val = gsl_spline_eval(iData, finalDimlessSpin, acc);
+
+   gsl_spline_free(iData);
+   gsl_interp_accel_free(acc);
+   return return_val;
+ }
+
+
+ /**
+  *  evaluate interpolated data set QNMData_fdamp_22, see Berti et al, CQG, 26, 163001, (2009)
+  */
+static double interpolateQNMData_fdamp_22(double finalDimlessSpin) {
+   double return_val;
+
+   if (fabs(finalDimlessSpin) > 1.0) {
+ 	XLAL_ERROR(XLAL_EDOM, "PhenomX interpolateQNMData_fdamp_22 function: |finalDimlessSpin| > 1.0 not supported");
+   }
+   gsl_interp_accel *acc = gsl_interp_accel_alloc();
+   gsl_spline *iData = gsl_spline_alloc(gsl_interp_cspline, QNMData_fdamp_22_length);
+   gsl_spline_init(iData, QNMData_a, QNMData_fdamp_22, QNMData_fdamp_22_length);
+
+   return_val = gsl_spline_eval(iData, finalDimlessSpin, acc);
+
+   gsl_spline_free(iData);
+   gsl_interp_accel_free(acc);
+   return return_val;
+ }
+
+ #endif
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_qnm.h b/lalsimulation/lib/LALSimIMRPhenomX_qnm.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a33397468e52a0a7f29d98421703658a87efa04
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_qnm.h
@@ -0,0 +1,676 @@
+#ifndef _LALSIM_IMR_PHENOMX_QNM_H
+#define _LALSIM_IMR_PHENOMX_QNM_H
+
+/*
+ * Copyright (C) 2018 Sascha Husa, Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/*
+ * \author Sascha Husa
+ * \author Geraint Pratten
+ *
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <lal/LALDatatypes.h>
+#include <lal/LALConstants.h>
+#include <lal/LALStdlib.h>
+
+#define QNMfits 1
+
+#if QNMfits == 1
+ static double evaluate_QNMfit_fring22(double finalDimlessSpin);
+ static double evaluate_QNMfit_fdamp22(double finalDimlessSpin);
+
+#else
+ static double interpolateQNMData_fring_22(double finalDimlessSpin);
+ static double interpolateQNMData_fdamp_22(double finalDimlessSpin);
+
+#endif
+ 
+/*
+ 	Data from: 
+ 	Berti et al, CQG, 26, 163001, (2009); arXiv:0905.2975
+ 	https://pages.jh.edu/~eberti2/ringdown/
+*/
+
+/* dimensionless Kerr parameter a */
+static const int QNMData_a_length = 1200;
+static const double QNMData_a[] = {
+-1., -0.9983319432860718, -0.9966638865721434, -0.9949958298582152, -0.9933277731442869, -0.9916597164303587,\
+-0.9899916597164303, -0.9883236030025021, -0.9866555462885738, -0.9849874895746455, -0.9833194328607172, -0.981651376146789,\
+-0.9799833194328608, -0.9783152627189324, -0.9766472060050042, -0.9749791492910759, -0.9733110925771477, -0.9716430358632193,\
+-0.9699749791492911, -0.9683069224353628, -0.9666388657214345, -0.9649708090075062, -0.963302752293578, -0.9616346955796498,\
+-0.9599666388657214, -0.9582985821517932, -0.9566305254378649, -0.9549624687239366, -0.9532944120100083, -0.9516263552960801,\
+-0.9499582985821518, -0.9482902418682235, -0.9466221851542952, -0.944954128440367, -0.9432860717264387, -0.9416180150125104,\
+-0.9399499582985822, -0.9382819015846539, -0.9366138448707256, -0.9349457881567973, -0.9332777314428691, -0.9316096747289407,\
+-0.9299416180150125, -0.9282735613010842, -0.926605504587156, -0.9249374478732277, -0.9232693911592994, -0.9216013344453712,\
+-0.9199332777314428, -0.9182652210175146, -0.9165971643035863, -0.9149291075896581, -0.9132610508757297, -0.9115929941618015,\
+-0.9099249374478732, -0.908256880733945, -0.9065888240200167, -0.9049207673060884, -0.9032527105921602, -0.9015846538782318,\
+-0.8999165971643036, -0.8982485404503753, -0.896580483736447, -0.8949124270225187, -0.8932443703085905, -0.8915763135946623,\
+-0.8899082568807339, -0.8882402001668057, -0.8865721434528774, -0.8849040867389492, -0.8832360300250208, -0.8815679733110926,\
+-0.8798999165971643, -0.878231859883236, -0.8765638031693077, -0.8748957464553795, -0.8732276897414513, -0.8715596330275229,\
+-0.8698915763135947, -0.8682235195996664, -0.8665554628857381, -0.8648874061718098, -0.8632193494578816, -0.8615512927439533,\
+-0.859883236030025, -0.8582151793160967, -0.8565471226021685, -0.8548790658882403, -0.8532110091743119, -0.8515429524603837,\
+-0.8498748957464554, -0.8482068390325271, -0.8465387823185988, -0.8448707256046706, -0.8432026688907422, -0.841534612176814,\
+-0.8398665554628857, -0.8381984987489575, -0.8365304420350292, -0.8348623853211009, -0.8331943286071727, -0.8315262718932444,\
+-0.8298582151793161, -0.8281901584653878, -0.8265221017514596, -0.8248540450375312, -0.823185988323603, -0.8215179316096747,\
+-0.8198498748957465, -0.8181818181818182, -0.8165137614678899, -0.8148457047539617, -0.8131776480400333, -0.8115095913261051,\
+-0.8098415346121768, -0.8081734778982486, -0.8065054211843202, -0.804837364470392, -0.8031693077564637, -0.8015012510425354,\
+-0.7998331943286072, -0.7981651376146789, -0.7964970809007507, -0.7948290241868223, -0.7931609674728941, -0.7914929107589658,\
+-0.7898248540450375, -0.7881567973311092, -0.786488740617181, -0.7848206839032527, -0.7831526271893244, -0.7814845704753962,\
+-0.7798165137614679, -0.7781484570475397, -0.7764804003336113, -0.7748123436196831, -0.7731442869057548, -0.7714762301918265,\
+-0.7698081734778982, -0.76814011676397, -0.7664720600500416, -0.7648040033361134, -0.7631359466221852, -0.7614678899082569,\
+-0.7597998331943286, -0.7581317764804003, -0.7564637197664721, -0.7547956630525438, -0.7531276063386155, -0.7514595496246872,\
+-0.749791492910759, -0.7481234361968306, -0.7464553794829024, -0.7447873227689742, -0.7431192660550459, -0.7414512093411176,\
+-0.7397831526271893, -0.7381150959132611, -0.7364470391993327, -0.7347789824854045, -0.7331109257714762, -0.731442869057548,\
+-0.7297748123436196, -0.7281067556296914, -0.7264386989157632, -0.7247706422018348, -0.7231025854879066, -0.7214345287739783,\
+-0.7197664720600501, -0.7180984153461217, -0.7164303586321935, -0.7147623019182652, -0.713094245204337, -0.7114261884904087,\
+-0.7097581317764804, -0.7080900750625522, -0.7064220183486238, -0.7047539616346956, -0.7030859049207673, -0.7014178482068391,\
+-0.6997497914929107, -0.6980817347789825, -0.6964136780650542, -0.6947456213511259, -0.6930775646371977, -0.6914095079232694,\
+-0.6897414512093412, -0.6880733944954128, -0.6864053377814846, -0.6847372810675563, -0.683069224353628, -0.6814011676396997,\
+-0.6797331109257715, -0.6780650542118432, -0.6763969974979149, -0.6747289407839867, -0.6730608840700584, -0.6713928273561302,\
+-0.6697247706422018, -0.6680567139282736, -0.6663886572143453, -0.664720600500417, -0.6630525437864887, -0.6613844870725605,\
+-0.6597164303586321, -0.6580483736447039, -0.6563803169307757, -0.6547122602168474, -0.6530442035029191, -0.6513761467889908,\
+-0.6497080900750626, -0.6480400333611342, -0.646371976647206, -0.6447039199332777, -0.6430358632193495, -0.6413678065054211,\
+-0.6396997497914929, -0.6380316930775647, -0.6363636363636364, -0.6346955796497081, -0.6330275229357798, -0.6313594662218516,\
+-0.6296914095079232, -0.628023352793995, -0.6263552960800667, -0.6246872393661385, -0.6230191826522101, -0.6213511259382819,\
+-0.6196830692243537, -0.6180150125104253, -0.6163469557964971, -0.6146788990825688, -0.6130108423686406, -0.6113427856547122,\
+-0.609674728940784, -0.6080066722268557, -0.6063386155129274, -0.6046705587989991, -0.6030025020850709, -0.6013344453711427,\
+-0.5996663886572143, -0.5979983319432861, -0.5963302752293578, -0.5946622185154296, -0.5929941618015012, -0.591326105087573,\
+-0.5896580483736447, -0.5879899916597164, -0.5863219349457881, -0.5846538782318599, -0.5829858215179317, -0.5813177648040033,\
+-0.5796497080900751, -0.5779816513761468, -0.5763135946622185, -0.5746455379482902, -0.572977481234362, -0.5713094245204337,\
+-0.5696413678065054, -0.5679733110925771, -0.5663052543786489, -0.5646371976647206, -0.5629691409507923, -0.5613010842368641,\
+-0.5596330275229358, -0.5579649708090075, -0.5562969140950792, -0.554628857381151, -0.5529608006672226, -0.5512927439532944,\
+-0.5496246872393661, -0.5479566305254379, -0.5462885738115096, -0.5446205170975813, -0.5429524603836531, -0.5412844036697247,\
+-0.5396163469557965, -0.5379482902418682, -0.53628023352794, -0.5346121768140116, -0.5329441201000834, -0.5312760633861552,\
+-0.5296080066722268, -0.5279399499582986, -0.5262718932443703, -0.5246038365304421, -0.5229357798165137, -0.5212677231025855,\
+-0.5195996663886572, -0.517931609674729, -0.5162635529608006, -0.5145954962468724, -0.5129274395329442, -0.5112593828190158,\
+-0.5095913261050876, -0.5079232693911593, -0.5062552126772311, -0.5045871559633027, -0.5029190992493745, -0.5012510425354462,\
+-0.49958298582151794, -0.49791492910758967, -0.4962468723936614, -0.4945788156797331, -0.49291075896580483, -0.49124270225187655,\
+-0.48957464553794827, -0.48790658882402, -0.48623853211009177, -0.4845704753961635, -0.4829024186822352, -0.48123436196830693,\
+-0.47956630525437866, -0.4778982485404504, -0.4762301918265221, -0.4745621351125938, -0.47289407839866554, -0.47122602168473726,\
+-0.469557964970809, -0.46788990825688076, -0.4662218515429525, -0.4645537948290242, -0.4628857381150959, -0.46121768140116765,\
+-0.45954962468723937, -0.4578815679733111, -0.4562135112593828, -0.45454545454545453, -0.45287739783152625, -0.451209341117598,\
+-0.44954128440366975, -0.44787322768974147, -0.4462051709758132, -0.4445371142618849, -0.44286905754795663, -0.44120100083402836,\
+-0.4395329441201001, -0.4378648874061718, -0.4361968306922435, -0.43452877397831524, -0.43286071726438696, -0.43119266055045874,\
+-0.42952460383653046, -0.4278565471226022, -0.4261884904086739, -0.4245204336947456, -0.42285237698081735, -0.42118432026688907,\
+-0.4195162635529608, -0.4178482068390325, -0.41618015012510423, -0.41451209341117595, -0.41284403669724773, -0.41117597998331945,\
+-0.40950792326939117, -0.4078398665554629, -0.4061718098415346, -0.40450375312760634, -0.40283569641367806, -0.4011676396997498,\
+-0.3994995829858215, -0.3978315262718932, -0.396163469557965, -0.3944954128440367, -0.39282735613010844, -0.39115929941618016,\
+-0.3894912427022519, -0.3878231859883236, -0.3861551292743953, -0.38448707256046705, -0.38281901584653877, -0.3811509591326105,\
+-0.3794829024186822, -0.377814845704754, -0.3761467889908257, -0.37447873227689743, -0.37281067556296915, -0.3711426188490409,\
+-0.3694745621351126, -0.3678065054211843, -0.36613844870725604, -0.36447039199332776, -0.3628023352793995, -0.3611342785654712,\
+-0.359466221851543, -0.3577981651376147, -0.3561301084236864, -0.35446205170975814, -0.35279399499582986, -0.3511259382819016,\
+-0.3494578815679733, -0.347789824854045, -0.34612176814011675, -0.34445371142618847, -0.3427856547122602, -0.34111759799833197,\
+-0.3394495412844037, -0.3377814845704754, -0.33611342785654713, -0.33444537114261885, -0.3327773144286906, -0.3311092577147623,\
+-0.329441201000834, -0.32777314428690574, -0.32610508757297746, -0.3244370308590492, -0.32276897414512096, -0.3211009174311927,\
+-0.3194328607172644, -0.3177648040033361, -0.31609674728940784, -0.31442869057547956, -0.3127606338615513, -0.311092577147623,\
+-0.3094245204336947, -0.30775646371976645, -0.3060884070058382, -0.30442035029190995, -0.30275229357798167, -0.3010842368640534,\
+-0.2994161801501251, -0.29774812343619683, -0.29608006672226855, -0.2944120100083403, -0.292743953294412, -0.2910758965804837,\
+-0.28940783986655544, -0.2877397831526272, -0.28607172643869894, -0.28440366972477066, -0.2827356130108424, -0.2810675562969141,\
+-0.2793994995829858, -0.27773144286905754, -0.27606338615512926, -0.274395329441201, -0.2727272727272727, -0.27105921601334443,\
+-0.2693911592994162, -0.2677231025854879, -0.26605504587155965, -0.26438698915763137, -0.2627189324437031, -0.2610508757297748,\
+-0.25938281901584653, -0.25771476230191825, -0.25604670558799, -0.2543786488740617, -0.2527105921601334, -0.2510425354462052,\
+-0.2493744787322769, -0.24770642201834864, -0.24603836530442036, -0.24437030859049208, -0.2427022518765638, -0.24103419516263552,\
+-0.23936613844870724, -0.237698081734779, -0.23603002502085071, -0.23436196830692244, -0.23269391159299416, -0.23102585487906588,\
+-0.22935779816513763, -0.22768974145120935, -0.22602168473728107, -0.2243536280233528, -0.2226855713094245, -0.22101751459549623,\
+-0.21934945788156798, -0.2176814011676397, -0.21601334445371143, -0.21434528773978315, -0.21267723102585487, -0.21100917431192662,\
+-0.20934111759799834, -0.20767306088407006, -0.20600500417014178, -0.2043369474562135, -0.20266889074228525, -0.20100083402835697,\
+-0.1993327773144287, -0.19766472060050042, -0.19599666388657214, -0.19432860717264386, -0.1926605504587156, -0.19099249374478733,\
+-0.18932443703085905, -0.18765638031693077, -0.1859883236030025, -0.18432026688907424, -0.18265221017514596, -0.18098415346121768,\
+-0.1793160967472894, -0.17764804003336113, -0.17597998331943285, -0.1743119266055046, -0.17264386989157632, -0.17097581317764804,\
+-0.16930775646371976, -0.16763969974979148, -0.16597164303586323, -0.16430358632193495, -0.16263552960800667, -0.1609674728940784,\
+-0.15929941618015012, -0.15763135946622187, -0.1559633027522936, -0.1542952460383653, -0.15262718932443703, -0.15095913261050875,\
+-0.14929107589658047, -0.14762301918265222, -0.14595496246872394, -0.14428690575479566, -0.14261884904086738, -0.1409507923269391,\
+-0.13928273561301086, -0.13761467889908258, -0.1359466221851543, -0.13427856547122602, -0.13261050875729774, -0.13094245204336946,\
+-0.1292743953294412, -0.12760633861551293, -0.12593828190158465, -0.12427022518765637, -0.12260216847372811, -0.12093411175979983,\
+-0.11926605504587157, -0.11759799833194329, -0.11592994161801501, -0.11426188490408674, -0.11259382819015847, -0.11092577147623019,\
+-0.10925771476230192, -0.10758965804837364, -0.10592160133444536, -0.1042535446205171, -0.10258548790658882, -0.10091743119266056,\
+-0.09924937447873228, -0.097581317764804, -0.09591326105087573, -0.09424520433694746, -0.09257714762301918, -0.09090909090909091,\
+-0.08924103419516263, -0.08757297748123437, -0.08590492076730609, -0.08423686405337781, -0.08256880733944955, -0.08090075062552127,\
+-0.07923269391159299, -0.07756463719766472, -0.07589658048373644, -0.07422852376980818, -0.0725604670558799, -0.07089241034195162,\
+-0.06922435362802336, -0.06755629691409508, -0.0658882402001668, -0.06422018348623854, -0.06255212677231026, -0.060884070058381985,\
+-0.05921601334445371, -0.057547956630525435, -0.05587989991659716, -0.05421184320266889, -0.05254378648874062, -0.05087572977481234,\
+-0.04920767306088407, -0.0475396163469558, -0.045871559633027525, -0.04420350291909925, -0.042535446205170975, -0.0408673894912427,\
+-0.03919933277731443, -0.03753127606338615, -0.03586321934945788, -0.03419516263552961, -0.03252710592160134, -0.030859049207673062,\
+-0.029190992493744787, -0.027522935779816515, -0.02585487906588824, -0.02418682235195997, -0.022518765638031693, -0.020850708924103418,\
+-0.019182652210175146, -0.01751459549624687, -0.0158465387823186, -0.014178482068390326, -0.012510425354462052, -0.010842368640533779,\
+-0.009174311926605505, -0.007506255212677231, -0.005838198498748957, -0.004170141784820684, -0.0025020850708924102, -0.0008340283569641367,\
+0.0008340283569641367, 0.0025020850708924102, 0.004170141784820684, 0.005838198498748957, 0.007506255212677231, 0.009174311926605505,\
+0.010842368640533779, 0.012510425354462052, 0.014178482068390326, 0.0158465387823186, 0.01751459549624687, 0.019182652210175146,\
+0.020850708924103418, 0.022518765638031693, 0.02418682235195997, 0.02585487906588824, 0.027522935779816515, 0.029190992493744787,\
+0.030859049207673062, 0.03252710592160134, 0.03419516263552961, 0.03586321934945788, 0.03753127606338615, 0.03919933277731443,\
+0.0408673894912427, 0.042535446205170975, 0.04420350291909925, 0.045871559633027525, 0.0475396163469558, 0.04920767306088407,\
+0.05087572977481234, 0.05254378648874062, 0.05421184320266889, 0.05587989991659716, 0.057547956630525435, 0.05921601334445371,\
+0.060884070058381985, 0.06255212677231026, 0.06422018348623854, 0.0658882402001668, 0.06755629691409508, 0.06922435362802336,\
+0.07089241034195162, 0.0725604670558799, 0.07422852376980818, 0.07589658048373644, 0.07756463719766472, 0.07923269391159299,\
+0.08090075062552127, 0.08256880733944955, 0.08423686405337781, 0.08590492076730609, 0.08757297748123437, 0.08924103419516263,\
+0.09090909090909091, 0.09257714762301918, 0.09424520433694746, 0.09591326105087573, 0.097581317764804, 0.09924937447873228,\
+0.10091743119266056, 0.10258548790658882, 0.1042535446205171, 0.10592160133444536, 0.10758965804837364, 0.10925771476230192,\
+0.11092577147623019, 0.11259382819015847, 0.11426188490408674, 0.11592994161801501, 0.11759799833194329, 0.11926605504587157,\
+0.12093411175979983, 0.12260216847372811, 0.12427022518765637, 0.12593828190158465, 0.12760633861551293, 0.1292743953294412,\
+0.13094245204336946, 0.13261050875729774, 0.13427856547122602, 0.1359466221851543, 0.13761467889908258, 0.13928273561301086,\
+0.1409507923269391, 0.14261884904086738, 0.14428690575479566, 0.14595496246872394, 0.14762301918265222, 0.14929107589658047,\
+0.15095913261050875, 0.15262718932443703, 0.1542952460383653, 0.1559633027522936, 0.15763135946622187, 0.15929941618015012,\
+0.1609674728940784, 0.16263552960800667, 0.16430358632193495, 0.16597164303586323, 0.16763969974979148, 0.16930775646371976,\
+0.17097581317764804, 0.17264386989157632, 0.1743119266055046, 0.17597998331943285, 0.17764804003336113, 0.1793160967472894,\
+0.18098415346121768, 0.18265221017514596, 0.18432026688907424, 0.1859883236030025, 0.18765638031693077, 0.18932443703085905,\
+0.19099249374478733, 0.1926605504587156, 0.19432860717264386, 0.19599666388657214, 0.19766472060050042, 0.1993327773144287,\
+0.20100083402835697, 0.20266889074228525, 0.2043369474562135, 0.20600500417014178, 0.20767306088407006, 0.20934111759799834,\
+0.21100917431192662, 0.21267723102585487, 0.21434528773978315, 0.21601334445371143, 0.2176814011676397, 0.21934945788156798,\
+0.22101751459549623, 0.2226855713094245, 0.2243536280233528, 0.22602168473728107, 0.22768974145120935, 0.22935779816513763,\
+0.23102585487906588, 0.23269391159299416, 0.23436196830692244, 0.23603002502085071, 0.237698081734779, 0.23936613844870724,\
+0.24103419516263552, 0.2427022518765638, 0.24437030859049208, 0.24603836530442036, 0.24770642201834864, 0.2493744787322769,\
+0.2510425354462052, 0.2527105921601334, 0.2543786488740617, 0.25604670558799, 0.25771476230191825, 0.25938281901584653,\
+0.2610508757297748, 0.2627189324437031, 0.26438698915763137, 0.26605504587155965, 0.2677231025854879, 0.2693911592994162,\
+0.27105921601334443, 0.2727272727272727, 0.274395329441201, 0.27606338615512926, 0.27773144286905754, 0.2793994995829858,\
+0.2810675562969141, 0.2827356130108424, 0.28440366972477066, 0.28607172643869894, 0.2877397831526272, 0.28940783986655544,\
+0.2910758965804837, 0.292743953294412, 0.2944120100083403, 0.29608006672226855, 0.29774812343619683, 0.2994161801501251,\
+0.3010842368640534, 0.30275229357798167, 0.30442035029190995, 0.3060884070058382, 0.30775646371976645, 0.3094245204336947,\
+0.311092577147623, 0.3127606338615513, 0.31442869057547956, 0.31609674728940784, 0.3177648040033361, 0.3194328607172644,\
+0.3211009174311927, 0.32276897414512096, 0.3244370308590492, 0.32610508757297746, 0.32777314428690574, 0.329441201000834,\
+0.3311092577147623, 0.3327773144286906, 0.33444537114261885, 0.33611342785654713, 0.3377814845704754, 0.3394495412844037,\
+0.34111759799833197, 0.3427856547122602, 0.34445371142618847, 0.34612176814011675, 0.347789824854045, 0.3494578815679733,\
+0.3511259382819016, 0.35279399499582986, 0.35446205170975814, 0.3561301084236864, 0.3577981651376147, 0.359466221851543,\
+0.3611342785654712, 0.3628023352793995, 0.36447039199332776, 0.36613844870725604, 0.3678065054211843, 0.3694745621351126,\
+0.3711426188490409, 0.37281067556296915, 0.37447873227689743, 0.3761467889908257, 0.377814845704754, 0.3794829024186822,\
+0.3811509591326105, 0.38281901584653877, 0.38448707256046705, 0.3861551292743953, 0.3878231859883236, 0.3894912427022519,\
+0.39115929941618016, 0.39282735613010844, 0.3944954128440367, 0.396163469557965, 0.3978315262718932, 0.3994995829858215,\
+0.4011676396997498, 0.40283569641367806, 0.40450375312760634, 0.4061718098415346, 0.4078398665554629, 0.40950792326939117,\
+0.41117597998331945, 0.41284403669724773, 0.41451209341117595, 0.41618015012510423, 0.4178482068390325, 0.4195162635529608,\
+0.42118432026688907, 0.42285237698081735, 0.4245204336947456, 0.4261884904086739, 0.4278565471226022, 0.42952460383653046,\
+0.43119266055045874, 0.43286071726438696, 0.43452877397831524, 0.4361968306922435, 0.4378648874061718, 0.4395329441201001,\
+0.44120100083402836, 0.44286905754795663, 0.4445371142618849, 0.4462051709758132, 0.44787322768974147, 0.44954128440366975,\
+0.451209341117598, 0.45287739783152625, 0.45454545454545453, 0.4562135112593828, 0.4578815679733111, 0.45954962468723937,\
+0.46121768140116765, 0.4628857381150959, 0.4645537948290242, 0.4662218515429525, 0.46788990825688076, 0.469557964970809,\
+0.47122602168473726, 0.47289407839866554, 0.4745621351125938, 0.4762301918265221, 0.4778982485404504, 0.47956630525437866,\
+0.48123436196830693, 0.4829024186822352, 0.4845704753961635, 0.48623853211009177, 0.48790658882402, 0.48957464553794827,\
+0.49124270225187655, 0.49291075896580483, 0.4945788156797331, 0.4962468723936614, 0.49791492910758967, 0.49958298582151794,\
+0.5012510425354462, 0.5029190992493745, 0.5045871559633027, 0.5062552126772311, 0.5079232693911593, 0.5095913261050876,\
+0.5112593828190158, 0.5129274395329442, 0.5145954962468724, 0.5162635529608006, 0.517931609674729, 0.5195996663886572,\
+0.5212677231025855, 0.5229357798165137, 0.5246038365304421, 0.5262718932443703, 0.5279399499582986, 0.5296080066722268,\
+0.5312760633861552, 0.5329441201000834, 0.5346121768140116, 0.53628023352794, 0.5379482902418682, 0.5396163469557965,\
+0.5412844036697247, 0.5429524603836531, 0.5446205170975813, 0.5462885738115096, 0.5479566305254379, 0.5496246872393661,\
+0.5512927439532944, 0.5529608006672226, 0.554628857381151, 0.5562969140950792, 0.5579649708090075, 0.5596330275229358,\
+0.5613010842368641, 0.5629691409507923, 0.5646371976647206, 0.5663052543786489, 0.5679733110925771, 0.5696413678065054,\
+0.5713094245204337, 0.572977481234362, 0.5746455379482902, 0.5763135946622185, 0.5779816513761468, 0.5796497080900751,\
+0.5813177648040033, 0.5829858215179317, 0.5846538782318599, 0.5863219349457881, 0.5879899916597164, 0.5896580483736447,\
+0.591326105087573, 0.5929941618015012, 0.5946622185154296, 0.5963302752293578, 0.5979983319432861, 0.5996663886572143,\
+0.6013344453711427, 0.6030025020850709, 0.6046705587989991, 0.6063386155129274, 0.6080066722268557, 0.609674728940784,\
+0.6113427856547122, 0.6130108423686406, 0.6146788990825688, 0.6163469557964971, 0.6180150125104253, 0.6196830692243537,\
+0.6213511259382819, 0.6230191826522101, 0.6246872393661385, 0.6263552960800667, 0.628023352793995, 0.6296914095079232,\
+0.6313594662218516, 0.6330275229357798, 0.6346955796497081, 0.6363636363636364, 0.6380316930775647, 0.6396997497914929,\
+0.6413678065054211, 0.6430358632193495, 0.6447039199332777, 0.646371976647206, 0.6480400333611342, 0.6497080900750626,\
+0.6513761467889908, 0.6530442035029191, 0.6547122602168474, 0.6563803169307757, 0.6580483736447039, 0.6597164303586321,\
+0.6613844870725605, 0.6630525437864887, 0.664720600500417, 0.6663886572143453, 0.6680567139282736, 0.6697247706422018,\
+0.6713928273561302, 0.6730608840700584, 0.6747289407839867, 0.6763969974979149, 0.6780650542118432, 0.6797331109257715,\
+0.6814011676396997, 0.683069224353628, 0.6847372810675563, 0.6864053377814846, 0.6880733944954128, 0.6897414512093412,\
+0.6914095079232694, 0.6930775646371977, 0.6947456213511259, 0.6964136780650542, 0.6980817347789825, 0.6997497914929107,\
+0.7014178482068391, 0.7030859049207673, 0.7047539616346956, 0.7064220183486238, 0.7080900750625522, 0.7097581317764804,\
+0.7114261884904087, 0.713094245204337, 0.7147623019182652, 0.7164303586321935, 0.7180984153461217, 0.7197664720600501,\
+0.7214345287739783, 0.7231025854879066, 0.7247706422018348, 0.7264386989157632, 0.7281067556296914, 0.7297748123436196,\
+0.731442869057548, 0.7331109257714762, 0.7347789824854045, 0.7364470391993327, 0.7381150959132611, 0.7397831526271893,\
+0.7414512093411176, 0.7431192660550459, 0.7447873227689742, 0.7464553794829024, 0.7481234361968306, 0.749791492910759,\
+0.7514595496246872, 0.7531276063386155, 0.7547956630525438, 0.7564637197664721, 0.7581317764804003, 0.7597998331943286,\
+0.7614678899082569, 0.7631359466221852, 0.7648040033361134, 0.7664720600500416, 0.76814011676397, 0.7698081734778982,\
+0.7714762301918265, 0.7731442869057548, 0.7748123436196831, 0.7764804003336113, 0.7781484570475397, 0.7798165137614679,\
+0.7814845704753962, 0.7831526271893244, 0.7848206839032527, 0.786488740617181, 0.7881567973311092, 0.7898248540450375,\
+0.7914929107589658, 0.7931609674728941, 0.7948290241868223, 0.7964970809007507, 0.7981651376146789, 0.7998331943286072,\
+0.8015012510425354, 0.8031693077564637, 0.804837364470392, 0.8065054211843202, 0.8081734778982486, 0.8098415346121768,\
+0.8115095913261051, 0.8131776480400333, 0.8148457047539617, 0.8165137614678899, 0.8181818181818182, 0.8198498748957465,\
+0.8215179316096747, 0.823185988323603, 0.8248540450375312, 0.8265221017514596, 0.8281901584653878, 0.8298582151793161,\
+0.8315262718932444, 0.8331943286071727, 0.8348623853211009, 0.8365304420350292, 0.8381984987489575, 0.8398665554628857,\
+0.841534612176814, 0.8432026688907422, 0.8448707256046706, 0.8465387823185988, 0.8482068390325271, 0.8498748957464554,\
+0.8515429524603837, 0.8532110091743119, 0.8548790658882403, 0.8565471226021685, 0.8582151793160967, 0.859883236030025,\
+0.8615512927439533, 0.8632193494578816, 0.8648874061718098, 0.8665554628857381, 0.8682235195996664, 0.8698915763135947,\
+0.8715596330275229, 0.8732276897414513, 0.8748957464553795, 0.8765638031693077, 0.878231859883236, 0.8798999165971643,\
+0.8815679733110926, 0.8832360300250208, 0.8849040867389492, 0.8865721434528774, 0.8882402001668057, 0.8899082568807339,\
+0.8915763135946623, 0.8932443703085905, 0.8949124270225187, 0.896580483736447, 0.8982485404503753, 0.8999165971643036,\
+0.9015846538782318, 0.9032527105921602, 0.9049207673060884, 0.9065888240200167, 0.908256880733945, 0.9099249374478732,\
+0.9115929941618015, 0.9132610508757297, 0.9149291075896581, 0.9165971643035863, 0.9182652210175146, 0.9199332777314428,\
+0.9216013344453712, 0.9232693911592994, 0.9249374478732277, 0.926605504587156, 0.9282735613010842, 0.9299416180150125,\
+0.9316096747289407, 0.9332777314428691, 0.9349457881567973, 0.9366138448707256, 0.9382819015846539, 0.9399499582985822,\
+0.9416180150125104, 0.9432860717264387, 0.944954128440367, 0.9466221851542952, 0.9482902418682235, 0.9499582985821518,\
+0.9516263552960801, 0.9532944120100083, 0.9549624687239366, 0.9566305254378649, 0.9582985821517932, 0.9599666388657214,\
+0.9616346955796498, 0.963302752293578, 0.9649708090075062, 0.9666388657214345, 0.9683069224353628, 0.9699749791492911,\
+0.9716430358632193, 0.9733110925771477, 0.9749791492910759, 0.9766472060050042, 0.9783152627189324, 0.9799833194328608,\
+0.981651376146789, 0.9833194328607172, 0.9849874895746455, 0.9866555462885738, 0.9883236030025021, 0.9899916597164303,\
+0.9916597164303587, 0.9933277731442869, 0.9949958298582152, 0.9966638865721434, 0.9983319432860718, 1.
+};/* end of data for QNMData_a */
+
+/* fring for Mode 22 according to Berti et al, CQG, 26, 163001, (2009); arXiv:0905.2975 */
+static const int QNMData_fring_22_length = 1200;
+static const double QNMData_fring_22[] = {
+0.04640083138658345, 0.046416045285288365, 0.046431221903556134, 0.04644633303324355, 0.046461350466207404, 0.0464762459943045,\
+0.04649099140939163, 0.046505590357034846, 0.046520172888280434, 0.046534803653796704, 0.04654949035004092, 0.04656422577735437,\
+0.04657900074341005, 0.04659380753972615, 0.04660864046649851, 0.0466234956120709, 0.046638370328431655, 0.04665326289175636,\
+0.04666817224107223, 0.04668309770712659, 0.04669803889655771, 0.04671299558734215, 0.046727967686475164, 0.04674295517194224,\
+0.046757958057529934, 0.046772976345848476, 0.046788010095221454, 0.04680305936287465, 0.04681812421218104, 0.04683320467701052,\
+0.04684830082621223, 0.046863412705774134, 0.046878540369418804, 0.04689368384461222, 0.04690884319602748, 0.04692401843400433,\
+0.046939209616607774, 0.04695441677124491, 0.04696963994438345, 0.04698487916745876, 0.04700013446398896, 0.04701540587150822,\
+0.04703069342739411, 0.04704599715182191, 0.04706131709080824, 0.047076653270592454, 0.047092005714512115, 0.0471073744505355,\
+0.047122759536119094, 0.0471381609688458, 0.04715357879601272, 0.04716901304751874, 0.047184463749948564, 0.047199930940509734,\
+0.047215414644735026, 0.04723091490178183, 0.0472464317300051, 0.04726196516739749, 0.04727751526169452, 0.047293082009867045,\
+0.04730866547663811, 0.04732426567609586, 0.04733988262845993, 0.04735551640597694, 0.04737116698855076, 0.04738683445482311,\
+0.0474025188118124, 0.047418220098173675, 0.047433938347383235, 0.04744967359156163, 0.04746542584914413, 0.04748119517037804,\
+0.04749698159007448, 0.0475127851389163, 0.047528605830676626, 0.04754444371600672, 0.047560298824854144, 0.04757617119809698,\
+0.0475920608631721, 0.04760796784455911, 0.04762389219279064, 0.047639833924829386, 0.04765579307905283, 0.0476717696940082,\
+0.047687763796659385, 0.047703775432360034, 0.04771980463319255, 0.047735851415733034, 0.04775191583277254, 0.04776799791612676,\
+0.04778409769711027, 0.04780021520606504, 0.047816350476269934, 0.047832503561359346, 0.04784867447693275, 0.0478648632755591,\
+0.04788106996184503, 0.04789729460221568, 0.047913537214713794, 0.04792979783967174, 0.04794607652390947, 0.04796237327552489,\
+0.04797868815260338, 0.04799502118294788, 0.048011372403329845, 0.04802774186069244, 0.04804412956887076, 0.04806053558473838,\
+0.04807695992968822, 0.048093402638321944, 0.04810986376499624, 0.0481263433428112, 0.048142841384172734, 0.04815935796087274,\
+0.0481758930783604, 0.04819244678792947, 0.04820901913366398, 0.04822561013794186, 0.0482422198460762, 0.048258848302542665,\
+0.04827549552989936, 0.048292161565343446, 0.04830884645675486, 0.04832555024556013, 0.04834227296626944, 0.04835901464892196,\
+0.04837577533000013, 0.04839255505923284, 0.04840935387028627, 0.04842617180031043, 0.048443008888979074, 0.04845986517007509,\
+0.04847674069593977, 0.048493635480251235, 0.048510549589583084, 0.04852748305250568, 0.0485444358976066, 0.04856140817913823,\
+0.048578399926150845, 0.04859541119324516, 0.04861244199604985, 0.04862949236721213, 0.04864656239545641, 0.04866365208806359,\
+0.048680761493203314, 0.04869789065125766, 0.04871503958913544, 0.04873220835744691, 0.048749396998717866, 0.04876660555692777,\
+0.04878383406095885, 0.04880108256074607, 0.048818351086993936, 0.04883563970134531, 0.04885294842314372, 0.0488702772942541,\
+0.04888762637104158, 0.048904995686355125, 0.048922385290254645, 0.04893979521163742, 0.04895722549997, 0.04897467619692568,\
+0.04899214734040893, 0.049009638976453426, 0.049027151146086106, 0.049044683899824124, 0.04906223726942281, 0.04907981129835546,\
+0.04909740604073947, 0.04911502152528176, 0.04913265780347175, 0.049150314921015806, 0.049167992909142116, 0.04918569181289315,\
+0.049203411689653254, 0.049221152586075595, 0.04923891452520733, 0.04925669756485148, 0.049274501737255075, 0.04929232711278088,\
+0.049310173696213495, 0.049328041574874415, 0.049345930765989844, 0.049363841316960616, 0.049381773276815547, 0.049399726691204314,\
+0.049417701616154955, 0.04943569807710016, 0.049453716119530367, 0.04947175581701263, 0.04948981718612529, 0.049507900278435595,\
+0.049526005145640525, 0.04954413184641428, 0.04956228039670222, 0.04958045087170554, 0.04959864328976231, 0.04961685773500671,\
+0.04963509421511142, 0.04965335280546644, 0.04967163353756218, 0.049689936459145136, 0.04970826162551469, 0.04972660908237226,\
+0.04974497888122275, 0.049763371051759556, 0.049781785659566084, 0.049800222757829485, 0.04981868236729268, 0.049837164560333186,\
+0.04985566938305525, 0.04987419688422461, 0.0498927470949873, 0.04991132008096813, 0.049929915898170064, 0.049948534574124855,\
+0.04996717617439864, 0.04998584074354783, 0.05000452833887103, 0.05002323898900747, 0.05004197277539656, 0.05006072972204698,\
+0.05007950988090344, 0.0500983133159333, 0.05011714006947681, 0.0501359902047214, 0.05015486375090459, 0.05017376077263721,\
+0.05019268131722949, 0.05021162543287373, 0.05023059318450996, 0.050249584611107394, 0.05026859977549954, 0.050287638719384735,\
+0.05030670149717526, 0.0503257881540156, 0.05034489877353903, 0.05036403335651832, 0.050383192002612154, 0.05040237474890266,\
+0.05042158164174317, 0.050440812742846265, 0.05046006808833395, 0.05047934776253666, 0.05049865179397568, 0.050517980251718324,\
+0.05053733317896132, 0.05055671064064799, 0.05057611266861909, 0.050595539351143436, 0.05061499071619598, 0.05063446682555602,\
+0.050653967745234084, 0.05067349352504582, 0.050693044201216834, 0.050712619861889144, 0.05073222054663685, 0.05075184630819724,\
+0.050771497202081156, 0.05079117329842625, 0.05081087463030111, 0.050830601278496444, 0.0508503532966209, 0.05087013072968228,\
+0.05088993362872194, 0.05090976207209568, 0.050929616108211034, 0.05094949579512016, 0.05096940119052355, 0.05098933235995948,\
+0.05100928933327537, 0.05102927221566828, 0.05104928101774452, 0.05106931583908438, 0.05108937670816926, 0.05110946369323228,\
+0.0511295768637469, 0.05114971628253486, 0.05116988199510067, 0.05119007406338287, 0.0512102925502112, 0.05123053750847175,\
+0.051250809021103086, 0.05127110711958714, 0.05129143188334149, 0.05131178337710238, 0.051332161652914536, 0.05135256677512661,\
+0.05137299880740934, 0.05139345779148646, 0.05141394381879378, 0.05143445695561748, 0.05145499722831299, 0.05147556472647982,\
+0.05149615951298624, 0.0515167816505525, 0.051537431186738696, 0.051558108201745015, 0.051578812738874755, 0.05159954489715709,\
+0.051620304714722065, 0.051641092260274336, 0.051661907598562797, 0.05168275079300234, 0.051703621908285424, 0.05172452103011201,\
+0.05174544818950133, 0.05176640348299105, 0.05178738695946276, 0.0518083986865329, 0.051829438726130043, 0.05185050717416496,\
+0.05187160406269102, 0.05189272945585858, 0.051913883458791145, 0.05193506611662089, 0.051956277475378114, 0.051977517644343774,\
+0.05199878666575308, 0.05202008461882329, 0.052041411561096595, 0.0520627675694109, 0.05208415272068886, 0.052105567060545574,\
+0.05212701068680378, 0.05214848364955848, 0.05216998603043312, 0.05219151788396809, 0.05221307930194529, 0.05223467033499639,\
+0.05225629106087619, 0.05227794156322106, 0.052299621904578535, 0.05232133215561966, 0.05234307237882843, 0.052364842669152506,\
+0.052386643065340036, 0.05240847368041487, 0.05243033455970757, 0.052452225795841446, 0.0524741474281821, 0.05249609957093054,\
+0.05251808228376514, 0.052540095621421284, 0.05256213968202921, 0.052584214531752806, 0.052606320247210896, 0.05262845690221681,\
+0.05265062458762773, 0.05267282334948495, 0.05269505327275708, 0.05271731445486177, 0.052739606942525954, 0.052761930838124166,\
+0.052784286203975586, 0.05280667313100323, 0.052829091672623785, 0.05285154194183919, 0.05287402397916999, 0.05289653787992338,\
+0.05291908372654381, 0.05294166161342361, 0.05296427157484512, 0.052986913727622785, 0.053009588141609144, 0.05303229489562243,\
+0.05305503408303269, 0.05307780575678394, 0.053100610014509865, 0.05312344693180525, 0.053146316601207326, 0.05316921910972022,\
+0.05319215450593079, 0.053215122907175026, 0.05323812438347006, 0.053261159026563434, 0.053284226892079886, 0.05330732808607429,\
+0.053330462704425215, 0.053353630806121384, 0.05337683247722243, 0.053400067814285745, 0.053423336914968464, 0.05344663982743775,\
+0.05346997666857617, 0.05349334751606103, 0.053516752446365175, 0.05354019157272944, 0.053563664938810804, 0.05358717267519189,\
+0.05361071485214486, 0.05363429154364783, 0.05365790287033108, 0.05368154888782735, 0.05370522969508792, 0.05372894539385669,\
+0.053752696061051444, 0.053776481798337404, 0.053800302685099825, 0.05382415880965255, 0.05384805027996812, 0.053871977166666876,\
+0.053895939572774346, 0.053919937584768166, 0.05394397129960855, 0.053968040813376965, 0.05399214621525908, 0.05401628758634181,\
+0.05404046504228144, 0.054064678658980014, 0.054088928548528994, 0.05411321478302749, 0.05413753747035756, 0.054161896707643264,\
+0.05418629259740106, 0.054210725217819486, 0.05423519467749454, 0.05425970107020181, 0.054284244482617636, 0.05430882503148726,\
+0.05433344281383338, 0.05435809790798193, 0.05438279041817893, 0.05440752046452551, 0.05443228812707754, 0.054457093508754835,\
+0.05448193671725085, 0.054506817843942845, 0.054531736997288964, 0.05455669427056419, 0.054581689758571944, 0.05460672359270678,\
+0.05463179585107996, 0.054656906648533676, 0.05468205607774541, 0.05470724423487869, 0.054732471254076286, 0.05475773722213824,\
+0.05478304223126789, 0.054808386417210246, 0.054833769849128265, 0.05485919267809142, 0.05488465496411754, 0.05491015684448605,\
+0.05493569841828071, 0.05496127978355831, 0.05498690106859987, 0.055012562356617944, 0.05503826378519088, 0.05506400543902898,\
+0.05508978745343008, 0.05511560990625767, 0.05514147294603834, 0.055167376654561194, 0.05519332114267393, 0.05521930654818541,\
+0.05524533296667673, 0.055271400511897835, 0.055297509287412956, 0.05532365943317287, 0.05534985104532537, 0.05537608424460922,\
+0.0554023591388297, 0.055428675853745855, 0.05545503449337319, 0.05548143518038537, 0.05550787803567391, 0.055534363179108696,\
+0.05556089072203235, 0.05558746079276706, 0.05561407350465249, 0.05564072896166252, 0.05566742730150821, 0.05569416864650448,\
+0.05572095311268288, 0.05574778081815047, 0.05577465189191901, 0.05580156644853604, 0.05582852460590799, 0.05585552651151354,\
+0.05588257227002919, 0.05590966201480146, 0.05593679585575743, 0.05596397393344603, 0.055991196374327264, 0.05601846329164129,\
+0.056045774825968446, 0.05607313110316331, 0.05610053224737768, 0.05612797838346555, 0.05615546965571739, 0.05618300617404836,\
+0.056210588080984426, 0.056238215511439954, 0.05626588859205143, 0.05629360744724898, 0.056321372210433734, 0.056349183019342476,\
+0.056377040021547024, 0.05640494331850579, 0.056432893084057405, 0.05646088941264146, 0.05648893247737326, 0.056517022398672775,\
+0.056545159303523274, 0.05657334334336537, 0.0566015746555521, 0.05662985336551876, 0.056658179641914774, 0.056686553586743293,\
+0.05671497536330199, 0.0567434451148402, 0.05677196297828451, 0.05680052909534249, 0.056829143590513984, 0.056857806641478624,\
+0.05688651837370633, 0.056915278941370676, 0.05694408848202213, 0.05697294714171106, 0.057001855064766786, 0.05703081240521512,\
+0.05705981930170699, 0.05708887591398755, 0.05711798238395735, 0.05714713887397098, 0.057176345526559307, 0.05720560248445631,\
+0.05723490990671166, 0.05726426793965907, 0.057293676750477425, 0.05732313648995693, 0.05735264730158331, 0.05738220935411579,\
+0.057411822786245174, 0.05744148777640781, 0.05747120446880723, 0.05750097302258963, 0.057530793594380576, 0.057560666345005576,\
+0.05759059144048778, 0.05762056904189127, 0.05765059930591788, 0.057680682390089874, 0.05771081846720325, 0.05774100768407587,\
+0.0577712502359182, 0.05780154626870946, 0.05783189594013837, 0.05786229942397183, 0.05789275692761997, 0.05792326855895615,\
+0.05795383450454001, 0.05798445493964121, 0.05801513004046105, 0.05804585996684843, 0.058076644903464265, 0.05810748501136827,\
+0.05813838046907996, 0.058169331450282545, 0.058200338146844714, 0.05823140071213771, 0.05826251932283224, 0.058293694185738786,\
+0.058324925437837426, 0.058356213290897074, 0.05838755791336733, 0.0584189594814535, 0.05845041818485983, 0.05848193421418962,\
+0.058513507739413564, 0.05854513894039099, 0.058576828017207, 0.05860857514408799, 0.058640380515156194, 0.05867224432040756,\
+0.05870416673566146, 0.05873614797395607, 0.05876818819838471, 0.05880028761956125, 0.05883244643744913, 0.058864664810013574,\
+0.05889694296645908, 0.058929281096982145, 0.05896167936835614, 0.05899413802423128, 0.05902665722237533, 0.05905923717061363,\
+0.05909187809305216, 0.05912458016862594, 0.05915734359327818, 0.05919016859150924, 0.05922305534910527, 0.05925600408803763,\
+0.059289014984606696, 0.05932208828288423, 0.059355224154907564, 0.05938842283783196, 0.059421684537515035, 0.05945500944514747,\
+0.05948839778329334, 0.059521849778107525, 0.05955536562359741, 0.0595889455386083, 0.05962258974803167, 0.05965629847166624,\
+0.05969007191581925, 0.05972391030292596, 0.05975781384532689, 0.05979178278121788, 0.059825817313376904, 0.0598599176911774,\
+0.05989408412224005, 0.059928316830968116, 0.05996261606225925, 0.059996982021780464, 0.06003141494697049, 0.06006591506441675,\
+0.06010048262310349, 0.06013511783372122, 0.06016982095255301, 0.06020459218446821, 0.06023943179845929, 0.06027433999865859,\
+0.060309317057488765, 0.06034436319391422, 0.060379478647713376, 0.06041466367048005, 0.0604499185014342, 0.06048524339430952,\
+0.06052063857798629, 0.060556104307576145, 0.06059164084319936, 0.060627248414596976, 0.06066292729300014, 0.06069867770999867,\
+0.060734499934463136, 0.06077039422141819, 0.060806360827135045, 0.0608423999893577, 0.06087851199717229, 0.06091469708740355,\
+0.06095095553372722, 0.06098728759448922, 0.06102369354314139, 0.06106017363520467, 0.06109672813738292, 0.061133357325239286,\
+0.06117006147273227, 0.0612068408434555, 0.06124369570753412, 0.061280626338732554, 0.06131763303319828, 0.06135471604256311,\
+0.06139187565276798, 0.061429112155273566, 0.06146642582735172, 0.06150381694355167, 0.061541285792193215, 0.06157883267103826,\
+0.06161645785818982, 0.06165416163382778, 0.06169194430325959, 0.06172980616218852, 0.06176774749326967, 0.06180576859741373,\
+0.061843869776511996, 0.0618820513184556, 0.06192031353709836, 0.06195865671837061, 0.06199708118320639, 0.06203558722721956,\
+0.062074175166389786, 0.062112845303525045, 0.06215159793950075, 0.062190433400962565, 0.062229352009099556, 0.06226835406662883,\
+0.062307439891305924, 0.062346609802283834, 0.06238586411505239, 0.06242520317476955, 0.06246462730134629, 0.06250413679465333,\
+0.06254373201567948, 0.06258341327920552, 0.06262318091169097, 0.062663035258214, 0.0627029766574735, 0.06274300543066594,\
+0.06278312194304485, 0.06282332651951957, 0.06286361949651191, 0.0629040012365073, 0.06294447207922008, 0.0629850323772214,\
+0.06302568247879399, 0.0630664227422533, 0.06310725351894263, 0.06314817516250454, 0.06318918804840376, 0.06323029252772515,\
+0.06327148895753487, 0.06331277772006413, 0.06335415918204067, 0.06339563368968242, 0.06343720165342936, 0.06347886342430777,\
+0.06352061938532055, 0.06356246990407276, 0.06360441538670769, 0.0636464561969265, 0.06368859272765938, 0.06373082535915144,\
+0.06377315449216911, 0.06381558052202675, 0.06385810383110951, 0.0639007248338041, 0.06394344391585431, 0.06398626150374771,\
+0.06402917795890069, 0.06407219372805048, 0.06411530920847422, 0.0641585248131872, 0.06420184095073911, 0.06424525803022665,\
+0.06428877650266862, 0.06433239676663029, 0.06437611924417067, 0.06441994438505232, 0.0644638725950837, 0.0645079043214758,\
+0.06455204000158533, 0.06459628006437854, 0.06464062494963246, 0.06468507512256108, 0.06472963099829462, 0.06477429304540547,\
+0.06481906171761459, 0.06486393745808361, 0.06490892073058402, 0.06495401199483243, 0.06499921171217206, 0.06504452035875109,\
+0.06508993840127762, 0.06513546630268811, 0.06518110454632116, 0.06522685360663504, 0.06527271396111106, 0.06531868610340141,\
+0.06536477052610928, 0.0654109676925432, 0.06545727812691549, 0.06550370231067269, 0.06555024075405877, 0.06559689395468106,\
+0.0656436624139634, 0.06569054664507508, 0.0657375471647205, 0.06578466449110439, 0.06583189913820145, 0.06587925163765151,\
+0.06592672250508938, 0.06597431227535999, 0.06602202149360943, 0.06606985067900314, 0.06611780037898167, 0.0661658711385298,\
+0.06621406351803585, 0.06626237805764086, 0.06631081529980379, 0.06635937583041122, 0.06640806018627524, 0.06645686895851512,\
+0.06650580269746152, 0.06655486199510312, 0.06660404741789622, 0.0666533595370666, 0.06670279896727109, 0.06675236628226792,\
+0.06680206207201661, 0.0668518869337789, 0.06690184149224354, 0.06695192633159326, 0.06700214205981939, 0.06705248930804779,\
+0.06710296868772789, 0.0671535808077126, 0.06720432631929955, 0.06725520584380416, 0.06730622002234782, 0.0673573694963128,\
+0.06740865488745204, 0.06746007688369324, 0.06751163610037941, 0.0675633332261847, 0.06761516891745487, 0.06766714384514232,\
+0.06771925866662029, 0.06777151407838464, 0.0678239107377375, 0.06787644936601138, 0.0679291306283833, 0.06798195524443583,\
+0.06803492389848348, 0.0680880373127645, 0.06814129618011397, 0.06819470123238736, 0.06824825319952076, 0.0683019527869961,\
+0.06835580075889039, 0.06840979781843042, 0.06846394474873219, 0.06851824226735115, 0.068572691140973, 0.0686272921439019,\
+0.06868204601675153, 0.06873695356005836, 0.06879201553279835, 0.06884723272279125, 0.06890260592859003, 0.06895813592415304,\
+0.0690138235311319, 0.06906966956328889, 0.06912567480947326, 0.06918184010880743, 0.06923816627865814, 0.06929465415597137,\
+0.06935130456880825, 0.06940811839031165, 0.0694650964417054, 0.06952223959200644, 0.06957954870973097, 0.06963702466088795,\
+0.06969466833061633, 0.0697524805923507, 0.06981046235764361, 0.06986861451073419, 0.06992693795854302, 0.06998543361070782,\
+0.0700441023993864, 0.07010294523785494, 0.07016196307007304, 0.07022115684315737, 0.0702805274859328, 0.07034007599196863,\
+0.07039980329249869, 0.07045971036982943, 0.0705197982108741, 0.07058006781027264, 0.07064052014090759, 0.07070115621522008,\
+0.07076197706060115, 0.07082298369030879, 0.07088417712465003, 0.07094555841795919, 0.071007128588873, 0.07106888872630526,\
+0.0711308398665611, 0.07119298309355798, 0.07125531948864441, 0.07131785014016573, 0.07138057614521566, 0.07144349861839537,\
+0.07150661866009027, 0.0715699374261787, 0.07163345602180472, 0.07169717561393328, 0.07176109735157056, 0.07182522240431403,\
+0.07188955195466692, 0.07195408716323029, 0.07201882924326333, 0.07208377940139873, 0.07214893884235823, 0.07221430880248401,\
+0.0722798905264521, 0.07234568525558366, 0.07241169423262778, 0.07247791875463301, 0.07254436009691936, 0.07261101954250888,\
+0.07267789839223045, 0.07274499797429165, 0.07281231961121863, 0.07287986464581257, 0.07294763441561943, 0.07301563029205138,\
+0.0730838536540936, 0.07315230589526768, 0.07322098839669215, 0.07328990258898221, 0.07335904987645504, 0.07342843171880731,\
+0.0734980495658183, 0.0735679048754462, 0.073637999121921, 0.07370833381237711, 0.07377891044941164, 0.07384973054825084,\
+0.07392079563222681, 0.07399210726857526, 0.07406366700659678, 0.07413547645127638, 0.07420753715673667, 0.07427985075028914,\
+0.07435241885258666, 0.07442524310338856, 0.07449832514984121, 0.0745716666804213, 0.07464526936316082, 0.07471913490684799,\
+0.07479326503091133, 0.07486766146193444, 0.07494232595726458, 0.07501726029975939, 0.0750924662593657, 0.07516794564193771,\
+0.07524370027585418, 0.07531973198530086, 0.07539604265587285, 0.07547263413700128, 0.07554950835150229, 0.07562666718521435,\
+0.07570411260554205, 0.07578184652400113, 0.0758598709456061, 0.07593818785633712, 0.07601679926004865, 0.07609570720999645,\
+0.07617491374540698, 0.07625442093749107, 0.07633423089843855, 0.07641434573370401, 0.07649476760853598, 0.07657549865561925,\
+0.0766565410813123, 0.07673789709315082, 0.07681956891177961, 0.07690155880823485, 0.07698386907000049, 0.07706650197339734,\
+0.07714945987892498, 0.07723274511626924, 0.07731636007294448, 0.07740030716175496, 0.07748458880553763, 0.07756920746890943,\
+0.07765416563512754, 0.07773946581807967, 0.07782511056387659, 0.07791110242207207, 0.07799744401489915, 0.0780841379485141,\
+0.07817118688219482, 0.07825859350414585, 0.0783463605306955, 0.07843449071897814, 0.0785229868267978, 0.07861185165811725,\
+0.078701088077669, 0.07879069895782038, 0.07888068718729427, 0.07897105571633443, 0.07906180751947077, 0.07915294560878924,\
+0.07924447303665512, 0.07933639286511265, 0.07942870823467718, 0.07952142228900282, 0.07961453820634579, 0.07970805924895973,\
+0.07980198865096313, 0.07989632974632434, 0.0799910858652042, 0.08008626042060565, 0.08018185682217184, 0.08027787855608903,\
+0.08037432913014558, 0.08047121212093167, 0.08056853110169002, 0.08066628974772122, 0.08076449174864171, 0.08086314082333707,\
+0.08096224079285823, 0.08106179547984614, 0.08116180876548947, 0.08126228457365747, 0.08136322692856465, 0.08146463982166169,\
+0.08156652737984972, 0.0816688937207933, 0.08177174306360964, 0.0818750796349511, 0.08197890777355235, 0.08208323181925367,\
+0.08218805621000065, 0.08229338543449269, 0.08239922402752002, 0.08250557659110601, 0.08261244780681609, 0.08271984238633709,\
+0.08282776515752181, 0.0829362209494269, 0.08304521471682066, 0.08315475144082256, 0.08326483620916482, 0.08337547415956897,\
+0.08348667047955963, 0.08359843048954044, 0.08371075954070682, 0.08382366306338905, 0.08393714657986563, 0.08405121569604358,\
+0.08416587608047828, 0.08428113350063914, 0.08439699380472947, 0.08451346292237703, 0.08463054687905852, 0.08474825177956008,\
+0.08486658384081218, 0.08498554935062397, 0.08510515469384028, 0.08522540637963524, 0.08534631097252628, 0.08546787519493489,\
+0.08559010582319196, 0.08571300975732761, 0.0858365940216728, 0.08596086572359748, 0.08608583209617825, 0.08621150048179996,\
+0.08633787837414943, 0.08646497332494285, 0.08659279305062317, 0.08672134541108852, 0.08685063834317595, 0.0869806799601738,\
+0.08711147847938984, 0.08724304227105094, 0.08737537985574355, 0.08750849985867377, 0.08764241110311914, 0.08777712250949475,\
+0.08791264320999935, 0.08804898244931711, 0.0881861496681494, 0.08832415441753184, 0.08846300647916285, 0.08860271578659114,\
+0.08874329241511333, 0.08888474669701181, 0.08902708907563113, 0.08917033021260895, 0.0893144809922803, 0.08945955245263719,\
+0.0896055558839363, 0.08975250274147618, 0.08990040472125423, 0.0900492737506019, 0.09019912196270165, 0.09034996172484319,\
+0.09050180567461333, 0.09065466664895834, 0.09080855778364749, 0.09096349241909975, 0.0911194842303707, 0.09127654710215084,\
+0.09143469524056524, 0.0915939431149938, 0.0917543055203753, 0.0919157975151559, 0.0920784345236995, 0.09224223224802222,\
+0.09240720674015328, 0.09257337439178968, 0.09274075195366428, 0.09290935653416398, 0.09307920559817354, 0.0932503170146962,\
+0.09342270905992375, 0.09359640037252465, 0.09377141004679895, 0.09394775760562567, 0.09412546300226368, 0.09430454667568179,\
+0.09448502951819723, 0.0946669329160876, 0.09485027876222256, 0.09503508948944778, 0.0952213880575951, 0.09540919796213405,\
+0.09559854331315247, 0.09578944878387911, 0.09598193969063046, 0.09617604197364465, 0.09637178222117793, 0.09656918772478809,\
+0.09676828648507613, 0.09696910720412343, 0.09717167938052965, 0.09737603326696033, 0.09758219994959934, 0.0977902113478564,\
+0.09800010028875847, 0.09821190045891505, 0.09842564653121755, 0.09864137413441629, 0.09885911995371714, 0.09907892169096667,\
+0.09930081818969386, 0.0995248494047596, 0.09975105651687356, 0.09997948195233253, 0.10021016940568744, 0.10044316395503443,\
+0.10067851205476118, 0.10091626166601178, 0.10115646227055433, 0.10139916493874025, 0.10164442243626409, 0.1018922892862284,\
+0.10214282183140477, 0.10239607832024927, 0.10265211905413205, 0.1029110063890347, 0.10317280495055849, 0.1034375816037667,\
+0.10370540573209426, 0.10397634920372437, 0.10425048662547307, 0.10452789539950766, 0.10480865592094149, 0.10509285172265592,\
+0.10538056963488093, 0.10567189998373067, 0.10596693680744682, 0.10626577797274908, 0.10656852555753041, 0.10687528593525741,\
+0.1071861701346488, 0.10750129408120764, 0.10782077892717895, 0.10814475135735895, 0.10847334392613198, 0.1088066955015286,\
+0.10914495162619439, 0.10948826499345861, 0.10983679592730254, 0.1101907129548019, 0.1105501933384177, 0.11091542376443077,\
+0.11128660098844369, 0.11166393269624493, 0.11204763825276545, 0.1124379496710892, 0.1128351126975813, 0.11323938781757713,\
+0.1136510516852244, 0.11407039839545753, 0.11449774110252182, 0.11493341374486335, 0.11537777303628288, 0.1158312006269911,\
+0.11629410562512456, 0.116766927347042, 0.11725013850497187, 0.11774424888433493, 0.11824980940199216, 0.11876741688875031,\
+0.11929771956077777, 0.11984142331063923, 0.12039929912782288, 0.12097219167213774, 0.1215610294228461, 0.1221668365896629,\
+0.12279074749447122, 0.12343402356078188, 0.12409807403808233, 0.12478448116027412, 0.125495031053594, 0.12623175221607383,\
+0.1269969636518144, 0.1277933361619404, 0.12862397120438523, 0.1294925038128886, 0.1304032397718238, 0.13136134116730017,\
+0.13237308374729248, 0.13344622272811538, 0.13459052904212898, 0.13581860396558676, 0.13714717245609775, 0.13859924310304023,\
+0.14019735579091797, 0.1419421626126953, 0.1438299027176266, 0.14585681525496572, 0.148019139373967, 0.15031311422388427
+};/* end of data for QNMData_fring_22 */
+
+/* fdamp for Mode 22 according to Berti et al, CQG, 26, 163001, (2009) */
+static const int QNMData_fdamp_22_length = 1200;
+static const double QNMData_fdamp_22[] = {
+0.014023091005783306, 0.01402073291567241, 0.014018717953515789, 0.014017079898000143, 0.01401585252781218, 0.0140150696216386,\
+0.014014764958166104, 0.014014933310341177, 0.014015392038911478, 0.0140159924187949, 0.01401665931260062, 0.014017355307007125,\
+0.014018062100438294, 0.014018771032989418, 0.01401947827262184, 0.014020182362638136, 0.014020882975920485, 0.014021580283405596,\
+0.014022274639406323, 0.014022966435643977, 0.014023656034927265, 0.014024343740589126, 0.014025029803661628, 0.014025714416934032,\
+0.014026397755656459, 0.01402707987925098, 0.014027760893581672, 0.01402844086031029, 0.014029119819272785, 0.014029797800172253,\
+0.014030474818905235, 0.014031150888151963, 0.01403182601502976, 0.014032500199308984, 0.014033173442471047, 0.014033845743834357,\
+0.014034517097999131, 0.014035187501195728, 0.014035856951880402, 0.014036525442756196, 0.014037192971351574, 0.014037859532226858,\
+0.014038525121330726, 0.014039189735134404, 0.014039853368523305, 0.014040516019731034, 0.014041177682531663, 0.014041838355593389,\
+0.014042498035127162, 0.01404315671797984, 0.014043814399184812, 0.014044471079632385, 0.014045126752871055, 0.014045781417936842,\
+0.014046435072957511, 0.014047087713680323, 0.014047739338443362, 0.014048389943931752, 0.014049039527689816, 0.014049688087435706,\
+0.014050335621992371, 0.014050982128346377, 0.014051627602327343, 0.01405227204388785, 0.014052915447907434, 0.014053557815233065,\
+0.014054199141523019, 0.014054839425753415, 0.014055478663189439, 0.014056116854102527, 0.014056753994090093, 0.014057390082642156,\
+0.014058025114809516, 0.014058659091504697, 0.014059292006272723, 0.014059923861245896, 0.014060554651132004, 0.014061184372796015,\
+0.014061813026515782, 0.01406244060755965, 0.014063067115297584, 0.014063692545173131, 0.014064316897281201, 0.014064940167330032,\
+0.014065562354804946, 0.014066183454358006, 0.014066803466110235, 0.01406742238705225, 0.014068040212283117, 0.01406865694302957,\
+0.014069272574746976, 0.014069887105178898, 0.014070500530756761, 0.014071112852365498, 0.01407172406327499, 0.01407233416446183,\
+0.014072943151919017, 0.014073551022479374, 0.014074157774749763, 0.014074763405929332, 0.014075367912728337, 0.014075971294971013,\
+0.014076573546710608, 0.014077174668340835, 0.014077774654752715, 0.014078373505252874, 0.01407897121626927, 0.014079567787468534,\
+0.01408016321313049, 0.01408075749265052, 0.01408135062213047, 0.014081942600918803, 0.014082533425207133, 0.01408312309155044,\
+0.014083711599168311, 0.014084298944341158, 0.014084885125206902, 0.014085470138466739, 0.014086053981152721, 0.014086636651608277,\
+0.014087218146969945, 0.014087798464359716, 0.014088377602079781, 0.014088955555639689, 0.014089532324324052, 0.014090107904822761,\
+0.014090682293192614, 0.014091255488882723, 0.014091827487975515, 0.014092398287907803, 0.014092967886219892, 0.014093536279997095,\
+0.014094103467756929, 0.014094669445415412, 0.014095234210263234, 0.014095797761103514, 0.014096360093952843, 0.014096921205606799,\
+0.01409748109448454, 0.01409803975737829, 0.014098597193616641, 0.014099153365821643, 0.014099708335510263, 0.014100262067744687,\
+0.014100814560653359, 0.01410136581223634, 0.014101915818149001, 0.014102464576854616, 0.014103012084099647, 0.014103558339526829,\
+0.014104103337974397, 0.01410464707687779, 0.01410518955614958, 0.014105730770447758, 0.01410627071754479, 0.014106809394352115,\
+0.014107346799290618, 0.014107882928353643, 0.014108417778183745, 0.014108951348182555, 0.014109483633900948, 0.014110014632672887,\
+0.014110544342131735, 0.014111072759365845, 0.014111599880451364, 0.014112125703915636, 0.014112650226453777, 0.01411317344494448,\
+0.014113695356123562, 0.014114215958621225, 0.014114735249064208, 0.014115253223072999, 0.014115769879317985, 0.014116285214496318,\
+0.014116799224879758, 0.014117311908668778, 0.01411782326274485, 0.014118333284165651, 0.014118841968799317, 0.01411934931570914,\
+0.014119855319823902, 0.014120359981136043, 0.01412086329237721, 0.014121365254908933, 0.014121865863019022, 0.014122365115226538,\
+0.014122863008488105, 0.01412335953749925, 0.014123854702520134, 0.01412434849756578, 0.014124840921759436, 0.014125331971644502,\
+0.014125821644121449, 0.014126309936147977, 0.014126796844188945, 0.014127282365379695, 0.01412776649652548, 0.014128249234065396,\
+0.014128730577433189, 0.014129210520380034, 0.014129689061503364, 0.014130166197595138, 0.014130641925472255, 0.014131116241991778,\
+0.014131589143874582, 0.01413206062716303, 0.01413253069090912, 0.014132999330673381, 0.01413346654268895, 0.014133932323294436,\
+0.014134396671454854, 0.014134859583204285, 0.01413532105497732, 0.014135781083278443, 0.01413623966472284, 0.014136696797591823,\
+0.014137152476991518, 0.014137606701412725, 0.014138059466247988, 0.014138510767912157, 0.014138960605117566, 0.014139408972405098,\
+0.014139855868228647, 0.014140301286816762, 0.014140745228625833, 0.01414118768713632, 0.01414162865935375, 0.014142068143703746,\
+0.014142506135202907, 0.014142942632573775, 0.014143377630006587, 0.014143811126154798, 0.014144243116139786, 0.014144673596719124,\
+0.014145102564675664, 0.014145530017145531, 0.014145955951040557, 0.014146380360750348, 0.014146803246452722, 0.01414722460127355,\
+0.014147644422909583, 0.014148062708234333, 0.014148479454169149, 0.014148894656898916, 0.014149308311553041, 0.014149720416813156,\
+0.014150130966915146, 0.014150539960611884, 0.014150947393095126, 0.01415135326111705, 0.014151757559764873, 0.014152160287741583,\
+0.01415256144013386, 0.014152961013304497, 0.014153359007136613, 0.014153755410742059, 0.014154150225595385, 0.01415454344588375,\
+0.0141549350710647, 0.014155325094074332, 0.01415571351307772, 0.014156100322773993, 0.014156485521841466, 0.014156869103486548,\
+0.014157251067391066, 0.014157631408168427, 0.014158010121254574, 0.014158387203630883, 0.014158762651182585, 0.014159136461031493,\
+0.014159508629594862, 0.01415987915152788, 0.014160248024094066, 0.014160615241350316, 0.014160980802624044, 0.014161344701792776,\
+0.01416170693643168, 0.014162067501848761, 0.014162426393517205, 0.014162783609453666, 0.014163139142782794, 0.014163492992650583,\
+0.014163845152365519, 0.014164195619525095, 0.014164544390181498, 0.014164891459599824, 0.014165236823640747, 0.014165580478421936,\
+0.014165922421055792, 0.014166262645923798, 0.01416660115002394, 0.014166937928280686, 0.014167272976755735, 0.014167606290932585,\
+0.01416793786806809, 0.014168267704002183, 0.01416859579297018, 0.014168922131698401, 0.014169246714970688, 0.014169569540465953,\
+0.014169890602858356, 0.014170209897094594, 0.014170527419991575, 0.014170843166828321, 0.01417115713286861, 0.01417146931527375,\
+0.014171779708340765, 0.014172088307138802, 0.014172395108645703, 0.014172700107999144, 0.014173003302021982, 0.014173304683285485,\
+0.014173604249094326, 0.01417390199625945, 0.014174197918487445, 0.014174492010785302, 0.014174784270175255, 0.0141750746922631,\
+0.014175363271246195, 0.014175650002362919, 0.014175934882430172, 0.014176217906769706, 0.014176499068499143, 0.014176778365757332,\
+0.014177055792024641, 0.014177331342712672, 0.014177605014783186, 0.014177876801744527, 0.014178146699884717, 0.014178414703482259,\
+0.014178680808506578, 0.014178945008492367, 0.014179207300767827, 0.014179467681040994, 0.014179726141547153, 0.014179982679277128,\
+0.014180237288959662, 0.014180489966372622, 0.014180740704854398, 0.014180989500989468, 0.0141812363488144, 0.014181481245173747,\
+0.014181724181442519, 0.014181965156285024, 0.01418220416289832, 0.014182441195905754, 0.014182676249934906, 0.014182909320740502,\
+0.01418314040366973, 0.014183369491661883, 0.014183596581790426, 0.014183821666254712, 0.014184044741828012, 0.014184265803422795,\
+0.014184484844158282, 0.014184701858813232, 0.014184916843227278, 0.014185129791096039, 0.014185340698482908, 0.01418554955800345,\
+0.014185756364912596, 0.014185961113906147, 0.01418616379956459, 0.014186364415654289, 0.014186562957101054, 0.014186759419602546,\
+0.014186953794951707, 0.01418714608007017, 0.014187336268791872, 0.014187524354263454, 0.014187710329484918, 0.014187894193399928,\
+0.014188075936010942, 0.014188255553150555, 0.014188433040232075, 0.01418860838821527, 0.014188781594152062, 0.014188952651992288,\
+0.014189121553042345, 0.014189288294420257, 0.014189452869308696, 0.014189615270938778, 0.014189775494646426, 0.014189933532303795,\
+0.0141900893803399, 0.014190243030481012, 0.014190394477140197, 0.014190543713402186, 0.014190690735903826, 0.014190835537250856,\
+0.014190978110244485, 0.014191118449778984, 0.014191256549235374, 0.014191392400345828, 0.014191525998224515, 0.014191657337949476,\
+0.014191786411330789, 0.014191913212185388, 0.014192037734208237, 0.014192159970275937, 0.01419227991443369, 0.0141923975608467,\
+0.014192512901623093, 0.014192625930949531, 0.014192736642480875, 0.014192845027839152, 0.014192951081536691, 0.0141930547971732,\
+0.014193156167111129, 0.014193255183818648, 0.014193351841447127, 0.014193446134557999, 0.014193538053934694, 0.014193627593440119,\
+0.014193714747117022, 0.014193799505761572, 0.01419388186315409, 0.014193961813073402, 0.014194039347495848, 0.014194114459265165,\
+0.014194187143140252, 0.01419425738760862, 0.014194325190097288, 0.014194390540581883, 0.01419445343185067, 0.014194513858093479,\
+0.014194571809489543, 0.014194627280360094, 0.014194680263397803, 0.01419473075024032, 0.01419477873325098, 0.014194824204279104,\
+0.014194867157058847, 0.014194907583416372, 0.014194945476878778, 0.014194980827275654, 0.01419501362690765, 0.014195043870639848,\
+0.014195071548618342, 0.01419509665203217, 0.014195119174950512, 0.014195139109211425, 0.014195156444785858, 0.014195171175461253,\
+0.014195183293127304, 0.014195192789311596, 0.014195199654348734, 0.014195203882291074, 0.014195205463415949, 0.014195204390715036,\
+0.014195200654257537, 0.014195194245723903, 0.0141951851585689, 0.014195173381959804, 0.01419515890966224, 0.014195141729742546,\
+0.014195121837803025, 0.014195099222186975, 0.014195073874695825, 0.014195045787393853, 0.014195014950370904, 0.014194981357194342,\
+0.014194944994485731, 0.014194905858071094, 0.014194863935939253, 0.014194819220234559, 0.014194771702867873, 0.014194721372103505,\
+0.01419466822024318, 0.014194612238818167, 0.014194553416520398, 0.014194491746251467, 0.014194427217252073, 0.014194359820488178,\
+0.014194289546384511, 0.014194216385641896, 0.014194140328682922, 0.014194061366199757, 0.014193979487944151, 0.014193894684133365,\
+0.014193806944579284, 0.014193716260928402, 0.014193622622078069, 0.014193526019268548, 0.014193426441533112, 0.014193323877675827,\
+0.014193218321148126, 0.014193109757776089, 0.01419299818106485, 0.01419288357673561, 0.01419276593895786, 0.014192645253560666,\
+0.014192521512219865, 0.014192394704645327, 0.014192264818153109, 0.014192131844583535, 0.014191995773142018, 0.014191856590359405,\
+0.014191714288851916, 0.014191568855108055, 0.014191420280251525, 0.014191268552767707, 0.01419111366073014, 0.014190955594008474,\
+0.014190794341203098, 0.014190629892027892, 0.014190462233290194, 0.01419029135577161, 0.014190117246639893, 0.01418993989567902,\
+0.01418975929008574, 0.014189575418998254, 0.014189388271035145, 0.014189197834904632, 0.014189004096840777, 0.014188807047626694,\
+0.014188606673781884, 0.014188402962652802, 0.014188195904685928, 0.014187985486287658, 0.014187771695561454, 0.014187554520376138,\
+0.014187333947298274, 0.014187109965875529, 0.014186882562756818, 0.014186651724277998, 0.014186417441150706, 0.014186179697076204,\
+0.014185938482079028, 0.01418569378178105, 0.01418544558338013, 0.014185193874664673, 0.014184938643094565, 0.014184679874519102,\
+0.01418441755623592, 0.014184151675627537, 0.014183882218340169, 0.014183609170791592, 0.014183332520376816, 0.014183052253984346,\
+0.01418276835715573, 0.014182480817043569, 0.014182189619103787, 0.014181894749953386, 0.014181596194757187, 0.014181293940598779,\
+0.014180987973979197, 0.014180678279154483, 0.014180364843392641, 0.014180047650552845, 0.014179726613784792, 0.01417940186672159,\
+0.014179073321032113, 0.014178740962103368, 0.014178404773965106, 0.014178064741007235, 0.014177720850526345, 0.014177373086637315,\
+0.014177021433417137, 0.01417666587577837, 0.014176306399569119, 0.01417594298995275, 0.014175575630219841, 0.014175204304223138,\
+0.014174828997585638, 0.014174449693365003, 0.0141740663777928, 0.014173679033248501, 0.014173287644753677, 0.014172892195681621,\
+0.014172492669421203, 0.014172089050652361, 0.01417168132249019, 0.014171269467379427, 0.014170853470804339, 0.014170433314828685,\
+0.01417000898358082, 0.014169580458762302, 0.014169147723265673, 0.014168710761717376, 0.014168269556922939, 0.01416782408948395,\
+0.014167374345310672, 0.01416692030278435, 0.01416646194705543, 0.014165999260706472, 0.01416553222397828, 0.014165060820416665,\
+0.014164585030712589, 0.014164104838761227, 0.01416362022357378, 0.014163131168655533, 0.014162637655636884, 0.014162139665294131,\
+0.01416163717864765, 0.014161130178302577, 0.014160618642941283, 0.014160102555351845, 0.01415958189482876, 0.01415905664343747,\
+0.014158526777834026, 0.014157992276970604, 0.014157453125721026, 0.014156909305413636, 0.014156360795109863, 0.014155807576001277,\
+0.01415524962609109, 0.014154686925889495, 0.014154119455797415, 0.01415354719527399, 0.014152970199765252, 0.014152388301106255,\
+0.014151801550202745, 0.01415120992359207, 0.014150613401587174, 0.014150011962661148, 0.014149405585784071, 0.014148794248631585,\
+0.014148177928874937, 0.014147556606146123, 0.01414693025643752, 0.014146298859436175, 0.014145662392448029, 0.014145020831599908,\
+0.01414437415742398, 0.014143722342964895, 0.014143065369355652, 0.014142403210600691, 0.01414173584511795, 0.01414106324906092,\
+0.01414038540000816, 0.014139702272245988, 0.01413901384381967, 0.014138320088747975, 0.014137620985031253, 0.014136916508611062,\
+0.014136206633622353, 0.014135491334631258, 0.014134770588162503, 0.014134044370625244, 0.014133312655781152, 0.014132575416701544,\
+0.014131832630158794, 0.01413108427100524, 0.01413033031248222, 0.014129570727248866, 0.014128805492109363, 0.014128034579317005,\
+0.014127257961758915, 0.014126475613383897, 0.014125687508130065, 0.014124893618856132, 0.01412409391744918, 0.014123288377211942,\
+0.014122476970887565, 0.014121659669983916, 0.014120836448178792, 0.014120007276074358, 0.014119172126193109, 0.014118330969033496,\
+0.014117483776358963, 0.014116630520006142, 0.014115771169619047, 0.014114905697743648, 0.014114034073580405, 0.014113156267767274,\
+0.014112272250413501, 0.014111381992587999, 0.014110485462917308, 0.014109582630522598, 0.014108673464971652, 0.014107757937367788,\
+0.014106836014463907, 0.01410590766430495, 0.014104972858560081, 0.014104031562721064, 0.014103083744890667, 0.014102129374813328,\
+0.014101168418284033, 0.01410020084361369, 0.014099226618312961, 0.014098245707682939, 0.014097258077997292, 0.0140962636988641,\
+0.0140952625334802, 0.014094254549906478, 0.014093239711634781, 0.014092217986236461, 0.014091189336950041, 0.014090153731249501,\
+0.014089111130742123, 0.014088061503350142, 0.014087004811830754, 0.01408594101815321, 0.014084870088561057, 0.01408379198647456,\
+0.014082706673198008, 0.014081614113041003, 0.0140805142691036, 0.014079407102389889, 0.014078292575916553, 0.014077170651246392,\
+0.014076041289816325, 0.014074904452979745, 0.014073760102359957, 0.014072608197574369, 0.014071448699658146, 0.014070281569035163,\
+0.014069106764224244, 0.014067924245903732, 0.014066733974656513, 0.014065535906792142, 0.01406433000250774, 0.01406311621960538,\
+0.01406189451618789, 0.01406066484962191, 0.014059427177365686, 0.014058181456793179, 0.014056927645676436, 0.014055665698813596,\
+0.014054395573216184, 0.01405311722529565, 0.014051830608150647, 0.014050535678481142, 0.014049232391675267, 0.01404792070145724,\
+0.014046600561334908, 0.014045271924523737, 0.014043934747534889, 0.01404258897937611, 0.014041234575987258, 0.014039871487879833,\
+0.014038499668191548, 0.014037119066971455, 0.014035729632269463, 0.01403433132319618, 0.014032924085717944, 0.014031507869603757,\
+0.014030082624155286, 0.01402864830013213, 0.014027204845583757, 0.014025752208583481, 0.014024290338183028, 0.014022819181943076,\
+0.014021338687016653, 0.01401984880051768, 0.014018349466237878, 0.014016840634639783, 0.014015322248076344, 0.014013794252108929,\
+0.014012256592867877, 0.0140107092143585, 0.014009152059196886, 0.01400758507053925, 0.014006008193330713, 0.014004421368680301,\
+0.014002824539366741, 0.014001217645037426, 0.013999600629238823, 0.013997973432102129, 0.013996335992766713, 0.013994688252056558,\
+0.013993030147245625, 0.013991361619296738, 0.013989682604329898, 0.01398799304118639, 0.01398629286716261, 0.01398458201839084,\
+0.013982860431072379, 0.01398112804094968, 0.013979384782336944, 0.01397763059189501, 0.01397586540084346, 0.013974089145731335,\
+0.01397230175518683, 0.013970503165918422, 0.013968693307484566, 0.0139668721110892, 0.013965039507372913, 0.013963195427550621,\
+0.013961339799451345, 0.013959472553092721, 0.01395759361508075, 0.013955702916071152, 0.013953800380868636, 0.013951885936220815,\
+0.013949959508932509, 0.013948021021334873, 0.013946070401606414, 0.013944107571372032, 0.013942132455667706, 0.013940144973938317,\
+0.013938145051540056, 0.013936132607542477, 0.013934107563149684, 0.013932069841722546, 0.013930019355795803, 0.013927956027013468,\
+0.013925879773573737, 0.013923790510626694, 0.013921688156844454, 0.01391957262737653, 0.013917443835152518, 0.013915301697655872,\
+0.013913146124945168, 0.013910977030573136, 0.013908794327562955, 0.013906597925226867, 0.013904387734373259, 0.013902163664504403,\
+0.013899925625385497, 0.01389767352264961, 0.013895407264469362, 0.013893126756744834, 0.013890831905103514, 0.013888522613171046,\
+0.01388619878463324, 0.013883860324097556, 0.01388150713031896, 0.013879139106419344, 0.013876756151753863, 0.013874358164310468,\
+0.01387194504328618, 0.013869516686717877, 0.01386707298932237, 0.013864613846743574, 0.013862139154403768, 0.01385964880374819,\
+0.01385714268968079, 0.0138546207018417, 0.013852082729590329, 0.013849528664891171, 0.013846958393970522, 0.013844371805405225,\
+0.013841768784798536, 0.013839149216078999, 0.013836512985889112, 0.013833859974618182, 0.013831190064415352, 0.013828503139126406,\
+0.013825799073255372, 0.013823077748596318, 0.013820339042066289, 0.013817582828895622, 0.013814808983926166, 0.013812017380657285,\
+0.013809207892174692, 0.01380638038857305, 0.013803534740646781, 0.013800670817607563, 0.013797788485480338, 0.013794887611264238,\
+0.013791968058823711, 0.01378902969268268, 0.013786072374021444, 0.013783095963947285, 0.013780100321359883, 0.013777085299359176,\
+0.013774050764768961, 0.01377099656677384, 0.01376792255911772, 0.01376482859529384, 0.013761714525100744, 0.013758580197569146,\
+0.013755425459038361, 0.013752250158485762, 0.013749054138621424, 0.013745837241111152, 0.013742599309472364, 0.013739340183749378,\
+0.013736059700312208, 0.013732757695097814, 0.013729434004965388, 0.013726088461761687, 0.013722720895473915, 0.01371933113806531,\
+0.013715919015889746, 0.013712484353943557, 0.013709026979187288, 0.013705546710274125, 0.013702043370870085, 0.013698516777572592,\
+0.013694966747183221, 0.013691393093071191, 0.013687795630675365, 0.01368417416918341, 0.01368052851692466, 0.013676858480206982,\
+0.013673163864367026, 0.013669444473114448, 0.013665700103288249, 0.01366193055409652, 0.013658135622992137, 0.013654315102680736,\
+0.013650468784423445, 0.0136465964570567, 0.013642697908036426, 0.013638772922204896, 0.01363482128046459, 0.013630842762794903,\
+0.013626837145887898, 0.013622804206348288, 0.013618743713687764, 0.013614655440764402, 0.013610539151564655, 0.013606394613399995,\
+0.013602221585448448, 0.0135980198285018, 0.013593789098129172, 0.013589529147216988, 0.013585239728030114, 0.013580920589570587,\
+0.013576571473198917, 0.013572192123872968, 0.013567782279716117, 0.01356334167805217, 0.013558870049418664, 0.013554367125691741,\
+0.013549832633637602, 0.013545266295310297, 0.013540667835944327, 0.01353603696617865, 0.013531373400856027, 0.01352667685280669,\
+0.013521947026184084, 0.01351718362681765, 0.013512386353433662, 0.013507554901127043, 0.013502688964868316, 0.01349778823240712,\
+0.013492852387112186, 0.013487881113362948, 0.013482874085389918, 0.013477830979312771, 0.01347275146255969, 0.013467635202205636,\
+0.013462481857817215, 0.013457291087956383, 0.013452062544341744, 0.013446795875485501, 0.013441490725047982, 0.013436146734230443,\
+0.013430763538676426, 0.013425340764960712, 0.013419878043591326, 0.013414374992759728, 0.01340883122970479, 0.01340324636522493,\
+0.013397620006332508, 0.013391951754883611, 0.013386241205936423, 0.013380487950106898, 0.013374691574806051, 0.013368851659960755,\
+0.013362967778600215, 0.013357039502966229, 0.013351066394240352, 0.013345048010723531, 0.01333898390532056, 0.013332873622963528,\
+0.013326716704404325, 0.013320512683210396, 0.013314261086440207, 0.013307961435915961, 0.013301613246270815, 0.013295216027062838,\
+0.013288769277562685, 0.013282272493206555, 0.013275725162745892, 0.013269126765712715, 0.013262476776152972, 0.013255774660869937,\
+0.01324901987840269, 0.01324221187918041, 0.013235350109186026, 0.013228434001658476, 0.013221462985372266, 0.01321443648179027,\
+0.013207353900567294, 0.01320021464459221, 0.013193018105373227, 0.013185763677984512, 0.01317845073453016, 0.013171078642476878,\
+0.013163646761940057, 0.013156154442539057, 0.013148601022874476, 0.013140985836297305, 0.01313330820062799, 0.013125567427222274,\
+0.013117762816140518, 0.013109893657473566, 0.01310195923009179, 0.013093958803641816, 0.013085891634971666, 0.01307775696866308,\
+0.013069554041528928, 0.013061282074582459, 0.01305294028008011, 0.013044527856386852, 0.013036043989245821, 0.013027487853420717,\
+0.013018858611177853, 0.013010155408423162, 0.013001377380660168, 0.012992523647542987, 0.012983593316789685, 0.012974585481865896,\
+0.012965499218955363, 0.012956333593003796, 0.012947087651868205, 0.012937760427194606, 0.012928350938400987, 0.012918858184514593,\
+0.01290928115090077, 0.012899618806971977, 0.012889870101043808, 0.012880033968787038, 0.012870109322613316, 0.012860095064394604,\
+0.012849990068771341, 0.01283979319845126, 0.012829503291789456, 0.012819119170456458, 0.012808639634504593, 0.012798063464858988,\
+0.012787389417611563, 0.012776616230941848, 0.01276574262014602, 0.012754767276204377, 0.012743688868507725, 0.012732506043333354,\
+0.012721217420087229, 0.012709821596327628, 0.012698317148906915, 0.012686702611361336, 0.012674976509056723, 0.012663137332324836,\
+0.012651183545182056, 0.012639113583829197, 0.012626925852857816, 0.01261461873189764, 0.01260219056359108, 0.012589639665955487,\
+0.012576964320150688, 0.012564162774909534, 0.012551233249708962, 0.01253817392328594, 0.01252498294515821, 0.012511658423552566,\
+0.01249819843213641, 0.012484601006860831, 0.012470864144787229, 0.01245698580122314, 0.012442963891448285, 0.012428796287253038,\
+0.01241448082227898, 0.01240001527851976, 0.01238539739726454, 0.01237062487081388, 0.012355695345502578, 0.012340606417067173,\
+0.012325355628642757, 0.012309940476197661, 0.012294358397016945, 0.012278606777871657, 0.012262682944465442, 0.012246584167592577,\
+0.012230307658322573, 0.01221385056380981, 0.012197209969749878, 0.012180382895710665, 0.012163366297027314, 0.012146157055772438,\
+0.012128751987451135, 0.012111147828283021, 0.012093341245822516, 0.012075328826695148, 0.012057107077715247, 0.012038672422353399,\
+0.012020021201048779, 0.012001149658082652, 0.011982053967454182, 0.011962730191531457, 0.011943174301685497, 0.011923382168802017,\
+0.011903349562131944, 0.011883072145791235, 0.011862545472303294, 0.011841764981657529, 0.011820725997795064, 0.011799423720391635,\
+0.011777853228591158, 0.011756009467912627, 0.011733887250342427, 0.011711481252019953, 0.011688786001616205, 0.011665795880376075,\
+0.011642505115539098, 0.01161890777309494, 0.011594997753952641, 0.011570768786215801, 0.011546214419626612, 0.011521328020147315,\
+0.011496102758509033, 0.011470531605745338, 0.011444607327417563, 0.01141832247044249, 0.011391669356693064, 0.01136464007740015,\
+0.011337226475496056, 0.011309420145555233, 0.011281212413781659, 0.011252594333214995, 0.011223556669604565, 0.011194089888218269,\
+0.011164184143653963, 0.01113382926152445, 0.011103014727152328, 0.011071729670727783, 0.011039962848679058, 0.011007702635386696,\
+0.010974936973193464, 0.010941653396846463, 0.010907838989700132, 0.010873480359581893, 0.010838563624991181, 0.010803074383814965,\
+0.010766997685892898, 0.01073031801462699, 0.010693019242145777, 0.010655084611272644, 0.010616496695408349, 0.01057723735715634,\
+0.010537287721322832, 0.010496628118919967, 0.010455238052940645, 0.010413096147830415, 0.010370180091096332, 0.01032646658757884,\
+0.010281931291223482, 0.010236548745645658, 0.010190292310461323, 0.010143134088431708, 0.01009504483937559, 0.010045993895842166,\
+0.009995949066671918, 0.00994487652750819, 0.00989274071036916, 0.00983950417131604, 0.009785127480894629, 0.009729569035958481,\
+0.009672784921357492, 0.009614728724484347, 0.009555351338844527, 0.00949460074410494, 0.00943242176935106, 0.009368755818550492,\
+0.009303540585816412, 0.009236709715381614, 0.009168192440815022, 0.009097913173426144, 0.009025791037842592, 0.008951739356879531,\
+0.00887566506682176, 0.008797468051053593, 0.0087170403971518, 0.008634265527365553, 0.008549017228621189, 0.008461158518926887,\
+0.00837054035955161, 0.008277000116495467, 0.008180359848530674, 0.008080424222163816, 0.007976978101109537, 0.007869783683362608,\
+0.007758577080669007, 0.0076430642172667426, 0.007522915870611559, 0.007397761623485299, 0.007267182410050874, 0.0071307012731812065,\
+0.0069877717286391935, 0.006837762987626562, 0.006679940913802502, 0.006513443052964721, 0.006337245548935072, 0.00615011810765746,\
+0.005950561643572311, 0.005736719543007996, 0.0055062475465691195, 0.005256115992273224, 0.004982295815215829, 0.00467923404381926,\
+0.004341484797159593, 0.0039688904372225655, 0.0035623595594009, 0.0031228007590874234, 0.002651122631674851, 0.0021482337725560186
+};/* end of data for QNMData_fdamp_22 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LALSIM_IMR_PHENOMX_QNM_H */
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_ringdown.c b/lalsimulation/lib/LALSimIMRPhenomX_ringdown.c
new file mode 100644
index 0000000000000000000000000000000000000000..61aeee6f128d59efd097989767b0f62bf09d1f8e
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_ringdown.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ * \file
+ *
+ * \brief Internal function for IMRPhenomX phenomenological waveform model, arXiv:2001.11412
+ * See \ref LALSimIMRPhenom_c for more details.
+ *
+ */
+
+
+#include "LALSimIMRPhenomX_ringdown.h"
+
+
+/******************************* IMRPhenomX Amplitude Functions *******************************/
+
+/******************************* Amplitude Functions: Ringdown *******************************/
+
+/* Phenomenological Ringdown Amplitude Coefficient, gamma_2. See Section VI.C of arXiv:2001.11412. Note that this is just \lambda in the paper. */
+static double IMRPhenomX_Ringdown_Amp_22_gamma2(double eta, double S, double dchi, double delta, int RDAmpFlag){
+
+  /*
+      Effective Spin Used: STotR.
+  */
+
+  double S2   = S*S;
+
+  double eta2 = (eta*eta);
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDAmpFlag )
+	{
+	case 103:
+	{
+		noSpin = (0.8312293675316895 + 7.480371544268765*eta - 18.256121237800397*eta2)/(1. + 10.915453595496611*eta - 30.578409433912874*eta2);
+
+		eqSpin = (S*(0.5869408584532747 + eta*(-0.1467158405070222 - 2.8489481072076472*S) + 0.031852563636196894*S + eta2*(0.25295441250444334 + 4.6849496672664594*S)))/(3.8775263105069953 - 3.41755361841226*S + 1.*S2);
+
+		uneqSpin = -0.00548054788508203*dchi*delta*eta;
+		break;
+	}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_gamma2: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 103.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/* Phenomenological Ringdown Amplitude Coefficient, gamma_3. See Section VI.C of arXiv:2001.11412. Note that this is just \sigma in the paper. */
+static double IMRPhenomX_Ringdown_Amp_22_gamma3(double eta, double S, double dchi, double delta, int RDAmpFlag){
+
+  /*
+      Effective Spin: STotR.
+  */
+
+  double eta2 = (eta*eta);
+  double eta3 = (eta2*eta);
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDAmpFlag )
+	{
+    /* Canonical, 3 Coefficients */
+	case 103:
+	{
+		noSpin = (1.3666000000000007 - 4.091333144596439*eta + 2.109081209912545*eta2 - 4.222259944408823*eta3)/(1. - 2.7440263888207594*eta);
+
+		eqSpin = (0.07179105336478316 + eta2*(2.331724812782498 - 0.6330998412809531*S) + eta*(-0.8752427297525086 + 0.4168560229353532*S) - 0.05633734476062242*S)*S;
+
+		uneqSpin = 0. * delta * dchi;
+      break;
+	}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_gamma3: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 103.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/* Collocation point for ringdown amplitude evaluated at F1 = f_peak */
+static double IMRPhenomX_Ringdown_Amp_22_v1(double eta, double S, double dchi, double delta, int RDAmpFlag){
+
+  /*
+      Effective Spin: STotR.
+  */
+
+  double eta2 = (eta*eta);
+  UNUSED double eta3 = (eta2*eta);
+  UNUSED double eta4 = (eta3*eta);
+
+  double S2 = S * S;
+  double S3 = S * S2;
+  double S4 = S * S3;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDAmpFlag )
+	{
+    /* Canonical, 3 coefficients */
+	case 103:
+	{
+		noSpin = (0.03689164742964719 + 25.417967754401182*eta + 162.52904393600332*eta2)/(1. + 61.19874463331437*eta - 29.628854485544874*eta2);
+
+		eqSpin = (S*(-0.14352506969368556 + 0.026356911108320547*S + 0.19967405175523437*S2 - 0.05292913111731128*S3 + eta3*(-48.31945248941757 - 3.751501972663298*S + 81.9290740950083*S2 + 30.491948143930266*S3 - 132.77982622925845*S4) + eta*(-4.805034453745424 + 1.11147906765112*S + 6.176053843938542*S2 - 0.2874540719094058*S3 - 8.990840289951514*S4) - 0.18147275151697131*S4 + eta2*(27.675454081988036 - 2.398327419614959*S - 47.99096500250743*S2 - 5.104257870393138*S3 + 72.08174136362386*S4)))/(-1.4160870461211452 + 1.*S);
+
+		uneqSpin = -0.04426571511345366*dchi*delta*eta2;
+		break;
+	}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_v1: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 103.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/* Phenomenological Ringdown Amplitude Ansatz. See Eq. 6.17 or arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Amp_22_Ansatz(double ff, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp){
+
+  int RDAmpFlag   = pWF->IMRPhenomXRingdownAmpVersion;
+
+  double gammaR    = pAmp->gammaR;   // gamma2 / (gamma3 * fDAMP)
+  double gammaD13  = pAmp->gammaD13; // fDAMP * gamma1 * gamma3
+  double gammaD2   = pAmp->gammaD2;  // (fDAMP * gamma3)^2
+
+  double dfr       = ff - pWF->fRING;
+
+  double ampRD;
+
+  switch ( RDAmpFlag )
+	{
+    /* Canonical, 3 coefficients */
+	case 103:
+	{
+      // Switch to only doubles in the expression
+      ampRD = exp(- dfr * gammaR ) * (gammaD13) / (dfr*dfr + gammaD2);
+      break;
+    }
+    default:
+    {
+	  XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_Ansatz: IMRPhenomXRingdownAmpVersion is not valid. Recommended flag is 103.\n");
+      break;
+    }
+  }
+
+  return ampRD;
+}
+
+/* Derivative (with respect to f) of Phenomenological Ringdown Amplitude Ansatz.  See Eq. 6.17 or arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Amp_22_DAnsatz(double ff, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp) {
+
+  int RDAmpFlag = pWF->IMRPhenomXRingdownAmpVersion;
+
+  double g1    = pAmp->gamma1;
+  double g2    = pAmp->gamma2;
+  double g3    = pAmp->gamma3;
+
+  double frd   = pWF->fRING;
+  double fda   = pWF->fDAMP;
+  double dfr   = ff - frd;
+  double dfd   = fda * g3;
+
+  double numerator, denominator, prefactor;
+  double DampRD;
+
+  switch ( RDAmpFlag )
+	{
+    /* Canonical, 5 coefficients */
+		case 103:
+		{
+      prefactor   = - exp(- g2 * dfr / dfd) * g1;
+      numerator   = (dfr*dfr*g2 + 2.0*fda*dfr*g3 + fda*fda*g2*g3*g3);
+      denominator = (dfr*dfr + dfd*dfd) * (dfr*dfr + dfd*dfd);
+      DampRD      = prefactor * numerator / denominator;
+      break;
+    }
+    default:
+    {
+	  XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_Ansatz: IMRPhenomXRingdownAmpVersion is not valid. Recommended flag is 103. \n");
+      break;
+    }
+  }
+
+  return DampRD;
+}
+
+/* Frequency of amplitude peak (f_peak), see Eq. 20 of 1508.07253 or Eq. XX of YY.  */
+static double IMRPhenomX_Ringdown_Amp_22_PeakFrequency(double gamma2, double gamma3, double frd, double fda, int RDAmpFlag){
+
+  double fpeak;
+
+  switch ( RDAmpFlag )
+	{
+	case 103:
+	{
+      /* If gamma2 > 1, then the square root term can become imaginary. Set this term to zero. */
+      if(gamma2 <= 1.0)
+      {
+        fpeak = fabs(frd + fda * gamma3 * (sqrt(1.0 - gamma2 * gamma2) - 1.0) / gamma2);
+      }
+      else
+      {
+        fpeak = fabs(frd + fda*(-1.0)*gamma3/gamma2);
+      }
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Amp_22_PeakFrequency: IMRPhenomXRingdownAmpVersion is not valid. Recommended flag is 103. \n");
+      break;
+    }
+  }
+
+  return fpeak;
+}
+
+/******************************* Phase Functions: Ringdown *******************************/
+/* Collocation point for ringdown phase evaluated at f_ring = f_4. See Section VII.C of arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Phase_22_v4(double eta, double S, double dchi, double delta, int RDPhaseFlag){
+
+  /*
+      Effective Spin Used: STotR.
+  */
+
+  double eta2  = eta*eta;
+  double eta3  = eta2*eta;
+  double eta4  = eta3*eta;
+  double eta5  = eta4*eta;
+
+  double S2    = S*S;
+  double S3    = S2*S;
+  double S4    = S3*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDPhaseFlag )
+	{
+		case 105: 			/* Canonical, 5 coefficients */
+		{
+      noSpin = (-85.86062966719405 - 4616.740713893726*eta - 4925.756920247186*eta2 + 7732.064464348168*eta3 + 12828.269960300782*eta4 - 39783.51698102803*eta5)/(1. + 50.206318806624004*eta);
+
+      eqSpin = (S*(33.335857451144356 - 36.49019206094966*S + eta3*(1497.3545918387515 - 101.72731770500685*S)*S - 3.835967351280833*S2 + 2.302712009652155*S3 + eta2*(93.64156367505917 - 18.184492163348665*S + 423.48863373726243*S2 - 104.36120236420928*S3 - 719.8775484010988*S4) + 1.6533417657003922*S4 + eta*(-69.19412903018717 + 26.580344399838758*S - 15.399770764623746*S2 + 31.231253209893488*S3 + 97.69027029734173*S4) + eta4*(1075.8686153198323 - 3443.0233614187396*S - 4253.974688619423*S2 - 608.2901586790335*S3 + 5064.173605639933*S4)))/(-1.3705601055555852 + 1.*S);
+
+      uneqSpin = dchi*delta*eta*(22.363215261437862 + 156.08206945239374*eta);
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_v3: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 105. \n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+}
+
+/* Difference between collocation points 1 and 2 (d12 = v1 - v2). See Section VII.C of arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Phase_22_d12(double eta, double S, double dchi, double delta, int RDPhaseFlag){
+
+  /*
+      Effective Spin Used: STotR.
+  */
+
+  double eta2  = eta*eta;
+  double eta3  = eta2*eta;
+  double eta4  = eta3*eta;
+
+  double S2    = S*S;
+  double S3    = S2*S;
+  double S4    = S3*S;
+  double S5    = S4*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDPhaseFlag )
+	{
+		case 105: 			/* Canonical, 5 coefficients */
+		{
+
+      noSpin = (eta*(0.7207992174994245 - 1.237332073800276*eta + 6.086871214811216*eta2))/(0.006851189888541745 + 0.06099184229137391*eta - 0.15500218299268662*eta2 + 1.*eta3);
+
+      eqSpin = ((0.06519048552628343 - 25.25397971063995*eta - 308.62513664956975*eta4 + 58.59408241189781*eta2 + 160.14971486043524*eta3)*S + eta*(-5.215945111216946 + 153.95945758807616*eta - 693.0504179144295*eta2 + 835.1725103648205*eta3)*S2 + (0.20035146870472367 - 0.28745205203100666*eta - 47.56042058800358*eta4)*S3 + eta*(5.7756520242745735 - 43.97332874253772*eta + 338.7263666984089*eta3)*S4 + (-0.2697933899920511 + 4.917070939324979*eta - 22.384949087140086*eta4 - 11.61488280763592*eta2)*S5)/(1. - 0.6628745847248266*S);
+
+      uneqSpin = -23.504907495268824*dchi*delta*eta2;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_d12: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 105. \n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+}
+
+/* Difference between collocation points 2 and 4 (d24 = v2 - v4). See Section VII.C of arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Phase_22_d24(double eta, double S, double dchi, double delta, int RDPhaseFlag){
+
+  /*
+      Effective Spin Used: STotR.
+  */
+
+  double eta2  = eta*eta;
+  double eta3  = eta2*eta;
+  double eta4  = eta3*eta;
+
+  double S2    = S*S;
+  double S3    = S2*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDPhaseFlag )
+	{
+		case 105: 			/* Canonical, 5 coefficients */
+		{
+
+      noSpin = (eta*(-9.460253118496386 + 9.429314399633007*eta + 64.69109972468395*eta2))/(-0.0670554310666559 - 0.09987544893382533*eta + 1.*eta2);
+
+      eqSpin = (17.36495157980372*eta*S + eta3*S*(930.3458437154668 + 808.457330742532*S) + eta4*S*(-774.3633787391745 - 2177.554979351284*S - 1031.846477275069*S2) + eta2*S*(-191.00932194869588 - 62.997389062600035*S + 64.42947340363101*S2) + 0.04497628581617564*S3)/(1. - 0.7267610313751913*S);
+
+      uneqSpin = dchi*delta*(-36.66374091965371 + 91.60477826830407*eta)*eta2;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_d13: IMRPhenomXRingdownPhaseVersion is not valid. Recommended flag is 105.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+}
+
+/* Difference between collocation points 3 and 4 (d34 = v3 - v4). See Section VII.C of arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Phase_22_d34(double eta, double S, double dchi, double delta, int RDPhaseFlag){
+
+  double eta2  = eta*eta;
+  double eta3  = eta2*eta;
+  double eta5  = eta3*eta2;
+
+  double S2    = S*S;
+  double S3    = S2*S;
+  double S4    = S3*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDPhaseFlag )
+	{
+    /* Canonical, 5 coefficients */
+		case 105:
+		{
+      noSpin = (eta*(-8.506898502692536 + 13.936621412517798*eta))/(-0.40919671232073945 + 1.*eta);
+
+      eqSpin = (eta*(1.7280582989361533*S + 18.41570325463385*S3 - 13.743271480938104*S4) + eta2*(73.8367329022058*S - 95.57802408341716*S3 + 215.78111099820157*S4) + 0.046849371468156265*S2 + eta3*S*(-27.976989112929353 + 6.404060932334562*S - 633.1966645925428*S3 + 109.04824706217418*S2))/(1. - 0.6862449113932192*S);
+
+      uneqSpin = 641.8965762829259*dchi*delta*eta5;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_d43: IMRPhenomXRingdownPhaseVersion is not valid.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/* Difference between collocation points 5 and 4 (d54 = v5 - v4). See Section VII.C of arXiv:2001.11412. */
+static double IMRPhenomX_Ringdown_Phase_22_d54(double eta, double S, double dchi, double delta, int RDPhaseFlag){
+
+  double eta2  = eta*eta;
+  double eta3  = eta2*eta;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  switch ( RDPhaseFlag )
+	{
+		case 105: 			/* Canonical, 4 coefficients */
+		{
+      noSpin = (eta*(7.05731400277692 + 22.455288821807095*eta + 119.43820622871043*eta2))/(0.26026709603623255 + 1.*eta);
+
+      eqSpin = (eta2*(134.88158268621922 - 56.05992404859163*S)*S + eta*S*(-7.9407123129681425 + 9.486783128047414*S) + eta3*S*(-316.26970506215554 + 90.31815139272628*S))/(1. - 0.7162058321905909*S);
+
+      uneqSpin = 43.82713604567481*dchi*delta*eta3;
+
+  		break;
+		}
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_d53: IMRPhenomXRingdownPhaseVersion is not valid.\n");
+    }
+	}
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*
+    Phenomenological ringdown phase derivative ansatz:
+
+    a_0 + a_1 f^(-1) + a_2 f^(-2) + a_3 f^(-3) + a_4 f^(-4) + ( aRD ) / ( (f_damp^2 + (f - f_ring)^2 ) )
+
+    where a_5 = - dphase0 * aRD
+
+    The canonical ringdown ansatz used here sets a_3 = 0.
+
+	See Eq. 7.11 of arXiv:2001.11412.
+*/
+static double IMRPhenomX_Ringdown_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase){
+
+  int RDPhaseFlag = pWF->IMRPhenomXRingdownPhaseVersion;
+
+  //double invf    = powers_of_f->m_one;
+  double invf2   = powers_of_f->m_two;
+  double invf4   = powers_of_f->m_four;
+  double invf1o3 = powers_of_f->m_one_third;
+
+  double frd     = pWF->fRING;
+  double fda     = pWF->fDAMP;
+  double phaseRD;
+
+  // c0 = a0, c1 = a1, c2 = a2, c3 = a4 are the polynomial Coefficients
+  // c4 = a_L = -(dphase0 * a_RD) is the Lorentzian coefficient.
+  switch ( RDPhaseFlag )
+	{
+    /* Canonical, 5 coefficients */
+		case 105:
+		{
+      phaseRD = ( pPhase->c0 + pPhase->c1*invf1o3 + pPhase->c2*invf2 + pPhase->c4*invf4 + ( pPhase->cL / (fda*fda + (ff - frd)*(ff - frd)) ) );
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_AnsatzInt: IMRPhenomXRingdownPhaseVersion is not valid.\n");
+      break;
+    }
+  }
+
+  return phaseRD;
+}
+
+/*
+    Phenomenological ringdown phase ansatz (i.e. integral of phase derivative ansatz). See. Eq. 7.11 of arxiv:2001.11412.
+*/
+static double IMRPhenomX_Ringdown_Phase_22_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase){
+
+  int RDPhaseFlag = pWF->IMRPhenomXRingdownPhaseVersion;
+
+  double invf     = powers_of_f->m_one;
+  double invf3    = powers_of_f->m_three;
+  //double logf     = powers_of_f->log;
+  double f2o3     = powers_of_f->two_thirds;
+
+  double frd      = pWF->fRING;
+  double fda      = pWF->fDAMP;
+
+  double c0       = pPhase->c0;
+  double c1       = pPhase->c1;
+  double c2       = pPhase->c2;
+  double c4ov3    = pPhase->c4ov3;
+  double cLovfda  = pPhase->cLovfda;
+
+  double phaseRDInt;
+
+  switch ( RDPhaseFlag )
+	{
+    /* Canonical, 5 coefficients */
+		case 105:
+		{
+      phaseRDInt = ( c0*ff + 1.5*c1*f2o3 - c2*invf - c4ov3*invf3 + (cLovfda * atan( (ff - frd )/fda ) ) );
+      break;
+    }
+    default:
+    {
+      XLAL_ERROR_REAL8(XLAL_EINVAL, "Error in IMRPhenomX_Ringdown_Phase_22_AnsatzInt: IMRPhenomXRingdownPhaseVersion is not valid.\n");
+      break;
+    }
+  }
+
+  return phaseRDInt;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_ringdown.h b/lalsimulation/lib/LALSimIMRPhenomX_ringdown.h
new file mode 100644
index 0000000000000000000000000000000000000000..473a47e89cfc81e90b24e211b7cd748d767c022d
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_ringdown.h
@@ -0,0 +1,67 @@
+#ifndef _LALSIM_IMR_PHENOMX_RINGDOWN_H
+#define _LALSIM_IMR_PHENOMX_RINGDOWN_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/**
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+#include "LALSimIMRPhenomX.h"
+#include "LALSimIMRPhenomX_internals.h"
+#include "LALSimIMRPhenomX_utilities.h"
+
+/********************************* IMRPhenomX: Amplitude Functions *********************************/
+static double IMRPhenomX_Ringdown_Amp_22_v1(double eta, double S, double dchi, double delta, int RDAmpFlag);
+static double IMRPhenomX_Ringdown_Amp_22_gamma2(double eta, double S, double dchi, double delta, int RDAmpFlag);
+static double IMRPhenomX_Ringdown_Amp_22_gamma3(double eta, double S, double dchi, double delta, int RDAmpFlag);
+
+static double IMRPhenomX_Ringdown_Amp_22_PeakFrequency(double gamma2,double gamma3,double fRING,double fDAMP,int IMRPhenomXRingdownAmpVersion);
+
+static double IMRPhenomX_Ringdown_Amp_22_Ansatz( double ff, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+static double IMRPhenomX_Ringdown_Amp_22_DAnsatz(double ff, IMRPhenomXWaveformStruct *pWF, IMRPhenomXAmpCoefficients *pAmp);
+
+/********************************* IMRPhenomX: Phase Functions *********************************/
+static double IMRPhenomX_Ringdown_Phase_22_v4(double eta, double S, double dchi, double delta, int RDPhaseFlag);
+static double IMRPhenomX_Ringdown_Phase_22_d12(double eta, double S, double dchi, double delta, int RDPhaseFlag);
+static double IMRPhenomX_Ringdown_Phase_22_d24(double eta, double S, double dchi, double delta, int RDPhaseFlag);
+static double IMRPhenomX_Ringdown_Phase_22_d34(double eta, double S, double dchi, double delta, int RDPhaseFlag);
+static double IMRPhenomX_Ringdown_Phase_22_d54(double eta, double S, double dchi, double delta, int RDPhaseFlag);
+
+static double IMRPhenomX_Ringdown_Phase_22_Ansatz(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+static double IMRPhenomX_Ringdown_Phase_22_AnsatzInt(double ff, IMRPhenomX_UsefulPowers *powers_of_f, IMRPhenomXWaveformStruct *pWF, IMRPhenomXPhaseCoefficients *pPhase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// of #ifndef _LALSIM_IMR_PHENOMX_RINGDOWN_H
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_utilities.c b/lalsimulation/lib/LALSimIMRPhenomX_utilities.c
new file mode 100644
index 0000000000000000000000000000000000000000..3256837cbf8daa6fe3539c42a68dd5c5763d2d54
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_utilities.c
@@ -0,0 +1,636 @@
+/*
+ *  Copyright (C) 2018 Geraint Pratten
+ *
+ *  This code adapts functions from:
+ *    LALSimIMRPhenomP.c
+ *    LALSimIMRPhenomD.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+/**
+ * \author Geraint Pratten
+ *
+ * \file
+ *
+ * \brief Utility functions for IMRPhenomX framework, arXiv:2001.11412
+ *
+ */
+
+#include "LALSimIMRPhenomX_utilities.h"
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_math.h>
+
+/* ******************** MECO, ISCO, etc ******************** */
+
+/*
+ * Phenomenological fit to hybrid minimum energy circular orbit (MECO) function.
+ * Uses 3.5PN hybridised with test-particle limit.
+ * Reference: M Cabero et al, PRD, 95, 064016, (2017), arXiv:1602.03134
+ */
+REAL8 XLALSimIMRPhenomXfMECO(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+
+  REAL8 eta2  = (eta*eta);
+  REAL8 eta3  = (eta2*eta);
+  REAL8 eta4  = (eta3*eta);
+
+  REAL8 delta = sqrt(1.0 - 4.0*eta);
+
+  REAL8 S     = XLALSimIMRPhenomXchiPNHat(eta,chi1L,chi2L);
+  REAL8 S2    = (S*S);
+  REAL8 S3    = (S2*S);
+  //REAL8 S4    = (S3*S);
+
+  REAL8 noSpin, eqSpin, uneqSpin;
+
+  REAL8 dchi  = chi1L - chi2L;
+  REAL8 dchi2 = (dchi*dchi);
+
+
+  noSpin = (0.018744340279608845 + 0.0077903147004616865*eta + 0.003940354686136861*eta2 - 0.00006693930988501673*eta3)/(1. - 0.10423384680638834*eta);
+
+  eqSpin = (S*(0.00027180386951683135 - 0.00002585252361022052*S + eta4*(-0.0006807631931297156 + 0.022386313074011715*S - 0.0230825153005985*S2) + eta2*(0.00036556167661117023 - 0.000010021140796150737*S - 0.00038216081981505285*S2) + eta*(0.00024422562796266645 - 0.00001049013062611254*S - 0.00035182990586857726*S2) + eta3*(-0.0005418851224505745 + 0.000030679548774047616*S + 4.038390455349854e-6*S2) - 0.00007547517256664526*S2))/(0.026666543809890402 + (-0.014590539285641243 - 0.012429476486138982*eta + 1.4861197211952053*eta4 + 0.025066696514373803*eta2 + 0.005146809717492324*eta3)*S + (-0.0058684526275074025 - 0.02876774751921441*eta - 2.551566872093786*eta4 - 0.019641378027236502*eta2 - 0.001956646166089053*eta3)*S2 + (0.003507640638496499 + 0.014176504653145768*eta + 1.*eta4 + 0.012622225233586283*eta2 - 0.00767768214056772*eta3)*S3);
+
+  uneqSpin = dchi2*(0.00034375176678815234 + 0.000016343732281057392*eta)*eta2 + dchi*delta*eta*(0.08064665214195679*eta2 + eta*(-0.028476219509487793 - 0.005746537021035632*S) - 0.0011713735642446144*S);
+
+  return (noSpin + eqSpin + uneqSpin);
+}
+
+/*
+ * Fitting function for hybrid minimum energy circular orbit (MECO) function
+ */
+REAL8 XLALSimIMRPhenomXfISCO(REAL8 chif) {
+
+  REAL8 OmegaISCO, rISCO;
+  REAL8 rISCOsq, rISCO3o2;
+  REAL8 Z1, Z2;
+
+  Z1 = 1.0 + cbrt( (1.0 - chif*chif) ) * ( cbrt(1 + chif) + cbrt(1 - chif) );
+  if(Z1>3) Z1=3.; //Finite precission may give Z1>3, but this can not happen.
+  Z2 = sqrt(3.0*chif*chif + Z1*Z1);
+
+  rISCO    = 3.0 + Z2 - XLALSimIMRPhenomXsign(chif)*sqrt( (3 - Z1) * (3 + Z1 + 2*Z2) );
+  rISCOsq  = sqrt(rISCO);
+  rISCO3o2 = rISCOsq * rISCOsq * rISCOsq;
+
+  OmegaISCO = 1.0 / ( rISCO3o2 + chif);
+
+  return OmegaISCO / LAL_PI;
+
+}
+
+/* ******************** FINAL STATE ********************
+
+    These functions are here as we exposed them violate
+    the XLAL wrappers.
+*/
+
+/*
+ * Energy Radiated: X. Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
+ */
+REAL8 XLALSimIMRPhenomXErad2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+
+  REAL8 delta  = sqrt(1.0 - 4.0*eta);
+
+  REAL8 eta2   =  eta*eta;
+  REAL8 eta3   = eta2*eta;
+  REAL8 eta4   = eta3*eta;
+
+  REAL8 S      = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
+  REAL8 S2     =  S*S;
+  REAL8 S3     = S2*S;
+
+  REAL8 dchi   = chi1L - chi2L;
+  REAL8 dchi2  = dchi*dchi;
+
+  REAL8 noSpin, eqSpin, uneqSpin;
+
+  noSpin = 0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4;
+
+  /* Because of the way this is written, we need to subtract the noSpin term */
+  eqSpin = ((0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4)*
+    (    1
+      + (-0.13084389181783257 - 1.1387311580238488*eta + 5.49074464410971*eta2)*S
+      + (-0.17762802148331427 + 2.176667900182948*eta2)*S2
+      + (-0.6320191645391563 + 4.952698546796005*eta - 10.023747993978121*eta2)*S3))
+      / (1 + (-0.9919475346968611 + 0.367620218664352*eta + 4.274567337924067*eta2)*S);
+
+  eqSpin = eqSpin - noSpin;
+
+  uneqSpin =  - 0.09803730445895877*dchi*delta*(1 - 3.2283713377939134*eta)*eta2
+              + 0.01118530335431078*dchi2*eta3
+              - 0.01978238971523653*dchi*delta*(1 - 4.91667749015812*eta)*eta*S;
+
+  return (noSpin + eqSpin + uneqSpin);
+
+}
+
+/*
+ * Final Mass = 1 - Energy Radiated,  X. Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
+ */
+REAL8 XLALSimIMRPhenomXFinalMass2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+
+  REAL8 delta  = sqrt(1.0 - 4.0*eta);
+  REAL8 eta2   =  eta*eta;
+  REAL8 eta3   = eta2*eta;
+  REAL8 eta4   = eta3*eta;
+
+  REAL8 S      = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
+  REAL8 S2     =  S*S;
+  REAL8 S3     = S2*S;
+
+  REAL8 dchi   = chi1L - chi2L;
+  REAL8 dchi2  = dchi*dchi;
+
+  REAL8 noSpin, eqSpin, uneqSpin;
+
+  noSpin = 0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4;
+
+  /* Because of the way this is written, we need to subtract the noSpin term */
+  eqSpin = ((0.057190958417936644*eta + 0.5609904135313374*eta2 - 0.84667563764404*eta3 + 3.145145224278187*eta4)*
+    (    1
+      + (-0.13084389181783257 - 1.1387311580238488*eta + 5.49074464410971*eta2)*S
+      + (-0.17762802148331427 + 2.176667900182948*eta2)*S2
+      + (-0.6320191645391563 + 4.952698546796005*eta - 10.023747993978121*eta2)*S3))
+      / (1 + (-0.9919475346968611 + 0.367620218664352*eta + 4.274567337924067*eta2)*S);
+
+  eqSpin = eqSpin - noSpin;
+
+  uneqSpin =  - 0.09803730445895877*dchi*delta*(1 - 3.2283713377939134*eta)*eta2
+              + 0.01118530335431078*dchi2*eta3
+              - 0.01978238971523653*dchi*delta*(1 - 4.91667749015812*eta)*eta*S;
+
+  /* Mfinal = 1 - Erad, assuming that M = m1 + m2 = 1 */
+  return (1.0 - (noSpin + eqSpin + uneqSpin));
+
+
+}
+
+/*
+ * Final Dimensionless Spin,  X. Jimenez-Forteza et al, PRD, 95, 064024, (2017), arXiv:1611.00332
+ */
+REAL8 XLALSimIMRPhenomXFinalSpin2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+
+	REAL8 delta  = sqrt(1.0 - 4.0*eta);
+	REAL8 m1     = 0.5 * (1.0 + delta);
+	REAL8 m2     = 0.5 * (1.0 - delta);
+	REAL8 m1Sq   = m1*m1;
+	REAL8 m2Sq   = m2*m2;
+
+  REAL8 eta2   = eta*eta;
+  REAL8 eta3   = eta2*eta;
+
+	//REAL8 S  = (m1Sq * chi1L + m2Sq * chi2L) / (m1Sq + m2Sq);
+  REAL8 S  = XLALSimIMRPhenomXSTotR(eta,chi1L,chi2L);
+  REAL8 S2 =  S*S;
+  REAL8 S3 = S2*S;
+
+  REAL8 dchi  = chi1L - chi2L;
+  REAL8 dchi2 = dchi*dchi;
+
+  REAL8 noSpin, eqSpin, uneqSpin;
+
+  noSpin = (3.4641016151377544*eta + 20.0830030082033*eta2 - 12.333573402277912*eta3)/(1 + 7.2388440419467335*eta);
+
+  eqSpin = (m1Sq + m2Sq)*S
+  + ((-0.8561951310209386*eta - 0.09939065676370885*eta2 + 1.668810429851045*eta3)*S
+  + (0.5881660363307388*eta - 2.149269067519131*eta2 + 3.4768263932898678*eta3)*S2
+  + (0.142443244743048*eta - 0.9598353840147513*eta2 + 1.9595643107593743*eta3)*S3)
+  / (1 + (-0.9142232693081653 + 2.3191363426522633*eta - 9.710576749140989*eta3)*S);
+
+  uneqSpin = 0.3223660562764661*dchi*delta*(1 + 9.332575956437443*eta)*eta2           /* Linear in spin difference                */
+  - 0.059808322561702126*dchi2*eta3                                                   /* Quadratic in spin difference             */
+  + 2.3170397514509933*dchi*delta*(1 - 3.2624649875884852*eta)*eta3*S;                 /* Mixed spin difference + total spin term  */
+
+
+	return (noSpin + eqSpin + uneqSpin);
+}
+
+/* ******************** SPIN PARAMETERIZATIONS ******************** */
+/*
+ * PN reduced spin parameter
+ */
+REAL8 XLALSimIMRPhenomXchiPN(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+	// Convention m1 >= m2 and chi1 is the spin on m1
+	REAL8 delta    = sqrt(1.0 - 4.0*eta);
+  REAL8 mm1      = 0.5*(1+delta);
+  REAL8 mm2      = 0.5*(1-delta);
+  REAL8 chi_eff  = (mm1*chi1L + mm2*chi2L);
+
+	return chi_eff - (38.0/113.0)*eta*(chi1L + chi2L);
+}
+
+/*
+ * Normalised PN reduced spin parameter
+ */
+REAL8 XLALSimIMRPhenomXchiPNHat(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+  // Convention m1 >= m2 and chi1 is the spin on m1
+	REAL8 delta    = sqrt(1.0 - 4.0*eta);
+  REAL8 mm1      = 0.5*(1.0 + delta);
+  REAL8 mm2      = 0.5*(1.0 - delta);
+  REAL8 chi_eff  = (mm1*chi1L + mm2*chi2L);
+
+	return (chi_eff - (38.0/113.0)*eta*(chi1L + chi2L) ) / (1.0 - (76.0*eta/113.0));
+}
+
+/*
+ * Effective aligned spin parameter
+ */
+REAL8 XLALSimIMRPhenomXchiEff(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+	// Convention m1 >= m2 and chi1 is the spin on m1
+	REAL8 delta = sqrt(1.0 - 4.0*eta);
+	REAL8 mm1 = 0.5*(1+delta);
+  REAL8 mm2 = 0.5*(1-delta);
+
+  return (mm1*chi1L + mm2*chi2L);
+}
+
+/*
+ * Total spin normalised to [-1,1]
+ */
+REAL8 XLALSimIMRPhenomXSTotR(REAL8 eta, REAL8 chi1L, REAL8 chi2L) {
+	// Convention m1 >= m2 and chi1z is the spin projected along Lz on m1
+	REAL8 delta = sqrt(1.0 - 4.0*eta);
+	REAL8 m1    = 0.5*(1 + delta);
+	REAL8 m2    = 0.5*(1 - delta);
+	REAL8 m1s   = m1*m1;
+	REAL8 m2s   = m2*m2;
+
+	return ((m1s * chi1L + m2s * chi2L) / (m1s + m2s));
+}
+
+/*
+ * Spin difference
+ */
+REAL8 XLALSimIMRPhenomXdchi(REAL8 chi1L, REAL8 chi2L) {
+
+  return chi1L - chi2L;
+}
+
+/* ******************** FREQUENCY CONVERSIONS ******************** */
+/*
+ * Convert from geometric frequency to Hz
+ */
+REAL8 XLALSimIMRPhenomXUtilsMftoHz(
+    REAL8 Mf,       /**< Geometric frequency */
+    REAL8 Mtot_Msun /**< Total mass in solar masses */
+)
+{
+    return Mf / (LAL_MTSUN_SI * Mtot_Msun);
+}
+
+/*
+ * Convert from frequency in Hz to geometric frequency
+ */
+REAL8 XLALSimIMRPhenomXUtilsHztoMf(
+    REAL8 fHz,      /**< Frequency in Hz */
+    REAL8 Mtot_Msun /**< Total mass in solar masses */
+)
+{
+    return fHz * (LAL_MTSUN_SI * Mtot_Msun);
+}
+
+/*
+ * We apply a linear time and phase shift to ~ align peak
+ * LinShift = (PNLina[\[Eta],\[Chi]1,\[Chi]2] + \[Pi] + f PNLinb[\[Eta],\[Chi]1,\[Chi]2]);
+ * Linear time and phase shift: a + b*f
+ */
+REAL8 XLALSimIMRPhenomXLina(
+    REAL8 eta,       /**< Geometric frequency */
+    REAL8 S,         /**< Total mass in solar masses */
+    REAL8 dchi,      /**< Total mass in solar masses */
+    REAL8 delta      /**< Total mass in solar masses */
+)
+{
+
+  double eta2 = eta*eta;
+  double eta3 = eta2*eta;
+
+  double S2 = S*S;
+  double S3 = S2*S;
+  double S4 = S3*S;
+  double S5 = S4*S;
+
+  double noSpin, eqSpin, uneqSpin;
+
+  noSpin = (1.0691011796680957e7 + 1.185905809135487e6*eta)/(1. + 30289.726104019595*eta);
+
+  eqSpin = (3590.4466629551066 - 43200.79177912654*eta +
+              200094.57177252226*eta2 - 319307.42983118095*eta3)*S +
+              eta*(-1108.7615587239336 + 25622.545977741574*eta -
+              83180.15680637326*eta2)*S3 + (379.0250508368122 -
+              1355.868129015304*eta)*eta2*S4 + (-23306.844979169644 +
+              91977.08490230633*eta)*eta2*S5 + (-204.5064259069199 + 1046.9991525832384*eta - 5906.920781540527*eta3)*S2;
+
+  uneqSpin = 44.87175399132858*dchi*delta*eta;
+
+  return (noSpin + eqSpin + uneqSpin) + LAL_PI;
+
+}
+
+// this is a fit of the time-difference between t_peak of strain and t_peak of psi4
+// needed to align in time our waveforms, which are calibrated to psi4
+
+REAL8 XLALSimIMRPhenomXPsi4ToStrain(double eta, double S, double dchi) {
+    double eta2,eta3,eta4,S2,S3,S4;
+    eta2 = pow(eta,2);
+    eta3 = pow(eta,3);
+    eta4 = pow(eta,4);
+    S2 = pow(S,2);
+    S3 = pow(S,3);
+    S4 = pow(S,4);
+    double noSpin = 13.39320482758057 - 175.42481512989315*eta + 2097.425116152503*eta2 - 9862.84178637907*eta3 + 16026.897939722587*eta4;
+    double eqSpin = (4.7895602776763 - 163.04871764530466*eta + 609.5575850476959*eta2)*S + (1.3934428041390161 - 97.51812681228478*eta + 376.9200932531847*eta2)*S2 + (15.649521097877374 + 137.33317057388916*eta - 755.9566456906406*eta2)*S3 + (13.097315867845788 + 149.30405703643288*eta - 764.5242164872267*eta2)*S4;
+    double uneqSpin = 105.37711654943146*dchi*sqrt(1. - 4.*eta)*eta2;
+    return( noSpin + eqSpin + uneqSpin);
+    
+
+}
+
+
+REAL8 XLALSimIMRPhenomXLinb(
+  REAL8 eta,       /**< Geometric frequency */
+  REAL8 S,         /**< Total mass in solar masses */
+  REAL8 dchi,      /**< Total mass in solar masses */
+  REAL8 delta      /**< Total mass in solar masses */
+)
+{
+    double eta2 = eta*eta;
+    double eta3= eta2*eta, eta4= eta3*eta, eta5=eta3*eta2, eta6=eta4*eta2;
+    double S2 = S*S;
+    double S3 = S2*S;
+    double S4 = S3*S;
+    double noSpin = 3155.1635543201924 + 1257.9949740608242*eta - 32243.28428870599*eta2 + 347213.65466875216*eta3 - 1.9223851649491738e6*eta4 + 5.3035911346921865e6*eta5 - 5.789128656876938e6*eta6;
+    double eqSpin = (-24.181508118588667 + 115.49264174560281*eta - 380.19778216022763*eta2)*S + (24.72585609641552 - 328.3762360751952*eta + 725.6024119989094*eta2)*S2 + (23.404604124552 - 646.3410199799737*eta + 1941.8836639529036*eta2)*S3 + (-12.814828278938885 - 325.92980012408367*eta + 1320.102640190539*eta2)*S4;
+    double uneqSpin = -148.17317525117338*dchi*delta*eta2;
+    
+    
+    return (noSpin + eqSpin + uneqSpin);
+
+}
+
+
+/* ******************** NUMERICAL ROUTINES ******************** */
+// This function determines whether x and y are approximately equal to a relative accuracy epsilon.
+// Note that x and y are compared to relative accuracy, so this function is not suitable for testing whether a value is approximately zero.
+bool IMRPhenomX_ApproxEqual(REAL8 x, REAL8 y, REAL8 epsilon) {
+  return !gsl_fcmp(x, y, epsilon);
+}
+
+// If x and X are approximately equal to relative accuracy epsilon then set x = X.
+// If X = 0 then use an absolute comparison.
+
+void IMRPhenomX_InternalNudge(REAL8 x, REAL8 X, REAL8 epsilon) {
+  if (X != 0.0) {
+    if (IMRPhenomX_ApproxEqual(x, X, epsilon)) {
+      XLAL_PRINT_INFO("Nudging value %.15g to %.15g\n", x, X);
+      x = X;
+    }
+  }
+  else {
+    if (fabs(x - X) < epsilon)
+      x = X;
+  }
+}
+
+REAL8 XLALSimIMRPhenomXatan2tol(REAL8 a, REAL8 b, REAL8 tol)
+{
+  REAL8 c;
+  if (fabs(a) < tol && fabs(b) < tol)
+    c = 0.;
+  else
+    c = atan2(a, b);
+  return c;
+}
+
+/**** Define some useful powers ****/
+size_t NextPow2(const size_t n)
+{
+  // use pow here, not bit-wise shift, as the latter seems to run against an upper cutoff long before SIZE_MAX, at least on some platforms
+  return (size_t) pow(2,ceil(log2(n)));
+}
+
+bool IMRPhenomX_StepFuncBool(const double t, const double t1) {
+	return (t >= t1);
+}
+
+REAL8 XLALSimIMRPhenomXsign(REAL8 x)
+{
+  return (x > 0.) ? 1.0 : ((x < 0.0) ? -1.0 : 0.0);
+}
+
+/*
+VOID XLALSimIMRPhenomXRotateZ(REAL8 angle, REAL8 *vx, REAL8 *vy, REAL8 *vz)
+{
+  REAL8 tmp1, tmp2;
+
+  tmp1 = vx*cos(angle) - vy*sin(angle);
+  tmp2 = vx*sin(angle) + vy*cos(angle);
+
+  *vx = tmp1;
+  *vz = tmp2;
+  *vy = vy;
+}
+
+// Rotate Components of Vector About Y Axis
+VOID XLALSimIMRPhenomXRotateY(REAL8 angle, REAL8 *vx, REAL8 *vy, REAL8 *vz)
+{
+  REAL8 tmp1, tmp2;
+
+  tmp1 = vx*cos(angle) - vy*sin(angle);
+  tmp2 = vx*sin(angle) + vy*cos(angle);
+
+  *vx = tmp1;
+  *vz = tmp2;
+}
+*/
+
+/* Useful powers to avoid pow(.,.) function */
+/*
+ * calc square of number without floating point 'pow'
+ */
+double pow_2_of(double number)
+{
+ return (number*number);
+}
+
+/**
+ * calc cube of number without floating point 'pow'
+ */
+double pow_3_of(double number)
+{
+ return (number*number*number);
+}
+
+/**
+ * calc fourth power of number without floating point 'pow'
+ */
+double pow_4_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ return pow2 * pow2;
+}
+
+/**
+ * calc fifth power of number without floating point 'pow'
+ */
+double pow_5_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ return pow2 * pow2 * number;
+}
+
+/**
+ * calc sixth power of number without floating point 'pow'
+ */
+double pow_6_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ return pow2 * pow2 * pow2;
+}
+
+/**
+ * calc seventh power of number without floating point 'pow'
+ */
+double pow_7_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ return pow2 * pow2 * pow2 * number;
+}
+
+/**
+ * calc eigth power of number without floating point 'pow'
+ */
+double pow_8_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ double pow4 = pow2*pow2;
+ return pow4 * pow4;
+}
+
+/**
+ * calc ninth power of number without floating point 'pow'
+ */
+double pow_9_of(double number)
+{
+ double pow2 = pow_2_of(number);
+ double pow4 = pow2*pow2;
+ return pow4 * pow4 * number;
+}
+
+/* ******************** ANALYTICAL MODEL WRAPPERS ******************** */
+/*
+    "Analytical" phenomenological ringdown ansatz for phase. This is used by the higher mode functions and
+    can be used to prototype or test model. Convenient wrapper exposed via XLAL.
+*/
+REAL8 XLALSimIMRPhenomXRingdownPhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL)
+{
+
+  REAL8 invf  = 1.0 / ff;
+  REAL8 invf2 = invf  * invf;
+  REAL8 invf3 = invf2 * invf;
+  //REAL8 invf4 = invf2 * invf2;
+  REAL8 logfv  = log(ff);
+
+  REAL8 phaseOut;
+
+  phaseOut = ( a0*ff + a1*logfv - a2*invf - (a4 * invf3 / 3.0) + (aL * atan( (ff - fRD)/fDA ) / fDA ) );
+
+  return phaseOut;
+}
+
+/*
+    "Analytical" phenomenological ringdown ansatz for phase derivative. This is used by the higher mode functions and
+    can be used to prototype or test model. Convenient wrapper exposed via XLAL.
+
+    a_0 + a_1 f^(-1) + a_2 f^(-2) + a_3 f^(-3) + a_4 f^(-4) + ( aRD ) / ( (f_damp^2 + (f - f_ring)^2 ) )
+
+    where a_L = - dphase0 * aRD
+
+    Our canonical ringdown ansatz sets a_3 = 0.
+*/
+REAL8 XLALSimIMRPhenomXRingdownPhaseDeriv22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL)
+{
+
+  REAL8 invf  = 1.0 / ff;
+  REAL8 invf2 = invf  * invf;
+  //REAL8 invf3 = invf2 * invf;
+  REAL8 invf4 = invf2 * invf2;
+
+  REAL8 phaseOut;
+
+  phaseOut =  ( a0 + a1*invf + a2*invf2 + a4*invf4 + ( aL / (fDA*fDA + (ff - fRD)*(ff - fRD)) ) );
+
+  return phaseOut;
+}
+
+/*
+    "Analytical" phenomenological ringdown ansatz for amplitude. This is used by the higher mode functions but
+    can also be used to prototype or test model. Convenient wrapper exposed via XLAL.
+*/
+REAL8 XLALSimIMRPhenomXRingdownAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 gamma1, REAL8 gamma2, REAL8 gamma3)
+{
+  REAL8 gammaD13 = fDA * gamma1 * gamma3;
+  REAL8 gammaR   = gamma2 / (gamma3 * fDA);
+  REAL8 gammaD2  = (fDA * gamma3) * (fDA * gamma3);
+  REAL8 dfr      = ff - fRD;
+  REAL8 ampOut;
+
+  ampOut =  exp(- dfr * gammaR ) * (gammaD13) / (dfr*dfr + gammaD2);
+
+  return ampOut;
+}
+
+/*
+		This is the canonical intermediate ansatz:
+
+		a_0 + a_1 ft^(-1) + a_2 ft^(-2) + a_3 ft^(-3) + a4 ft^(-4) + (4 * a_RD) / ( (2 * f_fdamp)^2 + (f - f_ring)^2 )
+
+		ft = (f / f_ring)
+*/
+REAL8 XLALSimIMRPhenomXIntermediateAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 ff7o6, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 a5)
+{
+  return ff7o6 / ( a0 + ff*(a1 + ff*(a2 + ff*(a3 + ff*(a4 + ff*a5)))) );
+}
+
+/*
+		This is the canonical intermediate ansatz:
+
+		a_0 + a_1 ft^(-1) + a_2 ft^(-2) + a_3 ft^(-3) + a4 ft^(-4) + (4 * a_RD) / ( (2 * f_fdamp)^2 + (f - f_ring)^2 )
+
+		ft = (f / f_ring)
+*/
+REAL8 XLALSimIMRPhenomXIntermediatePhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 aL)
+{
+  REAL8 invff1 = 1.0 / ff;
+  REAL8 invff2 = invff1 * invff1;
+  REAL8 invff3 = invff2 * invff1;
+  REAL8 invff4 = invff3 * invff1;
+
+  REAL8 LorentzianTerm;
+  REAL8 phaseOut;
+
+  /* This is the Lorentzian term where aL = - a_{RD} dphase0 */
+  LorentzianTerm = (4.0 * aL) / ( (4.0*fDA*fDA) + (ff - fRD)*(ff - fRD) );
+
+  /* Return a polynomial embedded in the background from the merger */
+  phaseOut       = a0 + a1*invff1 + a2*invff2 + a3*invff3 + a4*invff4 + LorentzianTerm;
+
+  return phaseOut;
+}
diff --git a/lalsimulation/lib/LALSimIMRPhenomX_utilities.h b/lalsimulation/lib/LALSimIMRPhenomX_utilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..79016085cbb5f1c4a6b1ea9214bc9c34eaa6831f
--- /dev/null
+++ b/lalsimulation/lib/LALSimIMRPhenomX_utilities.h
@@ -0,0 +1,113 @@
+#ifndef _LALSIM_IMR_PHENOMX_UTILITIES_H
+#define _LALSIM_IMR_PHENOMX_UTILITIES_H
+
+/*
+ * Copyright (C) 2018 Geraint Pratten
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with with program; see the file COPYING. If not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *  MA  02111-1307  USA
+ */
+
+
+/*
+ * \author Geraint Pratten
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+#include <lal/LALDatatypes.h>
+#include <lal/LALConstants.h>
+#include <lal/LALStdlib.h>
+#include <lal/FrequencySeries.h>
+#include <lal/Units.h>
+#include <lal/Date.h>
+#include <lal/LALSimInspiral.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+  //#include <complex.h>
+
+/* ********************** NUMERICAL UTILITY FUNCTIONS ********************* */
+size_t NextPow2(const size_t n);
+bool IMRPhenomX_StepFuncBool(const double t, const double t1);
+void IMRPhenomX_InternalNudge(REAL8 x, REAL8 X, REAL8 epsilon);
+bool IMRPhenomX_ApproxEqual(REAL8 x, REAL8 y, REAL8 epsilon);
+
+double pow_2_of(double number);
+double pow_3_of(double number);
+double pow_4_of(double number);
+double pow_5_of(double number);
+double pow_6_of(double number);
+double pow_7_of(double number);
+double pow_8_of(double number);
+double pow_9_of(double number);
+
+REAL8 XLALSimIMRPhenomXsign(REAL8 x);
+
+REAL8 XLALSimIMRPhenomXatan2tol(REAL8 a, REAL8 b, REAL8 tol);
+
+
+/* We want to expose the functions below - they are useful */
+/* ********************** FREQUENCY CONVERSIONS ********************* */
+REAL8 XLALSimIMRPhenomXUtilsMftoHz(REAL8 Mf, REAL8 Mtot_Msun);
+REAL8 XLALSimIMRPhenomXUtilsHztoMf(REAL8 fHz, REAL8 Mtot_Msun);
+
+REAL8 XLALSimIMRPhenomXLina(REAL8 eta, REAL8 S, REAL8 dchi, REAL8 delta);
+REAL8 XLALSimIMRPhenomXLinb(REAL8 eta, REAL8 S, REAL8 dchi, REAL8 delta);
+REAL8 XLALSimIMRPhenomXPsi4ToStrain(double eta, double S, double dchi);
+
+/* ********************** MECO, ISCO, ETC ********************* */
+REAL8 XLALSimIMRPhenomXfMECO(REAL8 eta, REAL8 chi1L, REAL8 chi2L);
+REAL8 XLALSimIMRPhenomXfISCO(REAL8 chif);
+
+/* ********************** SPIN PARAMETERISATIONS ********************* */
+REAL8 XLALSimIMRPhenomXchiPN(REAL8 eta, REAL8 chi1l, REAL8 chi2l);
+REAL8 XLALSimIMRPhenomXchiPNHat(REAL8 eta, REAL8 chi1l, REAL8 chi2l);
+REAL8 XLALSimIMRPhenomXchiEff(REAL8 eta, REAL8 chi1l, REAL8 chi2l);
+REAL8 XLALSimIMRPhenomXdchi(REAL8 chi1l, REAL8 chi2l);
+REAL8 XLALSimIMRPhenomXSTotR(REAL8 eta, REAL8 chi1l, REAL8 chi2l);
+
+/* ********************** MASS PARAMETERISATIONS ********************* */
+
+/* ********************** FINAL STATE ********************* */
+REAL8 XLALSimIMRPhenomXFinalSpin2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L);
+REAL8 XLALSimIMRPhenomXFinalMass2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L);
+REAL8 XLALSimIMRPhenomXErad2017(REAL8 eta, REAL8 chi1L, REAL8 chi2L);
+
+//int  ComputeIMRPhenomXWaveformVariables(double eta, double chi1L, double chi2L, IMRPhenomXWaveformVariables *pWF);
+
+/* ********************** ANALYTICAL MODEL WRAPPERS *********************  */
+REAL8 XLALSimIMRPhenomXIntermediatePhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 aL);
+REAL8 XLALSimIMRPhenomXIntermediateAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 ff7o6, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a3, REAL8 a4, REAL8 a5);
+REAL8 XLALSimIMRPhenomXRingdownPhase22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL);
+REAL8 XLALSimIMRPhenomXRingdownPhaseDeriv22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 a0, REAL8 a1, REAL8 a2, REAL8 a4, REAL8 aL);
+REAL8 XLALSimIMRPhenomXRingdownAmplitude22AnsatzAnalytical(REAL8 ff, REAL8 fRD, REAL8 fDA, REAL8 gamma1, REAL8 gamma2, REAL8 gamma3);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LALSIM_IMR_PHENOMX_UTILITIES_H */
diff --git a/lalsimulation/lib/LALSimInspiral.c b/lalsimulation/lib/LALSimInspiral.c
index 931a6c2ac86d2c3a0560cff6bbf75c9c58c969b9..36e7010eeb8a565ec1b44edffef88526cbc091a0 100644
--- a/lalsimulation/lib/LALSimInspiral.c
+++ b/lalsimulation/lib/LALSimInspiral.c
@@ -175,6 +175,8 @@ static const char *lalSimulationApproximantNames[] = {
     INITIALIZE_NAME(NRSur7dq4),
     INITIALIZE_NAME(NR_hdf5),
     INITIALIZE_NAME(NRHybSur3dq8),
+    INITIALIZE_NAME(IMRPhenomXAS),
+    INITIALIZE_NAME(IMRPhenomXHM),
 };
 #undef INITIALIZE_NAME
 
@@ -1024,6 +1026,70 @@ int XLALSimInspiralChooseTDWaveform(
                     S1z, S2z, LALparams); 
             break;
 
+	case IMRPhenomXAS:
+			    if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALparams) )
+				    ABORT_NONDEFAULT_LALDICT_FLAGS(LALparams);
+			    if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+				    ABORT_NONZERO_TRANSVERSE_SPINS(LALparams);
+			    if( !checkTidesZero(lambda1, lambda2) )
+				    ABORT_NONZERO_TIDES(LALparams);
+			    // generate TD waveforms with zero inclincation so that amplitude can be
+			    // calculated from hplus and hcross, apply inclination-dependent factors
+			    // in loop below
+
+
+			    ret = XLALSimInspiralTDFromFD(hplus, hcross, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, distance, inclination, phiRef,
+						longAscNodes, eccentricity, meanPerAno, deltaT, f_min, f_ref, LALparams, approximant);
+
+					// The Fourier domain model is built such that the TD transformation peakds approximately at zero.
+					// Here we force an exact alignment at zero by computing the maximum of hp^2 + hc^2.
+				 	maxamp = 0;
+					maxind = (*hplus)->data->length - 1;
+					for (loopi = (*hplus)->data->length - 1; loopi > -1; loopi--)
+					{
+							REAL8 ampsqr = ((*hplus)->data->data[loopi]) * ((*hplus)->data->data[loopi]) +
+														 ((*hcross)->data->data[loopi]) * ((*hcross)->data->data[loopi]);
+							if (ampsqr > maxamp)
+							{
+									maxind = loopi;
+									maxamp = ampsqr;
+							}
+					}
+					// Shift peak to t=0.
+					XLALGPSSetREAL8(&((*hplus)->epoch), (-1.) * deltaT * maxind);
+					XLALGPSSetREAL8(&((*hcross)->epoch), (-1.) * deltaT * maxind);
+					break;
+
+	case IMRPhenomXHM:
+					if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALparams))
+						ABORT_NONDEFAULT_LALDICT_FLAGS(LALparams);
+					if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+						ABORT_NONZERO_TRANSVERSE_SPINS(LALparams);
+					if( !checkTidesZero(lambda1, lambda2) )
+						ABORT_NONZERO_TIDES(LALparams);
+
+					ret = XLALSimInspiralTDFromFD(hplus, hcross, m1, m2, S1x, S1y, S1z, S2x, S2y, S2z, distance, inclination, phiRef,
+						longAscNodes, eccentricity, meanPerAno, deltaT, f_min, f_ref, LALparams, approximant);
+
+					// The Fourier domain model is built such that the TD transformation peakds approximately at zero.
+					// Here we force an exact alignment at zero by computing the maximum of hp^2 + hc^2.
+					maxamp = 0;
+					maxind = (*hplus)->data->length - 1;
+					for (loopi = (*hplus)->data->length - 1; loopi > -1; loopi--)
+					{
+							REAL8 ampsqr = ((*hplus)->data->data[loopi]) * ((*hplus)->data->data[loopi]) +
+														 ((*hcross)->data->data[loopi]) * ((*hcross)->data->data[loopi]);
+							if (ampsqr > maxamp)
+							{
+									maxind = loopi;
+									maxamp = ampsqr;
+							}
+					}
+					// Shift peak to t=0.
+					XLALGPSSetREAL8(&((*hplus)->epoch), (-1.) * deltaT * maxind);
+					XLALGPSSetREAL8(&((*hcross)->epoch), (-1.) * deltaT * maxind);
+					break;
+
         default:
             XLALPrintError("TD version of approximant not implemented in lalsimulation\n");
             XLAL_ERROR(XLAL_EINVAL);
@@ -1858,6 +1924,82 @@ int XLALSimInspiralChooseFDWaveform(
                 if (ret == XLAL_FAILURE) XLAL_ERROR(XLAL_EFUNC);
             break;
 
+	        case IMRPhenomXAS:
+	            /* Waveform-specific sanity checks */
+	            if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALparams) )
+	                ABORT_NONDEFAULT_LALDICT_FLAGS(LALparams);
+	            if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+	                ABORT_NONZERO_TRANSVERSE_SPINS(LALparams);
+	            if( !checkTidesZero(lambda1, lambda2) )
+	                ABORT_NONZERO_TIDES(LALparams);
+
+							/* This is the factor that comes from Y_22star + (-1)^l * Y_2-2 without the dependence in inclination, that is included in pfac and cfac */
+							/* Ylm(inclination, beta), with beta = PI/2 - phiRef. phiRef is included in the individual mode */
+							COMPLEX16 Ylmfactor = 2.0*sqrt(5.0 / (64.0 * LAL_PI)) * cexp(-I*2*(LAL_PI_2));
+							/* The factor for hc is the same but opposite sign */
+
+	            /* Call the waveform driver routine. */
+							/* It returns h_2-2(f) for positive frequencies. h_2-2 is zero for negative frequencies. */
+							/* h_22(f) is zero for positive frequencies. For negatives frequencies h_22(f) = Conjugate[h_2-2(-f)] */
+							/* We returns h2_-2 because it is the mode with the positive frequencies,
+							 and we need this mode because XLALSimInspiralTDFromFD assumes that the input array is in the positive frequencies regime. */
+	            ret = XLALSimIMRPhenomXASGenerateFD(hptilde, m1, m2,
+	                  S1z, S2z, distance, f_min, f_max, deltaF, phiRef, f_ref, LALparams);
+	            if (ret == XLAL_FAILURE) XLAL_ERROR(XLAL_EFUNC);
+
+	            /* Produce both polarizations for positive frequencies */
+						  *hctilde = XLALCreateCOMPLEX16FrequencySeries("FD hcross",
+	                    &((*hptilde)->epoch), (*hptilde)->f0, (*hptilde)->deltaF,
+	                    &((*hptilde)->sampleUnits), (*hptilde)->data->length);
+	            for(j = 0; j < (*hptilde)->data->length; j++) {
+	                (*hctilde)->data->data[j] = -I*cfac * (*hptilde)->data->data[j] * Ylmfactor;
+									(*hptilde)->data->data[j] *= pfac * Ylmfactor;
+	            }
+	            break;
+
+			case IMRPhenomXHM:
+					/* Waveform-specific sanity checks */
+					if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALparams) )
+							ABORT_NONDEFAULT_LALDICT_FLAGS(LALparams);
+					if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+							ABORT_NONZERO_TRANSVERSE_SPINS(LALparams);
+					if( !checkTidesZero(lambda1, lambda2) )
+							ABORT_NONZERO_TIDES(LALparams);
+
+					/* Activate or not the debug info. */
+					#ifndef PHENOMXHMDEBUG  // Defined at compilation time. ./configure --prefix=... CFLAGS='-g -D PHENOMXHMDEBUG'
+					  #define DEBUG 0
+					#else
+						#define DEBUG 1 //print debugging info
+					#endif
+
+					/* Return hp and hc for positive frequencies. Only negatives modes contribute to positive frequencies.  */
+					/* The negative frquencies contribution is the complex conjugate of the positive one. */
+
+			    /* Take input/default value for the threshold of the Multibanding. If = 0 then do not use Multibanding. */
+			    REAL8 resTest  = XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(LALparams);
+
+					/* If total mass is very high (>500 solar masses), we only have a few points in the ringdown, interpolation is not efficient, do not use Multibanding */
+					REAL8 Mtot = (m1 + m2)/LAL_MSUN_SI;
+					if(resTest!=0 && Mtot > 500){
+						resTest = 0.;
+					}
+
+					if(resTest == 0.){ //Do not use multibanding
+						ret = XLALSimIMRPhenomXHM2(hptilde, hctilde, m1, m2, S1z, S2z, f_min, f_max, deltaF, distance, inclination, phiRef, f_ref, LALparams);
+					}
+					else{ // Use multibanding
+						ret = XLALSimIMRPhenomXHM(hptilde, hctilde, m1, m2, S1z, S2z, f_min, f_max, deltaF, distance, inclination, phiRef, f_ref, LALparams);
+					}
+
+					if (ret == XLAL_FAILURE)
+             XLAL_ERROR(XLAL_EFUNC);
+
+				  #if DEBUG == 1
+					printf("\n\n**********Leaving ChooseFDWaveform *********************\n\n");
+				  #endif
+					break;
+
         default:
             XLALPrintError("FD version of approximant not implemented in lalsimulation\n");
             XLAL_ERROR(XLAL_EINVAL);
@@ -5029,6 +5171,8 @@ int XLALSimInspiralImplementedTDApproximants(
         case IMRPhenomPv2_NRTidal:
         case IMRPhenomPv2_NRTidalv2:
         case IMRPhenomD_NRTidalv2:
+		case IMRPhenomXAS:
+		case IMRPhenomXHM:
         case PhenSpinTaylorRD:
         case SEOBNRv1:
         case SpinDominatedWf:
@@ -5081,6 +5225,8 @@ int XLALSimInspiralImplementedFDApproximants(
         case IMRPhenomPv2:
         case IMRPhenomPv2_NRTidal:
         case IMRPhenomPv2_NRTidalv2:
+		case IMRPhenomXAS:
+		case IMRPhenomXHM:
         case EOBNRv2_ROM:
         case EOBNRv2HM_ROM:
         case SEOBNRv1_ROM_EffectiveSpin:
@@ -5520,6 +5666,8 @@ int XLALSimInspiralGetSpinSupportFromApproximant(Approximant approx){
     case IMRPhenomD_NRTidal:
     case IMRPhenomD_NRTidalv2:
     case IMRPhenomHM:
+    case IMRPhenomXAS:
+    case IMRPhenomXHM:
     case SEOBNRv1:
     case SEOBNRv2:
     case SEOBNRv4:
@@ -5752,6 +5900,8 @@ int XLALSimInspiralApproximantAcceptTestGRParams(Approximant approx){
     case NRSur7dq4:
     case NRHybSur3dq8:
     case IMRPhenomHM:
+    case IMRPhenomXAS:
+    case IMRPhenomXHM:
     case NumApproximants:
       testGR_accept=LAL_SIM_INSPIRAL_NO_TESTGR_PARAMS;
       break;
diff --git a/lalsimulation/lib/LALSimInspiral.h b/lalsimulation/lib/LALSimInspiral.h
index 795c2af86fe6ca70bd750c957fcec027049349c5..52132ae40baabf4bcc8c34ed8335b7d3d2c4ca13 100644
--- a/lalsimulation/lib/LALSimInspiral.h
+++ b/lalsimulation/lib/LALSimInspiral.h
@@ -415,6 +415,8 @@ typedef enum tagApproximant {
    SEOBNRv4HM,	/**< Spin nonprecessing EOBNR model v4 with higher modes, PhysRevD.98.084028 [arXiv:1803.10701]
                      * @remarks Implemented in lalsimulation (time domain). */
    NRHybSur3dq8,        /**< Time domain, aligned-spin, higher modes, hybridized. Paper arxiv:1812.07865 */
+    IMRPhenomXAS, 		/**< Frequency domain, non-precessing phenomenological IMR waveform model ([arXiv: 20XY.ZZZZZ]). */
+    IMRPhenomXHM, 		/**< Frequency domain, non-precessing phenomenological IMR waveform model with subdominant modes ([arXiv:2001.10914 [gr-qc]]) and accelerated evaluation through adapted grids (arXiv:2001.10897 [gr-qc]) */
    NumApproximants,	/**< Number of elements in enum, useful for checking bounds */
  } Approximant;
 
diff --git a/lalsimulation/lib/LALSimInspiralWaveformCache.c b/lalsimulation/lib/LALSimInspiralWaveformCache.c
index ac50939a97de373301c51907abe307dc48653203..26cd3ab3a23dabc9dedcfc093a99d59f426301d8 100644
--- a/lalsimulation/lib/LALSimInspiralWaveformCache.c
+++ b/lalsimulation/lib/LALSimInspiralWaveformCache.c
@@ -1292,6 +1292,81 @@ int XLALSimInspiralChooseFDWaveformSequence(
                 XLAL_ERROR(XLAL_EFUNC);
             break;
 
+	      case IMRPhenomXAS:
+              /* Waveform-specific sanity checks */
+              if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALpars) )
+              ABORT_NONDEFAULT_LALDICT_FLAGS(LALpars);
+              if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+              ABORT_NONZERO_TRANSVERSE_SPINS(LALpars);
+              if( !checkTidesZero(lambda1, lambda2) )
+              ABORT_NONZERO_TIDES(LALpars);
+
+              /*
+              This is the factor that comes from Y_22star + (-1)^l * Y_2-2 without the dependence in inclination, that is included in pfac and cfac
+              We add the azimuthal part exp^{i*m*beta} of the spherical harmonics Ylm(inclination, beta),
+              with beta = PI/2 - phiRef, phiRef is included in the individual mode
+              */
+              COMPLEX16 Ylmfactor = 2.0*sqrt(5.0 / (64.0 * LAL_PI)) * cexp(-I*2*(LAL_PI/2 ));
+              /* The factor for hc is the same but opposite sign */
+
+              ret = XLALSimIMRPhenomXASFrequencySequence(hptilde, frequencies,
+                m1, m2, S1z, S2z, distance, phiRef, f_ref, LALpars);
+                if (ret == XLAL_FAILURE) XLAL_ERROR(XLAL_EFUNC);
+
+                /* Produce both polarizations */
+                *hctilde = XLALCreateCOMPLEX16FrequencySeries("FD hcross",
+                &((*hptilde)->epoch), (*hptilde)->f0, (*hptilde)->deltaF,
+                &((*hptilde)->sampleUnits), (*hptilde)->data->length
+              );
+              for(j = 0; j < (*hptilde)->data->length; j++)
+              {
+                (*hctilde)->data->data[j] = -I*cfac * (*hptilde)->data->data[j] * Ylmfactor;
+                (*hptilde)->data->data[j] *= pfac * Ylmfactor;
+              }
+              break;
+
+          case IMRPhenomXHM:
+    					/* Waveform-specific sanity checks */
+    					if( !XLALSimInspiralWaveformParamsFlagsAreDefault(LALpars) )
+    							ABORT_NONDEFAULT_LALDICT_FLAGS(LALpars);
+    					if( !checkTransverseSpinsZero(S1x, S1y, S2x, S2y) )
+    							ABORT_NONZERO_TRANSVERSE_SPINS(LALpars);
+    					if( !checkTidesZero(lambda1, lambda2) )
+    							ABORT_NONZERO_TIDES(LALpars);
+
+    					/* Activate or not the debug info. */
+    					#ifndef PHENOMXHMDEBUG  // Defined at compilation time. ./configure --prefix=... CFLAGS='-g -D PHENOMXHMDEBUG'
+    					  #define DEBUG 0
+    					#else
+    						#define DEBUG 1 //print debugging info
+    					#endif
+
+              REAL8 f_max = frequencies->data[frequencies->length-1];
+              REAL8 deltaF = frequencies->data[1]-frequencies->data[0];
+
+    					/* Return hp and hc for positive frequencies. Only negatives modes contribute to positive frequencies.  */
+    					/* The negative frquencies contribution is the complex conjugate of the positive one. */
+
+    			    /* Take input/default value for the threshold of the Multibanding. If = 0 then do not use Multibanding. */
+    			    REAL8 resTest  = XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(LALpars);
+
+    					/* If total mass is very high (>500 solar masses), we only have a few points in the ringdown, interpolation is not efficient, do not use Multibanding */
+    					REAL8 Mtot = (m1 + m2)/LAL_MSUN_SI;
+    					if(resTest!=0 && Mtot > 500){
+    						resTest = 0.;
+    					}
+
+    					if(resTest == 0.){ //Do not use multibanding
+    						ret = XLALSimIMRPhenomXHM2(hptilde, hctilde, m1, m2, S1z, S2z, f_min, f_max, deltaF, distance, inclination, phiRef, f_ref, LALpars);
+    					}
+    					else{ // Use multibanding
+    						ret = XLALSimIMRPhenomXHM(hptilde, hctilde, m1, m2, S1z, S2z, f_min, f_max, deltaF, distance, inclination, phiRef, f_ref, LALpars);
+    					}
+
+    					if (ret == XLAL_FAILURE)
+                 XLAL_ERROR(XLAL_EFUNC);
+    				 	break;
+
         default:
             XLALPrintError("FD version of approximant not implemented in lalsimulation\n");
             XLAL_ERROR(XLAL_EINVAL);
diff --git a/lalsimulation/lib/LALSimInspiralWaveformParams.c b/lalsimulation/lib/LALSimInspiralWaveformParams.c
index 6b7861c03d6bc3c5d8f14ebed74a784d65fc2015..c88ed3a65a5bdc38bf26775bd29e7668fa04de78 100644
--- a/lalsimulation/lib/LALSimInspiralWaveformParams.c
+++ b/lalsimulation/lib/LALSimInspiralWaveformParams.c
@@ -148,6 +148,29 @@ DEFINE_INSERT_FUNC(NLTidesF2, REAL8, "nlTidesF2", 0)
 /* SEOBNRv4P */
 DEFINE_INSERT_FUNC(EOBChooseNumOrAnalHamDer, INT4, "EOBChooseNumOrAnalHamDer", 1)
 
+/* IMRPhenomX Parameters */
+DEFINE_INSERT_FUNC(PhenomXInspiralPhaseVersion, INT4, "InsPhaseVersion", 104)
+DEFINE_INSERT_FUNC(PhenomXInspiralAmpVersion, INT4, "InsAmpVersion", 103)
+DEFINE_INSERT_FUNC(PhenomXIntermediatePhaseVersion, INT4, "IntPhaseVersion", 105)
+DEFINE_INSERT_FUNC(PhenomXIntermediateAmpVersion, INT4, "IntAmpVersion", 104)
+DEFINE_INSERT_FUNC(PhenomXRingdownPhaseVersion, INT4, "RDPhaseVersion", 105)
+DEFINE_INSERT_FUNC(PhenomXRingdownAmpVersion, INT4, "RDAmpVersion", 103)
+DEFINE_INSERT_FUNC(PhenomXPrecVersion, INT4, "PrecVersion", 0)
+
+/* IMRPhenomXHM Parameters */
+DEFINE_INSERT_FUNC(PhenomXHMInspiralPhaseVersion, INT4, "InsPhaseHMVersion", 122019)
+DEFINE_INSERT_FUNC(PhenomXHMIntermediatePhaseVersion, INT4, "IntPhaseHMVersion", 122019)
+DEFINE_INSERT_FUNC(PhenomXHMRingdownPhaseVersion, INT4, "RDPhaseHMVersion", 122019)
+DEFINE_INSERT_FUNC(PhenomXHMInspiralAmpVersion, INT4, "InsAmpHMVersion", 3)
+DEFINE_INSERT_FUNC(PhenomXHMIntermediateAmpVersion, INT4, "IntAmpHMVersion", 2)
+DEFINE_INSERT_FUNC(PhenomXHMRingdownAmpVersion, INT4, "RDAmpHMVersion", 0)
+DEFINE_INSERT_FUNC(PhenomXHMInspiralAmpFitsVersion, INT4, "InsAmpFitsVersion", 122018)
+DEFINE_INSERT_FUNC(PhenomXHMIntermediateAmpFitsVersion, INT4, "IntAmpFitsVersion", 122018)
+DEFINE_INSERT_FUNC(PhenomXHMRingdownAmpFitsVersion, INT4, "RDAmpFitsVersion", 122018)
+DEFINE_INSERT_FUNC(PhenomXHMPhaseRef21, REAL8, "PhaseRef21", 0.)
+DEFINE_INSERT_FUNC(PhenomXHMThresholdMband, REAL8, "ThresholdMband", 0.001)
+DEFINE_INSERT_FUNC(PhenomXHMAmpInterpolMB, INT4, "AmpInterpol", 1)
+
 /* LOOKUP FUNCTIONS */
 
 DEFINE_LOOKUP_FUNC(ModesChoice, INT4, "modes", LAL_SIM_INSPIRAL_MODES_CHOICE_ALL)
@@ -251,6 +274,29 @@ DEFINE_LOOKUP_FUNC(NLTidesF2, REAL8, "nlTidesF2", 0)
 /* SEOBNRv4P */
 DEFINE_LOOKUP_FUNC(EOBChooseNumOrAnalHamDer, INT4, "EOBChooseNumOrAnalHamDer", 1)
 
+/* IMRPhenomX Parameters */
+DEFINE_LOOKUP_FUNC(PhenomXInspiralPhaseVersion, INT4, "InsPhaseVersion", 104)
+DEFINE_LOOKUP_FUNC(PhenomXInspiralAmpVersion, INT4, "InsAmpVersion", 103)
+DEFINE_LOOKUP_FUNC(PhenomXIntermediatePhaseVersion, INT4, "IntPhaseVersion", 105)
+DEFINE_LOOKUP_FUNC(PhenomXIntermediateAmpVersion, INT4, "IntAmpVersion", 104)
+DEFINE_LOOKUP_FUNC(PhenomXRingdownPhaseVersion, INT4, "RDPhaseVersion", 105)
+DEFINE_LOOKUP_FUNC(PhenomXRingdownAmpVersion, INT4, "RDAmpVersion", 103)
+DEFINE_LOOKUP_FUNC(PhenomXPrecVersion, INT4, "PrecVersion", 0)
+
+/* IMRPhenomXHM Parameters */
+DEFINE_LOOKUP_FUNC(PhenomXHMInspiralPhaseVersion, INT4, "InsPhaseHMVersion", 122019)
+DEFINE_LOOKUP_FUNC(PhenomXHMIntermediatePhaseVersion, INT4, "IntPhaseHMVersion", 122019)
+DEFINE_LOOKUP_FUNC(PhenomXHMRingdownPhaseVersion, INT4, "RDPhaseHMVersion", 122019)
+DEFINE_LOOKUP_FUNC(PhenomXHMInspiralAmpVersion, INT4, "InsAmpHMVersion", 3)
+DEFINE_LOOKUP_FUNC(PhenomXHMIntermediateAmpVersion, INT4, "IntAmpHMVersion", 2)
+DEFINE_LOOKUP_FUNC(PhenomXHMRingdownAmpVersion, INT4, "RDAmpHMVersion", 0)
+DEFINE_LOOKUP_FUNC(PhenomXHMInspiralAmpFitsVersion, INT4, "InsAmpFitsVersion", 122018)
+DEFINE_LOOKUP_FUNC(PhenomXHMIntermediateAmpFitsVersion, INT4, "IntAmpFitsVersion", 122018)
+DEFINE_LOOKUP_FUNC(PhenomXHMRingdownAmpFitsVersion, INT4, "RDAmpFitsVersion", 122018)
+DEFINE_LOOKUP_FUNC(PhenomXHMPhaseRef21, REAL8, "PhaseRef21", 0.)
+DEFINE_LOOKUP_FUNC(PhenomXHMThresholdMband, REAL8, "ThresholdMband", 0.001)
+DEFINE_LOOKUP_FUNC(PhenomXHMAmpInterpolMB, INT4, "AmpInterpol", 1)
+
 /* ISDEFAULT FUNCTIONS */
 
 DEFINE_ISDEFAULT_FUNC(ModesChoice, INT4, "modes", LAL_SIM_INSPIRAL_MODES_CHOICE_ALL)
@@ -337,4 +383,27 @@ DEFINE_ISDEFAULT_FUNC(NonGRBetaPPE7, REAL8, "betaPPE7", 0)
 /* SEOBNRv4P */
 DEFINE_ISDEFAULT_FUNC(EOBChooseNumOrAnalHamDer, INT4, "EOBChooseNumOrAnalHamDer", 1)
 
+/* IMRPhenomX Parameters */
+DEFINE_ISDEFAULT_FUNC(PhenomXInspiralPhaseVersion, INT4, "InsPhaseVersion", 104)
+DEFINE_ISDEFAULT_FUNC(PhenomXInspiralAmpVersion, INT4, "InsAmpVersion", 103)
+DEFINE_ISDEFAULT_FUNC(PhenomXIntermediatePhaseVersion, INT4, "IntPhaseVersion", 105)
+DEFINE_ISDEFAULT_FUNC(PhenomXIntermediateAmpVersion, INT4, "IntAmpVersion", 104)
+DEFINE_ISDEFAULT_FUNC(PhenomXRingdownPhaseVersion, INT4, "RDPhaseVersion", 105)
+DEFINE_ISDEFAULT_FUNC(PhenomXRingdownAmpVersion, INT4, "RDAmpVersion", 103)
+DEFINE_ISDEFAULT_FUNC(PhenomXPrecVersion, INT4, "PrecVersion", 0)
+
+/* IMRPhenomXHM Parameters */
+DEFINE_ISDEFAULT_FUNC(PhenomXHMInspiralPhaseVersion, INT4, "InsPhaseHMVersion", 122019)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMIntermediatePhaseVersion, INT4, "IntPhaseHMVersion", 122019)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMRingdownPhaseVersion, INT4, "RDPhaseHMVersion", 122019)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMInspiralAmpVersion, INT4, "InsAmpHMVersion", 3)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMIntermediateAmpVersion, INT4, "IntAmpHMVersion", 2)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMRingdownAmpVersion, INT4, "RDAmpHMVersion", 0)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMInspiralAmpFitsVersion, INT4, "InsAmpFitsVersion", 122018)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMIntermediateAmpFitsVersion, INT4, "IntAmpFitsVersion", 122018)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMRingdownAmpFitsVersion, INT4, "RDAmpFitsVersion", 122018)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMPhaseRef21, REAL8, "PhaseRef21", 0.)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMThresholdMband, REAL8, "ThresholdMband", 0.001)
+DEFINE_ISDEFAULT_FUNC(PhenomXHMAmpInterpolMB, INT4, "AmpInterpol", 1)
+
 #undef String
diff --git a/lalsimulation/lib/LALSimInspiralWaveformParams.h b/lalsimulation/lib/LALSimInspiralWaveformParams.h
index 9a32ac7f18a03664586be3e86267f2e74531bb9f..93b8b29841a41a2bc825d1e53a2a35f9dfd0f074 100644
--- a/lalsimulation/lib/LALSimInspiralWaveformParams.h
+++ b/lalsimulation/lib/LALSimInspiralWaveformParams.h
@@ -38,6 +38,29 @@ int XLALSimInspiralWaveformParamsInsertdQuadMon2(LALDict *params, REAL8 value);
 int XLALSimInspiralWaveformParamsInsertRedshift(LALDict *params, REAL8 value);
 int XLALSimInspiralWaveformParamsInsertEccentricityFreq(LALDict *params, REAL8 value);
 
+/* IMRPhenomX Parameters */
+int XLALSimInspiralWaveformParamsInsertPhenomXInspiralPhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXInspiralAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXIntermediatePhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXIntermediateAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXRingdownPhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXRingdownAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXPrecVersion(LALDict *params, INT4 value);
+
+/* IMRPhenomXHM Parameters */
+int XLALSimInspiralWaveformParamsInsertPhenomXHMInspiralPhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMIntermediatePhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMRingdownPhaseVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMInspiralAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMIntermediateAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMRingdownAmpVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMInspiralAmpFitsVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMIntermediateAmpFitsVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMRingdownAmpFitsVersion(LALDict *params, INT4 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMPhaseRef21(LALDict *params, REAL8 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMThresholdMband(LALDict *params, REAL8 value);
+int XLALSimInspiralWaveformParamsInsertPhenomXHMAmpInterpolMB(LALDict *params, INT4 value);
+
 int XLALSimInspiralWaveformParamsInsertNonGRPhi1(LALDict *params, REAL8 value);
 int XLALSimInspiralWaveformParamsInsertNonGRPhi2(LALDict *params, REAL8 value);
 int XLALSimInspiralWaveformParamsInsertNonGRPhi3(LALDict *params, REAL8 value);
@@ -128,6 +151,29 @@ REAL8 XLALSimInspiralWaveformParamsLookupRedshift(LALDict *params);
 REAL8 XLALSimInspiralWaveformParamsLookupEccentricityFreq(LALDict *params);
 INT4 XLALSimInspiralWaveformParamsLookupLscorr(LALDict *params);
 
+/* IMRPhenomX Parameters */
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXInspiralPhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXInspiralAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXIntermediatePhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXIntermediateAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXRingdownPhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXRingdownAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXPrecVersion(LALDict *params);
+
+/* IMRPhenomXHM Parameters */
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralPhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediatePhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownPhaseVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediateAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownAmpVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMInspiralAmpFitsVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMIntermediateAmpFitsVersion(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMRingdownAmpFitsVersion(LALDict *params);
+REAL8 XLALSimInspiralWaveformParamsLookupPhenomXHMPhaseRef21(LALDict *params);
+REAL8 XLALSimInspiralWaveformParamsLookupPhenomXHMThresholdMband(LALDict *params);
+INT4 XLALSimInspiralWaveformParamsLookupPhenomXHMAmpInterpolMB(LALDict *params);
+
 REAL8 XLALSimInspiralWaveformParamsLookupNonGRPhi1(LALDict *params);
 REAL8 XLALSimInspiralWaveformParamsLookupNonGRPhi2(LALDict *params);
 REAL8 XLALSimInspiralWaveformParamsLookupNonGRPhi3(LALDict *params);
@@ -217,6 +263,29 @@ int XLALSimInspiralWaveformParamsdQuadMon2IsDefault(LALDict *params);
 int XLALSimInspiralWaveformParamsRedshiftIsDefault(LALDict *params);
 int XLALSimInspiralWaveformParamsEccentricityFreqIsDefault(LALDict *params);
 
+/* IMRPhenomX Parameters */
+int XLALSimInspiralWaveformParamsPhenomXInspiralPhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXInspiralAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXIntermediatePhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXIntermediateAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXRingdownPhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXRingdownAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXPrecVersionIsDefault(LALDict *params);
+
+/* IMRPhenomXHM Parameters */
+int XLALSimInspiralWaveformParamsPhenomXHMInspiralPhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMIntermediatePhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMRingdownPhaseVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMInspiralAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMIntermediateAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMRingdownAmpVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMInspiralAmpFitsVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMIntermediateAmpFitsVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMRingdownAmpFitsVersionIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMPhaseRef21IsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMThresholdMbandIsDefault(LALDict *params);
+int XLALSimInspiralWaveformParamsPhenomXHMAmpInterpolMBIsDefault(LALDict *params);
+
 int XLALSimInspiralWaveformParamsNonGRPhi1IsDefault(LALDict *params);
 int XLALSimInspiralWaveformParamsNonGRPhi2IsDefault(LALDict *params);
 int XLALSimInspiralWaveformParamsNonGRPhi3IsDefault(LALDict *params);
diff --git a/lalsimulation/lib/Makefile.am b/lalsimulation/lib/Makefile.am
index 00fde1553dc346c44e26de133896e850c733ce71..d8070dab283fc66d60d0c001e02b8c5eed1c0730 100644
--- a/lalsimulation/lib/Makefile.am
+++ b/lalsimulation/lib/Makefile.am
@@ -145,6 +145,8 @@ pkginclude_HEADERS = \
 	LALSimBurst.h \
 	LALSimIMR.h \
 	LALSimIMRPhenomUtils.h \
+	LALSimIMRPhenomX_utilities.h \
+	LALSimIMRPhenomX_internals.h \
 	LALSimInspiral.h \
 	LALSimInspiralPrecess.h \
 	LALSimInspiralTestGRParams.h \
@@ -192,6 +194,30 @@ noinst_HEADERS = \
 	LALSimIMRPhenomD.h \
 	LALSimIMRPhenomD_internals.c \
 	LALSimIMRPhenomD_internals.h \
+	LALSimIMRPhenomX.h \
+	LALSimIMRPhenomX_internals.c \
+	LALSimIMRPhenomX_qnm.c \
+	LALSimIMRPhenomX_qnm.h \
+	LALSimIMRPhenomX_inspiral.c \
+	LALSimIMRPhenomX_inspiral.h \
+	LALSimIMRPhenomX_intermediate.c \
+	LALSimIMRPhenomX_intermediate.h \
+	LALSimIMRPhenomX_ringdown.c \
+	LALSimIMRPhenomX_ringdown.h \
+	LALSimIMRPhenomXHM.h \
+	LALSimIMRPhenomXHM_internals.c \
+	LALSimIMRPhenomXHM_internals.h \
+	LALSimIMRPhenomXHM_qnm.c \
+	LALSimIMRPhenomXHM_qnm.h \
+	LALSimIMRPhenomXHM_inspiral.c \
+	LALSimIMRPhenomXHM_inspiral.h \
+	LALSimIMRPhenomXHM_intermediate.c \
+	LALSimIMRPhenomXHM_intermediate.h \
+	LALSimIMRPhenomXHM_ringdown.c \
+	LALSimIMRPhenomXHM_ringdown.h \
+	LALSimIMRPhenomXHM_structs.h \
+	LALSimIMRPhenomXHM_multiband.c \
+	LALSimIMRPhenomXHM_multiband.h \
 	LALSimIMRPhenomHM.h \
 	LALSimIMRPhenomP.c \
 	LALSimIMRPhenomP.h \
@@ -265,6 +291,9 @@ liblalsimulation_la_SOURCES = \
 	LALSimIMRPhenomP.c \
 	LALSimIMRPhenomInternalUtils.c \
 	LALSimIMRPhenomUtils.c \
+	LALSimIMRPhenomX.c \
+	LALSimIMRPhenomX_utilities.c \
+	LALSimIMRPhenomXHM.c \
 	LALSimIMRPSpinInspiralRD.c \
 	LALSimPhenSpinRingDown.c \
 	LALSimInspiralWaveformFlags.c \
diff --git a/lalsimulation/test/GenerateSimulation.c b/lalsimulation/test/GenerateSimulation.c
index 021d6f19db41b0eb52d1a68f2a4f5d472857acd0..87b39ab1c6aee8bc68657bae9bbbe744b6f34b9d 100644
--- a/lalsimulation/test/GenerateSimulation.c
+++ b/lalsimulation/test/GenerateSimulation.c
@@ -193,6 +193,10 @@ const char * usage =
 "--higher-modes VALUE       specify l modes with value 'VALUE' (L2 or RESTRICTED is default)\n"
 "--outname FNAME            Output to file FNAME (default 'simulation.dat')\n"
 "--verbose                  If included, add verbose output\n"
+"--phenomXHMMband float     Threshold parameter for the Multibanding of IMRPhenomXHM. By default set to 10^-4. If set to 0 then do not use multibanding.\n"
+"--modesList string         List of modes to be used by the model, e.g. --modesList '2,2, 2,-2, 2,1, 2,-1'. \n"
+"                           To use all the modes available in the mode do not add --modesList. Do not use if you do not know which modes the model returns!\n"
+
 ;
 
 /* Parse command line, sanity check arguments, and return a newly
@@ -365,7 +369,26 @@ static GSParams *parse_args(ssize_t argc, char **argv) {
             snprintf(params->outname, sizeof(params->outname), "%s", argv[++i]);
         } else if (strcmp(argv[i], "--nr-file") == 0) {
 	  XLALSimInspiralWaveformParamsInsertNumRelData(params->params, argv[++i]);
-        } else {
+        } else if (strcmp(argv[i], "--modesList") == 0) {
+            char numbers_str[50], *currnum;
+            strncpy(numbers_str, argv[++i], 50);
+            int numbers[25], iii = 0;
+            while ((currnum = strtok(iii ? NULL : numbers_str, ",")) != NULL){
+              numbers[iii++] = atoi(currnum);
+            }
+            //printf("\nChoosing modesList\n");
+            LALValue *ModeArray = XLALSimInspiralCreateModeArray();
+            for (int ii=0; ii<iii; ii+=2){
+                // printf("numbers[%i] = %d\n", ii, numbers[ii]);
+                // printf("numbers[%i] = %d\n", ii+1, numbers[ii+1]);
+               XLALSimInspiralModeArrayActivateMode(ModeArray, numbers[ii], numbers[ii+1]);
+               XLALSimInspiralWaveformParamsInsertModeArray(params->params, ModeArray);
+             }
+             XLALDestroyValue(ModeArray);
+
+        }else if(strcmp(argv[i], "--phenomXHMMband") == 0){
+            XLALSimInspiralWaveformParamsInsertPhenomXHMThresholdMband(params->params, atof(argv[++i]));
+        }else {
             XLALPrintError("Error: invalid option: %s\n", argv[i]);
             goto fail;
         }
@@ -465,7 +488,7 @@ static int dump_TD(FILE *f, REAL8TimeSeries *hplus, REAL8TimeSeries *hcross) {
 
     fprintf(f, "# t hplus hcross\n");
     for (i=0; i < hplus->data->length; i++)
-        fprintf(f, "%25.16e %25.16e %25.16e\n", t0 + i * hplus->deltaT, 
+        fprintf(f, "%25.16e %25.16e %25.16e\n", t0 + i * hplus->deltaT,
                 hplus->data->data[i], hcross->data->data[i]);
     return 0;
 }