/*****************************************************************************
  Function name: SurfaceEnergyBalance()

  Purpose      : Calculate the surface energy balance in the absence of snow

  Required     :
    float TSurf           - new estimate of effective surface temperature
    va_list ap            - Argument list initialized by va_start().  For
                            elements of list and order, see beginning of
                            routine

  Returns      :
    float RestTerm        - Rest term in the energy balance

  Modifies     : none

  Comments     :
*****************************************************************************/


/*********************************************************************
   void cublic_spline_sp(size1, size2, grid1, grid2, data1, data2)

   Calculate a shape preserving cubic spline. Monotonicity is ensured over each subinterval
   unlike classic cubic spline interpolation.
   It will be used to interpolation data in 1-D space.

   INPUT Arguments:
    grid1:    grid for input data grid.
    grid2:    grid for output data grid.
    size1:    size of input grid.
    size2:    size of output grid.
    data1:    input data associated with grid1.

   OUTPUT ARGUMENTS:
    data2:    output data associated with grid2. (OUTPUT)

*********************************************************************/


/*******************************************************************************
   Revise Sutherland-Hodgeman algorithm to find the vertices of the overlapping
   between any two grid boxes. It return the number of vertices for the exchange grid.
   Each edge of grid box is a part of great circle. All the points are cartesian
   coordinates. Here we are assuming each polygon is convex.
   range_check_criteria is used to determine if the two grid boxes are possible to be
   overlap. The size should be between 0 and 0.5. The larger the range_check_criteria,
   the more expensive of the computatioin. When the value is close to 0,
   some small exchange grid might be lost. Suggest to use value 0.05 for C48.
*******************************************************************************/


/* Intersects between the line a and the seqment s
   where both line and segment are great circle lines on the sphere represented by
   3D cartesian points.
   [sin sout] are the ends of a line segment
   returns true if the lines could be intersected, false otherwise.
*/


/*******************************************************************************
 int inside_edge(double x0, double y0, double x1, double y1, double x, double y)
 determine a point(x,y) is inside or outside a given edge with vertex,
 (x0,y0) and (x1,y1). return 1 if inside and 0 if outside. <y1-y0, -(x1-x0)> is
 the outward edge normal from vertex <x0,y0> to <x1,y1>. <x-x0,y-y0> is the vector
 from <x0,y0> to <x,y>.
 if Inner produce <x-x0,y-y0>*<y1-y0, -(x1-x0)> > 0, outside, otherwise inside.
 inner product value = 0 also treate as inside.
*******************************************************************************/


/*----------------------------------------------------------------------
    double* vect_cross(p1, p2)
    return cross products of 3D vectors: = P1 X P2
    -------------------------------------------------------------------*/


/* transfer the index from supergrid to model grid
   return 0 if istart = iend
   otherwise return 1.
*/


/******************************************************************************
  void read_mosaic_grid_data(const char *mosaic_file, const char *name, int nx, int ny,
                             double *data, int level, int ioff, int joff)
  read mosaic grid information onto model grid. We assume the refinement is 2 right now.
  We may remove this restriction in the future. nx and ny are model grid size. level
  is the tile number. ioff and joff to indicate grid location. ioff =0 and joff = 0
  for C-cell. ioff=0 and joff=1 for E-cell, ioff=1 and joff=0 for N-cell,
  ioff=1 and joff=1 for T-cell
******************************************************************************/


/* This function accepts a single acceleration vector recorded in
 * the sensor fixed coordinate system, and the orientation of the
 * sensor in the real world coordinate system (North, East, Down)
 * as recorded in quaternion form.  The sensor fixed acceleration
 * is then rotated to the real world coordinate system using the
 * quaternion.
 *
 * The actual function definition is found in:
 * "SWIFT_OrientationCorrection.c"
 *
 * Adam Brown, 2015 (brownapl@uw.edu)
 *
 */


/*
 * Arguments    : int n
 *                const emxArray_real_T *x
 *                int ix0
 * Return Type  : double
 */


/* Function: rtGetNaN ==================================================
 * Abstract:
 * Initialize rtNaN needed by the generated code.
 * NaN is initialized as non-signaling. Assumes IEEE.
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                emxArray_real_T *b_x
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *x
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 * Return Type  : double
 */


/*
 * Arguments    : const emxArray_real_T *A
 *                const emxArray_real_T *B
 *                double Y[2]
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_boolean_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int32_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_boolean_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int32_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_boolean_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int32_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : int n
 *                double a
 *                emxArray_real_T *x
 *                int ix0
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                const emxArray_real_T *y
 *                emxArray_real_T *z
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_boolean_T *x
 * Return Type  : double
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                emxArray_real_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_creal_T *x
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int xoffInit
 *                int nfft
 *                int nRows
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                const emxArray_real_T *costabinv
 *                const emxArray_real_T *sintabinv
 *                const emxArray_creal_T *wwc
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_creal_T *x
 *                int unsigned_nRows
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int N2
 *                int n1
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                const emxArray_real_T *sintabinv
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : double u
 * Return Type  : double
 */


/*
 * matlab function to read and process GPS data
 *    to estimate wave height, period, direction, and spectral moments
 *    assuming deep-water limit of surface gravity wave dispersion relation
 *
 *  Inputs are east velocity [m/s], north velocity [m/s], vertical
 *  elevation relative to MSL [m], and sampling rate [Hz]
 *
 *  Some inputs can be empty variables, in which case the algorithm will use
 *  whatever non-empty inputs are available, with preference for GPS
 *  velocities
 *
 *  Required input is sampling rate, which must be at least 1 Hz and the same
 *  for all variables.  Additionaly, non-empty input time series data must
 *  have at least 512 points and all be the same size.
 *
 *  Outputs are significat wave height [m], dominant period [s], dominant direction
 *  [deg T, using meteorological from which waves are propagating], spectral
 *  energy density [m^2/Hz], frequency [Hz], and
 *  the normalized spectral moments a1, b1, a2, b2,
 *
 *  Outputs will be '9999' for invalid results.
 *
 *  Outputs can be supressed, in order, thus full usage is as follows:
 *
 *    [ Hs, Tp, Dp, E, f, a1, b1, a2, b2 ] = GPSwaves(u,v,z,fs);
 *
 *  and minimal usage is:
 *
 *    [ Hs, Tp ] = GPSwaves(u,v,[],[],[],fs);
 *
 *
 *  J. Thomson,  12/2013, v1, modified from PUVspectra.m (2003)
 *               10/2015, v2, include vertical GPS estimate to get all four directional moments
 *               10/2017, v3, change the RC filter parameter to 3.5, after
 *                            realizing that the cuttoff period is 2 pi * RC, not RC
 *               11/2018, v4, force velocity spectra as source for scalar energy spectra
 *                            remove LFNR usage
 *                            correct sign of a1, b1
 *                8/2019  force use of Tp from velocity spectra, increase max f to 1 Hz
 * Arguments    : emxArray_real_T *u
 *                emxArray_real_T *v
 *                emxArray_real_T *z
 *                double fs
 *                double *Hs
 *                double *Tp
 *                double *Dp
 *                emxArray_real_T *E
 *                emxArray_real_T *f
 *                emxArray_real_T *a1
 *                emxArray_real_T *b1
 *                emxArray_real_T *a2
 *                emxArray_real_T *b2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T *x
 *                const emxArray_int32_T *idx
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T *x
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *x
 *                const emxArray_boolean_T *idx
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                const emxArray_boolean_T *idx
 *                emxArray_real_T *b_x
 * Return Type  : void
 */


/*
 * Arguments    : int numDimensions
 *                int *size
 * Return Type  : emxArray_real_T *
 */


/*
 * Arguments    : double *data
 *                int numDimensions
 *                int *size
 * Return Type  : emxArray_real_T *
 */


/*
 * Arguments    : double *data
 *                int rows
 *                int cols
 * Return Type  : emxArray_real_T *
 */


/*
 * Arguments    : int rows
 *                int cols
 * Return Type  : emxArray_real_T *
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int vlen
 * Return Type  : double
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *a
 *                emxArray_real_T *y
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *A
 *                double tau_data[]
 *                int tau_size[1]
 *                int jpvt[2]
 * Return Type  : void
 */


/* Function: rtGetInf ==================================================
 * Abstract:
 * Initialize rtInf needed by the generated code.
 * Inf is initialized as non-signaling. Assumes IEEE.
 */


/* Function: rtGetMinusInf ==================================================
 * Abstract:
 * Initialize rtMinusInf needed by the generated code.
 * Inf is initialized as non-signaling. Assumes IEEE.
 */


/*
 * Arguments    : const emxArray_real_T *y
 *                const emxArray_real_T *x
 *                emxArray_real_T *r
 * Return Type  : void
 */


/*
 * Arguments    : int32_T nlhs
 *                const mxArray *plhs[9]
 *                int32_T nrhs
 *                const mxArray *prhs[4]
 * Return Type  : void
 */


/*
 * Arguments    : int32_T nlhs
 *                const mxArray * const plhs[]
 *                int32_T nrhs
 *                const mxArray * const prhs[]
 * Return Type  : void
 */


/*
 * Arguments    : void
 * Return Type  : emlrtCTX
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *u
 *                const emlrtMsgIdentifier *parentId
 *                emxArray_real_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *fs
 *                const char_T *identifier
 * Return Type  : real_T
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *u
 *                const emlrtMsgIdentifier *parentId
 * Return Type  : real_T
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *src
 *                const emlrtMsgIdentifier *msgId
 *                emxArray_real_T *ret
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *u
 *                const char_T *identifier
 *                emxArray_real_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const real_T u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emlrtStack *sp
 *                emxArray_real_T **pEmxArray
 *                int32_T numDimensions
 *                boolean_T doPush
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *src
 *                const emlrtMsgIdentifier *msgId
 * Return Type  : real_T
 */


/*
 * Arguments    : const mxArray *prhs[4]
 *                const mxArray *plhs[9]
 * Return Type  : void
 */


/*
 * Arguments    : void
 * Return Type  : void
 */


/*
 * Arguments    : void
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : void
 * Return Type  : mxArray *
 */


/*
 * Arguments    : void
 * Return Type  : emxArray_real_T *
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_real32_T *in1
 *                const emxArray_real_T *in2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real32_T *in1
 *                const emxArray_real32_T *in2
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/*
 * matlab function to process GPS velocity components north, east, down
 *    to estimate wave height, period, direction, and spectral moments
 *    assuming deep-water limit of surface gravity wave dispersion relation
 *
 *  input time series are velocity components north [m/s], east [m/s], down
 * [m/s] and sampling rate [Hz], which must be at least 1 Hz Input time series
 * data must have at least 512 points and all be the same size.
 *
 *  Outputs are significat wave height [m], dominant period [s], dominant
 * direction [deg T, using meteorological from which waves are propagating],
 * spectral energy density [m^2/Hz], frequency [Hz], and the normalized spectral
 * moments a1, b1, a2, b2, and the check factor (ratio of vertical to horizontal
 * motion)
 *
 *  Outputs will be '9999' for invalid results.
 *
 *  Usage is as follows:
 *
 *    [ Hs, Tp, Dp, E, fmin, fmax, a1, b1, a2, b2, check ] =
 * NEDwaves_memlight(north,east,down,fs);
 *
 *  note that outputs are slightly different than other wave codes
 *  b/c this matches the half-float precision format of telemetry type 52
 *  and only uses frequency limits, not full f array
 *
 *  J. Thomson,  12/2022 (modified from GPSwaves)
 *
 *               1/2023 memory light version... removes filtering, windowing,etc
 *                        assumes input data is clean and ready
 *
 *               6/2023 put windowing back in (as for loop that over-writes)
 *                    abandon convention that upper cases is in frequency domain
 *
 *               9/2023 reverse convention for wave direction and filter twice
 *
 *               10/2023 fix major bug introduced at 6/2023 wherein raw fft
 *               coefficients where merged across neighbor frequencies before
 *               calculating auto and cross spectra (i.e., averaging before
 *               applying a nonlinear operator)
 *
 *               10/2023 reintroduce simply despiking
 *
 *
 * Arguments    : emxArray_real32_T *north
 *                emxArray_real32_T *east
 *                emxArray_real32_T *down
 *                double fs
 *                real16_T *Hs
 *                real16_T *Tp
 *                real16_T *Dp
 *                real16_T E[42]
 *                real16_T *b_fmin
 *                real16_T *b_fmax
 *                signed char a1[42]
 *                signed char b1[42]
 *                signed char a2[42]
 *                signed char b2[42]
 *                unsigned char check[42]
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real32_T *x
 * Return Type  : float
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                int vlen
 * Return Type  : float
 */


/* Function Definitions */
/*
 * Arguments    : int numDimensions
 *                const int *size
 * Return Type  : emxArray_real32_T *
 */


/*
 * Arguments    : float *data
 *                int numDimensions
 *                const int *size
 * Return Type  : emxArray_real32_T *
 */


/*
 * Arguments    : float *data
 *                int rows
 *                int cols
 * Return Type  : emxArray_real32_T *
 */


/*
 * Arguments    : int rows
 *                int cols
 * Return Type  : emxArray_real32_T *
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_creal32_T *x
 *                int unsigned_nRows
 *                const emxArray_real32_T *costab
 *                const emxArray_real32_T *sintab
 *                emxArray_creal32_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                emxArray_creal32_T *y
 *                int nrowsx
 *                int nRows
 *                int nfft
 *                const emxArray_creal32_T *wwc
 *                const emxArray_real32_T *costab
 *                const emxArray_real32_T *sintab
 *                const emxArray_real32_T *costabinv
 *                const emxArray_real32_T *sintabinv
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                emxArray_creal32_T *y
 *                int unsigned_nRows
 *                const emxArray_real32_T *costab
 *                const emxArray_real32_T *sintab
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                int n2blue
 *                int nfft
 *                const emxArray_real32_T *costab
 *                const emxArray_real32_T *sintab
 *                const emxArray_real32_T *sintabinv
 *                emxArray_creal32_T *y
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : double b
 *                emxArray_real_T *y
 * Return Type  : void
 */


/*
 * Arguments    : double b
 *                emxArray_real_T *y
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_creal32_T *x
 * Return Type  : creal32_T
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real_T *x
 * Return Type  : double
 */


/*
 * Arguments    : const float x[42]
 *                float *ex
 *                int *idx
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                float *ex
 *                int *idx
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real32_T *x
 *                emxArray_creal32_T *y
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_creal32_T *x
 *                const emxArray_int32_T *idx
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T *x
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_boolean_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real32_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real32_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real32_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real_T *x
 *                double xi
 * Return Type  : int
 */


/* Convert half to float */


/* Convert float to half */


/* Convert double to half */


/* Function Definitions */
/*
 * Arguments    : float in1[42]
 *                const float in2[42]
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : void
 * Return Type  : emxArray_real32_T *
 */


/* Function Definitions */
/*
 * Arguments    : int32_T nlhs
 *                mxArray *plhs[]
 *                int32_T nrhs
 *                const mxArray *prhs[]
 * Return Type  : void
 */


/*
 * Arguments    : int32_T nlhs
 *                mxArray *plhs[11]
 *                int32_T nrhs
 *                const mxArray *prhs[4]
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *u
 *                const emlrtMsgIdentifier *parentId
 *                emxArray_real32_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const real16_T u[42]
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const int8_T u[42]
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const uint8_T u[42]
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *src
 *                const emlrtMsgIdentifier *msgId
 *                emxArray_real32_T *ret
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                const mxArray *north
 *                const char_T *identifier
 *                emxArray_real32_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const real16_T u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : emxArray_real32_T *emxArray
 *                int32_T oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                emxArray_real32_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : const mxArray * const prhs[4]
 *                int32_T nlhs
 *                const mxArray *plhs[11]
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_real_T *in2
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_real_T *in2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_creal_T *in2
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_creal_T *in2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_real_T *in2
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : int n
 *                const emxArray_real_T *x
 *                int ix0
 * Return Type  : double
 */


/*
 * Arguments    : int n
 *                const emxArray_real32_T *x
 *                int ix0
 * Return Type  : float
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real_T *x
 *                emxArray_real_T *y
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real32_T *x
 *                int vlen
 * Return Type  : float
 */


/* Function Definitions */
/*
 * Arguments    : int numDimensions
 *                const int *size
 * Return Type  : emxArray_int8_T *
 */


/*
 * Arguments    : int numDimensions
 *                const int *size
 * Return Type  : emxArray_real16_T *
 */


/*
 * Arguments    : int numDimensions
 *                const int *size
 * Return Type  : emxArray_real32_T *
 */


/*
 * Arguments    : int numDimensions
 *                const int *size
 * Return Type  : emxArray_uint8_T *
 */


/*
 * Arguments    : signed char *data
 *                int numDimensions
 *                const int *size
 * Return Type  : emxArray_int8_T *
 */


/*
 * Arguments    : real16_T *data
 *                int numDimensions
 *                const int *size
 * Return Type  : emxArray_real16_T *
 */


/*
 * Arguments    : unsigned char *data
 *                int numDimensions
 *                const int *size
 * Return Type  : emxArray_uint8_T *
 */


/*
 * Arguments    : signed char *data
 *                int rows
 *                int cols
 * Return Type  : emxArray_int8_T *
 */


/*
 * Arguments    : real16_T *data
 *                int rows
 *                int cols
 * Return Type  : emxArray_real16_T *
 */


/*
 * Arguments    : unsigned char *data
 *                int rows
 *                int cols
 * Return Type  : emxArray_uint8_T *
 */


/*
 * Arguments    : int rows
 *                int cols
 * Return Type  : emxArray_int8_T *
 */


/*
 * Arguments    : int rows
 *                int cols
 * Return Type  : emxArray_real16_T *
 */


/*
 * Arguments    : int rows
 *                int cols
 * Return Type  : emxArray_uint8_T *
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_creal32_T *x
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal_T *x
 *                const emxArray_boolean_T *idx
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T *x
 *                const emxArray_int32_T *idx
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_real_T *x
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                double *ex
 *                int *idx
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_real_T *in2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_creal32_T *in1
 *                const emxArray_creal32_T *in2
 *                const emxArray_creal32_T *in3
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real_T *in1
 *                double in2
 *                const emxArray_real_T *in3
 * Return Type  : void
 */


/*
 * matlab function to process GPS velocity components north, east, down
 *    to estimate wave height, period, direction, and spectral moments
 *    assuming deep-water limit of surface gravity wave dispersion relation
 *
 *  input time series are velocity components north [m/s], east [m/s], down
 * [m/s] and sampling rate [Hz], which must be at least 1 Hz Input time series
 * data must have at least 512 points and all be the same size.
 *
 *  Outputs are significat wave height [m], dominant period [s], dominant
 * direction [deg T, using meteorological from which waves are propagating],
 * spectral energy density [m^2/Hz], frequency [Hz], and the normalized spectral
 * moments a1, b1, a2, b2, and the check factor (ratio of vertical to horizontal
 * motion)
 *
 *  Outputs will be '9999' for invalid results.
 *
 *  Usage is as follows:
 *
 *    [ Hs, Tp, Dp, E, fmin, fmax, a1, b1, a2, b2, check ] =
 * NEDwaves(north,east,down,fs);
 *
 *  note that outputs are slightly different than other wave codes
 *  b/c this matches the half-float precision format of telemetry type 52
 *  and only uses frequency limits, not full f array
 *
 *  J. Thomson,  12/2022 (modified from GPSwaves)
 *
 *
 * Arguments    : emxArray_real32_T *north
 *                emxArray_real32_T *east
 *                emxArray_real32_T *down
 *                double fs
 *                real16_T *Hs
 *                real16_T *Tp
 *                real16_T *Dp
 *                emxArray_real16_T *E
 *                real16_T *b_fmin
 *                real16_T *b_fmax
 *                emxArray_int8_T *a1
 *                emxArray_int8_T *b1
 *                emxArray_int8_T *a2
 *                emxArray_int8_T *b2
 *                emxArray_uint8_T *check
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int8_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real16_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_uint8_T *emxArray
 *                int oldNumel
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int8_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real16_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_uint8_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_int8_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real16_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_uint8_T **pEmxArray
 *                int numDimensions
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_creal_T *x
 *                int unsigned_nRows
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int xoffInit
 *                emxArray_creal_T *y
 *                int nrowsx
 *                int nRows
 *                int nfft
 *                const emxArray_creal_T *wwc
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                const emxArray_real_T *costabinv
 *                const emxArray_real_T *sintabinv
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int xoffInit
 *                emxArray_creal_T *y
 *                int unsigned_nRows
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real_T *x
 *                int n2blue
 *                int nfft
 *                const emxArray_real_T *costab
 *                const emxArray_real_T *sintab
 *                const emxArray_real_T *sintabinv
 *                emxArray_creal_T *y
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : const emxArray_creal32_T *x
 *                emxArray_creal32_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *x
 *                emxArray_real32_T *y
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real32_T *A
 *                const emxArray_real32_T *B
 *                float Y[2]
 *                int *rankA
 * Return Type  : void
 */


/* Function Definitions */
/*
 * Arguments    : emxArray_real32_T *in1
 *                const emxArray_real32_T *in2
 * Return Type  : void
 */


/*
 * Arguments    : emxArray_real32_T *x
 * Return Type  : void
 */


/*
 * Arguments    : const emxArray_real16_T *u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emxArray_int8_T *u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emxArray_uint8_T *u
 * Return Type  : const mxArray *
 */


/*
 * Arguments    : const emlrtStack *sp
 *                emxArray_int8_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                emxArray_real16_T **pEmxArray
 * Return Type  : void
 */


/*
 * Arguments    : const emlrtStack *sp
 *                emxArray_uint8_T **pEmxArray
 * Return Type  : void
 */


/**
  *
  * @param v pointer to 4 byte memory chunk to be endian-swapped
  *
  *   Utility functions for swapping a specific endianness to
  *    accomodate the machine's native format.
  *
  */


/**
  *
  * @param v pointer to 2 byte memory chunk to be endian-swapped
  *
  * Utility functions for swapping  a specific endianness to
  *   accomodate the machine's native format.
  *
  */


/*------ C code for interpolation calcs ----*/


/*
 * Hapke's BRDF model (times Pi/Mu0):
 *   Hapke, B., Theory of reflectance and emittance spectroscopy, Cambridge University Press, 1993,
 * eq. 8.89 on page 233. Parameters are from Fig. 8.15 on page 231, except for w.

  INPUT:

    wvnmlo : Lower wavenumber (inv cm) of spectral interval
    wvnmhi : Upper wavenumber (inv cm) of spectral interval
    mu     : Cosine of angle of reflection (positive)
    mup    : Cosine of angle of incidence (positive)
    dphi   : Difference of azimuth angles of incidence and reflection
                (radians)

  LOCAL VARIABLES:

    iref   : bidirectional reflectance options; 1 - Hapke's BDR model
    b0     : empirical factor to account for the finite size of particles in Hapke's BDR model
    b      : term that accounts for the opposition effect (retroreflectance, hot spot) in Hapke's BDR model
    ctheta : cosine of phase angle in Hapke's BDR model
    gamma  : albedo factor in Hapke's BDR model
    h0     : H(mu0) in Hapke's BDR model
    h      : H(mu) in Hapke's BDR model
    hh     : angular width parameter of opposition effect in Hapke's BDR model
    p      : scattering phase function in Hapke's BDR model
    theta  : phase angle (radians); the angle between incidence and reflection directions in Hapke's BDR model
    w      : single scattering albedo in Hapke's BDR model

   Called by- c_bidir_reflectivity
-------------------------------------------------------------------------*/


/*
  Solves eigenfunction problem for real asymmetric matrix for which it
  is known a priori that the eigenvalues are real. This is an adaptation
  of a subroutine EIGRF in the IMSL library to use real instead of complex
  arithmetic, accounting for the known fact that the eigenvalues and
  eigenvectors in the discrete ordinate solution are real.

  EIGRF is based primarily on EISPACK routines.  The matrix is first
  balanced using the Parlett-Reinsch algorithm.  Then the Martin-Wilkinson
  algorithm is applied. There is a statement 'j = wk(i)' that converts a
  double precision variable to an integer variable; this seems dangerous
  to us in principle, but seems to work fine in practice.

  References:

  Dongarra, J. and C. Moler, EISPACK -- A Package for Solving Matrix
      Eigenvalue Problems, in Cowell, ed., 1984: Sources and Development of
      Mathematical Software, Prentice-Hall, Englewood Cliffs, NJ
  Parlett and Reinsch, 1969: Balancing a Matrix for Calculation of
      Eigenvalues and Eigenvectors, Num. Math. 13, 293-304
  Wilkinson, J., 1965: The Algebraic Eigenvalue Problem, Clarendon Press,
      Oxford

   I N P U T    V A R I A B L E S:

       aa    :  input asymmetric matrix, destroyed after solved
        m    :  order of aa
       ia    :  first dimension of aa
    ievec    :  first dimension of evec

   O U T P U T    V A R I A B L E S:

       evec  :  (unnormalized) eigenvectors of aa (column j corresponds to EVAL(J))
       eval  :  (unordered) eigenvalues of aa (dimension m)
       ier   :  if != 0, signals that EVAL(ier) failed to converge;
                   in that case eigenvalues ier+1,ier+2,...,m  are
                   correct but eigenvalues 1,...,ier are set to zero.

   S C R A T C H   V A R I A B L E S:

       wk    :  work area (dimension at least 2*m)

   Called by- c_solve_eigen
   Calls- c_errmsg
 -------------------------------------------------------------------*/


/*
       Prepares double scattering integration according to alternative
       Buras-Emde algorithm(201X).

                I N P U T   V A R I A B L E S

       nphase    number of angles for which original phase function
                     (ds->phase) is defined
       ntau
       nf        number of angular phase integration grid point
                     (zenith angle, theta)
       mu_phase  cos(theta) grid of phase function
       phas2     residual phase function

                O U T P U T   V A R I A B L E S

       mu_eq     cos(theta) phase integration grid points,
                     equidistant in abs(f_phas2)
       neg_phas  index whether phas2 is negative
       norm_phas normalization factor for phase integration

                I N T E R N A L   V A R I A B L E S

       f_phas2_abs absolute value of integrated phase function
                      phas2
       f_phas2     cumulative integrated phase function phas2
       df          step length for calculating mu_eq

   Called by- c_new_intensity_correction
   Calls- c_dbl_vector, locate
 -------------------------------------------------------------------*/


/*
    Calculate coefficient matrix for the set of equations obtained from the
    boundary conditions and the continuity-of-intensity-at-layer-interface equations.

    Store in the special banded-matrix format required by LINPACK routines

    I N P U T      V A R I A B L E S:

       ds       :  Disort state variables
       bdr      :  surface bidirectional reflectivity
       cmu,cwt  :  abscissae, weights for Gauss quadrature over angle cosine
       delm0    :  Kronecker delta, delta-sub-m0
       gc       :  Eigenvectors at polar quadrature angles, SC(1)
       kk       :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       lyrcut   :  Logical flag for truncation of computational layers
       nn       :  Number of streams in a hemisphere (NSTR/2)
       ncut     :  Total number of computational layers considered
       taucpr   :  Cumulative optical depth (delta-M-scaled)

   O U T P U T     V A R I A B L E S:

       cband    :  Left-hand side matrix of linear system eq. SC(5), scaled by eq. SC(12);
                   in banded form required by LINPACK solution routines
       ncol     :  Number of columns in cband

   I N T E R N A L    V A R I A B L E S:

       irow     :  Points to row in CBAND
       jcol     :  Points to position in layer block
       lda      :  Row dimension of CBAND
       ncd      :  Number of diagonals below or above main diagonal
       nshift   :  For positioning number of rows in band storage
       wk       :  Temporary storage for EXP evaluations

   BAND STORAGE

      LINPACK requires band matrices to be input in a special
      form where the elements of each diagonal are moved up or
      down (in their column) so that each diagonal becomes a row.
      (The column locations of diagonal elements are unchanged.)

      Example:  if the original matrix is

          11 12 13  0  0  0
          21 22 23 24  0  0
           0 32 33 34 35  0
           0  0 43 44 45 46
           0  0  0 54 55 56
           0  0  0  0 65 66

      then its LINPACK input form would be:

           *  *  *  +  +  +  , * = not used
           *  * 13 24 35 46  , + = used for pivoting
           * 12 23 34 45 56
          11 22 33 44 55 66
          21 32 43 54 65  *

      If A is a band matrix, the following program segment
      will convert it to the form (ABD) required by LINPACK
      band-matrix routines:

        n  = (column dimension of a, abd)
        ml = (band width below the diagonal)
        mu = (band width above the diagonal)
        m = ml+mu+1;
        for (j = 1; j <= n; j++) {
          i1 = IMAX(1,j-mu);
          i2 = IMIN(n,j+ml);
          for (i = i1; i <= i2; i++) {
            k = i-j+m;
            ABD(k,j) = A(i,j);
          }
        }

      This uses rows  ml+1 through  2*ml+mu+1  of ABD.
      The total number of rows needed in ABD is 2*ml+mu+1.
      In the example above, n = 6, ml = 1, mu = 2, and the
      row dimension of ABD must be >= 5.

   Called by- c_disort, c_albtrans
 -------------------------------------------------------------------*/


/*
        Calculates single-scattered intensity from eqs. STWL (65b,d,e)

                I N P U T   V A R I A B L E S

        dither   small multiple of machine precision
        layru    index of utau in multi-layered system
        nlyr     number of sublayers
        phase    phase functions of sublayers
        omega    single scattering albedos of sublayers
        tau      optical thicknesses of sublayers
        umu      cosine of emergent angle
        umu0     cosine of incident zenith angle
        utau     user defined optical depth for output intensity
        fbeam   incident beam radiation at top

   Called by- c_intensity_correction
 -------------------------------------------------------------------*/


/*
       Computes the normalized associated Legendre polynomial, defined
       in terms of the associated Legendre polynomial Plm = P-sub-l-super-m as

          Ylm(MU) = sqrt( (l-m)!/(l+m)! ) * Plm(MU)

       for fixed order m and all degrees from l = m to TWONM1.
       When m.GT.0, assumes that Y-sub(m-1)-super(m-1) is available
       from a prior call to the routine.

       REFERENCE: Dave, J.V. and B.H. Armstrong, Computations of High-Order
                    Associated Legendre Polynomials, J. Quant. Spectrosc. Radiat. Transfer 10,
                    557-562, 1970. (hereafter D/A)

       METHOD: Varying degree recurrence relationship.

       NOTES:
       (1) The D/A formulas are transformed by setting m=n-1; l=k-1.
       (2) Assumes that routine is called first with  m = 0, then with
           m = 1, etc. up to  m = twonm1.

  I N P U T     V A R I A B L E S:

       nmu    :  Number of arguments of YLM
       m      :  Order of YLM
       maxmu  :
       twonm1 :  Max degree of YLM
       MU(i)  :  Arguments of YLM (i = 1 to nmu)

       If m > 0, YLM(m-1,i) for i = 1 to nmu is assumed to exist from a prior call.

  O U T P U T     V A R I A B L E:

       YLM(l,i) :  l = m to twonm1, normalized associated Legendre polynomials
                   evaluated at argument MU(i)

   Called by- c_disort, c_albtrans
 -------------------------------------------------------------------*/


/*
 * Calculate ratio a/b with overflow and underflow protection
 * (thanks to Prof. Jeff Dozier for some suggestions here).
 *
 * Modification in this C version: in the case b == 0., returns 1.+a.
 *
 * Called by: c_disort
 */


/*
   DISORT special case to get only albedo and transmissivity of entire medium as a function of incident beam angle
   (many simplifications because boundary condition is just isotropic illumination, there are no thermal sources, and
   particular solutions do not need to be computed).  See Ref. S2 and references therein for details.
   The basic idea is as follows.  The reciprocity principle leads to the following relationships for a plane-parallel,
   vertically inhomogeneous medium lacking thermal (or other internal) sources:

      albedo(theta) = u_0(theta) for unit-intensity isotropic
                       illumination at *top* boundary
       trans(theta) =  u_0(theta) for unit-intensity isotropic
                       illumination at *bottom* boundary
    where

       albedo(theta) = albedo for beam incidence at angle theta
       trans(theta)  = transmissivity for beam incidence at angle theta
       u_0(theta)    = upward azim-avg intensity at top boundary
                       at angle theta

   O U T P U T    V A R I A B L E S:

       ALBMED(iu)   Albedo of the medium as a function of incident
                    beam angle cosine UMU(IU)

       TRNMED(iu)   Transmissivity of the medium as a function of
                    incident beam angle cosine UMU(IU)

    I N T E R N A L   V A R I A B L E S:

       ncd         number of diagonals below/above main diagonal
       rcond       estimate of the reciprocal condition of matrix CBAND; for system  CBAND*X = B, relative
                   perturbations in CBAND and B of size epsilon may cause relative perturbations in X of size
                   epsilon/RCOND.  If RCOND is so small that
                          1.0 + RCOND .eq. 1.0
                   is true, then CBAND may be singular to working precision.
       cband       Left-hand side matrix of linear system eq. SC(5), scaled by eq. SC(12);
                   in banded form required by LINPACK solution routines
       ncol        number of columns in CBAND matrix
       ipvt        INTEGER vector of pivot indices (most others documented in DISORT)

   Called by- c_disort
   Calls- c_legendre_poly, c_sgbco, c_solve_eigen, c_interp_eigenvec, c_set_matrix, c_solve1,
          c_albtrans_intensity, c_albtrans_spherical, c_print_albtrans
 --------------------------------------------------------------------------------------*/


/*
   Factors a real matrix by Gaussian elimination
   and estimates the condition of the matrix.
   Revision date:  8/1/82
   Author:  Moler, C. B. (Univ. of New Mexico)
   If rcond is not needed, sgefa is slightly faster.
   To solve  A*X = B, follow sgeco by sgesl.

     Inputs:
        a       double(lda, n), the matrix to be factored.
        lda     int, the leading dimension of the array a.
        n       int, the order of the matrix a.

     Outputs:
        a       an upper triangular matrix and the multipliers
                which were used to obtain it.
                The factorization can be written  A = L*U , where
                L  is a product of permutation and unit lower
                triangular matrices and U is upper triangular.
        ipvt    int(n), an integer vector of pivot indices.
        rcond   double, an estimate of the reciprocal condition of a.
                For the system A*X = B, relative perturbations
                in A and B of size epsilon may cause relative
                perturbations in X of size epsilon/rcond.
                If rcond is so small that the logical expression
                  1.+rcond == 1.
                is true, then A may be singular to working precision.
                In particular, rcond is zero if exact singularity
                is detected or the estimate underflows.
        z       double(n), a work vector whose contents are usually
                unimportant. If A is close to a singular matrix, then z
                is an approximate null vector in the sense that
                norm(A*Z) = rcond*norm(A)*norm(Z) .
 ------------------------------------------------------------------*/


/*
  Solves the real system
     A*X = B  or  transpose(A)*X = B
  using the factors computed by sgeco or sgefa.
  Revision date:  8/1/82
  Author:  Moler, C. B. (Univ. of New Mexico)

     Inputs:
        a       double(lda, n), the output from sgeco or sgefa.
        lda     int, the leading dimension of the array  A
        n       int, the order of the matrix  A
        ipvt    int(n), the pivot vector from sgeco or sgefa.
        b       double(n), the right hand side vector.
        job     int,
                = 0         to solve  A*X = B ,
                = nonzero   to solve  transpose(A)*X = B

     Outputs:
        b       the solution vector x

     Error condition:
        A division by zero will occur if the input factor contains a
        zero on the diagonal. Technically, this indicates singularity,
        but it is often caused by improper arguments or improper setting
        of lda. It will not occur if the subroutines are called correctly
        and if sgeco has set rcond > 0. or sgefa has set info = 0 .
     To compute  inverse(a)*c where c is a matrix with p columns
           c_sgeco(a,lda,n,ipvt,rcond,z);
           if (rcond is too small) ...
           for (j = 1; j <= p; j++) {
             c_sgesl(a,lda,n,ipvt,c(1,j),0);
           }
 ---------------------------------------------------------------------*/


/*
 Calculates the Chapman factor.

 I n p u t       v a r i a b l e s:

      lc        : Computational layer
      taup      :
      tauc      :
      nlyr      : Number of layers in atmospheric model
      zd(lc)    : lc = 0, nlyr. zd(lc) is distance from bottom
                  surface to top of layer lc. zd(nlyr) = 0. km
      dtau_c    : Optical thickness of layer lc (un-delta-m-scaled)
      zenang    : Solar zenith angle as seen from bottom surface
      r         : Radial parameter, see Velinow & Kostov (2001). NOTE: Use the same dimension as zd,
                  for instance both in km.

 O u t p u t      v a r i a b l e s:

      ch        : Chapman-factor. In a pseudo-spherical atmosphere, replace exp(-tau/umu0) by exp(-ch(lc)) in the
                  beam source in

 I n t e r n a l     v a r i a b l e s:

      dhj       : delta-h-sub-j in eq. B2 (DS)
      dsj       : delta-s-sub-j in eq. B2 (DS)
      fact      : =1 for first  sum in eq. B2 (DS)
                  =2 for second sum in eq. B2 (DS)
      rj        : r-sub-j   in eq. B1 (DS)
      rjp1      : r-sub-j+1 in eq. B1 (DS)
      xpsinz    : The length of the line OG in Fig. 1, (DS)

 NOTE: Assumes a spherical planet. One might consider generalizing following
       Velinow YPI, Kostov VI, 2001, Generalization on Chapman Function for the Atmosphere of an Oblate Rotating Planet,
         Comptes Rendus de l'Academie Bulgare des Sciences 54, 29-34.
*/


/*-------------------------------------------------------------------
 * Copyright (C) 1994 Arve Kylling
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * To obtain a copy of the GNU General Public License write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *-------------------------------------------------------------------
 * Linearly interpolate to get approximate tau corresponding to
 * altitude zout
 *
 * Input/output variables described in phodis.f
 *
 *
 * This code was translated to c from fortran by Robert Buras
 *
 */


/* This simple routine frees up the pointer *ptr, and sets *ptr to NULL */


/* The problem we are optimizing will have 2 rows, 3 columns,
   6 nonzeros, and 7 nonzeros in the quadratic coefficient matrix. */


// Catmull-Rom cubic spline


/**
     * @brief Initialize class variables; call CosmoArray::init for array members
     * @details Set "dt" for class instance; grid dimensions
     *
     * @param nx_in num. grid points in x-direction
     * @param ny_in num. grid points in y-direction
     * @param nz_in num. grid points in z-direction
     * @param sim_dt_in initial timestep
     */


/* Fill in the `fields' structure in LINE. */


/* Read a line from FP into LINE and split it into fields.
   Return 0 if EOF, 1 otherwise. */


/* Print field N of LINE if it exists and is nonempty, otherwise
   `empty_filler' if it is nonempty. */


/* Print the join of the files in FP1 and FP2. */


/* Add the comma or blank separated field spec(s) in STR to `outlist'.
   Return the number of fields added. */


/* Clean up any remaining temporary files. */


/* Search through the list of temporary files for NAME;
   remove it if it is found on the list. */


/* Initialize the character class tables. */


/* Initialize BUF, allocating ALLOC bytes initially. */


/* Initialize LINES, allocating space for ALLOC lines initially.
   LIMIT is the maximum possible number of lines to allocate space
   for, ever.  */


/* Compare strings A and B containing decimal fractions < 1.  Each string
   should begin with a decimal point followed immediately by the digits
   of the fraction.  Strings not of this form are considered to be zero. */


/* Compare strings A and B as numbers without explicitly converting them to
   machine numbers.  Comparatively slow for short strings, but asymptotically
   hideously fast. */


/* Sort the array LINES with NLINES members, using TEMP for temporary space. */


/* Check that each of the NFILES FILES is ordered.
   Return a count of disordered files. */


/* Insert key KEY at the end of the list (`keyhead'). */


/**
   * shift the spectrum such that we can calculate if the line would be at 1keV
   * (if the line is at 5keV, the energy grid is multiplied by 1/5)
   */


/**
   * shift the spectrum in redshift
   */


/**
 *  @function: write_binned_data_to_file
 *  @synopsis: write data to file, where the x-value is interpreted as a binned grid,
 *    with rlo[ii]=rad[ii] and rhi[ii]=rad[ii+1]
 *  @input:
 *   - double[n_rad+1] rad
 *   - double[n_rad] intens
 *   - int n_rad
 **/


/**
 *  @function: write_data_to_file
 *  @synopsis: write data to file, where the x-value and y-value is written
 *  @input:
 *   - double[n_rad] rad
 *   - double[n_rad] intens
 *   - int n_rad
 **/


/**
 * @function save_emis_profiles
 * @param sysPar
 * @synopsis: saves the emissivity profile, the incident one and (if exists) also
 * the returning radiation profile
 */


/** linear interpolation in 2 dimensions **/


/** check and report FITS error   */


/**  FLOAT search for value "val" in array "arr" (sorted ASCENDING!) with length n and
 	 return bin k for which arr[k]<=val<arr[k+1] **/


/**  search for value "val" in array "arr" (sorted ASCENDING!) with length n and
 	 return bin k for which arr[k]<=val<arr[k+1] **/


/**  FLOAT search for value "val" in array "arr" (sorted DESCENDING!) with length n and
 	 return bin k for which arr[k]<=val<arr[k+1] **/


/**  search for value "val" in array "arr" (sorted DESCENDING!) with length n and
 	 return bin k for which arr[k]<=val<arr[k+1] **/


/** test if it is a relxill flavour model **/


/** trapez integration around a single bin
 *  caveat: only returns half of the full 2*PI*r*dr due to computational speed
 *  radius is descending **/


/** check if we are currently debugging the model **/


/** check if we should return the relline/relconv physical norm from ENV **/


/* A simple implementation of the FFT taken from http://paulbourke.net/miscellaneous/dft/
   (uses the Radix-2 Cooley-Tukey algorithm)

   This computes an in-place complex-to-complex FFT
   x and y are the real and imaginary arrays of 2^m points.
   dir =  1 gives forward transform
   dir = -1 gives reverse transform
*/


/** rebin spectrum to a given energy grid
 *  length of ener is num_flux_bins+1       **/


// for x0 descending and xn ascending, calculate the mean at xn


// for x0 and xn ascending, calculate the mean at xn  (x0 has n0+1 bins and xn has nn+1 bins)


/* Function: calculate the sum of an array
 *
 */


/*
 * ener has n_array+1 bins
 */


/*     Multi-Color Disk SPECTRUM */
/*     SEE MITSUDA ET AL. 1984 PASJ 36, 741. */
/*     & MAKISHIMA ET AL. APJ 308, 635 1986) */
/*     NORMALIZATION={RIN(KM)/(D/10KPC)}^2*COS(THETA) */
/*     TIN=     INNER TEMPERATURE OF THE DISK */
/*     E  =     ENERGY */
/*     Rin2 = Normalization factor in the unit of above normalization. */
/*     PHOTON = PHOTONS/S/KEV/CM2 */


/* create a new LP table structure*/


/** get a new and empty rel table (structure will be allocated)  */


/** load one single data extension from the relline table   */


/** load the complete relline table */


/* destroy the LP table structure */


// convert the index from the (actual) xillver FITS table parameter
// extension to out (strange!) universal parameter index which can
// handle 5dim and 6dim tables


/* cheap man's version of a 6dim interpolation */


/**
 * @brief check boundary of the Ecut parameter and set ipol_factor accordingly
 * @detail grav. redshift can lead to the code asking for an Ecut not tabulated,
 * although actually observed ecut is larger. We set it to the lowest/highest value in this case
 * @param: (input) tab
 * @param: (input) param
 * @param: (output) ipol_fac
 **/


// empty the cache


/*
 |   NAME: dtdz
 |
 |   ARGS: z     Redshift
 |
 |   RETS: dtdz at that redshift (as a POSITIVE NUMBER)
 |
 |   DESC: dt / dz (z)
 |
 */


/*
 |   NAME: Hubble
 |
 |   ARGS: z     Redshift
 |
 |   RETS: Hubble parameter at that redshift (in 1/s)
 |
 |   Try speaking the function declaration three times fast.
 |
 */


/*
    This returns the Hubble length today over the Hubble length at z.  The
    reason is that the formulae given by ZS do dimensionless scattering
    probabilities per today's Hubble length.  If one wishes to get the corres-
    ponding value for far in the past, multiply by the output of this function.
*/


/*
    The dimensionless scattering probability for photoionization from neutral
    gas at photon energies E > 250 eV.  See ZS equation 3.3.  If the energy
    falls below this range, the function returns zero.
*/


/*
    Compton scattering by cold matter.
    See ZS equation 4.1a
*/


/*
    Photon-photon scattering
    ZS equation 6.1
*/


/* This function finds tau_eff / dt

DHW: i commented this out because you can just add optical depths.
     also, od_dlnEdl_Compton() does not return an optical depth, but an
     energy loss.

double od_dtau_eff(double z, double eV)
{

    double dtau1,
         dtau;

    Find the dominant process and use this for the optical depth.
    There may be a less clumsy way of doing this

    dtau1 = od_dtdl_photion(z,eV);

    dtau1 = max(dtau1, od_dlnEdl_Compton(z,eV));

    dtau1 = max(dtau1, od_dtdl_pp_atom(z,eV));

    dtau1 = max(dtau1, od_dtdl_pp_ions(z,eV));

    dtau1 = max(dtau1, od_dtdl_2photon(z,eV));

    Return dtau/dt, units are s^-1
    dtau = dtau1 * TODAY_H0;

    return dtau;

} */


/**
 * 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 inter_mode Input: interpolation mode (normal or growing_closeby)
 * @param last_index Input/Output: index of the previous/current point in the interpolation array (input only for closeby mode, output for both)
 * @param pvecback   Input: vector of background quantities (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
 */


/**
 * 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
 */


/**
 * This function is used by the energy injection module for two different interpolations:
 * Either to directly interpolate the f(z) functions per channels or to interpolate
 * the chi(x_e) functions  per channels when the factorisation approximation is assumed.
 *
 * @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
 */


// /****************MODIF Vivian Poulin 2 : Add f_eff function****************/


/**********************************************************************************************/
/******************************Energy Injection DM annihilation**********************************/


/******************************Energy Injection DM decay**********************************/


/******************************Energy Injection low mass PBH (evaporation)**********************************/


/******************************Energy Injection high mass PBH (accretion)**********************************/


/*************************New version, improved by Vivian Poulin******************************/


/**
 * In case of non-minimal cosmology, this function determines the
 * effective energy rate absorbed by the IGM at a given redshift
 * (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 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 quantities (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 quantities (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 CosmoRec.
 *
 * Integrate thermodynamics with CosmoRec, 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().
 *
 *************************************************************************************************
 *                 CosmoRec: Cosmological Recombination Project
 *                Written by Jens Chluba (University of Manchester)
 *************************************************************************************************
 * @param ppr      Input: pointer to precision structure
 * @param pba      Input: pointer to background structure
 * @param pth      Input: pointer to thermodynamics structure
 * @param preco    Output: pointer to recombination structure
 * @param pvecback Input: pointer to an allocated (but empty) vector of background variables
 */


/**
 * 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    Output: 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    Output: 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
 */


/**
 * Single place where the fluid equation of state is
 * defined. Parameters of the function are passed through the
 * background structure. Generalisation to arbitrary functions should
 * be simple.
 *
 * @param pba            Input: pointer to background structure
 * @param a              Input: current value of scale factor
 * @param w_fld          Output: equation of state parameter w_fld(a)
 * @param dw_over_da_fld Output: function dw_fld/da
 * @param integral_fld   Output: function \f$ \int_{a}^{a_0} da 3(1+w_{fld})/a \f$
 * @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
 */


/**
 * Use this routine to extract initial parameters from files 'xxx.ini'
 * and/or 'xxx.pre'. They can be the arguments of the main() routine.
 *
 * If class is embedded into another code, you will probably prefer to
 * call directly input_init() in order to pass input parameters
 * through a 'file_content' structure.
 */


/**
 * 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 ptr Input: pointer to transfer structure
 * @param ppm Input: pointer to primordial structure
 * @param psp Input: pointer to spectra structure
 * @param pnl Input: pointer to nonlinear structure
 * @param ple Input: pointer to lensing structure
 * @param pop Input: pointer to output structure
 * @return the error status
 */


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


//====================================================================================
// Xe & X1s
//====================================================================================


/* Hyrec Hubble expansion rate.
   Note: neutrinos are assumed to be massless. */


/*****************************************************************************************
Matter temperature -- 1st order steady state, from Hirata 2008.
The input and output temperatures are in KELVIN.
Added December 2014: possibility for additional energy deposition dEdtdV in eV/s/cm^3.
******************************************************************************************/


/******************************************************************************************
Matter temperature evolution derivative. Input and output temperatures are in KELVIN.
Added May 2012: when Tm = Tr, return -Tr (needed by CLASS)
Corrected June 2016: in the presence of heating, Tm can cross Tr, so added a criterion
for returning -Tr when quasi-steady state. Note: this is not very "clean", there should
be some flag for quasi-steady-state, will eventually fix.
Added December 2014: possibility of additional energy deposition dEdtdV in eV/s/cm^3.
******************************************************************************************/


/************************************************************************
Explicit integrator.
Inputs: deriv: derivative at current time step
        deriv_prev: derivatives at two previous timesteps
        (deriv_prev[0] = previous time, deriv_prev[1] = 2 timesteps ago)
Output: change in x per dt
*************************************************************************/


/**********************************************************************************************
Second-order explicit integrator for HeII abundance during HeII->HeI recombination.
Assumes hydrogen ionization is in Saha equilibrium (free electrons being provided by both H and He).
If xHeII is close enough to Saha equilibrium do a post-Saha expansion.
dxHeIIdlna_prev[0] = derivative at previous timestep
dxHeIIdlna_prev[1] = derivative 2 timesteps prior
z = input z
H = Hubble parameter(z)
***********************************************************************************************/


/***************************************************************************************************
Quasi-equilibrium solution for the hydrogen neutral density at z
Used at early stages when the system is stiff. After that switch to explicit second-order solver.
input:  xH1 at previous time step
output: xH1 at z.
iz_rad is the index for the radiation field at z
***************************************************************************************************/


/*********************************************************************************************************
Second-order integrator (unless stiff system) to evolve hydrogen only, assuming helium has entirely recombined.
Tm is given as an input (to avoid computing it twice) and fixed to quasi-equilibrium value with Tr.
Input : xe [at z_in]
Output: xe [at next timestep]
**********************************************************************************************************/


/**********************************************************************************************
Second-order integrator for evolving xe and Tm simultaneously
Used for Hydrogen recombination only
May 2012: added a switch so Peebles model can be used at low redshift.
September 2016: added dEdtdV_dep, the *deposited* energy
(as opposed to dE_dtdV which is the instantaenously injected energy)
***********************************************************************************************/


/****************************************************************************************************
Builds a recombination history with a given model
(model = PEEBLES, RECFAST, EMLA2s2p or FULL)
Added May 2012: The radiation field was added as an input so it can be extracted if desired
Replaced condition iz < param->nz by equivalent z >= 0 (so param.nz not needed anymore)
Added September 2016: follow the deposited energy dEdtdV_dep
****************************************************************************************************/


/***********************************************************
Function to allocate and initialize HyRec internal tables
***********************************************************/


/******************************************************************
Compute a recombination history given input cosmological parameters
********************************************************************/


/*****
     Once HYREC_DATA outputs are computed, obtain xe(z) and Tm(z) by interpolation
*****/


/**************************************************************************************************
Effective three-level atom model with adjustable fudge factor.
Fudge = 1 is Peebles' model. Fudge = 1.14 is similar to RecFast (Seager et al. 1999, 2000).
Changes (May 2012):
- Correction: detailed balance implies that the photoionization rate is proportional to alpha_B(Tr) rather than alpha_B(Tm)
- Analytically subtract nearly-cancelling terms at high-z
- Explicit dependence on alpha_fs and m_e now accounted for
- Added explicit dependence on xHII, which is not necessarily equal to xe if Helium has not entirely recombined
December 2014:
- Added additional ionization and excitations due to additional energy injection.
  dEdtdV is the rate of energy deposition rate per unit volume (in eV/s/cm^3)
***************************************************************************************************/


/**********************************************************************************************
Allocates memory for the structure HYREC_ATOMIC, and reads and stores
effective-few-level rates and two-photon rates.
This function is a merger of two previous functions for effective rates and two-photon rates.
**********************************************************************************************/


/************************************************************************************************
Interpolation of tabulated effective rates
To be (slightly) more efficient, not using the external interpolation routine.
Gets the correct rates for given fine-structure constant and electron mass.
- Modified May 2012:   - Accounts for different alpha_fs and m_e
                       - Also returns DAlpha[2], table of ALpha(Tm, Tr) - ALpha(Tr, Tr)
INPUT TEMPERATURE ASSUMED TO BE ALREADY RESCALED FOR VALUES OF alpha_fs and me
- Modified December 2014: additional heating sometimes brings Tm slightly larger than Tr.
  If this is the case, use Tm = Tr in the recombination rates.
  Will eventually re-tabulate the effective rates for Tm/Tr > 1 to fix this.
************************************************************************************************/


/************************************************************************************************
Solves for the populations of the 2s and 2p states in steady-state, and returns dxe/dlna.
Uses standard rate for 2s-->1s decay and Sobolev for Lyman alpha (no feedback),
and fully accounts for virtually all transitions among excited states through effective rates.
Inputs: xe, nH in cm^{-3}, H in s^{-1}, TM, TR in eV. Output: dxe/dlna
Changes May 2012:
- Now use the analytic expressions using the generalized Peebles' C factors
[see companion paper, Eqs. (43)-(46)].
- Also explicitly subtract nearly cancelling terms at early times.
- Account for explicit dependence on alpha_fs and m_e
- Added explicit dependence on xHII, which is not necessarily equal to xe if Helium has not entirely recombined
December 2014:
- Added dependence on extra energy deposited in the plasma, dEdtdV in eV/s/cm^3
************************************************************************************************/


/*********************************************************************************************************
 Populate the real-real, real-virtual, virtual-real and virtual-virtual T-matrices,
 as well as the source vectors sr, sv, given Dxe = xe - xe[Saha] as an input.
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

Modified May 2012: - now uses the photon distortion
instead of absolute photon occupation number.
- Accounts for explicit dependence on alpha_fs and m_e
INPUT TEMPERATURE ASSUMED TO BE ALREADY RESCALED FOR VALUES OF alpha_fs and me
- Added explicit dependence on xHII, which is not necessarily equal to xe if Helium has not entirely recombined

December 2014: Added dependence on additional energy deposition dEdtdV in eV/s/cm^3.
**********************************************************************************************************/


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


/*********************************************************************************************
Interpolation of the photon distortion used to get f+ from f- at a higher frequency bin and earlier time.
Use a simple linear interpolation so the spectrum is always positive.
Added May 2012
*********************************************************************************************/


/*************************************************************************************************************
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
Dfminus_hist is a NVIRT by nz array of previous Delta f(nu_b - epsilon)(z)
Dfminus_Ly_hist is a 3 by nz array of previous Deltaf(nu - epsilon) redward of Ly alpha, beta and gamma lines

Changed May 2012: Now using the interpolation function interp_Dfnu, which only interpolates
                    over 2 nearest neighbors, which ensures that the distortion is always positive
*************************************************************************************************************/


/******************************************************************************************************************
dxe/dlna when including two-photon processes.
Assume fminus[0..iz-1] is known. Update fminus[iz]

Modified May 2012:
- now use the photon distortion instead of absolute photon occupation number
- Accounts for explicit dependence on alpha_fs and m_e
- Added Dfnu_hist as a variable. Will contain the *average* distortion within each bin

December 2014: added dependence on additional energy injection dEdtdV in eV/s/cm^3.
The fractions that goes into ionizations, excitations and heat are assumed to be those of Chen & Kamionkowski 2004.
In the next version I'll make them potentialy changeable.
******************************************************************************************************************/


/**************************************************************************************
Allocate and free memory for the structure RADIATION
***************************************************************************************/


/*****************************************************************************************
Single function that handles all cases depending on the switch.
December 2014: added dependence on additional energy injection.
******************************************************************************************/


/* Spin temperature minus Tcmb */


/***************************************************************************************
Total volumic rate of energy *injection*, in eV/cm^3/s due to DM annihilation
in the smooth background and in haloes as in Giesen et al 1209.0247
****************************************************************************************/


/* Dimensionless Compton drag rate */


/* Dimensionless accretion rate */


/* Accretion rate (in g/s), accounting for Compton drag and Compton cooling.*/
/* This is assuming Omega_b h^2 = 0.022 (sufficient at the level of accuracy we need) */


/* Temperature of the flow near the Shchwarzschild radius divided by m_e c^2 */
/** Changed 01/26/2017: added a parameter "coll_ion":
    if set to 1, assume collisional ionizations
    if set to 0, assume photoionizations.
**/


/* Radiative efficiency divided by \dot{m} */


/* Luminosity of a single PBH in erg/s*/


/* Average of the relative velocity over the distribution of relative velocities */


/* Average of the pbh luminosity (erg/s) over the distribution of relative velocities */


/* Rate of energy *injection* per unit volume (in eV/cm^3/s) due to PBHs */
/* Taking Omega_c h^2 = 0.12                                             */


// double dEdtdV_stars(double z, INJ_PARAMS *params){
//   double ainv = 1+z;
//   double rho_sfr =params->ap*pow(ainv,params->bp)/(1+pow((ainv)/params->cp,params->dp))*ainv*ainv*ainv*(1+tanh((params->z_start_reio_stars-z1)))/2;//Comoving to physical
//   double dNion_over_dt;
//   double joules_to_ev = 6.24150647996e+18;
//   double MPCcube_to_mcube=pow(3.085677581282e22,3);
//   double stars_xe;
//   dNion_over_dt = params->f_esc*params->Zeta_ion*rho_sfr;
//   double L_x = param->Ex  * param->fx* 2*rho_sfr/(3*MPCcube_to_mcube*kBoltz*nH*H*(1.+xe_in+param->fHe));
//   return dNion_over_dt/(MPCcube_to_mcube);
//
// }
/***********************************************************************************
Total energy *injection* rate per unit volume
Add in your favorite energy injection mechanism here
***********************************************************************************/


/**********************************************************************************
Energy *deposition* rate per unit volume
Essentially use a very simple ODE solution
**********************************************************************************/


/*******************************************************************************
Fraction of energy deposited in the form of heat, ionization and excitations
*******************************************************************************/


/***********************************************************************************************************/
/***********************Return values for the annihilation coefficients after interpolation*****************/
//
//


/************************************************************************************************
Gets xe in He II + III equilibrium
*************************************************************************************************/


/***************************************************************************************************
Gets xHeII (NOT xe) in Saha equilibrium, hydrogen assumed fully ionized.
****************************************************************************************************/


/*******************************************************************************************
Gets xH1s for Saha equilibrium HII + e <-> H(1s) + gamma, where xe = xHII + xHeII
(in case Helium has not full recombined). Added May 2012.
*******************************************************************************************/


/*************************************************************************************
 He II->I recombination rate evolution equation.
 Incorporates 2(1)P-->1(1)S escape, with H continuum opacity
              2(1)S-->1(1)S 2 photon decay
              2(3)P-->1(1)S Sobolev
 Assumes Compton temperature equilibrium, no Thomson opacity.
 Added May 2012: Explicit dependence on xH1s, which may differ from its Saha equilibrium
value if hydrogen has already started to recombine (if H and He recombinations overlap).
**************************************************************************************/


/**************************************************************************
Creates a [n1] array.
***************************************************************************/


/************************************************************************************
 Interpolation routine for 1-D table.  Uses cubic interpolation assuming
 uniformly spaced x-values, x0 ... x0+(Nx-1)*dx.
The table is assumed to have dimension Nx >= 4
*************************************************************************************/


/********************************************************************************
Cubic interpolation for non-regular grid
*******************************************************************************/


/*initializes the lookup table for the beta paremeter in MHR00 model*/


/* returns the "effective Jeans mass" in Msun
   corresponding to the gas analog of WDM ; eq. 10 in Barkana+ 2001 */


/* converts a linear overdensity, del, at z=0 to a non-linear overdensity at redshift z */


/*
  JBM:
  this function reads the z=0 matter (CDM+baryons) transfer function from CLASS
	flag = 0 to initialize interpolator, flag = -1 to free memory, flag = else to interpolate.
	similar to built-in function "double T_RECFAST(float z, int flag)"
*/


/*
  JBM:
  this function reads the z=zkin relative velocity transfer function from CLASS
  same caveats as for Tfm_CLASS
*/


/*
  FUNCTION sigma_z0(M)
  Returns the standard deviation of the normalized, density excess (delta(x)) field,
  smoothed on the comoving scale of M (see filter definitions for M<->R conversion).
  The sigma is evaluated at z=0, with the time evolution contained in the dicke(z) factor,
  i.e. sigma(M,z) = sigma_z0(m) * dicke(z)

  normalized so that sigma_z0(M->8/h Mpc) = SIGMA8 in ../Parameter_files/COSMOLOGY.H

  NOTE: volume is normalized to = 1, so this is equvalent to the mass standard deviation

  M is in solar masses

  References: Padmanabhan, pg. 210, eq. 5.107
*/


/*
  Returns the value of the linear power spectrum DENSITY (i.e. <|delta_k|^2>/V)
  at a given k mode linearly extrapolated to z=0
*/


/*
  JBM: Returns the value of the linear power spectrum of the DM-b relative velocity
  at kinematic decoupling (which we set at zkin=1010)
*/


/*
  FUNCTION dsigmasqdm_z0(M)
  returns  d/dm (sigma^2) (see function sigma), in units of Msun^-1
*/


/*
  FUNCTION TFmdm is the power spectrum transfer function from Eisenstein & Hu ApJ, 1999, 511, 5
*/


/*
  Function FILTER filters the k-space box, <box>, using filter type
  <filter_type> on a characteristic comoving scale <R> (in Mpc), where:
  0 = top-hat real space filter
  1 = top-hat k-space filter
  2 = gaussian

  Relavant box parameters are taken from INIT_PARAMS.H

  The function returns the filtered k field, <box>.
*/


//JBM: also to smooth the HII_DIM boxes from the output:
//NB: identical to void HII_filter, which is not here but in bubbles.c ....


//JBM:anisotropic version of the power spectrum


//JBM: output velocity power spectrum, just a diagnostic
//note that it's P(v) and not P(v^2).


/**** Arrays declared and used *****/


/********************************************************************
 ************************** IGM Evolution ***************************
  This function creates the d/dz' integrands
*********************************************************************/


/* Interpolate exact results for kappa_10^eH.  The table goes up to
 * 10^5 K, but values are only accurate for T<2x10^4 K.  From
 * Furlanetto & Furlanetto 2006 */


/* Interpolate exact results for kappa_10^pH.  The table goes up to
 * 10^5 K, but values are only accurate for T<2x10^4 K.  From
 * Furlanetto & Furlanetto 2006 */


//This is from bison


//1: Overlaps
//0: No Overlap
//-1: End of BED file
//This should eventually be modified to use a hash


//-1 if region is before pos (need to go to the next region)
// 0 if pos not in region
//>0 if pos in region


//Return 1 on overlap, otherwise 0


//Returns a NULL pointer on error, which should cause the program to exit
//N.B., If column 4 exists it can't contain a space (quotes won't help)
//It might make sense to just use a regex


// The opposite strand of a C should be a G. Ns are ignored


//Agresti-Coull confidence interval around a methylation value
//If which is 1, return the upper 99.9% CI, otherwise the return the lower 99.9% CI


//"which" denotes where the methylation metrics came from:
// bit 0: CpG
// bit 1: CHG
// bit 2: CHH


//Convert bases outside of the bounds to N and their phred scores to 0


//This will need to be restructured to handle multiple input files


//Ensure that CpGs and CHGs are never split between threads. Move end positions to the right


/* Code to convert NEAT pointing logs,  as found at

https://sbnarchive.psi.edu/pds4/surveys/gbo.ast.neat.survey/data_tricam/tricam_archive_masterlist.tab
https://sbnarchive.psi.edu/pds4/surveys/gbo.ast.neat.survey/data_geodss/geodss_archive_masterlist.tab
https://sbnarchive.psi.edu/pds3/neat/tricam2/data/tricam_archive_masterlist_delivery2.tab

into the .csv-formatted type of pointing log CSS uses and which Find_Orb
can use for precovery searches,  and which list_gps can use to determine where
you may have found navigation satellites.  This is similar to 'sw_xvt.c'
and 'sw_xvt2.c' (q.v.,  should be distributed with this source),  which do
the same conversion for pre-2016 and post-2016 Spacewatch pointing logs.
And there will probably be other pointing log converters to come.

Compile with

gcc -Wall -O3 -o neat_xvt neat_xvt.c -lm

NOTE that dark images have RA = 99 99 99.999,  and that some images have RAs
slightly past 24 hours/360 degrees.  Which is why we allow RAs of 24 hours
and do an fmod( ) on the RA to put it in the 0 to 360 range.

ALSO NOTE that some files have extension ',fit' and others '.fit'.  I think
the former is an error.

The times in NEAT logs are for the _start_ of the image,  so we have to
add half the exposure time to get the mid-point of the exposure.  Lucky
us,  Haleakala and Palomar are in daylight at 0:00:00 UTC.   */


/* The Spacewatch logs give the time for the start of the exposure,  and
we really want the midpoint time.  Fortunately,  Spacewatch never observes
near 00:00:00 UTC,  so we can just add half the exposure time and leave the
day/month/year ignored. */


/* Initialize data structure */


/* Compute the infall velocities statistics related to full dataset,
 * starting from those already calculated for the single blocks
 */


/* Write to file the results for the whole dataset
 */


/* Read in the pre-computed files containing the linear infall velocities
 * of each block
 */


/* Free the memory associated to the structure */


/**
 * All default parameter values (for input parameters)
 */


/* Initialise params structure.  Basically, fill the structure using
 * the arguments passed to the function, create the separation binning
 * arrays, and build the filenames of the various blocks
 */


/* Free the structure */


/* Initialise block structure */


/* Calculate statistics considering all pairs of galaxies */


/* Compute the pairwise velocity statistics for isolated galaxy pairs.
 * The degree of isolation is controlled by 'params->r_isolation' and
 * 'params->n_neighbours_max'.
 */


/* Read in the file associated to a block.
 * Here we allocate and fill the arrays block->xx, block->yy, block->zz,
 * block->vxx, block->vyy, block->vzz.
 * We also assign a value to block->n_gals.
 */


/* Save the statistic associated to a block to its output file */


/* Determine the number of neighbours for each galaxy in a sphere of radius
 * 'r_isolation' centred on the galaxy.
 * In the worst case (big 'r_isolation' and unlimited 'n_neighbours_max'),
 * this is a n_gals^2 algorithm.  However, for reasonable values of the
 * parameters, it is much faster.  This is possible because the galaxies
 * are sorted according to their 'x' component.
 */


/* Free temporary arrays, i.e. all those that we do not want to keep
 * after we finished processing the block.
 */


/* Calculate pairwise velocity statistics considering only isolated pairs of galaxies.
 * The results obtained with this function should be equal to those obtained with
 * 'data_block_vinfall_stat_with_isolation' when params->n_neighbours_max=1.
 * The difference is that here we use a different algorithm, useful for testing purposes.
 * The speed of the two algorithms is more or less the same.
 */


/// =====================================
/// = Function to read and split a file =
/// =====================================


/// =================
/// = Sorting array =
/// =================
// Sort an array according to an array of integers.


/// =============
/// = lin_space =
/// =============
// Return an array with linearly spaced points


/// =============
/// = log_space =
/// =============
// Return an array with logarithmically spaced points.


/**
     * @brief  Get the value of current parameter
     * @note   This function will take care of updating value if necessary
     * @retval current updated value of the parameter
     */


/**
     * @brief  Get the amplitude integrated over final state phase space
     * @note   Inside this function, the internal parameters will be updated first
     * @param  sqrt_shat: the process energy
     * @retval Return the amplitude integrated over final state phase space
     */


/*
  Right-hand side function of the ODE system.
*/


/*
  Solve the ODE system
 */


/**
 * Close the solver
 */


/**
 *  Allocate the abundance vector
 */


/**
 * Free the abundances
 */


/*
  Allocate the network structure. We get the number of reactions from
  the number of lines in the network file. For the number of species,
  we assume a number equal to the number of reactions divided by 10,
  and we reallocate the array if needed.
*/


/*
  Add a species in the network
*/


/*
   Look up the index of a given species in the species array.
*/


/*
  Allocate the network structure.
*/


/*
  Reallocate species array, without overwriting existing species
*/


/*
  Free the network structure.
*/


/*
  Read the input file containing the parameters needed by the code:
  name of the chemistry network and source file names, physical
  parameters, solver parameters, and initial abundances.
*/


/*
  Read the file containing the source model.
*/


/*
  Allocate the structure containing the input parameters
*/


/*
   Free the input structure.
 */


/*
  Allocate the structure containing the source model
*/


/*
   Free the source model structure
*/


/*
  Read the source model and network filenames from an input file
*/


/*
   Display help message.
   */