/*
** The iterator passed as the first argument has the following fields set
** as follows. This function sets up the rest of the iterator so that it
** points to the first rowid in the doclist-index.
**
**   pData:
**     pointer to doclist-index record,
**
** When this function is called pIter->iLeafPgno is the page number the
** doclist is associated with (the one featuring the term).
*/


/*
** Fts5SegIter.iLeafOffset currently points to the first byte of a
** position-list size field. Read the value of the field and store it
** in the following variables:
**
**   Fts5SegIter.nPos
**   Fts5SegIter.bDel
**
** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
** position list content (if any).
*/


/*
** Advance the iterator passed as the second argument until it is at or
** past rowid iFrom. Regardless of the value of iFrom, the iterator is
** always advanced at least once.
*/


/*
** Return a pointer to a buffer containing the term associated with the
** entry that the iterator currently points to.
*/


/*
** Return the size of the prefix, in bytes, that buffer
** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
**
** Buffer (pNew/<length-unknown>) is guaranteed to be greater
** than buffer (pOld/nOld).
*/


/*
** Buffer aBuf[] contains a list of varints, all small enough to fit
** in a 32-bit integer. Return the size of the largest prefix of this
** list nMax bytes or less in size.
*/


/*
** Move to the next matching rowid.
*/


/*
** Read and decode the "averages" record from the database.
**
** Parameter anSize must point to an array of size nCol, where nCol is
** the number of user defined columns in the FTS table.
*/


/*
** Replace the current "averages" record with the contents of the buffer
** supplied as the second argument.
*/


/*
** This is part of the fts5_decode() debugging aid.
**
** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This
** function appends a human-readable representation of the same object
** to the buffer passed as the second argument.
*/


/*
** This is part of the fts5_decode() debugging aid.
**
** Arguments pBlob/nBlob contain an "averages" record. This function
** appends a human-readable representation of record to the buffer passed
** as the second argument.
*/


/*
** The start of buffer (a/n) contains the start of a doclist. The doclist
** may or may not finish within the buffer. This function appends a text
** representation of the part of the doclist that is present to buffer
** pBuf.
**
** The return value is the number of bytes read from the input buffer.
*/


/*
** This function is part of the fts5_decode() debugging function. It is
** only ever used with detail=none tables.
**
** Buffer (pData/nData) contains a doclist in the format used by detail=none
** tables. This function appends a human-readable version of that list to
** buffer pBuf.
**
** If *pRc is other than SQLITE_OK when this function is called, it is a
** no-op. If an OOM or other error occurs within this function, *pRc is
** set to an SQLite error code before returning. The final state of buffer
** pBuf is undefined in this case.
*/


/*
** This is the xRowid method. The SQLite core calls this routine to
** retrieve the rowid for the current row of the result set. fts5
** exposes %_content.rowid as the rowid for the virtual table. The
** rowid should be written to *pRowid.
*/


/*
** Find a tokenizer. This is the implementation of the
** fts5_api.xFindTokenizer() method.
*/


/*
** Load the contents of the "averages" record from disk into the
** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
** argument bCache is true, set the p->bTotalsValid flag to indicate
** that the contents of aTotalSize[] and nTotalRow are valid until
** further notice.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error
** occurs.
*/


/*
** Store the current contents of the p->nTotalRow and p->aTotalSize[]
** variables in the "averages" record on disk.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error
** occurs.
*/


/*! \brief Value inside integral, general w case.
   wfac is -3(1+w)*/


/*! \brief Value inside integral, \f$w_0, w_a\f$ case.
   wfac is -3(1+w_0+w_a)*/


/*! \brief Value inside integral, \f$w_0, w_a\f$, Komatsu form */


//!< Return axis extent


//!< Return min of axis


//!< Return max of axis


//!< Get parameter spec


/**
 * Primordial spectra for arbitrary argument and for all initial conditions.
 *
 * This routine evaluates the primordial spectrum at a given value of k by
 * interpolating in the pre-computed table.
 *
 * When k is not in the pre-computed range but the spectrum can be found
 * analytically, finds it. Otherwise returns an error.
 *
 * Can be called in two modes: linear or logarithmic.
 *
 * - linear: takes k, returns P(k)
 *
 * - logarithmic: takes ln(k), return ln(P(k))
 *
 * One little subtlety: in case of several correlated initial conditions,
 * the cross-correlation spectrum can be negative. Then, in logarithmic mode,
 * the non-diagonal elements contain the cross-correlation angle P_12/sqrt(P_11 P_22)
 * (from -1 to 1) instead of ln(P_12)
 *
 * This function can be
 * called from whatever module at whatever time, provided that
 * primordial_init() has been called before, and primordial_free() has not
 * been called yet.
 *
 * @param ppm        Input: pointer to primordial structure containing tabulated primordial spectrum
 * @param index_md Input: index of mode (scalar, tensor, ...)
 * @param mode       Input: linear or logarithmic
 * @param k          Input: wavenumber in 1/Mpc (linear mode) or its logarithm (logarithmic mode)
 * @param pk         Ouput: for each pair of initial conditions, primordial spectra P(k) in Mpc**3 (linear mode), or their logarithms and cross-correlation angles (logarithmic mode)
 * @return the error status
 */


/**
 * This routine initializes the primordial structure (in particular, compute table of primordial spectrum values)
 *
 * @param ppr Input : pointer to precision structure (defines method and precision for all computations)
 * @param ppt Input : pointer to perturbation structure (useful for knowing k_min, k_max, etc.)
 * @param ppm Output: pointer to initialized primordial structure
 * @return the error status
 */


/**
 * This routine frees all the memory space allocated by primordial_init().
 *
 * To be called at the end of each run.
 *
 * @param ppm Input: pointer to primordial structure (which fields must be freed)
 * @return the error status
 */


/**
 * This routine defines indices and allocates tables in the primordial structure
 *
 * @param ppt  Input : pointer to perturbation structure
 * @param ppm  Input/output: pointer to primordial structure
 * @return the error status
 */


/**
 * This routine allocates and fills the list of wavenumbers k
 *
 *
 * @param ppm  Input/output: pointer to primordial structure
 * @param kmin Input : first value
 * @param kmax Input : last value that we should encompass
 * @param k_per_decade Input : number of k per decade
 * @return the error status
 */


/**
 * This routine returns the primordial spectrum in the simple analytic case with
 * amplitudes, tilts, runnings, for each mode (scalar/tensor...),
 * pair of initial conditions, and wavenumber.
 *
 * @param ppm            Input/output: pointer to primordial structure
 * @param index_md     Input: index of mode (scalar, tensor, ...)
 * @param index_ic1_ic2  Input: pair of initial conditions (ic1, ic2)
 * @param k              Input: wavenumber in same units as pivot scale, i.e. in 1/Mpc
 * @param pk             Output: primordial power spectrum A (k/k_pivot)^(n+...)
 * @return the error status
 */


/**
 * This routine encodes the inflaton scalar potential
 *
 * @param ppm            Input: pointer to primordial structure
 * @param phi            Input: background inflaton field value in units of Mp
 * @param V              Output: inflaton potential in units of MP^4
 * @param dV             Output: first derivative of inflaton potential wrt the field
 * @param ddV            Output: second derivative of inflaton potential wrt the field
 * @return the error status
 */


/**
 * This routine defines indices used by the inflation simulator
 *
 * @param ppm  Input/output: pointer to primordial structure
 * @return the error status
 */


/**
 * Routine coordinating the computation of the primordial
 * spectrum. For each wavenumber it calls primordial_inflation_one_k() to
 * integrate the perturbation equations, and then it stores the result
 * for the scalar/tensor spectra.
 *
 * @param ppt   Input: pointer to perturbation structure
 * @param ppm   Input/output: pointer to primordial structure
 * @param ppr   Input: pointer to precision structure
 * @param y_ini Input: initial conditions for the vector of background/perturbations, already allocated and filled
 * @param y     Input: running vector of background/perturbations, already allocated
 * @param dy    Input: running vector of background/perturbation derivatives, already allocated
 * @return the error status
 */


/**
 * Routine integrating the background plus perturbation equations for
 * or each wavenumber, and returning the scalr and tensor spectrum.
 *
 * @param ppm   Input: pointer to primordial structure
 * @param ppr   Input: pointer to precision structure
 * @param k     Input: Fourier wavenumber
 * @param y     Input: running vector of background/perturbations, already allocated and initialized
 * @param dy    Input: running vector of background/perturbation derivatives, already allocated
 * @param curvature  Output: curvature perturbation
 * @param tensor     Output: tensor perturbation
 * @return the error status
 */


/**
 * Routine searching for the inflationary attractor solution, by
 * iterations, with a given tolerance. If no solution found within
 * tolerance, returns error message.
 *
 * @param ppm       Input: pointer to primordial structure
 * @param ppr       Input: pointer to precision structure
 * @param phi_0     Input: field value at which we wish to find the solution
 * @param precision Input: tolerance on output values (if too large, an attractor will always considered to be found)
 * @param y         Input: running vector of background variables, already allocated and initialized
 * @param dy        Input: running vector of background derivatives, already allocated
 * @param H0        Output: Hubble value at phi_0 for attractor solution
 * @param dphidt_0  Output: field derivative value at phi_0 for attractor solution
 * @return the error status
 */


/**
 * Routine integrating background equations only, from initial field
 * value (stored in y) to final value (passed as phi_stop). In output,
 * y contrains the final background values.
 *
 * @param ppm       Input: pointer to primordial structure
 * @param ppr       Input: pointer to precision structure
 * @param y         Input/output: running vector of background variables, already allocated and initialized
 * @param dy        Input: running vector of background derivatives, already allocated
 * @param phi_stop  Input: final field value
 * @return the error status
 */


/**
 * Routine integrating background equations only, from initial AH
 * value (stored in y) to final value (passed as aH_stop). In output,
 * y contrains the final background values.
 *
 * @param ppm       Input: pointer to primordial structure
 * @param ppr       Input: pointer to precision structure
 * @param y         Input/output: running vector of background variables, already allocated and initialized
 * @param dy        Input: running vector of background derivatives, already allocated
 * @param aH_stop  Input: final aH value
 * @return the error status
 */


/**
 * Routine checking positivity and negative slope of potential. The
 * negative slope is an arbitrary choice. Currently the code can only
 * deal with monotonic variations of the inflaton during inflation. So
 * the slope had to be always negative or always positive... we took
 * the first option.
 *
 * @param ppm       Input: pointer to primordial structure
 * @param phi       Input: field value where to perform the check
 * @return the error status
 */


/**
 * Routine computing the first slow-roll parameter epsilon
 *
 * @param ppm       Input: pointer to primordial structure
 * @param phi       Input: field value where to compute epsilon
 * @param epsilon   Ouput: result
 * @return the error status
 */


/**
 * Routine creturning derivative of system of background/perturbation
 * variables. Like other routines used by the generic integrator
 * (background_derivs, thermodynamics_derivs, perturb_derivs), this
 * routine has a generci list of arguments, and a slightly different error management, with the error
 * message returned directly in an ErrMsg field.
 *
 * @param tau                      Input: time (not used explicitely inside the routine, but requested by the generic integrator)
 * @param y                        Input/output: running vector of background variables, already allocated and initialized
 * @param dy                       Input: running vector of background derivatives, already allocated
 * @param parameters_and_workspace Input: all necessary input variables apart from y
 * @return the error status
 */


/**
 * Transfer function \f$ \Delta_l^{X} (k) \f$ at a given wavenumber k.
 *
 * For a given mode (scalar, vector, tensor), initial condition, type
 * (temperature, polarization, lensing, etc) and multipole, compute
 * the transfer function for an arbitary value of k by interpolating
 * between pre-computed values of k. This
 * function can be called from whatever module at whatever time,
 * provided that transfer_init() has been called before, and
 * transfer_free() has not been called yet.
 *
 * @param index_md Input: index of requested mode
 * @param index_ic   Input: index of requested initial condition
 * @param index_tt   Input: index of requested type
 * @param index_l    Input: index of requested multipole
 * @param k          Input: any wavenumber
 * @param transfer_function Output: transfer function
 * @return the error status
 */


/**
 * This routine initializes the transfers structure, (in particular,
 * computes table of transfer functions \f$ \Delta_l^{X} (k) \f$)
 *
 * Main steps:
 *
 * - initialize all indices in the transfers structure
 *   and allocate all its arrays using transfer_indices_of_transfers().
 *
 * - for a all requested modes (scalar, vector, tensor),
 *   initial conditions and types (temperature, polarization, lensing,
 *   etc), compute the transfer function \f$ \Delta_l^{X} (k) \f$
 *   following the following steps:
 &
 * -# interpolate sources \f$ S(k, \tau) \f$ to get them at the right
 *    values of k using transfer_interpolate_sources()
 *
 * -# for each l, compute the transfer function by convolving the
 *    sources with the Bessel functions using transfer_compute_for_each_l()
 *    (this step is parallelized). Store result in the transfer table
 *    transfer[index_md][((index_ic * ptr->tt_size[index_md] + index_tt) * ptr->l_size[index_md] + index_l) * ptr->k_size[index_md] + index_k]
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param pth Input : pointer to thermodynamics structure
 * @param ppt Input : pointer to perturbation structure
 * @param pbs Input : pointer to bessels structure
 * @param ptr Output: pointer to initialized transfers structure
 * @return the error status
 */


/**
 * This routine frees all the memory space allocated by transfer_init().
 *
 * To be called at the end of each run, only when no further calls to
 * transfer_functions_at_k() are needed.
 *
 * @param ptr Input: pointer to transfers structure (which fields must be freed)
 * @return the error status
 */


/**
 * This routine defines all indices and allocates all tables
 * in the transfers structure
 *
 * Compute list of (k, l) values, allocate and fill corresponding
 * arrays in the transfers structure. Allocate the array of transfer
 * function tables.
 *
 * @param ppr Input : pointer to precision structure
 * @param ppt Input : pointer to perturbation structure
 * @param pbs Input : pointer to bessels structure
 * @param ptr Input/Output: pointer to transfer structure
 * @param rs_rec  Input : comoving distance to recombination
 * @return the error status
 */


/**
 * This routine interpolates sources \f$ S(k, \tau) \f$ for each mode,
 * initial condition and type (of perturbation module), to get them at
 * the right values of k, using the spline interpolation method.
 *
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param index_md            Input : index of mode
 * @param index_ic              Input : index of initial condition
 * @param index_type            Input : index of type of source (in perturbation module)
 * @param source_spline         Output: array of second derivative of sources (filled here but allocated in transfer_init() to avoid numerous reallocation)
 * @param interpolated_sources  Output: array of interpolated sources (filled here but allocated in transfer_init() to avoid numerous reallocation)
 * @return the error status
 */


/**
 * infer delta_tau array from tau0_minus_tau array (will be used in
 * transfer_integrate for a fast trapezoidal integration
 *
 * @param ptr                   Input: pointer to transfers structure
 * @param tau0_minus_tau        Input: values of (tau0-tau) at which source are sample
 * @param tau_size              Input: size of previous array
 * @param delta_tau             Output: corresponding values delta_tau
 * @return the error status
 */


/**
 * arbitrarily normalized selection function dN/dz(z,bin)
 *
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param bin                   Input : redshift bin number
 * @param z                     Input : one value of redshift
 * @param selection             Output: pointer to selection function
 * @return the error status
 */


/**
 * for sources that need to be mutiplied by a selection function,
 * redefine a finer time sampling in a small range
 *
 * @param ppr                   Input : pointer to precision structure
 * @param pba                   Input : pointer to background structure
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param bin                   Input : redshift bin number
 * @param tau0_minus_tau        Output: values of (tau0-tau) at which source are sample
 * @param tau_size              Output: pointer to size of previous array
 * @param index_md            Input : index of mode
 * @param tau0                  Input : time today
 * @param interpolated_sources  Input : interpolated perturbation source
 * @param sources               Output: resampled transfer source
 * @return the error status
 */


/**
 * for lensing sources that need to be convolved with a selection
 * function, redefine the sampling within the range extending from the
 * tau_min of the selection function up to tau0
 *
 * @param ppr                   Input : pointer to precision structure
 * @param pba                   Input : pointer to background structure
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param bin                   Input : redshift bin number
 * @param tau0_minus_tau        Output: values of (tau0-tau) at which source are sample
 * @param tau_size              Output: pointer to size of previous array
 * @param index_md            Input : index of mode
 * @param tau0                  Input : time today
 * @param interpolated_sources  Input : interpolated perturbation source
 * @param sources               Output: resampled transfer source
 * @return the error status
 */


/**
 * for sources that need to be mutiplied by a selection function,
 * redefine a finer time sampling in a small range, and resample the
 * perturbation sources at the new value by linear interpolation
 *
 * @param ppr                   Input : pointer to precision structure
 * @param pba                   Input : pointer to background structure
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param bin                   Input : redshift bin number
 * @param tau0_minus_tau        Output: values of (tau0-tau) at which source are sample
 * @param tau_size              Output: pointer to size of previous array
 * @param index_md            Input : index of mode
 * @param tau0                  Input : time today
 * @param interpolated_sources  Input : interpolated perturbation source
 * @param sources               Output: resampled transfer source
 * @return the error status
 */


/**
 * for each selection function, compute the min, mean and max values
 * of conformal time (associated to the min, mean and max values of
 * redshift specified by the user)
 *
 * @param ppr                   Input : pointer to precision structure
 * @param pba                   Input : pointer to background structure
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param bin                   Input : redshift bin number
 * @param tau_min               Output: smallest time in the selection interval
 * @param tau_mean              Output: time corresponding to z_mean
 * @param tau_max               Output: largest time in the selection interval
 * @return the error status
 */


/**
 * compute and normalise selection function for a set of time values
 *
 *
 * @param pba                   Input : pointer to background structure
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param selection             Output: normalized selection function
 * @param tau0_minus_tau        Input : values of (tau0-tau) at which source are sample
 * @param delta_tau             Input : corresponding values dtau, used for trapezoidal integration
 * @param tau_size              Input : size of previous two arrays
 * @param pvecback              Input : allocated array of background values
 * @param tau_0                 Input : time today
 * @param bin                   Input : redshift bin number
 * @return the error status
 */


/**
 * This routine computes the transfer functions \f$ \Delta_l^{X} (k) \f$)
 * for each mode, initial condition, type, multipole l and wavenumber k,
 * by convolving  the source function (passed in input in the array
 * interpolated_sources) with Bessel functions (passed in input in the
 * bessels structure).
 *
 * @param ppt                   Input : pointer to perturbation structure
 * @param pbs                   Input : pointer to bessels structure
 * @param ptr                   Input : pointer to transfers structure
 * @param tau0                  Input : conformal time today
 * @param tau_rec               Input : conformal time at recombination
 * @param index_md            Input : index of mode
 * @param index_tt              Input : index of type
 * @param index_l               Input : index of multipole
 * @param index_k               Input : index of wavenumber
 * @param interpolated_sources  Input: array of interpolated sources
 * @param ptw                   Input : pointer to transfer_workspace structure (allocated in transfer_init() to avoid numerous reallocation)
 * @param trsf                  Output: transfer function \f$ \Delta_l(k) \f$
 * @return the error status
 */


/**
* This routine computes the transfer functions \f$ \Delta_l^{X} (k) \f$)
* for each mode, initial condition, type, multipole l and wavenumber k,
  * by using the Limber approximation, i.e by evaluating the source function
* (passed in input in the array interpolated_sources) at a single value of
* tau (the Bessel function being approximated as a Dirac distribution)
*
* @param ppt                   Input : pointer to perturbation structure
* @param ptr                   Input : pointer to transfers structure
* @param tau0                  Input : conformal time today
* @param index_md            Input : index of mode
* @param index_tt              Input : index of type
* @param index_l               Input : index of multipole
* @param index_k               Input : index of wavenumber
* @param interpolated_sources  Input: array of interpolated sources
* @param trsf                  Output: transfer function \f$ \Delta_l(k) \f$
* @return the error status
*/


/**
 * This routine computes the transfer functions \f$ \Delta_l^{X} (k)
 * \f$) for each mode, initial condition, type, multipole l and
 * wavenumber k, by using the Limber approximation at ordet two, i.e
 * as a function of the source function and its first two derivatives
 * at a single value of tau
 *
 * @param ppt                   Input : pointer to perturbation structure
 * @param ptr                   Input : pointer to transfers structure
 * @param tau0                  Input : conformal time today
 * @param index_md            Input : index of mode
 * @param index_tt              Input : index of type
 * @param index_l               Input : index of multipole
 * @param index_k               Input : index of wavenumber
 * @param interpolated_sources  Input: array of interpolated sources
 * @param trsf                  Output: transfer function \f$ \Delta_l(k) \f$
 * @return the error status
 */


/**
 * This routine computes the envelop of transfer functions \f$
 * \Delta_l^{X} (k) \f$) for each mode, initial condition, type,
 * multipole l and wavenumber k, by convolving the source function
 * (passed in input in the array interpolated_sources) with Bessel
 * functions (passed in input in the bessels structure).
 *
 * @param ppt                   Input : pointer to perturbation structure
 * @param pbs                   Input : pointer to bessels structure
 * @param ptr                   Input : pointer to transfers structure
 * @param tau0                  Input : conformal time today
 * @param tau_rec               Input : conformal time at recombination
 * @param index_md            Input : index of mode
 * @param index_tt              Input : index of type
 * @param index_l               Input : index of multipole
 * @param index_k               Input : index of wavenumber
 * @param interpolated_sources  Input: array of interpolated sources
 * @param ptw                   Input : pointer to transfer_workspace structure (allocated in transfer_init() to avoid numerous reallocation)
 * @param trsf                  Output: transfer function \f$ \Delta_l(k) \f$
 * @return the error status
 */


/**
 * Anisotropy power spectra C_l's for all types, modes and initial conditions.
 *
 * This routine evaluates all the C_l's at a given value of l by
 * interpolating in the pre-computed table. When relevant, it also
 * sums over all initial conditions for each mode, and over all modes.
 *
 * This function can be
 * called from whatever module at whatever time, provided that
 * spectra_init() has been called before, and spectra_free() has not
 * been called yet.
 *
 * @param psp        Input: pointer to spectra structure (containing pre-computed table)
 * @param l          Input: multipole number
 * @param cl_tot     Ouput: total C_l's for all types (TT, TE, EE, etc..)
 * @param cl_md      Ouput: C_l's for all types (TT, TE, EE, etc..) decomposed mode by mode (scalar, tensor, ...) when relevant
 * @param cl_md_ic   Ouput: C_l's for all types (TT, TE, EE, etc..) decomposed by pairs of initial conditions (adiabatic, isocurvatures) for each mode (usually, only for the scalar mode) when relevant
 * @return the error status
 */


/**
 * Matter power spectrum for arbitrary redshift and for all initial conditions.
 *
 * This routine evaluates the matter power spectrum at a given value of z by
 * interpolating in the pre-computed table (if several values of z have been stored)
 * or by directly reading it (if it only contains values at z=0 and we want P(k,z=0))
 *
 *
 * Can be called in two modes: linear or logarithmic.
 *
 * - linear: returns P(k) (units: Mpc^3)
 *
 * - logarithmic: returns ln(P(k))
 *
 * One little subtlety: in case of several correlated initial conditions,
 * the cross-correlation spectrum can be negative. Then, in logarithmic mode,
 * the non-diagonal elements contain the cross-correlation angle P_12/sqrt(P_11 P_22)
 * (from -1 to 1) instead of ln(P_12)
 *
 * This function can be
 * called from whatever module at whatever time, provided that
 * spectra_init() has been called before, and spectra_free() has not
 * been called yet.
 *
 * @param pba        Input: pointer to background structure (used for converting z into tau)
 * @param psp        Input: pointer to spectra structure (containing pre-computed table)
 * @param mode       Input: linear or logarithmic
 * @param z          Input: redshift
 * @param output_tot Ouput: total matter power spectrum P(k) in Mpc**3 (linear mode), or its logarithms (logarithmic mode)
 * @param output_ic  Ouput: for each pair of initial conditions, matter power spectra P(k) in Mpc**3 (linear mode), or their logarithms and cross-correlation angles (logarithmic mode)
 * @return the error status
 */


/**
 * Matter power spectrum for arbitrary wavenumber, redshift and initial condition.
 *
 * This routine evaluates the matter power spectrum at a given value of k and z by
 * interpolating in a table of all P(k)'s computed at this z by spectra_pk_at_z() (when kmin <= k <= kmax),
 * or eventually by using directly the primordial spectrum (when 0 <= k < kmin):
 * the latter case is an approximation, valid when kmin << comoving Hubble scale today.
 * Returns zero when k=0. Returns an error when k<0 or k > kmax.
 *
 * This function can be
 * called from whatever module at whatever time, provided that
 * spectra_init() has been called before, and spectra_free() has not
 * been called yet.
 *
 * @param pba        Input: pointer to background structure (used for converting z into tau)
 * @param ppm        Input: pointer to primordial structure (used only in the case 0 < k < kmin)
 * @param psp        Input: pointer to spectra structure (containing pre-computed table)
 * @param k          Input: wavenumber in 1/Mpc
 * @param z          Input: redshift
 * @param pk_tot     Ouput: total matter power spectrum P(k) in Mpc**3
 * @param pk_ic      Ouput: for each pair of initial conditions, matter power spectra P(k) in Mpc**3
 * @return the error status
 */


/**
 * Matter transfer functions T_i(k) for arbitrary redshift and for all
 * initial conditions.
 *
 * This routine evaluates the matter transfer functions at a given value of z by
 * interpolating in the pre-computed table (if several values of z have been stored)
 * or by directly reading it (if it only contains values at z=0 and we want T_i(k,z=0))
 *
 *
 * This function can be
 * called from whatever module at whatever time, provided that
 * spectra_init() has been called before, and spectra_free() has not
 * been called yet.
 *
 * @param pba        Input: pointer to background structure (used for converting z into tau)
 * @param psp        Input: pointer to spectra structure (containing pre-computed table)
 * @param z          Input: redshift
 * @param output     Ouput: matter transfer functions
 * @return the error status
 */


/**
 * Matter transfer functions T_i(k) for arbitrary wavenumber, redshift
 * and initial condition.
 *
 * This routine evaluates the matter transfer functions at a given
 * value of k and z by interpolating in a table of all T_i(k,z)'s
 * computed at this z by spectra_tk_at_z() (when kmin <= k <= kmax).
 * Returns an error when k<kmin or k > kmax.
 *
 * This function can be called from whatever module at whatever time,
 * provided that spectra_init() has been called before, and
 * spectra_free() has not been called yet.
 *
 * @param pba        Input: pointer to background structure (used for converting z into tau)
 * @param psp        Input: pointer to spectra structure (containing pre-computed table)
 * @param k          Input: wavenumber in 1/Mpc
 * @param z          Input: redshift
 * @param output     Ouput: matter transfer functions
 * @return the error status
 */


/**
 * This routine initializes the spectra structure (in particular,
 * computes table of anisotropy and Fourier spectra \f$ C_l^{X}, P(k), ... \f$)
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure (will provide H, Omega_m at redshift of interest)
 * @param ppt Input : pointer to perturbation structure
 * @param ptr Input : pointer to transfer structure
 * @param ppm Input : pointer to primordial structure
 * @param psp Output: pointer to initialized spectra structure
 * @return the error status
 */


/**
 * This routine frees all the memory space allocated by spectra_init().
 *
 * To be called at the end of each run, only when no further calls to
 * spectra_cls_at_l(), spectra_pk_at_z(), spectra_pk_at_k_and_z() are needed.
 *
 * @param psp Input: pointer to spectra structure (which fields must be freed)
 * @return the error status
 */


/**
 * This routine defines indices and allocates tables in the spectra structure
 *
 * @param ppt  Input : pointer to perturbation structure
 * @param ptr  Input : pointer to transfers structure
 * @param ppm  Input : pointer to primordial structure
 * @param psp  Input/output: pointer to spectra structure
 * @return the error status
 */


/**
 * This routine computes a table of values for all harmonic spectra C_l's,
 * given the transfer functions and primordial spectra.
 *
 * @param ppt Input : pointer to perturbation structure
 * @param ptr Input : pointer to transfers structure
 * @param ppm Input : pointer to primordial structure
 * @param psp Input/Output: pointer to spectra structure
 * @return the error status
 */


/**
 * This routine computes the C_l's for a given mode, pair of initial conditions
 * and multipole, but for all types (TT, TE...), by convolving the
 * transfer functions with the primordial spectra.
 *
 * @param ppt           Input : pointer to perturbation structure
 * @param ptr           Input : pointer to transfers structure
 * @param ppm           Input : pointer to primordial structure
 * @param psp           Input/Output: pointer to spectra structure (result stored here)
 * @param index_md    Input : index of mode under consideration
 * @param index_ic1     Input : index of first initial condition in the correlator
 * @param index_ic2     Input : index of second initial condition in the correlato
 * @param index_l       Input : index of multipole under consideration
 * @param cl_integrand_num_column Input : number of columns in cl_integrand
 * @param cl_integrand  Input : an allocated workspace
 * @param primordial_pk Input : table of primordial spectrum values
 * @param transfer_ic1  Input : table of transfer function values for first initial condition
 * @param transfer_ic2  Input : table of transfer function values for second initial condition
 * @return the error status
 */


/**
 * This routine computes the values of k and tau at which the matter
 * power spectra P(k,tau) and the matter transfer functions T_i(k,tau)
 * will be stored.
 *
 * @param pba Input : pointer to background structure (for z to tau conversion)
 * @param ppt Input : pointer to perturbation structure (contain source functions)
 * @param psp Input/Output: pointer to spectra structure
 * @return the error status
 */


/**
 * This routine computes a table of values for all matter power spectra P(k),
 * given the source functions and primordial spectra.
 *
 * @param pba Input : pointer to background structure (will provide H, Omega_m at redshift of interest)
 * @param ppt Input : pointer to perturbation structure (contain source functions)
 * @param ppm Input : pointer to primordial structure
 * @param psp Input/Output: pointer to spectra structure
 * @return the error status
 */


/**
 * This routine computes sigma(R) given P(k) (does not check that k_max is large
 * enough)
 *
 * @param pba   Input: pointer to background structure
 * @param ppm   Input: pointer to primordial structure
 * @param psp   Input: pointer to spectra structure
 * @param z     Input: redhsift
 * @param R     Input: radius in Mpc
 * @param sigma Output: variance in a sphere of radius R (dimensionless)
 */


/**
 * This routine computes a table of values for all matter power spectra P(k),
 * given the source functions and primordial spectra.
 *
 * @param pba Input : pointer to background structure (will provide density of each species)
 * @param ppt Input : pointer to perturbation structure (contain source functions)
 * @param psp Input/Output: pointer to spectra structure
 * @return the error status
 */


/**
 * Bessel function for arbitrary argument x.
 *
 * Evaluates the spherical Bessel function x at a given value of x by
 * interpolating in the pre-computed table.  This function can be
 * called from whatever module at whatever time, provided that
 * bessel_init() has been called before, and bessel_free() has not
 * been called yet.
 *
 * @param pbs     Input: pointer to bessels structure
 * @param x       Input: argument x
 * @param index_l Input: index defining l = pbs->l[index_l]
 * @param j       Ouput: \f$j_l(x) \f$
 * @return the error status
 */


/**
 * Get spherical Bessel functions (either read from file or compute
 * from scratch).
 *
 * Each table of spherical Bessel functions \f$ j_l(x) \f$ corresponds
 * to a set of values for:
 *
 * -# pbs->l[index_l]: list of l values l of size pbs->l_size
 * -# pbs->x_step: step dx for sampling Bessel functions \f$ j_l(x) \f$
 * -# pbs->x_max: last value of x (always a multiple of x_step!)
 * -# pbs->j_cut: value of \f$ j_l \f$ below which it is approximated by zero (in the region x << l)
 *
 * This function checks whether there is alread a file "bessels.dat"
 * with the same l's, x_step, x_max, j_cut).
 * If yes, it fills the table of bessel functions (and
 * their second derivatives, needed for spline interpolation) with the
 * values read from the file. If not, it computes all values using
 * bessel_j_for_l(), and stores them both in the bessels
 * stucture pbs, and in a file "bessels.dat" (in view of the next
 * runs).
 *
 * @param ppr Input : pointer to precision strucutre
 * @param pbs Output: initialized bessel structure
 * @return the error status
 */


/**
 * Free all memory space allocated by bessel_init().
 *
 * To be called at the end of each run.
 *
 * @param pbs Input : Initialized bessel structure
 * @return the error status
 */


/**
 * Define number and values of mutipoles l. This is crucial since not
 * only the Bessel functions, but also the transfer functions and
 * anisotropy spectra C_l will automatically be sampled at the same
 * values (there would be no logic in having various l lists differing
 * from each other).
 *
 *
 * @param ppr Input : pointer to precision structure
 * @param pbs Input/Output : pointer to besseld structure (result stored here)
 * @return the error status
 */


/**
 * Get spherical Bessel functions for given value of l.
 *
 * Find the first value x_min(l) at which the function is not
 * negligible (for large l values, Bessel functions are very close to
 * zero nearly until x=l).
 * Then, sample it with step x_step till x_max.
 *
 * @param ppr Input : pointer to precision structure
 * @param pbs Input/Output : pointer to bessel structure (store result here)
 * @return the error status
 */


/**
 * Compute spherical Bessel function \f$ j_l(x) \f$ for a given l and x.
 *
 * Inspired from Numerical Recipies.
 *
 * @param pbs Input : pointer to bessel structure (used only for error mess ge)
 * @param l   Input: l value
 * @param x   Input: x value
 * @param jl  Output: \f$ j_l(x) \f$ value
 * @return the error status
 */


/**
 * Source function \f$ S^{X} (k, \tau) \f$ at a given conformal time tau.
 *
 * Evaluate source functions at given conformal time tau by reading
 * the pre-computed table and interpolating.
 *
 * @param ppt        Input : pointer to perturbation structure containing interpolation tables
 * @param index_md Input : index of requested mode
 * @param index_ic   Input : index of requested initial condition
 * @param index_type Input : index of requested source function type
 * @param tau        Input : any value of conformal time
 * @param psource    Output: vector (already allocated) of source function as a function of k
 * @return the error status
 */


/**
 * Initialize the perturbs structure, and in particular the table of source functions.
 *
 * Main steps:
 *
 * - given the values of the flags describing which kind of
 *    perturbations should be considered (modes: scalar/vector/tensor,
 *    initial conditions, type of source functions needed...),
 *    initialize indices and wavenumber list
 *
 * - define the time sampling for the output source functions
 *
 * - for each mode (scalar/vector/tensor): initialize the indices of
 *    relevant perturbations, integrate the differential system,
 *    compute and store the source functions.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background strucutre
 * @param pth Input : pointer to thermodynamics structure
 * @param ppt Output: Initialized perturbation structure
 * @return the error status
 */


/**
 * Free all memory space allocated by perturb_init().
 *
 * To be called at the end of each run, only when no further calls to
 * perturb_sources_at_tau() are needed.
 *
 * @param ppt Input: perturbation structure to be freed
 * @return the error status
 */


/**
 * Define time sampling for source functions.
 *
 * For each type, compute the list of values of tau at which sources
 * will be sampled.  Knowing the number of tau values, allocate all
 * arrays of source functions.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background strucutre
 * @param pth Input : pointer to thermodynamics structure
 * @param ppt Input/Output: Initialized perturbation structure
 * @return the error status
 */


/**
 * Solve the perturbation evolution for a given mode, initial
 * condition and wavenumber, and compute the corresponding source
 * functions.
 *
 * For a given mode, initial condition and wavenumber, this function
 * finds the time ranges over witch the perturbations can be described
 * within a given approximation. For each such range, it initializes
 * (or redistribute) perturbations using perturb_vector_init(), and
 * integrates over time. Whenever a "source sampling time" is passed,
 * the source terms are computed and stored temporarily (for each
 * type) using perturb_source_terms().  Finally, the actual source
 * functions are computed using the source terms, and stored in the
 * source table using perturb_sources().
 *
 * @param ppr        Input: pointer to precision structure
 * @param pba        Input: pointer to background structure
 * @param pth        Input: pointer to the thermodynamics structure
 * @param ppt        Input/Output: pointer to the perturbation structure (output source functions S(k,tau) written here)
 * @param index_md Input: index of mode under consideration (scalar/.../tensor)
 * @param index_ic   Input: index of initial condition under consideration (ad, iso...)
 * @param index_k    Input: index of wavenumber
 * @param ppw        Input: pointer to perturb_workspace structure containing index values and workspaces
 * @return the error status
 */


/**
 * For a given mode and wavenumber, find the number of interval of
 * times bewteen tau_ini and tau_end such that the approximation
 * scheme (and the number of perturbation equations) is uniform.
 *
 * @param ppr                Input: pointer to precision structure
 * @param pba                Input: pointer to background structure
 * @param pth                Input: pointer to the thermodynamics structure
 * @param ppt                Input: pointer to the perturbation structure
 * @param index_md         Input: index of mode under consideration (scalar/.../tensor)
 * @param index_k            Input: index of wavenumber
 * @param ppw                Input: pointer to perturb_workspace structure containing index values and workspaces
 * @param tau_ini            Input: initial time of the perturbation integration
 * @param tau_end            Input: final time of the perturbation integration
 * @param interval_number    Output: total number of intervals
 * @param interval_number_of Output: number of intervals with respect to each particular approximation
 * @return the error status
 */


/**
 * Free the perturb_vector structure.
 *
 * @param pv        Input: pointer to perturb_vector structure to be freed
 * @return the error status
 */


/**
 * Compute typical timescale over which the perturbation equation
 * vary. Some integrators (e.g. Runge-Kunta) benefit from calling this
 * routine at each step in order to adapt the next step.
 *
 * This is one of the few functions in the code which are passed to the generic_integrator() routine.
 * Since generic_integrator() should work with functions passed from various modules, the format of the arguments
 * is a bit special:
 * - fixed parameters and workspaces are passed through a generic pointer.
 *   generic_integrator() doesn't know the content of this pointer.
 * - the error management is a bit special: errors are not written as usual to pth->error_message, but to a generic
 *   error_message passed in the list of arguments.
 *
 * @param tau                      Input : conformal time
 * @param parameters_and_workspace Input : fixed parameters (e.g. indices), workspace, approximation used, etc.
 * @param timescale                Output: perturbation variation timescale (given the apprtoximation used)
 * @param error_message            Output: error message
 */


/**
 * Infer source functions from source terms.
 *
 * For a given mode, initial condition, wavenumber and source type,
 * take the array of source terms \f$ (S_0, S_1, S_2) \f$ at all times
 * (stored in source_terms_array) and infer the source function \f$ S = S_0 + S_1' +
 * S_2'' \f$ by numerical differentiation
 *
 * @param ppt        Input : pointer to perturbation structure containing interpolation tables
 * @param index_md Input : index of requested mode
 * @param index_ic   Input : index of requested initial condition
 * @param index_k    Input : index of requested wavenumber
 * @param ppw        Input/Output : pointer to workspace (contains source terms in input, sources in output)
 * @return the error status
 */


/**
 * When testing the code or a cosmological model, it can be useful to
 * output perturbations at each step of integration (and not just the
 * delta's at each source sampling point, which is acheived simply by
 * asking for matter transfer functions). Then this function can be
 * passed to the generic_evolver routine.
 *
 * By default, instead of passing this function to generic_evolver,
 * one passes a null pointer. Then this function is just not used.
 *
 * @param tau                      Input: conformal time
 * @param y                        Input: vector of perturbations
 * @param dy                       Input: vector of its derivatives (already allocated)
 * @param parameters_and_workspace Input: fixed parameters (e.g. indices)
 * @param error_message            Output : error message
 *
 */


/**
 * Thermodynamics quantities at given redshift z.
 *
 * Evaluates all thermodynamics quantities at a given value of
 * the redshift by reading the pre-computed table and interpolating.
 *
 * @param pba        Input: pointer to background structure
 * @param pth        Input: pointer to the thermodynamics structure (containing pre-computed table)
 * @param z          Input: redshift
 * @param intermode  Input: interpolation mode (normal or growing_closeby)
 * @param last_index Input/Ouput: index of the previous/current point in the interpolation array (input only for closeby mode, output for both)
 * @param pvecback   Input: vector of background quantitites (used only in case z>z_initial for getting ddkappa and dddkappa; in that case, should be already allocated and filled, with format short_info or larger; in other cases, will be ignored)
 * @param pvecthermo Output: vector of thermodynamics quantities (assumed to be already allocated)
 * @return the error status
 */


/**
 * Initialize the thermo structure, and in particular the
 * thermodynamics interpolation table.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param pth Input/Output : pointer to initialized thermo structure
 * @return the error status
 */


/**
 * Free all memory space allocated by thermodynamics_init().
 *
 *
 * @param pth Input/Output : pointer to thermo structure (to be freed)
 * @return the error status
 */


/**
 * Assign value to each relevant index in vectors of thermodynamical quantities,
 * as well as in vector containing reionization parameters.
 *
 *
 * @param pth   Input/Output: pointer to thermo structure
 * @param preco Input/Output: pointer to recombination structure
 * @param preio Input/Output: pointer to reionization structure
 * @return the error status
 */


/**
 * Infer the primordial helium fraction from standard BBN, as a
 * function of the baryon density and expansion rate during BBN.
 *
 * This module is simpler then the one used in arXiv:0712.2826 because
 * it neglects the impact of a possible significant chemical
 * potentials for electron neutrinos. The full code with xi_nu_e could
 * be introduced here later.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param pth Input/Output : pointer to initialized thermo structure
 * @return the error status
 */


/**
 * In case of non-minimal cosmology, this function determines the
 * energy rate injected in the IGM at a given redhsift z (= on-the-spot
 * annihilation). This energy injection may come e.g. from dark matter
 * annihilation or decay.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param preco Input : pointer to recombination structure
 * @param z Input : redshift
 * @param energy_rate Output : energy density injection rate
 * @param error_message Output: error message
 * @return the error status
 */


/**
 * In case of non-minimal cosmology, this function determines the
 * effective energy rate absorbed by the IGM at a given redhsift
 * (beyond the on-the-spot annihilation). This energy injection may
 * come e.g. from dark matter annihilation or decay.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param preco Input : pointer to recombination structure
 * @param z Input : redshift
 * @param energy_rate Output : energy density injection rate
 * @param error_message Output: error message
 * @return the error status
 */


/**
 * This subroutine contains the reionization function \f$ X_e(z) \f$
 * (one for each scheme; so far, only the function corresponding to
 * the reio_camb scheme is coded)
 *
 * @param z     Input : redshift
 * @param pth   Input : pointer to thermo structure, to know which scheme is used
 * @param preio Input : pointer to reionization structure, containing the parameters of the function \f$ X_e(z) \f$
 * @param xe    Output: \f$ X_e(z) \f$
 */


/**
 * This subroutine reads \f$ X_e(z) \f$ in the recombination table at
 * the time at which reionization starts. Hence it provides correct
 * initial conditions for the reionization function.
 *
 * @param ppr   Input : pointer to precision structure
 * @param pth   Input : pointer to thermo structure
 * @param preco Input : pointer to recombination structure
 * @param z     Input : redshift z_reio_start
 * @param xe    Output: \f$ X_e(z) \f$ at z
 */


/**
 * This routine computes the reionization history. In the reio_camb
 * scheme, this is straightforward if the input parameter is the
 * reionization redshift. If the input is the optical depth, need to
 * find z_reio by dichotomy (trying several z_reio until the correct
 * tau_reio is approached).
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param pth Input : pointer to thermo structure
 * @param preco Input : pointer to filled recombination structure
 * @param preio Input/Output: pointer to reionization structure (to be filled)
 * @param pvecback   Input: vector of background quantitites (used as workspace: must be already allocated, with format short_info or larger, but does not need to be filled)
 * @return the error status
 */


/**
 * For fixed input reionization parameters, this routine computes the
 * reionization history and fills the reionization table.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input : pointer to background structure
 * @param pth Input : pointer to thermo structure
 * @param preco Input : pointer to filled recombination structure
 * @param preio Input/Output: pointer to reionization structure (to be filled)
 * @param pvecback   Input: vector of background quantitites (used as workspace: must be already allocated, with format short_info or larger, but does not need to be filled)
 * @return the error status
 */


/**
 * Integrate thermodynamics with your favorite recombination code.
 *
 */


/**
 * Integrate thermodynamics with HyRec.
 *
 * Integrate thermodynamics with HyRec, allocate and fill the part
 * of the thermodynamics interpolation table (the rest is filled in
 * thermodynamics_init()). Called once by
 * thermodynamics_recombination(), from thermodynamics_init().
 *
 *************************************************************************************************
 *                 HYREC: Hydrogen and Helium Recombination Code                                 *
 *         Written by Yacine Ali-Haimoud and Chris Hirata (Caltech)                              *
 *************************************************************************************************
 *
 * @param ppr      Input: pointer to precision structure
 * @param pba      Input: pointer to background structure
 * @param pth      Input: pointer to thermodynamics structure
 * @param preco    Ouput: pointer to recombination structure
 * @param pvecback Input: pointer to an allocated (but empty) vector of background variables
 *
 */


/**
 * Integrate thermodynamics with RECFAST.
 *
 * Integrate thermodynamics with RECFAST, allocate and fill the part
 * of the thermodynamics interpolation table (the rest is filled in
 * thermodynamics_init()). Called once by
 * thermodynamics_recombination, from thermodynamics_init().
 *
 *******************************************************************************
 * RECFAST is an integrator for Cosmic Recombination of Hydrogen and Helium,   *
 * developed by Douglas Scott (dscott@astro.ubc.ca)                            *
 * based on calculations in the paper Seager, Sasselov & Scott                 *
 * (ApJ, 523, L1, 1999).                                                       *
 * and "fudge" updates in Wong, Moss & Scott (2008).                           *
 *                                                                             *
 * Permission to use, copy, modify and distribute without fee or royalty at    *
 * any tier, this software and its documentation, for any purpose and without  *
 * fee or royalty is hereby granted, provided that you agree to comply with    *
 * the following copyright notice and statements, including the disclaimer,    *
 * and that the same appear on ALL copies of the software and documentation,   *
 * including modifications that you make for internal use or for distribution: *
 *                                                                             *
 * Copyright 1999-2010 by University of British Columbia.  All rights reserved.*
 *                                                                             *
 * THIS SOFTWARE IS PROVIDED "AS IS", AND U.B.C. MAKES NO                      *
 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.                          *
 * BY WAY OF EXAMPLE, BUT NOT LIMITATION,                                      *
 * U.B.C. MAKES NO REPRESENTATIONS OR WARRANTIES OF                            *
 * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT               *
 * THE USE OF THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE         *
 * ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.            *
 *******************************************************************************
 *
 * Version 1.5: includes extra fitting function from
 *              Rubino-Martin et al. arXiv:0910.4383v1 [astro-ph.CO]
 *
 * @param ppr      Input: pointer to precision structure
 * @param pba      Input: pointer to background structure
 * @param pth      Input: pointer to thermodynamics structure
 * @param preco    Ouput: pointer to recombination structure
 * @param pvecback Input: pointer to an allocated (but empty) vector of background variables
 * @return the error status
 */


/**
 * Subroutine evaluating the derivative with respect to redshift of
 * thermodynamical quantities (from RECFAST version 1.4).
 *
 * Computes derivatives of the three variables to integrate: \f$ d x_H
 * / dz, d x_{He} / dz, d T_{mat} / dz \f$.
 *
 * This is one of the few functions in the code which are passed to
 * the generic_integrator() routine.  Since generic_integrator()
 * should work with functions passed from various modules, the format
 * of the arguments is a bit special:
 *
 * - fixed parameters and workspaces are passed through a generic
 *   pointer. Here, this pointer contains the precision, background
 *   and recombination structures, plus a background vector, but
 *   generic_integrator() doesn't know its fine structure.
 *
 * - the error management is a bit special: errors are not written as
 *   usual to pth->error_message, but to a generic error_message
 *   passed in the list of arguments.
 *
 * @param z                        Input : redshift
 * @param y                        Input : vector of variable to integrate
 * @param dy                       Output: its derivative (already allocated)
 * @param parameters_and_workspace Input : pointer to fixed parameters (e.g. indices) and workspace (already allocated)
 * @param error_message            Output: error message
 */


/**
 * This routine merges the two tables 'recombination_table' and
 * 'reionization_table' inside the table 'thermodynamics_table', and
 * frees the temporary structures 'recombination' and 'reionization'.
 *
 * @param ppr   Input : pointer to precision structure
 * @param pth   Input/Output : pointer to thermo structure
 * @param preco Input : pointer to filled recombination structure
 * @param preio Input : pointer to reionization structure
 * @return the error status
 */


/**
 * Gamma function 121, for any set of wavevectors (k,p,q)
 *
 * Encodes the non linear behaviour of the evolution
 *
 * @param k       Input: wave-vector
 * @param p       Input: wave-vector
 * @param q       Input: wave-vector
 * @param result  Output: computed the rational interaction function
 */


/**
 * Gamma function 222, for any set of wavevectors (k,p,q)
 *
 * Encodes the non linear behaviour of the evolution
 *
 * @param k       Input: wave-vector
 * @param p       Input: wave-vector
 * @param q       Input: wave-vector
 * @param result  Output: computed the rational interaction function
 */


/**
 * Interpolates-extrapolates p_ab for any k different from pnl->k
 *
 * It is just a renaming of the already existing structure
 * array_interpolate_extrapolate_logspline_loglinear_one_column for simple
 * convenient reasons : this routine is called many times in the trg_arg_*
 * functions, with many redundancy in the arguments.
 *
 * @param pnl       Input: pointer to spectra_nl structure
 * @param p_ab      Input: table of values containing any spectrum, already allocated, and supposed filled until [any_index_k+pnl->k_size*index_eta]
 * @param ddp_ab    Input: table of values containing the second derivative of any spectrum, already allocated, and supposed filled until [any_index_k+pnl->k_size*index_eta]
 * @param index_eta Input: index of the time evolution
 * @param any_k     Input: desired value of the wavenumber to calculate the spectrum. If it is already part of pnl->k, then the answer is given. If any_k < k_max, the result is interpolated. If any_k > k_max, the result is extrapolated
 * @param result    Output: P_ab at the given any_k for the desired eta (pnl->eta[index_eta])
 * @return the error status
 */


/**
 * Argument of the integral defining AA[name] for the TRG method
 *
 * Returns the argument (symmetrized in p,m) of the desired integral,
 * called by the 'name' argument, at the desired wave-number values,
 * and time pnl->eta[index_eta]. The names 'p' and 'm' stands resp. for
 * 'plus' and 'minus', standing themselves resp. for
 * '(x + y)/sqrt(2)' and '(x - y)/sqrt(2)'
 *
 * This trg version uses the full non-linear spectrum computed at each time
 *
 * @param pnl       Input: pointer to spectra_nl structure
 * @param name      Input: select the desired A function to get the argument from, from _A0_ to _B3_
 * @param k         Input: wave-vector
 * @param p         Input: wave-vector corresponding to (x+y)/sqrt(2)
 * @param m         Input: wave-vector corresponding to (x-y)/sqrt(2)
 * @param index_eta Input: index of time evolution
 * @param result    Output: argument of the integral for the given wave numbers and at the given time
 * @return the error status
 */


/**
 * Argument of the integral defining AA[name] for the TRG method
 *
 * Returns the argument (symmetrized in p,m) of the desired integral,
 * called by the 'name' argument, at the desired wave-number values,
 * and time pnl->eta[index_eta]. The names 'p' and 'm' stands resp. for
 * 'plus' and 'minus', standing themselves resp. for
 * '(x + y)/sqrt(2)' and '(x - y)/sqrt(2)'
 *
 * This one-loop version uses the linear spectrum computed initially, and
 * hence do not need any index_eta. It is indeed called only once, before
 * the time evolution loop, and is copied from time step to time step to
 * keep the same structure than for the trg computation.
 *
 * @param pnl       Input: pointer to spectra_nl structure
 * @param name      Input: select the desired A function to get the argument from, from _A0_ to _B3_
 * @param k         Input: wave-vector
 * @param p         Input: wave-vector corresponding to (x+y)/sqrt(2)
 * @param m         Input: wave-vector corresponding to (x-y)/sqrt(2)
 * @param result    Output: argument of the integral for the given wave numbers and at the given time
 * @return the error status
 */


/**
 * Performs the integration of the arguments given by the trg_A_arg functions
 *
 * The integration pattern used here is rather complicated. It is described step
 * by step inside the function, but here is summarized the ideas. For each pnl->k,
 *
 * - in a first step, determine the boundaries of the integration on x and y.
 *
 * - in a second step, perform the integration over the computed domain. To smooth out
 *   the function, the mean value of the argument on a square is integrated, and not
 *   simply the argument. Cases are thus defined on the grid domain.
 *
 * - to avoid computing several times the function over the same point, local variables
 *   are used, and the computation takes place on two adjacent horizontal lines (h_up and h_do(wn))
 *   and two adjacent vertical lines (h_le(ft) and h_ri(ght)). Every step, the lines are
 *   switched one step right and down, moving all computed values from h_do and l_ri to h_up and l_le,
 *   leaving the rest to be computed.
 *
 * - this integration scheme consists thus in integrating over L-shaped region, starting
 *   from the upper left corner. Since the region is not exactly squared, the last lower-right
 *   corner is integrated line per line at the end. This scheme has been designed to
 *   better follow the compensations in the computation:
 *     - the majority of the features of the argument takes place in the first "L" region, with
 *     opposite signs on the horizontal and the vertical
 *     - though, the integration has to be performed over all the region because small contributions
 *     continue to add even in the lower-right corner
 *
 * - a large k_max is defined in this function to replace the 'infinity' upper limit of the integral
 *   over y. The value has been defined to get the convergence of the integral,
 *   while keeping the computing time reasonnable.
 *
 * - finally, a 'double escape' scheme has been implemented to get rid of numerical divergences.
 *   It concretely consists in forgetting a fixed number of points (pnl->double_escape) at each half-step
 *   in time, meaning every time new P's are calculated and every time new A's are calculated.
 *
 *
 * @param pba       Input: pointer to background structure
 * @param ppm       Input: pointer to primordial structure
 * @param psp       Input: pointer to spectra structure
 * @param pnl       Input: pointer to spectra_nl structure
 * @param name      Input: select the desired A function to compute, from _A0_ to _B3_
 * @param index_eta Input: index of time evolution
 * @param result    Output: returns the computed integral corresponding to the whole function A[name]
 * @return the error status
 */


/**
 * Logarithmic step in k for the low k values
 *
 * It simply affects the correct logstep corresponding to a certain
 * value of k.  A hyperbolic tangent has been selected to get a smooth
 * tranisition between the two ends of the spectrum, in order to avoid
 * numerical troubles in case of a brutal change in step.
 *
 * The values are adjusted to fit the default values of steps in eta
 * and of double escape parameters. Change at your own risk !
 *
 * @param k 		Input:  current value of the wavenumber
 * @param logstep	Output: logstep associated with the desired wavenumber
 */


/**
 * Logarithmic step in k for the high k values
 *
 * It simply affects the correct logstep corresponding to a certain
 * value of k.  A hyperbolic tangent has been selected to get a smooth
 * tranisition between the two ends of the spectrum, in order to avoid
 * numerical troubles in case of a brutal change in step.
 *
 * The values are adjusted to fit the default values of steps in eta
 * and of double escape parameters. Change at your own risk !
 *
 * @param k 		Input:  current value of the wavenumber
 * @param logstep	Output: logstep associated with the desired wavenumber
 */


/**
 * Computes the non-linear spectra for matter (cold dark matter and
 * baryons, so far) and fills in the spectra_nl structure with pk_nl,
 * p_12_nl, p_22_nl.
 *
 *
 * Since this sub-routine uses a different k table, one should also
 * uses pnl->k to output the results.
 *
 * The program can be told to compute the non linear spectra with
 * (resp.) the Time Renormalization Group method, the one-loop method,
 * or the simple linear method (for testing purposes), by letting the
 * non-linearity mode option in a .ini file be (resp.) 2, 1 or 0.
 *
 * The starting redshift of the non-linear computation can be selected
 * via the .ini file as well (CHECK TROUBLES IF THIS VALUE IS CHANGED
 * AND NOT Z_MAX_PK).  It is set by default to z=35.
 *
 * It is possible (so far) to compute exactly the cdm + baryon
 * spectra, or the approximated cdm + baryon via the option b+c
 * spectrum (YET TO BE IMPLEMENTED)
 *
 * @param ppr Input: pointer to precision structure
 * @param pba Input: pointer to background structure (provides H, Omega_m at redshift of interest)
 * @param pth Input: pointer to thermo structure (provides the baryon sound speed)
 * @param ppm Input: pointer to primordial structure
 * @param psp Input: pointer to spectra structure
 * @param pnl Output: pointer to initialized spectra_nl structure
 * @return the error status
 */


/**
 * This routine frees all the memory space allocated by trg_init().
 *
 * To be called at the end of each run, when no further use of the nl_functions are needed.
 *
 * @param pnl Input : pointer to spectra_nl structure (which fields must be freed).
 * @return the error status
 */


/**
 * This routine writes the output in files.
 *
 *
 * @param pba Input: pointer to background structure (needed for calling spectra_pk_at_z())
 * @param ppt Input : pointer perturbation structure
 * @param psp Input : pointer to spectra structure
 * @param pop Input : pointer to output structure
 */


/**
 * This routines writes the output in files for Fourier matter power spectra P(k)'s.
 *
 * @param pba Input: pointer to background structure (needed for calling spectra_pk_at_z())
 * @param ppt Input : pointer perturbation structure
 * @param psp Input : pointer to spectra structure
 * @param pop Input : pointer to output structure
 */


/**
 * This routines writes the output in files for matter transfer functions T_i(k)'s.
 *
 * @param pba Input: pointer to background structure (needed for calling spectra_pk_at_z())
 * @param ppt Input : pointer perturbation structure
 * @param psp Input : pointer to spectra structure
 * @param pop Input : pointer to output structure
 */


/**
 * This routine opens one file where some C_l's will be written, and writes
 * a heading with some general information concerning its content.
 *
 * @param psp        Input : pointer to spectra structure
 * @param pop        Input : pointer to output structure
 * @param clfile     Output: returned pointer to file pointer
 * @param filename   Input : name of the file
 * @param first_line Input : text describing the content (mode, initial condition..)
 * @param lmax       Input : last multipole in the file (the first one is assmued to be 2)
 * @return the error status
 */


/**
 * This routine write one line with l and all C_l's for all types (TT, TE...)
 *
 * @param pba        Input: pointer to background structure (needed for T_cmb)
 * @param psp        Input : pointer to spectra structure
 * @param pop        Input : pointer to output structure
 * @param clfile  Input : file pointer
 * @param l       Input : multipole
 * @param cl      Input : C_l's for all types
 * @param ct_size Input : number of types
 * @return the error status
 */


/**
 * This routine opens one file where some P(k)'s will be written, and writes
 * a heading with some general information concerning its content.
 *
 * @param pba        Input: pointer to background structure (needed for h)
 * @param psp        Input : pointer to spectra structure
 * @param pop        Input : pointer to output structure
 * @param tkfile     Output: returned pointer to file pointer
 * @param filename   Input : name of the file
 * @param first_line Input : text describing the content (initial conditions, ...)
 * @param z          Input : redshift of the output
 * @return the error status
 */


/**
 * This routine writes one line with k and P(k)
 *
 * @param tkfile  Input : file pointer
 * @param one_k   Input : wavenumber
 * @param one_pk  Input : matter power sectrum
 * @return the error status
 */


/**
 * This routine opens one file where some P_nl(k)'s will be written, and writes
 * a heading with some general information concerning its content.
 *
 * @param pba        Input: pointer to background structure (needed for h)
 * @param pnl        Input : pointer to nonlinear structure
 * @param pop        Input : pointer to output structure
 * @param tkfile     Output: returned pointer to file pointer
 * @param filename   Input : name of the file
 * @param first_line Input : text describing the content (initial conditions, ...)
 * @param z          Input : redshift of the output
 * @param k_size     Input : number of k values
 * @return the error status
 */


/**
 * This routine opens one file where some T_i(k)'s will be written, and writes
 * a heading with some general information concerning its content.
 *
 * @param psp        Input : pointer to spectra structure
 * @param pop        Input : pointer to output structure
 * @param tkfile     Output: returned pointer to file pointer
 * @param filename   Input : name of the file
 * @param first_line Input : text describing the content (initial conditions, ...)
 * @param z          Input : redshift of the output
 * @return the error status
 */


/**
 * This routine writes one line with k and T_i(k)'s
 *
 * @param tkfile  Input : file pointer
 * @param one_k   Input : wavenumber
 * @param tk      Input : vector of transfer functions tk[index_tr]
 * @param tr_size Input : number of transfer functions
 * @return the error status
 */


/**
 * This routine opens one file where some background quantitites will be written, and writes
 * a heading with some general information concerning its content.
 *
 * @param pba        Input: pointer to background structure
 * @param pop        Input : pointer to output structure
 * @param backfile   Output: returned pointer to file pointer
 * @param filename   Input : name of the file
 * @return the error status
 */


/**
 * This routine writes one line with background quantitites
 *
 * @param pba        Input: pointer to background structure
 * @param backfile   Input : file pointer
 * @param pvecback   Input : vector of background quantitites
 * @return the error status
 */


/**
 * Anisotropy power spectra C_l's for all types, modes and initial conditions.
 * SO FAR: ONLY SCALAR
 *
 * This routine evaluates all the lensed C_l's at a given value of l by
 * picking it in the pre-computed table. When relevant, it also
 * sums over all initial conditions for each mode, and over all modes.
 *
 * This function can be called from whatever module at whatever time,
 * provided that lensing_init() has been called before, and
 * lensing_free() has not been called yet.
 *
 * @param ple        Input : pointer to lensing structure
 * @param l          Input : multipole number
 * @param cl_lensed  Output: lensed C_l's for all types (TT, TE, EE, etc..)
 * @return the error status
 */


/**
 * This routine initializes the lensing structure (in particular,
 * computes table of lensed anisotropy spectra \f$ C_l^{X} \f$)
 *
 * @param ppt Input : pointer to perturbation structure (just in case, not used in current version...)
 * @param psp Input : pointer to spectra structure
 * @param pnl Input : pointer to nonlinear structure
 * @param ple Output: pointer to initialized lensing structure
 * @return the error status
 */


/**
 * This routine defines indices and allocates tables in the lensing structure
 *
 * @param psp  Input       : pointer to spectra structure
 * @param ple  Input/output: pointer to lensing structure
 * @return the error status
 */


/**
 * This routine computes the lensed power spectra by Gaussian quadrature
 *
 * @param ksi  Input       : Lensed correlation function (ksi[index_mu])
 * @param d00  Input       : Legendre polynomials (d^l_{00}[l][index_mu])
 * @param w8   Input       : Legendre quadrature weights (w8[index_mu])
 * @param nmu  Input       : Number of quadrature points (0<=index_mu<=nmu)
 * @param ple  Input/output: Pointer to the lensing structure
 * @return the error status
 */


/**
 * This routine computes the lensed power spectra by Gaussian quadrature
 *
 * @param ksiX Input       : Lensed correlation function (ksiX[index_mu])
 * @param d20  Input       : Wigner d-function (d^l_{20}[l][index_mu])
 * @param w8   Input       : Legendre quadrature weights (w8[index_mu])
 * @param nmu  Input       : Number of quadrature points (0<=index_mu<=nmu)
 * @param ple  Input/output: Pointer to the lensing structure
 * @return the error status
 */


/**
 * This routine computes the lensed power spectra by Gaussian quadrature
 *
 * @param ksip Input       : Lensed correlation function (ksi+[index_mu])
 * @param ksim Input       : Lensed correlation function (ksi-[index_mu])
 * @param d22  Input       : Wigner d-function (d^l_{22}[l][index_mu])
 * @param d2m2 Input       : Wigner d-function (d^l_{2-2}[l][index_mu])
 * @param w8   Input       : Legendre quadrature weights (w8[index_mu])
 * @param nmu  Input       : Number of quadrature points (0<=index_mu<=nmu)
 * @param ple  Input/output: Pointer to the lensing structure
 * @return the error status
 */


/**
 * Initialize each parameters, first to its default values, and then
 * from what can be interpreted from the values passed in the input
 * 'file_content' structure. If its size is null, all parameters keep
 * their default values.
 */


/**
 * All default parameter values (for input parameters)
 *
 * @param pba Input : pointer to background structure
 * @param pth Input : pointer to thermodynamics structure
 * @param ppt Input : pointer to perturbation structure
 * @param pbs Input : pointer to bessels structure
 * @param ptr Input : pointer to transfer structure
 * @param ppm Input : pointer to primordial structure
 * @param psp Input : pointer to spectra structure
 * @param pop Input : pointer to output structure
 * @return the error status
 */


/**
 * Initialize the precision parameter structure.
 *
 * All precision parameters used in the other moduels are listed here
 * and assigned here a default value.
 *
 * @param ppr Input/Ouput: a precision_params structure pointer
 * @return the error status
 *
 */


/**
 * Background quantities at given conformal time tau.
 *
 * Evaluates all background quantities at a given value of
 * conformal time by reading the pre-computed table ant interpolating.
 *
 * @param pba           Input: pointer to background structure (containing pre-computed table)
 * @param tau           Input: value of conformal time
 * @param return_format Input: format of output vector (short, normal, long)
 * @param intermode     Input: interpolation mode (normal or closeby)
 * @param last_index    Input/Ouput: index of the previous/current point in the interpolation array (input only for closeby mode, output for both)
 * @param pvecback      Output: vector (assumed to be already allocated)
 * @return the error status
 */


/**
 * Conformal time at given redhsift.
 *
 * Returns tau(z) by interpolation from pre-computed table.
 *
 * @param pba Input: pointer to background structure
 * @param z   Input: redshift
 * @param tau Output: conformal time
 * @return the error status
 */


/**
 * Background quantities at given a.
 *
 * Function evaluating all background quantities which can be computed
 * analytically as a function of parameters like the scale factor 'a'
 * (see discussion at the beginnign of this file). In extended
 * comsological models, we would include other input parameters than
 * just 'a', e.g. (phi, phidot) for quintessence, some temperature of
 * exotic relics, etc...
 *
 * @param pba           Input: pointer to background structure
 * @param a             Input: value of scale factor
 * @param return_format Input: format of output vector
 * @param pvecback      Output: vector of background quantities (assmued to be already allocated)
 * @return the error status
 */


/**
 * Initialize the background structure, and in particular the
 * background interpolation table.
 *
 * @param ppr Input : pointer to precision structure
 * @param pba Input/Output : pointer to initialized background structure
 * @return the error status
 */


/**
 * Free all memory space allocated by background_init().
 *
 *
 * @param pba Input : pointer to background structure (to be freed)
 * @return the error status
 */


/**
 * Assign value to each relevant index in vectors of background quantities.
 *
 * @param pba Input : pointer to background structure
 * @return the error status
 */


/**
 * This is the routine where the distribution function f0(q) of each
 * ncdm species is specified (it is the only place to modify if you
 * need a partlar f0(q))
 *
 * @param pbadist Input:  structure containing all parameters defining f0(q)
 * @param q       Input:  momentum
 * @param f0      Output: phase-space distribution
 */


/**
 * This function finds optimal quadrature weights for each ncdm
 * species
 *
 * @param ppr Input: precision structure
 * @param pba Input/Output: background structure
 */


/**
 * For a given ncdm sepcies: given the quadrature weights, the mass
 * and the redshift, find background quantities by a quick weighted
 * sum over.  Input parameters passed as NULL pointers are not
 * evaluated for speed-up
 *
 * @param qvec     Input: smapled momenta
 * @param wvec     Input: quadrature weigths
 * @param qsize    Input: number of momenta/weigths
 * @param M        Input: mass
 * @param factor   Input: normalization factor for the p.s.d.
 * @param z        Input: redhsift
 * @param n        Output: number density
 * @param rho      Output: energy density
 * @param p        Output: pressure
 * @param drho_dM  Output: derivative used in next function
 * @param pseudo_p Ouput: pseudo-pressure used in perturbation module for fluid approx
 *
 */


/**
 * When the user passed in input the density fraction Omeha_ncdm or
 * omega_ncdm but not the mass, infer the mass with Newton iteration method.
 *
 * @param ppr    Input: precision structure
 * @param pba    Input/Output: background structure
 * @param n_ncdm Input: index of ncdm species
 */


/**
 *  This function integrates the background over time, allocates and
 *  fills the background table
 *
 * @param ppr Input: precision structure
 * @param pba Input/Output: background structure
 */


/**
 * Assign initial values to background integrated variables.
 *
 * @param ppr                  Input : pointer to precision structure
 * @param pba                  Input : pointer to background structure
 * @param pvecback             Input : vector of background quantitites used as workspace
 * @param pvecback_integration Output : vector of background quantitites to be integrated, returned with proper initial values
 * @return the error status
 */


/**
 * Subroutine evaluating the derivative with respect to conformal time
 * of quantities which are integrated (a, t, etc).
 *
 * This is one of the few functions in the code which are passed to
 * the generic_integrator() routine.  Since generic_integrator()
 * should work with functions passed from various modules, the format
 * of the arguments is a bit special:
 *
 * - fixed input parameters and wokspaces are passed through a generic
 * pointer. Here, this is just a pointer to the background structure
 * and to a background vector, but generic_integrator() doesn't know
 * its fine structure.
 *
 * - the error management is a bit special: errors are not written as
 * usual to pba->error_message, but to a generic error_message passed
 * in the list of arguments.
 *
 * @param tau                      Input : conformal time
 * @param y                        Input : vector of variable
 * @param dy                       Output : its derivative (already allocated)
 * @param parameters_and_workspace Input: pointer to fixed parameters (e.g. indices)
 * @param error_message            Output : error message
 */


/*************************************************************************************************
Cosmological parameters Input/Output
*************************************************************************************************/


/*****************************************************************************************
Matter temperature -- 1st order steady state, from Hirata 2008
******************************************************************************************/


/******************************************************************************************
Matter temperature evolution derivative
******************************************************************************************/


/**********************************************************************************************
Second order integrator using derivative from previous time steps
Evolves xe only, assumes Tm is given by the steady-state solution
***********************************************************************************************/


/**********************************************************************************************
Second order integrator using derivative from previous time steps
Evolves xe and Tm simultaneously
***********************************************************************************************/


/****************************************************************************************************
Builds a recombination history
****************************************************************************************************/


/**************************************************************************************************
Case-B recombination coefficient, fit of Pequignot et al 1991, in cm^3 s^{-1}
***************************************************************************************************/


/**************************************************************************************************
Peebles recombination rate
***************************************************************************************************/


/****************************************************************************************************
RecFast recombination rate (Seager et al 1999, 2000): effective three-level atom
with a fudge factor F = 1.14
****************************************************************************************************/


/**********************************************************************************************
Store tabulated temperatures and read effective MLA rates from files.
**********************************************************************************************/


/************************************************************************************************
Interpolation of tabulated effective rates
To be more (slightly) efficient, not using the external interpolation routine.
************************************************************************************************/


/************************************************************************************************
Solves for the populations of the 2s and 2p states in steady-state, and returns dxe/dt.
Uses standard rate for 2s-->1s decay and Sobolev for Lyman alpha (no feedback)
Inputs: xe, nH in cm^{-3}, H in s^{-1}, TM, TR in eV. Output: dxe/dlna
************************************************************************************************/


/*********************************************************************************************
Read two-photon rates from table
**********************************************************************************************/


/*********************************************************************************************************
 Populate the real-real, real-virtual, virtual-real and virtual-virtual T-matrices,
 as well as the source vectors sr, sv,
WITH DIFFUSION. Tvv[0][b] is the diagonal element Tbb, Tvv[1][b] = T{b,b-1} and Tvv[2][b] = T{b,b+1}
Also, computes and stores the optical depths Delta tau_b for future use
**********************************************************************************************************/


/*********************************************************************
Solves the linear system T*X = B, where T is a DIAGONALLY DOMINANT
tridiagonal matrix, and X and B are both one-column vectors of N elements.
diag[i] = T_{ii}, updiag[i] = T_{i,i+1}, dndiag[i] = T_{i,i-1}
IMPORTANT: This is NOT THE MOST GENERAL ALGORITHM. Only adapted for the
case we will consider, i.e. |T_{ii}| > |T_{i,i+1}| + |T_{i,i-1}|.
**********************************************************************/


/**************************************************************************************************************
Solves for the populations of the real (2s, 2p) and virtual states
***************************************************************************************************************/


/*************************************************************************************************************
Obtain fplus at each bin, given the history of fminus (simple free-streaming). iz is the current time step.
fminus[0..iz-1] is known.
Assume the Lyman lines are optically thick
logfminus_hist is a NVIRT by nz array of previous log(f(nu_b - epsilon)(z))
logfminus_Ly_hist is a 3 by nz array of previous log(f(nu - epsilon)) redward of Ly alpha, beta and gamma lines
*************************************************************************************************************/


/******************************************************************************************************************
d(x_e)/dt when including two-photon processes
This is independent of whether diffusion is present or not.
fminus[0..iz-1] is known. Update fminus[iz]
******************************************************************************************************************/


/******************************************************************************************
Post-Saha expansion using the full derivative with two-photon processes and diffusion
ADDED JANUARY 2011
*******************************************************************************************/


/*****************************************************************************************************
Update fminus(z) given the history of previous fminus's, assuming:
- thermal radiation field and Boltzmann equilibrium for the excited states if func_select = 0
- excited states are in Saha eq. with xe, and free-streaming for the radiation field between
  optically thick Lyman lines if func_select = 1
*****************************************************************************************************/


/* Python 3 has a print function */


/**
 * Initialize the integrator
 *
 */


/**
 * Called by thermodynamics_init(); perturb_sources().
 */


/**
 * Called by thermodynamics_init().
 */


/**
  * interpolate to get y_i(x), when x and y_i are in different arrays
  *
  * Called by background_at_eta(); background_eta_of_z(); background_solve(); thermodynamics_at_z().
  */


/**
 * interpolate to get y_i(x), when x and y_i are in different arrays
 *
 * Called by background_at_eta(); background_eta_of_z(); background_solve(); thermodynamics_at_z().
 */


/**
  * interpolate to get y_i(x), when x and y_i are in different arrays
  *
  *
  */


/**
  * interpolate to get y_i(x), when x and y_i are all columns of the same array, x is arranged in growing order, and the point x is presumably very close to the previous point x from the last call of this function.
  *
  * Called by background_at_eta(); background_eta_of_z(); background_solve(); thermodynamics_at_z().
  */


/**
  * interpolate to get y_i(x), when x and y_i are all columns of the same array, x is arranged in growing order, and the point x is presumably close (but maybe not so close) to the previous point x from the last call of this function.
  *
  * Called by background_at_eta(); background_eta_of_z(); background_solve(); thermodynamics_at_z().
  */


/**
 * Called by transfer_solve().
 */


/**
 * cubic interpolation of array with equally space abscisses
 */


/* Subroutine that interpolates from information stored in dif */


/**********************************************************************/
/* Here are some routines related to the calculation of the jacobian: */
/* "numjac", "initialize_jacobian", "uninitialize_jacobian",					*/
/* "initialize_numjac_workspace", "uninitialize_numjac_workspace".		*/
/**********************************************************************/


/* End of numjac */


/***
 * gt_init Initialize the growTable.
 * gt_init will initialize the growTable structure. It must be already allocated.
 *
 * Called by background_solve().
 */


/**
 * returns the size of the growTable
 *
 *  Not called.
 */


/**
 * returns a pointer on the data contained in the growTable.
 * No Data can be added afterward !!!!! This is not for the faint of heart.
 *
 * Called by background_solve().
 */


/* Timing variables
  runTimes[0] - total time to compute density
  runTimes[1] - total time to do MG solve
  runTimes[2] - time to prep density kernels
  runTimes[3] - time to normalize density kernels
  runTimes[4] - time to assign density kernels
  runTimes[5] - total time to comute BCs for MG solve
  runTimes[6] - total time to compute initial guess for MG solve solution
  runTimes[7] - total extra time not covered above by 0,1,5,6
  runTimes[8] - time to compute derivs of potential
  runTimes[9] - time to assign derivs to rays
  runTimes[10] - time to rot derivs back to global coords
*/


/* init function  - some help from Gadget-2 applied here */


/* write ratys to disk in HDF5 format
   inspired by Gadget-2
*/


/* does the actual write of the file */


/*
  this routine writes unformatted binary restart files
  for the ray tracing
*/


//remove gals from previous planes not needed during restart


/* code to quickly query disc in healpix
   uses rings of pixels for small angles (<0.5 radians) or a tree for large angles(> 0.5)
   if the rings of pixels function fails, it just defualts to the tree version

   you feed it a pointer to either previousl allocated memory and NlistpixMax = size of memory, or a null pointer if there is no memory
   on return NlistpixMax holds the amount of memory allocated to listpix
   the function itself returns the number of pixels found in the disc

   Matthew R. Becker, UofC 2012
*/


//basic query function from healpix - uses rings of pixels to find pixels in the disc - this version has slighty different memory allocation


//helper function for query_disc_inclusive_nest_realloc - looks in each ring and adds pixels


//tree walk based query of pixels in a disc


/* generic io interface */


/* reads light cone particles into bundleCells for the given planeNum */


/* parallel transport a vector on the sphere along the great circle connecting vec to rvec
   this function is based on the healpix package rotate_coord.pro IDL routine
   tvec is the tangent vector on the sphere where tvec[0] points along theta unit vector and tvec[1] points along phi unit vector
   vec is the location on the sphere of this tangent vector
   rvec is position to which tvec is to be parallel transported from vec
   rtvec is the parallel transported vector
*/


/* parallel transport a tensor on the sphere along the great circle connecting vec to rvec
   this function is based on the healpix package rotate_coord.pro IDL routine
   ttensor is a tensor on the sphere where the i,j component has basis vectors with 0 = e_theta, and 1 = e_phi for i,j in {0,1}
   vec is the location on the sphere of this tensor
   rvec is position to which ttensor is to be parallel transported from vec
   rttensor is the parallel transported vector
*/


// parallel transports a ray to the observer position from its current position


// parallel transports a ray to the current position from its observer position


// converts a ray from ra-dec basis to theta-phi basis


//util function for finding rays with nest value


//util data structs and functions for getting buffer rays


/* outputs the bundle cells with their domain decomp information */


/* makes map cells and creates and index through the bundle cells for searching */


//does all domain decomp and indexing functions
//do not change unless you know what you are doing (and even then it might be a good idea not to change this)


//reorder code a la Gadget-2


//this function sorts gals in REVERSE order - notice sign flips in first two if statements


/* gets a set of triangles for each pixel on the sphere
   ring - ring index of the pixel
   tri[4][3] - array where the jth vertex of the ith triangle is in tri[i][j]
   order - the order of the healpix grid

   returns the number of triangles per pixel

   The number of triangles returned per pixel varies because of the geometry of healpix.
   Thus to use this function properly, do this
   Ntri = ring2triangle(ring,tri,order);
   for(i=0;i<Ntri;++i)
     for(j=0;j<3;++j)
       trivertex_ij = tri[i][j];

   If you call this function for every ring index on the sphere at a given order,
   the tirangles will completely cover the sphere and every triangle will be retruned at most once.
   Some pixles near the north pole return no triangles (Ntri = 0) and others return up to four (Ntri = 4).
*/


/*
  propagates rays using lensing potential phi
*/


//routine to do case insens. string comp.


/*gets the number of lines in a file*/


/* Notes for how to do this

1) compute for each bundle cell the range of grid cells needed
   for now do this step using an array of cells and inthash.c

2) sort cells by index

3) send/recv cells needed from other processors

4) do integral over the cells

*/


//make a healpix map of the lens plane for debugging


/*3D NFW profile
  -- for an overdensity of overdens in units of whatever, radii in untis of whatever, and concentration c
  -- returns in same units as overdens
*/


/*
generates random draws from an NFW given r200 conc and overdens
points are in coords with respect to center of halo in box that is boxW wide on two sides and boxL long on one side
set idnum to a negative value to seed random number generator
*/


//gives total mass of particles for an NFW halo centered in a box of boxW width on two sides and boxL length on the other


/**GRDATE -- get date and time as character string (Cray)
 *+
 *    SUBROUTINE GRDATE(STRING, L)
 *    CHARACTER*(*) STRING
 *     INTEGER L
 *
 * Return the current date and time, in format 'dd-Mmm-yyyy hh:mm'.
 * To receive the whole string, the STRING should be declared
 * CHARACTER*17.
 *
 * Arguments:
 *  STRING : receives date and time, truncated or extended with
 *           blanks as necessary.
 *  SLEN   : receives the number of characters in STRING, excluding
 *           trailing blanks. This will always be 17, unless the length
 *           of the string supplied is shorter.
 *--
 * 09-Nov-1994 - [mcs] Fortran callable C version for CRAY.
 *-----------------------------------------------------------------------
 */


/*
  Fortran callable memory deallocator

  Called as :
	ier = grfmem (size,pointer)

  where : size is an integer size of memory to deallocate (not used)
	  pointer is an integer that contains the pointer

*/


/*
 **&GROFIL -- Open file for writing with GRFILEIO
 *+
 *     FUNCTION GROFIL (FNAME)
 *     INTEGER GROFIL
 *     CHARACTER*(*) FNAME
 *
 * Opens file FNAME for writing.
 * GROFIL returns the file descriptor for use in subsequent calls to
 * grwfil or grcfil. If GROFIL is negative, an error occurred while
 * opening the file.
 *
 **
 * Usage:
 *
 *     FD = GROFIL ('output_file')
 *     CALL GRWFIL (FD, 4, ARRAY)
 *
 * Arguments:
 *  FNAME  (input) : File name of the input or output file
 *  GROFIL (output) : Contains the file descriptor on return. If GROFIL < 0
 *                   an error occurred while opening the file.
 *-
 */