/******************************************************************************
 *                                                                            *
 * DECS.H                                                                     *
 *                                                                            *
 * GLOBAL MACROS, FUNCTION DEFINITIONS, INCLUDES, AND DECLARATIONS            *
 *                                                                            *
 ******************************************************************************/

#include <gsl/gsl_eigen.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_sf_bessel.h>
#include <gsl/gsl_vector.h>
#include <limits.h>
#include <math.h>
#include <mpi.h>
#include <omp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "constants.h"
#include "params.h"

/*******************************************************************************
      PRE-PROCESSOR MAGIC :
*******************************************************************************/
#define XSTR(x) STR(x)
#define STR(x) #x

/*******************************************************************************
      CONSTANTS :
*******************************************************************************/

#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923132169164
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.4142135623730950488016887242
#endif

/*******************************************************************************
      COMPILE-TIME PARAMETERS :
*******************************************************************************/

// Number of active zones on each MPI process
#define N1 (N1TOT / N1CPU)
#define N2 (N2TOT / N2CPU)
#define N3 (N3TOT / N3CPU)

// Max size for 1D slice is NMAX
#define N12 (N1 > N2 ? N1 : N2)
#define NMAX (N12 > N3 ? N12 : N3)

#define NDIM (4) // Number of total dimensions
#define NPG (5)  // Number of positions on grid for grid functions
#define NG (3)   // Number of ghost zones
#define N123G                      \
  ((N1 + 2 * NG) * (N2 + 2 * NG) * \
      (N3 + 2 * NG)) // total number of cells on a cpu

// Fixup parameters
// rho_flor = RHOMIN / pow(r, -FLOOR_POWER)
#define FLR_POWER1 (2.)
#define FLR_POWER2 (2.)
#define FLR_R0 (50.) // TODO change this?
#define RHOMINLIMIT (1.e-17)
#define UUMINLIMIT (1.e-3 * RHOMINLIMIT)
#define RHOMIN (1.e-5)
#define UUMIN (1.e-3 * RHOMIN)
#define BSQORHOMAX (50.)
#define BSQOUMAX (2500.)
#define RHOEPS (0.9)
#define UORHOMAX (50.)
#define COLD_FLOORS (1)
#define ATM_THRESH (0.1)

// Numerical convenience to represent a small (<< 1) non-zero quantity
#define SMALL (1.e-20)
#define ABSURDLY_LARGE (1.e100)

// Maximum value of gamma, the Lorentz factor
#define GAMMAMAX (50.)

// Maximum fractional increase in timestep per timestep
#define SAFE (1.3)

// Superphoton diagnostics
#define MAXNSCATT (3)

// Chosen to give some wiggle room
// in scattering stability criterion
#define SCATT_BIAS_SAFETY (0.75) // (0.9/RAD_SCATT_TYPES)

//#define NUMIN     (1.e10)
//#define NUMAX     (1.e25)
//#define NU_BINS_SPEC    (200)
//#define NTH (8)
//#define NPHI (8)

// Whether to move polar axis slightly off of coordinate singularity
#define COORDSINGFIX 1
#define SINGSMALL (1.E-20)

// Whether to record a representative sample of superphoton positions
#define TRACK_PH (0)

// I/O format strings
#define FMT_DBL_OUT "%28.18e"
#define FMT_INT_OUT "%10d"
#define STRLEN (2048)

// Reconstruction algorithms
#define LINEAR (0)
#define PPM (1)
#define WENO (2)
#define MP5 (3)

// Primitive and conserved variables
#define RHO (0)
#define UU (1)
#define U1 (2)
#define U2 (3)
#define U3 (4)
#define B1 (5)
#define B2 (6)
#define B3 (7)
#define NVAR_BASE (B3 + 1)

// Passive variables (if present)
#define PASSIVE_START (NVAR_BASE)
#define PASSIVE_STOP (NVAR_BASE + NVAR_PASSIVE)
#define PASSTYPE_INTRINSIC (0)
#define PASSTYPE_NUMBER (1)
#if EOS == EOS_TYPE_TABLE
#define YE (PASSIVE_START)
#define YE_EM (YE + 1)
#if METRIC == MKS
#define ATM (YE + 2)
#define IS_ATM (0.0)
#define NOT_ATM (1.0)
#endif // METRIC
#endif // EOS_TYPE_TABLE

#if ELECTRONS
#define KEL (B3 + NVAR_PASSIVE + 1)
#define KTOT (B3 + NVAR_PASSIVE + 2)
#define NVAR (NVAR_BASE + NVAR_PASSIVE + 2)
#else
#define NVAR (NVAR_BASE + NVAR_PASSIVE)
#endif

// NETRINOS
#define RATYPE_NONE (0)
#define RADTYPE_LIGHT (1)
#define RADTYPE_NEUTRINOS (2)
#define RAD_TYPE_START (0)
#define TYPE_TRACER (-1)
#if RADIATION == RADTYPE_NEUTRINOS
#define RAD_NUM_TYPES (3)
#define NU_ELECTRON (0)
#define ANTINU_ELECTRON (1)
#define NU_HEAVY (2)
#if MULTISCATT_TEST
#define RAD_SCATT_TYPES (3)
#else
#define RAD_SCATT_TYPES (4) // TODO: Should be 5, including electrons
#define RSCATT_TYPE_P (0)
#define RSCATT_TYPE_N (1)
#define RSCATT_TYPE_A (2)
#define RSCATT_TYPE_ALPHA (3)
#define RSCATT_TYPE_E (4) // TOOD: implement me
#endif
#define NRADCOMP (2)
#define RADG_YE (4)
#define RADG_YE_EM (5)
#elif RADIATION == RADTYPE_LIGHT
#define RAD_NUM_TYPES (1)
#define RAD_SCATT_TYPES (1)
#define NRADCOMP (0)
#define PHOTON (0)
#else
#define RAD_NUM_TYPES (0)
#define RAD_SCATT_TYPES (0)
#define NRADCOMP (0)
#endif
#define DLEPTON_THRESH (1e-10)

// EOS
#define EOS_TYPE_GAMMA (0)
#define EOS_TYPE_POLYTROPE (1)
#define EOS_TYPE_TABLE (2)
#if EOS == EOS_TYPE_GAMMA
#define EOS_NUM_EXTRA (0)
#define POLYTROPE_FALLBACK (0)
#elif EPS == EOS_TYPE_POLYTROPE
#define EOS_NUM_EXTRA (0)
#define POLYTROPE_FALLBACK (0)
#elif EOS == EOS_TYPE_TABLE
#if GAMMA_FALLBACK
#define POLYTROPE_FALLBACK (0)
// #define POLYTROPE_FALLBACK (1)
#else
#define POLYTROPE_FALLBACK (1)
#endif // GAMMA_FALLBACK
#define EOS_NUM_EXTRA (3)
#define EOS_LRHO (0)
#define EOS_LT (1)
#define EOS_YE (2)
// mass fractions
#define NUM_MASS_FRACTIONS (4)
#define MF_XA (0)
#define MF_XH (1)
#define MF_XN (2)
#define MF_XP (3)
#endif // EOS

// Centering of grid functions
#define FACE1 (0)
#define FACE2 (1)
#define FACE3 (2)
#define CORN (3)
#define CENT (4)
#define FACESTART (FACE1)
#define FACEEND (FACE3 + 1)
#define PGSTART (FACE1)
#define PGEND (NPG)

// Slope limiter
#define MC (0)
#define VANL (1)
#define MINM (2)

// Fluid and radiation boundaries
#define BC_OUTFLOW (0)
#define BC_PERIODIC (1)
#define BC_POLAR (2)
#define BC_PROB (3)
#define BC_ESCAPE (4)
#define BC_CAMERA (5)
#define BC_EQUILIB (6)

// Metric
#define MINKOWSKI (0)
#define SPHERICAL (1)
#define MKS (2)

// Diagnostic calls
#define DIAG_INIT (0)
#define DIAG_DUMP (1)
#define DIAG_LOG (2)
#define DIAG_FINAL (3)

// Types of restarts
#define RESTART_TEMP (0)
#define RESTART_PERM (1)

// Failure modes
#define FAIL_UTOPRIM (0)
#define FAIL_VCHAR_DISCR (1)
#define FAIL_COEFF_NEG (2)
#define FAIL_COEFF_SUP (3)
#define FAIL_GAMMA (4)
#define FAIL_METRIC (5)

// Geodesic integration and interpolation
#define PUSH_FAIL (0)
#define PUSH_SUCCESS (1)
#define SPH_INTERP_FAIL (0)
#define SPH_INTERP_SUCCESS (1)

// Root finding
#define ROOT_SUCCESS (1)
#define ROOT_FAIL (0)
#define FCOUNT_NBINS (6)
#define FCOUNT_MORE (FCOUNT_NBINS - 1)

// Timers
#define TIMER_UPDATE (0)
#define TIMER_FLUXCALC (1)
#define TIMER_FIXUP (2)
#define TIMER_BOUND (3)
#define TIMER_DIAG (4)
#define TIMER_OUT (5)
#define TIMER_ELECTRON (6)
#define TIMER_MAKE (7)
#define TIMER_PUSH (8)
#define TIMER_INTERACT (9)
#define TIMER_MICRO (10)
#define TIMER_ALL (11)
#define NUM_TIMERS (12)

// Units
#define NEED_UNITS (RADIATION || EOS == EOS_TYPE_TABLE)

/*******************************************************************************
    GLOBAL ARRAYS
*******************************************************************************/
typedef double grid_prim_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG][NVAR];
typedef double grid_double_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG];
typedef double grid_radtype_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG]
                                [RAD_NUM_TYPES];
typedef double grid_fourvector_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG]
                                   [NDIM];
typedef double grid_radg_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG]
                             [NDIM + NRADCOMP];
typedef double grid_tensor_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG][NDIM]
                               [NDIM];
typedef int    grid_int_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG];
typedef double grid_eosvar_type[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG]
                               [EOS_NUM_EXTRA];
typedef void (*passive_init_ftype)(int, int, int, double *, double *);
typedef double (*hc_ftype)(double, double);

extern grid_prim_type       P;     // Primitive variables
extern grid_prim_type       F1;    // X1 fluxes
extern grid_prim_type       F2;    // X2 fluxes
extern grid_prim_type       F3;    // X3 fluxes
extern grid_prim_type       Ph;    // Half-step primitives
extern grid_prim_type       Psave; // Half-step primitives
extern grid_int_type        pflag; // Failure points
extern grid_int_type        fail_save;
extern grid_int_type        fixup_required;
extern grid_fourvector_type jcon;
extern grid_eosvar_type     extra; // extra variables needed by EOS
#if RADIATION
extern grid_radg_type   radG;     // Radiation four-force
extern grid_radg_type   radG_int; // ...integrated
extern grid_radg_type   radG_buf; // ...buffer for communication
extern grid_tensor_type Rmunu;    // Radiation stress-energy tensor
extern grid_int_type    Nsph;
extern grid_double_type nph;

extern struct of_photon **photon_lists;
extern struct of_photon **photon_mpi_lists;

#if DIAGNOSTICS_USE_RADTYPES
#define NULNU_IDX0 (RAD_NUM_TYPES)
#else
#define NULNU_IDX0 (MAXNSCATT + 1)
#endif
extern double nuLnu[NULNU_IDX0][NTH][NPHI][NU_BINS_SPEC];

#if RADIATION == RADTYPE_NEUTRINOS
extern double rad_type_counts[RAD_NUM_TYPES];
extern double lepton_tot, lepton_last, dlepton_tot, dlepton_perc;
extern double lepton_gas, lepton_rad;
extern double lepton_lost, lepton_lost_step, lepton_lost_local;
#endif

extern double Jrad[MAXNSCATT + 2][N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG];
extern double Jrad_buf[MAXNSCATT + 2][N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG];
extern double dtau_avg[RAD_SCATT_TYPES + 1][N1 + 2 * NG][N2 + 2 * NG]
                      [N3 + 2 * NG];
extern double en_int_avg[RAD_SCATT_TYPES + 1][N1 + 2 * NG][N2 + 2 * NG]
                        [N3 + 2 * NG];
extern grid_int_type     Nem, Nabs, Nsc;
extern grid_radtype_type Nem_phys, Nabs_phys, radtype_buf;

extern grid_int_type    Nsuper;
extern grid_double_type Esuper;
extern grid_prim_type   psupersave;
#endif // RADIATION

// Default initialization is 0, which in this case is
// PASSTYPE_INTRINSIC, i.e., volume densities.
extern int                passive_type[NVAR_PASSIVE];
extern char               passive_name[NVAR_PASSIVE][STRLEN];
extern passive_init_ftype do_passive_fixup[NVAR_PASSIVE];

#if ELECTRONS
extern grid_double_type Qvisc, Qcoul;
#endif // ELECTRONS

/*******************************************************************************
    GLOBAL VARIABLES SECTION
*******************************************************************************/
// Command line arguments
extern char outputdir[STRLEN], dumpdir[STRLEN], restartdir[STRLEN];
extern char xmfdir[STRLEN];
#if RADIATION && TRACERS
extern char tracerdir[STRLEN];
#endif
extern char init_from_grmhd[STRLEN];
extern char metric[STRLEN], reconstruction[STRLEN];
extern char eos[STRLEN], nulnutype[STRLEN];
extern int  tracers;

// path for eos
#if EOS == EOS_TYPE_TABLE
extern char eospath[STRLEN];
#endif

// opacity table paths
#if RADIATION
#if (RADIATION == RADTYPE_NEUTRINOS)
#if BURROWS_OPACITIES
extern char opac_param_file[STRLEN];
extern char opac_file[STRLEN];
#endif // BURROWS
#if HDF5_OPACITIES
extern char opac_file[STRLEN];
#endif // hdf5
#endif // neutrinos
#endif // radiation

// Physics parameters
extern double a;
#if EOS == EOS_TYPE_GAMMA || GAMMA_FALLBACK
extern double gam;
#endif
#if EOS == EOS_TYPE_POLYTROPE
extern double poly_K, poly_gam;
#endif
#if POLYTROPE_FALLBACK
extern double rho_poly_thresh;
#endif
extern double M_unit;
extern double Reh;
extern double Risco;
#if NEED_UNITS
extern double mbh, Mbh, L_unit, T_unit, M_unit, RHO_unit, U_unit, B_unit;
#endif
#if EOS == EOS_TYPE_TABLE
extern double TEMP_unit;
#endif
#if RADIATION
extern double Ne_unit, Thetae_unit, kphys_to_num;
extern double tp_over_te, thetae_max, sigma_max, kdotk_tol;
#endif

// Numerical parameters
extern double Rin, Rout, Rout_vis, hslope;
extern double poly_norm, poly_xt, poly_alpha, mks_smooth;
#if RADIATION
extern double Rout_rad;
extern double nph_per_proc;
extern double tune_emiss, t_tune_emiss, dt_tune_emiss;
extern double tune_scatt, t_tune_scatt, dt_tune_scatt;
extern int    made_tune_proc, abs_tune_proc, scatt_tune_proc;
extern double numin, numax;
extern double kappa;
extern double startx_rad[NDIM], stopx_rad[NDIM];
extern double wgtC;
extern int    step_made, step_abs, step_scatt, step_lost, step_rec, step_tot;
extern int    tracer_tot, tracer_tot_all, ntcr_per_proc;
extern int    step_sent, step_rcvd, step_fail;
extern int    step_made_all, step_abs_all, step_scatt_all, step_lost_all;
extern int    step_rec_all, step_sent_all, step_rcvd_all, step_tot_all;
extern int    step_fail_all;
extern int    step_tot_max, step_tot_min;
extern double load_imbalance;
extern double Nph_to_track;
extern double sim_vol;
#if FLATEMISS
extern double cnu_flat;
#endif // FLATEMISS
#if MULTISCATT_TEST
extern double ms_theta_nu0, ms_delta0;
#endif // MULTISCATT_TEST
#endif // RADIATION
#if ELECTRONS
extern double tptemin, tptemax;
#endif
extern double cour;
#if RADIATION
extern double cour_cool;
#endif
extern double dV, dx[NDIM], startx[NDIM], stopx[NDIM], startx_proc[NDIM],
    stopx_proc[NDIM];
extern double x1Min, x1Max, x2Min, x2Max, x3Min, x3Max;
extern double dt, dtsave;
extern double t, tf;
extern int    nstep;
extern int    is_restart;

// Output parameters
extern double DTd;
extern double DTl;
extern double DTr;
extern int    DNr;
extern int    DTp;
extern int    DTf;
extern double DTw;
extern int    dump_cnt;
extern int    rdump_cnt;
extern double tdump, trestart, tlog;
extern double root_fcount[FCOUNT_NBINS];

// Global flags
extern int failed;
extern int lim;

// Diagnostics
extern double mdot, mdot_eh;
extern double edot, edot_eh;
extern double ldot, ldot_eh;
extern int    icurr, jcurr, kcurr;

// Parallelism
extern int nthreads;

// Electrons
#if ELECTRONS
extern double game, gamp;
extern double fel0;
#endif

// Set global variables that indicate current local metric, etc.
struct of_geom {
  double gcon[NDIM][NDIM];
  double gcov[NDIM][NDIM];
  double g;
  double alpha;
};

struct of_state {
  double ucon[NDIM];
  double ucov[NDIM];
  double bcon[NDIM];
  double bcov[NDIM];
};

#if RADIATION
// WARNING: if you change struct_of_photon, be sure to change
// the the photon hdf5 and MPI  types in io.c and mpi.c
#define NSUP 3
struct of_photon {
  // NSUP >=3 X^{\mu}, K^{\mu}, K_{\mu} so photon data always available anywhere
  // between n and n+1
  double X[NSUP][NDIM];
  double Kcov[NSUP][NDIM];
  double Kcon[NSUP][NDIM];
  double w;
  double KdotKprev;
  // radiation type. For neutrinos, flavor. Always active.
  // Not always important.
  // TODO: make sure to always set type when it's needed.
  int               type;
  int               nscatt;
  int               origin[NDIM];
  double            t0;
  int               is_tracked;
  struct of_photon *next;
};

#define PH_ELEM (11)
struct of_track_photon {
  double X1;
  double X2;
  double X3;
  int    nscatt;
};
struct of_microphysics {
#if RADIATION == RADTYPE_NEUTRINOS
  double rho;
  double T;
  double Ye;
  double Abar, Zbar;
  double Xi[NUM_MASS_FRACTIONS];
#if BURROWS_OPACITIES || HDF5_OPACITIES
  double jgrp[RAD_NUM_TYPES][NU_BINS + 1];
  double alphagrp[RAD_NUM_TYPES][NU_BINS + 1];
#endif
#else // RADTYPE_LIGHT
  double Thetae;
  double Ne;
#endif
  // needed for Bk-angle (which isn't really needed for neutrinos, but
  // this is the easy engineering solution)
  double B;
};
typedef double (*dsdom_ftype)(
    double, double, const struct of_microphysics *, int, int);
#endif // RADIATION

#if EOS == EOS_TYPE_TABLE
struct of_adiabat {
  double  s, ye;
  double  lrho_min, lrho_max;
  int     imin, imax;
  double  hm1_min, hm1_max;
  double *lT;
};
#endif

#if EOS == EOS_TYPE_TABLE || HDF_OPACITIES || BURROWS_OPACITIES
struct of_tablebounds {
  int    Nrho, NT, NYe;
  double lrho_min, lrho_max, dlrho;
  double lT_min, lT_max, dlT;
  double Ye_min, Ye_max, dYe;
};
#endif

// More grid functions. Axisymmetry assumed.
extern double         conn[N1 + 2 * NG][N2 + 2 * NG][NDIM][NDIM][NDIM];
extern struct of_geom ggeom[N1 + 2 * NG][N2 + 2 * NG][NPG];
#if RADIATION
// extern double dt_light, dt_light_min;
extern double                 dt_light[N1 + 2 * NG][N2 + 2 * NG], dt_light_min;
extern struct of_microphysics m_grd[N1 + 2 * NG][N2 + 2 * NG][N3 + 2 * NG];
extern grid_fourvector_type   Ucon_grd, Ucov_grd, Bcon_grd, Bcov_grd;
#endif

// MPI-specific stuff
extern int global_start[NDIM];
extern int global_stop[NDIM];

/*******************************************************************************
    MACROS
*******************************************************************************/
#define ILOOP for (int i = 0 + NG; i < N1 + NG; i++)
#define ILOOPALL for (int i = 0; i < N1 + 2 * NG; i++)
#define JLOOP for (int j = 0 + NG; j < N2 + NG; j++)
#define JLOOPALL for (int j = 0; j < N2 + 2 * NG; j++)
#define KLOOP for (int k = 0 + NG; k < N3 + NG; k++)
#define KLOOPALL for (int k = 0; k < N3 + 2 * NG; k++)
#define ZLOOP                              \
  for (int i = 0 + NG; i < N1 + NG; i++)   \
    for (int j = 0 + NG; j < N2 + NG; j++) \
      for (int k = 0 + NG; k < N3 + NG; k++)
#define ZLOOPALL ILOOPALL JLOOPALL KLOOPALL
#define ISLOOP(istart, istop) for (int i = istart + NG; i <= istop + NG; i++)
#define JSLOOP(jstart, jstop) for (int j = jstart + NG; j <= jstop + NG; j++)
#define KSLOOP(kstart, kstop) for (int k = kstart + NG; k <= kstop + NG; k++)
#define ZSLOOP(istart, istop, jstart, jstop, kstart, kstop) \
  for (int i = istart + NG; i <= istop + NG; i++)           \
    for (int j = jstart + NG; j <= jstop + NG; j++)         \
      for (int k = kstart + NG; k <= kstop + NG; k++)
// Loop over faces
#define FACELOOP for (int face = FACESTART; face < FACEEND; face++)
// Loop over all locations
#define LOCLOOP for (int loc = PGSTART; loc < PGEND; loc++)
// Loop over primitive variables
#define PLOOP for (int ip = 0; ip < NVAR; ip++)
#define BASELOOP for (int ip = 0; ip < NVAR_BASE; ip++)

// Loop over spacetime indices
#define DLOOP1 for (int mu = 0; mu < NDIM; mu++)
#define DLOOP2                      \
  for (int mu = 0; mu < NDIM; mu++) \
    for (int nu = 0; nu < NDIM; nu++)
#define DLOOP3                        \
  for (int mu = 0; mu < NDIM; mu++)   \
    for (int nu = 0; nu < NDIM; nu++) \
      for (int sigma = 0; sigma < NDIM; sigma++)
// spacelike indices
#define SDLOOP for (int mu = 1; mu < NDIM; mu++)

// Loop over extra variables
// TODO: Figure out how to make this conditionally defined. ~JMM
#define EOS_ELOOP for (int e = 0; e < EOS_NUM_EXTRA; e++)

// Loop over passive scalars
#define PASSLOOP for (int ipass = PASSIVE_START; ipass < PASSIVE_STOP; ipass++)
#define PASSELEM(ipass) (ipass - PASSIVE_START)
#define PASSTYPE(ipass) (passive_type[PASSELEM(ipass)])
#define PASSNAME(ipass) (passive_name[PASSELEM(ipass)])

#define TYPELOOP for (int itp = RAD_TYPE_START; itp < RAD_NUM_TYPES; itp++)
#define SCATTLOOP for (int iscatt = 0; iscatt < RAD_SCATT_TYPES; iscatt++)
#define JRADLOOP for (int n = 0; n < MAXNSCATT + 2; n++)
#define NULOOP for (int inu = 0; inu < NU_BINS + 1; inu++)

#define MY_MIN(fval1, fval2) (((fval1) < (fval2)) ? (fval1) : (fval2))
#define MY_MAX(fval1, fval2) (((fval1) > (fval2)) ? (fval1) : (fval2))
#define MY_SIGN(fval) (((fval) < 0.) ? -1. : 1.)

#define delta(i, j) ((i == j) ? 1. : 0.)
#define dot(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3])

/*******************************************************************************
    FUNCTION DECLARATIONS
*******************************************************************************/

// bounds.c
void bound_prim(grid_prim_type prim);
void fix_flux(grid_prim_type F1, grid_prim_type F2, grid_prim_type F3);
#if RADIATION
void bound_superphotons(grid_prim_type P, double t, double dt);
void polar_fix(double X[NDIM], struct of_photon *ph);
int  rad_error_check(struct of_photon **ph);
// int rad_boundary_transport(double X[NDIM], double Kcov[NDIM]);
void bound_rad_transport(
    double X[NDIM], struct of_photon *ph, int is_transported);
int bound_rad_isactive(double X[NDIM], struct of_photon *ph);
int rad_mpi_transport(struct of_photon **ph, struct of_photon **prev,
    struct of_photon **head, double X[NDIM], int active);
#endif

// coord.c
void   coord(int i, int j, int k, int loc, double X[NDIM]);
double r_of_X(const double X[NDIM]);
double th_of_X(const double X[NDIM]);
void   jac_harm_to_bl(
      const double X[NDIM], double Jcov[NDIM][NDIM], double Jcon[NDIM][NDIM]);
void jac_bl_to_cart(
    const double X[NDIM], double Jcov[NDIM][NDIM], double Jcon[NDIM][NDIM]);
void jac_harm_to_cart(
    const double X[NDIM], double Jcov[NDIM][NDIM], double Jcon[NDIM][NDIM]);
void set_dxdX(double X[NDIM], double dxdX[NDIM][NDIM]);
void bl_coord(const double X[NDIM], double *r, double *th);
int  bl_i_of_r(double r);
void cart_coord(const double X[NDIM], double Xcart[NDIM]);
void set_gcov(double X[NDIM], double gcov[NDIM][NDIM]);
void set_metric(double X[NDIM], struct of_geom *g);
void set_points();
void zero_arrays(void);
void set_grid(void);
void cart_to_sph(const double X[NDIM], double *r, double *th, double *ph);

// current.c
void current_calc();

// diag.c
void   reset_log_variables();
void   reset_dump_variables();
void   diag(int call_code);
void   fail(int fail_type);
void   area_map(int i, int j, int k, grid_prim_type prim);
void   diag_flux(grid_prim_type F1, grid_prim_type F2, grid_prim_type F3);
double flux_ct_divb(int i, int j, int k);
#if RADIATION
void record_superphoton(double X[NDIM], struct of_photon *ph);
void bin_all_superphotons();
void report_load_imbalance();
#if RADIATION == RADTYPE_NEUTRINOS
void print_rad_types();
void count_leptons(grid_prim_type P, double dt, int nstep);
#endif
#endif

// electrons.c
#if ELECTRONS
void init_electrons();
void heat_electrons(
    grid_prim_type Pi, grid_prim_type Ps, grid_prim_type Pf, double Dt);
double get_fel(int i, int j, int k, double p[NVAR]);
#if RADIATION
void coulomb(
    grid_prim_type Pi, grid_prim_type Ps, grid_prim_type Pf, double Dt);
void apply_rad_force_e(
    grid_prim_type Prh, grid_prim_type Pr, grid_radg_type radG, double Dt);
#endif // RADIATION
void fixup_electrons(grid_prim_type p);
#endif

// emissivity.c
#if RADIATION
double jnu(double nu, int type, const struct of_microphysics *m, double theta);
double Jnu(double nu, int type, const struct of_microphysics *m);
double get_J(struct of_microphysics *m);
void   init_emissivity();
#endif

// eos.c
void   init_EOS();
double EOS_bad_eos_error();
double EOS_get_gamma(const double *extra);
double EOS_pressure_rho0_u(double rho, double u, const double *extra);
double EOS_pressure_rho0_w(double rho, double w, double gamma,
    const struct of_geom *geom, double *extra);
double EOS_enthalpy_rho0_u(double rho, double u, const double *extra);
double EOS_sound_speed_rho0_u(double rho, double u, const double *extra);
void   EOS_set_floors(double scale, double rho, double u, double bsq,
      double *rhoflr, double *uflr, const double *extra);
double EOS_entropy_rho0_u(double rho, double u, const double *extra);
double EOS_adiabatic_constant(double rho, double u, const double *extra);
double EOS_temperature(double rho, double u, const double *extra);
double EOS_u_press(double press, double rho, double *extra);
#if RADIATION
double EOS_u_N_Theta(double rho, double N, double Theta, double *extra);
double EOS_pressure_N_Theta(double N, double Theta);
double EOS_Theta_unit();
#endif // RADIATION

// eos_gamma.c
#if EOS == EOS_TYPE_GAMMA || GAMMA_FALLBACK
double EOS_Gamma_pressure_rho0_u(double rho, double u);
double EOS_Gamma_pressure_rho0_w(double rho, double w);
double EOS_Gamma_entropy_rho0_u(double rho, double u);
double EOS_Gamma_enthalpy_rho0_u(double rho, double u);
double EOS_Gamma_adiabatic_constant_rho0_u(double rho, double u);
double EOS_Gamma_sound_speed_rho0_u(double rho, double u);
void   EOS_Gamma_set_floors(double scale, double rho, double u, double bsq,
      double *rhoflr, double *uflr);
double EOS_Gamma_rho_floor(double scale, double bsq);
double EOS_Gamma_u_floor(double scale, double bsq);
double EOS_Gamma_u_scale(double rho);
double EOS_Gamma_u_press(double press);
double EOS_Gamma_temp(double rho, double u);
#if RADIATION
double EOS_Gamma_Theta_unit();
#endif // RADIATION
#endif // EOS_TYPE_GAMMA

// eos_poly.c
#if EOS == EOS_TYPE_POLYTROPE || POLYTROPE_FALLBACK
double EOS_Poly_pressure_rho0_u(double rho, double u, double K, double Gam);
double EOS_Poly_pressure_rho0_w(double rho, double w, double K, double Gam);
double EOS_Poly_enthalpy_rho0_u(double rho, double u, double K, double Gam);
double EOS_Poly_entropy_rho0_u(double rho, double u, double K, double Gam);
double EOS_Poly_sound_speed_rho0_u(double rho, double u, double K, double Gam);
void   EOS_Poly_set_floors(double scale, double rho, double u, double bsq,
      double *rhoflr, double *uflr);
double EOS_Poly_rho_floor(double scale, double bsq);
double EOS_Poly_u_floor(double scale, double bsq);
double EOS_Poly_adiabatic_constant(double rho, double u, double K, double Gam);
#endif // EOS_TYPE_POLY

// eos_stellar_collapse.c
#if EOS == EOS_TYPE_TABLE
void   EOS_SC_init(char *name);
void   EOS_SC_fill(double *restrict p, double *restrict eos);
double EOS_SC_pressure_rho0_u(double lrho, double lT, double ye);
double EOS_SC_pressure_rho0_w(double rho, double w, double ye, double *lTold);
double EOS_SC_specific_enthalpy_rho0_u(double lrho, double lT, double ye);
double EOS_SC_sound_speed(double lrho, double lT, double ye);
double EOS_SC_entropy(double lrho, double lT, double ye);
double EOS_SC_gamma(double lrho, double lT, double ye);
double EOS_SC_temperature(double lT);
double EOS_SC_get_u_of_T(double rho, double T, double ye);
double EOS_SC_u_press(double press, double rho, double ye, double *lTold);
void EOS_SC_mass_fractions(double Xi[NUM_MASS_FRACTIONS], const double *extra);
void EOS_SC_avg_ions(double *Abar, double *Zbar, const double *extra);
void EOS_SC_set_floors(double scale, double rho, double u, double ye,
    double bsqr, double *rhoflr, double *uflr);
double EOS_SC_rho_floor(double scale, double bsq);
double EOS_SC_u_floor(double scale, double bsq, double ye);
double EOS_SC_get_min_lrho();
double EOS_SC_get_min_rho();
double EOS_SC_get_min_lT();
double EOS_SC_get_minu(double rho, double ye, double scale);
void   EOS_SC_get_polytrope(
      double lrho, double lT, double ye, double *poly_K, double *poly_gamma);
double EOS_SC_hm1_min_adiabat(const struct of_adiabat *a);
int    EOS_SC_find_adiabat_1d(double s, double ye, struct of_adiabat *a);
void   EOS_SC_print_adiabat(const struct of_adiabat *a);
void   EOS_SC_adiabat_free(struct of_adiabat *a);
void   EOS_SC_isoentropy_hm1(double hm1, const struct of_adiabat *a,
      double *lrho_guess, double *rho, double *u);
void   do_ye_fixup(
      int i, int j, int k, double pv[NVAR], double pv_prefloor[NVAR]);
void do_ye_em_fixup(
    int i, int j, int k, double pv[NVAR], double pv_prefloor[NVAR]);
void do_atm_fixup(
    int i, int j, int k, double pv[NVAR], double pv_prefloor[NVAR]);
void EOS_SC_get_bounds(struct of_tablebounds *b);
void EOS_SC_print_table_mins();
#endif // EOS_TYPE_TABLE

// estimate_thetae.c
#if RADIATION
double get_Thetae_est(int i, int j, int k);
void   estimate_Thetae(
      grid_prim_type P, grid_eosvar_type extra, double t, double dt);
#endif

// fixup.c
void   fixup(grid_prim_type pv, grid_eosvar_type extra);
double get_scale(int i, int j, int k);
void   fixup1zone(
      int i, int j, int k, double pv[NVAR], double extra[EOS_NUM_EXTRA]);
void fixup_utoprim(grid_prim_type pv, grid_eosvar_type extra);

// interact.c
#if RADIATION
void interact(grid_prim_type P, grid_eosvar_type extra, double t, double dt);
#endif

// input.c
void init_params(char *pfname);
void set_param(char *key, void *data);

// io.c
// void set_core_params();
// void set_param(char *key, void *data);
// void read_params(char *pfname);
void init_io();
void init_fluid_restart();
#if RADIATION
void track_ph();
#if TRACERS
void dump_tracers();
#endif
#endif
void dump_grid();
void dump();
void restart_write(int restart_type);
void restart_read(char *fname);
int  restart_init();

// make_superphotons.c
#if RADIATION
void make_superphotons(
    grid_prim_type Prad, grid_eosvar_type extra, double t, double dt);
void set_weight(grid_prim_type Prad, grid_eosvar_type extra);
void get_dnz(grid_prim_type Prad, grid_eosvar_type extra);
#endif

// metric.c
double gcon_func(double lgcov[][NDIM], double lgcon[][NDIM]);
void   conn_func(double *X, struct of_geom *geom, double conn[][NDIM][NDIM]);
void   lower(double ucon[NDIM], double gcov[NDIM][NDIM], double ucov[NDIM]);
void   raise(double ucov[NDIM], double gcon[NDIM][NDIM], double ucon[NDIM]);
struct of_geom *get_geometry(int ii, int jj, int kk, int loc);
void            blgset(int i, int j, struct of_geom *geom);
double          bl_gdet_func(double r, double th);
void            bl_gcov_func(double r, double th, double gcov[][NDIM]);
void            bl_gcon_func(double r, double th, double gcon[][NDIM]);
double MINOR(double m[16], int r0, int r1, int r2, int c0, int c1, int c2);
void   adjoint(double m[16], double adjOut[16]);
double determinant(double m[16]);
double invert(double *m, double *invOut);

// mpi.c
void init_mpi();
void sync_mpi_boundaries_X1L(grid_prim_type Pr);
void sync_mpi_boundaries_X1R(grid_prim_type Pr);
void sync_mpi_boundaries_X2L(grid_prim_type Pr);
void sync_mpi_boundaries_X2R(grid_prim_type Pr);
void sync_mpi_boundaries_X3L(grid_prim_type Pr);
void sync_mpi_boundaries_X3R(grid_prim_type Pr);
#if RADIATION
void sync_radG();
void sync_Jrad();
void sync_radtype_vec(grid_radtype_type v);
void sync_mpi_photons(
    struct of_photon **ph_mpi, grid_prim_type P, double t, double dt);
void mpi_reduce_nuLnu();
#endif
int    mpi_nprocs();
double mpi_max(double f);
double mpi_min(double f);
int    mpi_max_int(int f);
double mpi_reduce(double f);
int    mpi_reduce_int(int f);
void   mpi_dbl_allreduce_array(double *A, int size);
int    mpi_io_proc();
void   mpi_int_broadcast(int *val);
void   mpi_int_broadcast_array(int *val, int size);
void   mpi_int_broadcast_proc(int *val, int root);
void   mpi_dbl_broadcast(double *val);
void   mpi_allgather_int1(int *buffer, int element);
int    mpi_accumulate_int(int my_val);
double mpi_io_reduce(double val);
double mpi_io_max(double val);
int    mpi_myrank();
void   mpi_sync_output();
void   mpi_barrier();
int    mpi_is_periodic(int dir);

// opac_emis_neutrino.c
#if RADIATION
#if RADIATION == RADTYPE_NEUTRINOS && BURROWS_OPACITIES
void   init_opac_emis_burrows();
void   fill_opac_emis_burrows(struct of_microphysics *m);
double jnu_burrows(double nu, int type, const struct of_microphysics *m);
double Jnu_burrows(double nu, int type, const struct of_microphysics *m);
double int_jnudnudOmega_burrows(const struct of_microphysics *m);
double alpha_nu_burrows(double nu, int type, const struct of_microphysics *m);
void   test_opac_emis();
#if EOS == EOS_TYPE_TABLE
void opac_emis_to_hdf(const char *name, const struct of_tablebounds *b);
#endif // EOS
#endif // Burrows opacities
#if RADIATION == RADTYPE_NEUTRINOS && HDF5_OPACITIES
void   init_opac_emis_hdf(char *name);
void   fill_opac_emis_hdf(struct of_microphysics *m);
double jnu_hdf(double nu, int type, const struct of_microphysics *m);
double Jnu_hdf(double nu, int type, const struct of_microphysics *m);
double int_jnudnudOmega_hdf(const struct of_microphysics *m);
double alpha_nu_hdf(double nu, int type, const struct of_microphysics *m);
#endif // HDF opacities
#endif // RADIATION

// passive.c
//#if NVAR_PASSIVE > 0
void fixup_passive(
    int i, int j, int k, double pv[NVAR], double pv_prefloor[NVAR]);
void init_passives();
void name_passives();
//#endif

// phys.c
void   primtoflux(double *pr, struct of_state *q, int dir, int magnetic,
      struct of_geom *geom, double *flux);
void   bcon_calc(double *pr, double *ucon, double *ucov, double *bcon);
void   mhd_calc(double *pr, int dir, int magnetic, struct of_state *q,
      double *extra, double *mhd);
void   source(double *ph, struct of_geom *geom, int ii, int jj, double *dU,
      double Dt, double *extra);
double bsq_calc(double *pr, struct of_geom *geom);
void   get_state(double *pr, struct of_geom *geom, struct of_state *q);
void   ucon_calc(double *pr, struct of_geom *geom, double *ucon);
int    mhd_gamma_calc(double *pr, struct of_geom *geom, double *gamma);
void   mhd_vchar(double *pr, struct of_state *q, struct of_geom *geom, int js,
      double *vmax, double *vmin);

// problem.c
void set_problem_params();
void init_prob();
void bound_gas_prob_x1l(int i, int j, int k, grid_prim_type P);
void bound_gas_prob_x1r(int i, int j, int k, grid_prim_type P);
void bound_gas_prob_x2l(int i, int j, int k, grid_prim_type P);
void bound_gas_prob_x2r(int i, int j, int k, grid_prim_type P);
void bound_gas_prob_x3l(int i, int j, int k, grid_prim_type P);
void bound_gas_prob_x4r(int i, int j, int k, grid_prim_type P);

// push_superphotons.c
#if RADIATION
int push_X_K(double X[NDIM], double Kcov[NDIM], double Kcon[NDIM],
    grid_prim_type P, grid_prim_type Prad, double KdotKprev, int type,
    double dtpush);
int push_superphoton(
    struct of_photon *ph, grid_prim_type P, grid_prim_type Prad, double dtpush);
void push_superphotons(grid_prim_type P, grid_prim_type Prad, double dt);
#endif

// rad_utils.c
#if RADIATION
void init_rad(grid_prim_type Prad);
void init_superphoton_resolution();
void update_superphoton_resolution(grid_prim_type Prad, grid_eosvar_type extra);
double linear_interp_log(double x, double *table, double lmin, double dl);
void   list_remove(struct of_photon **ph, struct of_photon **ph_head,
      struct of_photon **ph_prev);
double get_Thetae(double P[NVAR]);
double scatterer_dimensionless_temp(
    int radtype, int interaction, const struct of_microphysics *m);
double scatterer_number_density(
    int radtype, int interaction, const struct of_microphysics *m);
void precompute_microphysics();
void get_fluid_zone(int i, int j, int k, grid_prim_type Prad,
    grid_eosvar_type extra, struct of_microphysics *m, double Ucon[NDIM],
    double Ucov[NDIM], double Bcon[NDIM], double Bcov[NDIM]);
int  is_null(double Kcov[NDIM], double Kcon[NDIM], double K0, double KdotKprev,
     double *KdotK);
void set_Rmunu();
// int is_null(struct of_photon *ph, double *KdotK);
void   Xtoijk(double X[NDIM], int *i, int *j, int *k);
void   copy_photon(struct of_photon *ph, struct of_photon *phc);
void   print_ph_diag(struct of_photon *ph);
int    get_X_K_interp(struct of_photon *ph, double t_interp, grid_prim_type P,
       double X[NDIM], double Kcov[NDIM], double Kcon[NDIM]);
int    to_be_pushed(double t, double dt, struct of_photon *ph);
double get_dtpush(struct of_photon *ph, double dt);
void   swap_ph(struct of_photon **donor, struct of_photon **recipient);
void   get_nuLnu_bin(double X[NDIM], int *thbin, int *phibin);
void   bin_superphoton_direction(const struct of_photon *ph);
double get_min_dt_cool(grid_prim_type P, grid_eosvar_type extra);
void   set_cooling_time(
      grid_double_type tau_cool, grid_prim_type P, grid_eosvar_type extra);
#if RADIATION == RADTYPE_NEUTRINOS
void record_lepton_flux(const struct of_photon *ph);
void check_nu_type(const char *location);
int  get_lepton_sign(const struct of_photon *ph);
#endif // NEUTRINOS
#endif // RADIATION

// radiation.c
#if RADIATION
double Bnu_inv(double nu, const struct of_microphysics *m); // TODO?
double jnu_inv(
    double nu, int type, const struct of_microphysics *m, double theta);
double alpha_inv_scatt(
    double nu, int type, int interaction, const struct of_microphysics *m);
double alpha_inv_abs(
    double nu, int type, const struct of_microphysics *m, double theta);
double get_fluid_nu(double X[NDIM], double Kcov[NDIM], double Ucon[NDIM]);
double get_bk_angle(double X[NDIM], double K[NDIM], double Ucov[NDIM],
    double Bcov[NDIM], double B);
#endif

// random.c
void   init_random(int seed);
double get_rand();
double get_chisq(double nu);
double get_gaussian(double mu, double sigma);
void   get_ran_dir_3d(double *nx, double *ny, double *nz);

// reconstruction.c
void reconstruct(double ptmp[NMAX + 2 * NG][NVAR], int N,
    double p_l[NMAX + 2 * NG][NVAR], double p_r[NMAX + 2 * NG][NVAR]);

// root_finding.c
// counts root_finding iterations
void initialize_root_fcounts();
void print_root_fcounts();
// solves for f(x,params) - ytarget = 0
int find_root(double (*f)(const double, const void *), const void *params,
    const double ytarget, double xguess, const double xmin, const double xmax,
    const double xtol, const double ytol, double *xroot);

// scattering.c
#if RADIATION
int    scatt_temp_too_small(const struct of_microphysics *m);
int    scatter_superphoton(grid_prim_type P, grid_eosvar_type extra,
       struct of_photon *ph, double X[NDIM], double Kcov[NDIM], double Kcon[NDIM],
       int interaction);
void   init_all_hotcross();
double total_cross_lkup(
    double w, int type, int interaction, const struct of_microphysics *m);
#endif

// step.c
void step();

// tetrads.c
#if RADIATION
void coord_to_tetrad(
    double Ecov[NDIM][NDIM], double Kcoord[NDIM], double Ktetrad[NDIM]);
void tetrad_to_coord(
    double Econ[NDIM][NDIM], double Ktetrad[NDIM], double Kcoord[NDIM]);
void make_tetrad(int i, int j, int k, double Ucon[NDIM], double trial[NDIM],
    double Gcov[NDIM][NDIM], double Econ[NDIM][NDIM], double Ecov[NDIM][NDIM]);
void normalize_null(double Gcov[NDIM][NDIM], double K[NDIM]);
void normalize_null_cov(double Gcon[NDIM][NDIM], double K[NDIM]);
#endif

// timing.c
void   time_set(int n, double val);
double time_read(int n);
void   time_init();
void   timer_start(int timerCode);
void   timer_stop(int timerCode);
double get_time_per_step(int timerCode);
void   report_performance();
void   timers_reset();

// tracers.c
#if RADIATION && TRACERS
double get_total_tracer_mass();
int    tracer_max_id(long unsigned int ntracers);
int    count_tracers_local();
void   lagrange_interp_grid_3d(
      double v_interp[], double X[NDIM], double *v, int size);
void lagrange_interp_prim_3d(
    double P_interp[NVAR], double X[NDIM], grid_prim_type P);
void   push_tracers(double X[NDIM], double Kcov[NDIM], double Kcon[NDIM],
      grid_prim_type P, grid_prim_type Ph, double dt);
int    tracer_get_id(struct of_photon *ph);
double tracer_get_mass(struct of_photon *ph);
void   tracer_get_X_u(struct of_photon *ph, double t_interp, double X[NDIM],
      double ucov[NDIM], double ucon[NDIM]);
void   set_tracer(struct of_photon *ph, int id, int nstep, double t,
      double X[NDIM], double mass, grid_prim_type P);
void   make_tracer(struct of_photon **head, int id, int nstep, double t,
      double X[NDIM], double mass, grid_prim_type P);
void   sample_tracers_in_cell(struct of_photon **head, int nstep, int i, int j,
      int k, int *last_id, int ntracers_per_cell, double t, grid_prim_type P);
void   sample_all_tracers(long unsigned int ntracers_tot, int nstep, double t,
      grid_int_type tcrs_in_cell, grid_prim_type P);
void   prune_tracers();
#endif

// util.c
double find_min(const double *array, int size);
double find_max(const double *array, int size);
double find_median(double *array, int size);
double interp_1d(double x, const double xmin, const double xmax, const int imin,
    const int imax, const double *restrict tab_x, const double *restrict tab_y);
int    find_index(double value, const double *array, int size);
void * safe_malloc(size_t size);
void   safe_system(const char *command);
void   safe_fscanf(FILE *stream, const char *format, ...);
int    is_practically_nan(double v);
#if NEED_UNITS
void set_units();
#endif

// utop.c
int Utoprim(double U[NVAR], struct of_geom *geom, double prim[NVAR]);

// xdmf_output.c
void write_xml_file(int dump_id, double t, const char *vnams[NVAR]);


/* This file is part of the KDE project
   Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef KSPREAD_SOLVER
#define KSPREAD_SOLVER

#include <gsl/gsl_multimin.h>

#include <kxmlguiclient.h>

#include <Cell.h>

#include <QObject>
#include <QVariantList>

namespace Calligra
{
namespace Sheets
{
namespace Plugins
{

/**
 * \class Solver Function Optimizer
 * \author Stefan Nikolaus <stefan.nikolaus@kdemail.net>
 */
class Solver : public QObject, public KXMLGUIClient
{
    Q_OBJECT

public:
    struct Parameters {
        QList<Cell> cells;
    };

    /**
     * Constructor.
     */
    Solver(QObject* parent, const QVariantList& args);

    /**
     * Destructor.
     */
    ~Solver();

    double evaluate(const gsl_vector* vector, void* parameters);

protected Q_SLOTS:
    /**
     * Called when the Solver action is triggered.
     * Opens the dialog.
     */
    void showDialog();

    /**
     * This method does the real work.
     * Uses the parameters of the dialog to optimize the given function.
     */
    void optimize();

private:
    Q_DISABLE_COPY(Solver)

    class Private;
    Private * const d;
};

} // namespace Plugins
} // namespace Sheets
} // namespace Calligra

#endif


/*
 * C version of Diffusive Nested Sampling (DNest4) by Brendon J. Brewer
 *
 * Yan-Rong Li, liyanrong@mail.ihep.ac.cn
 * Jun 30, 2016
 *
 */
#ifndef _DNESTVARS_H
#define _DNESTVARS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <gsl/gsl_rng.h>

#include "dnest.h"

enum PRIOR_TYPE {UNIFORM=0, GAUSSIAN=1, LOG=2};

/* output files */
extern FILE *fsample, *fsample_info;

/* random number generator */
extern const gsl_rng_type * dnest_gsl_T;
extern gsl_rng * dnest_gsl_r;

typedef struct
{
  double value;
  double tiebreaker;
}LikelihoodType;

typedef struct
{
  LikelihoodType log_likelihood;
  double log_X;
  unsigned long long int visits, exceeds;
  unsigned long long int accepts, tries;
}Level;

extern DNestOptions options;
extern char options_file[STR_MAX_LENGTH];

typedef struct
{
  int id;
  void *addr;
  char tag[50];
  int isset;
}DNestPARDICT;

extern void *particles;
extern int dnest_size_of_modeltype;
extern int particle_offset_size, particle_offset_double;

// sampler
extern bool save_to_disk;
extern unsigned int num_threads;
extern double compression;
extern unsigned int regularisation;

extern void *particles;
extern LikelihoodType *log_likelihoods;
extern unsigned int *level_assignments;

// number account of unaccepted times
extern unsigned int *account_unaccepts;

extern int size_levels, size_levels_combine;
extern Level *levels;
extern Level *copies_of_levels, *levels_combine;
extern LikelihoodType *all_above;
extern unsigned int count_saves, num_saves, num_saves_restart;
extern unsigned long long int count_mcmc_steps;
extern LikelihoodType *above;
extern unsigned int size_above, size_all_above;

extern int dnest_flag_restart, dnest_flag_postprc, dnest_flag_sample_info, dnest_flag_limits;
extern double dnest_post_temp;
extern char file_restart[STR_MAX_LENGTH], file_save_restart[STR_MAX_LENGTH];

extern double post_logz;
extern int dnest_num_params;
extern char dnest_sample_postfix[STR_MAX_LENGTH], dnest_sample_tag[STR_MAX_LENGTH], dnest_sample_dir[STR_MAX_LENGTH];
extern double *dnest_param_range, *dnest_prior_info;
extern int *dnest_prior_type;
extern void *dnest_args;

//the limits of parameters for each level;
extern double *limits, *copies_of_limits;

extern int dnest_which_particle_update; // which particle to be updated
extern int dnest_which_level_update;    // which level to be updated;
extern int dnest_thistask, dnest_totaltask;
extern int *dnest_perturb_accept;
extern int dnest_root;
//***********************************************
/*                  functions                  */
extern double mod(double y, double x);
extern void wrap_limit(double *x, double min, double max);
extern int mod_int(int y, int x);
extern int dnest_cmp(const void *pa, const void *pb);

extern void options_load(char *optfile, DNestOptions *opts);
extern void setup(int argc, char** argv, DNestFptrSet *fptrset, int num_params,
           double *param_range, int *prior_type, double *prior_info,
           char *sample_dir, char *optfile, DNestOptions *opts, void *args);
extern void finalise();

extern void dnest_run();
extern void dnest_mcmc_run();
extern void update_particle(unsigned int which);
extern void update_level_assignment(unsigned int which);
extern double log_push(unsigned int which_level);
extern bool enough_levels(Level *l, int size_l);
extern void do_bookkeeping();
extern void save_levels();
extern void save_particle();
extern void save_limits();
extern void kill_lagging_particles();
extern void renormalise_visits();
extern void recalculate_log_X();
extern void dnest_postprocess(double temperature,char *optfile, DNestOptions *opts);
extern void postprocess(double temperature);
extern void initialize_output_file();
extern void close_output_file();
extern void dnest_save_restart();
extern void dnest_restart();
extern void dnest_restart_action(int iflag);
extern void dnest_accept_action();
extern void dnest_kill_action(int i, int i_copy);
extern void dnest_from_prior(void *model);
extern double dnest_perturb(void *model);
extern void dnest_print_particle(FILE *fp, const void *model);
extern void dnest_read_particle(FILE *fp, void *model);
extern void dnest_check_directory(char *sample_dir);
/*=====================================================*/
// users responsible for following functions
extern void (*print_particle)(FILE *fp, const void *model);
extern void (*read_particle)(FILE *fp, void *model);
extern void (*from_prior)(void *model);
extern double (*log_likelihoods_cal)(const void *model);
extern double (*log_likelihoods_cal_initial)(const void *model);
extern double (*log_likelihoods_cal_restart)(const void *model);
extern double (*perturb)(void *model);
extern void (*restart_action)(int iflag);
extern void (*accept_action)();
extern void (*kill_action)(int i, int i_copy);
/*=====================================================*/

#ifdef __cplusplus
}
#endif

#endif


#pragma once
#include "halley/maths/vector3.h"
#include <gsl/span>

namespace Halley
{
	class AudioListenerData;
	class AudioChannelData;

	class AudioPosition
	{
	public:
		struct SpatialSource {
			SpatialSource();
			SpatialSource(Vector2f pos, float referenceDistance = 200.0f, float maxDistance = 400.0f);
			SpatialSource(Vector3f pos, float referenceDistance = 200.0f, float maxDistance = 400.0f);

			Vector3f pos;
			float referenceDistance;
			float maxDistance;
		};

		AudioPosition();

		static AudioPosition makeUI(float pan = 0.0f); // -1.0f = left, 1.0f = right
		static AudioPosition makePositional(Vector2f pos, float referenceDistance = 200.0f, float maxDistance = 400.0f);
		static AudioPosition makePositional(Vector3f pos, float referenceDistance = 200.0f, float maxDistance = 400.0f);
		static AudioPosition makePositional(std::vector<SpatialSource> sources);
		static AudioPosition makeFixed();

		void setMix(size_t srcChannels, gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const;
		void setPosition(Vector3f position);

	private:
		std::vector<SpatialSource> sources;
		float pan = 0;
		bool isUI = false;
		bool isPannable = false;

		void setMixFixed(size_t srcChannels, gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const;
		void setMixUI(gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const;
		void setMixPositional(gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const;
	};
}


// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once

#include <memory>
#include <future>
#include <array>
#include <gsl\gsl>

#include <boost\optional.hpp>

#include "Data\Data.h"
#include "MageSettings.h"
#include "Device\Device.h"

#include <SensorSample.h>
#include <Plat/CameraDevice/CameraSettings.h>

namespace mage
{
    class PoseHistory;

    /* Entry point of the MAGESlam library */
    class MAGESlam
    {
        struct Impl;
    public:

        struct CameraConfiguration
        {
            CameraIdentity CameraIdentity;
            Size Size{};
            PixelFormat Format;
            Matrix Extrinsics;

            CameraConfiguration(mage::CameraIdentity cameraIdentity, const mage::Size& size, PixelFormat format, const Matrix& extrinsics)
                : CameraIdentity{ cameraIdentity },
                Format{ format },
                Size{ size },
                Extrinsics{ extrinsics }
            {
            };
        };

        struct FrameFormat
        {
            const mage::FrameId FrameId;
            std::shared_ptr<const calibration::CameraModel> CameraModel;
            std::chrono::system_clock::time_point Timestamp;
            mira::CameraSettings CameraSettings;

            FrameFormat(
                const mage::FrameId& frameId,
                std::shared_ptr<const calibration::CameraModel> cameraModel,
                const std::chrono::system_clock::time_point& timestamp,
                const mira::CameraSettings& cameraSettings)
                : FrameId{ frameId },
                CameraModel{ cameraModel },
                Timestamp{ timestamp },
                CameraSettings{ cameraSettings }
            {}
        };

        struct Tracking
        {
            /*
                The Matrix is a row-major column-vector view matrix. right handed
                    R, R, R, Tx
                    R, R, R, Ty
                    R, R, R, Tz
                    0, 0, 0, 1
            */
            Matrix Pose;
            TrackingState State;

            Tracking(const Matrix& mat, TrackingState state)
                : Pose{ mat }, State{ state }
            {}

            Tracking()
                : Pose{ }, State{ TrackingState::SKIPPED }
            {}

            bool IsPoseGood() const
            {
                return State == TrackingState::TRACKING;
            }

            bool IsPoseSkipped() const
            {
                return State == TrackingState::SKIPPED;
            }
        };

        struct TrackedFrame
        {
            Tracking Tracking;
            std::shared_ptr<const calibration::CameraModel> CameraModel;
            Depth Depth;

            TrackedFrame(const MAGESlam::Tracking& tracking, std::shared_ptr<const calibration::CameraModel> cameraModel, const mage::Depth& depth)
                : Tracking{ tracking }, CameraModel{ cameraModel }, Depth{ depth }
            {}

            TrackedFrame() = default;
        };

        class FossilizedMap
        {
        public:
            ~FossilizedMap();

            /*
                Get the most up-to-date pose for the specified frame ID
            */
            std::vector<boost::optional<MAGESlam::TrackedFrame>> GetTrackingResultsForFrames(const gsl::span<const FrameId> frameIds) const;

            bool TryGetVolumeOfInterest(AxisAlignedVolume& volumeOfInterest) const;

        private:
            FossilizedMap(std::unique_ptr<const PoseHistory> history, std::vector<Position> mapPoints, const MageSlamSettings& settings);

            friend class MAGESlam;

            struct Impl;
            std::unique_ptr<Impl> m_impl;
        };

        explicit MAGESlam(const MageSlamSettings&, gsl::span<const CameraConfiguration> cameras, const device::IMUCharacterization& imu);

        MAGESlam(const MAGESlam&) = delete;
        MAGESlam& operator =(const MAGESlam&) = delete;

        struct Frame
        {
            FrameFormat Format;
            gsl::span<const uint8_t> Bytes;

            Frame(const FrameFormat& format, gsl::span<const uint8_t> bytes)
                : Format(format),
                Bytes(bytes)
            {}
        };

        /*
            Processes an image frame and returns a future Pose and the state of the
            tracker while it was generating it.
        */
        std::future<Tracking> ProcessFrame(const Frame& frame);

        /*
            Processes an stereo image pair and returns a future Pose for each frame and the state of the
            tracker while it was generating it.
        */
        std::pair<std::future<Tracking>, std::future<Tracking>> ProcessStereoFrames(const Frame& one, const Frame& two);

        /*
            Get the most up-to-date pose for the specified frame ID
        */
        std::vector<boost::optional<MAGESlam::TrackedFrame>> GetTrackingResultsForFrames(const gsl::span<const FrameId> frameIds) const;

        // adds a sensor sample to the sample queue for sensor fusion
        void AddSensorSample(const SensorSample& sample);

        // get normalized vector in mage's world coordinate frame describing the fuser's gravity estimate
        // returns whether the gravity estimate is valid.
        bool GetGravityDirection(Direction& gravDir) const;

        // gets the scale to apply to mage to bring it to meters as estimated by
        // the stereo tracking code
        float GetStereoMageMeterEstimate() const;

        // gets the scale to apply to mage to bring it to meters as estimated by the fuser
        // returns whether the scale is valid
        bool  GetScaleFromIMU(float& scaleMAGEtoMeters) const;

        bool TryGetVolumeOfInterest(AxisAlignedVolume& volumeOfInterest) const;

        // Destroys the current instance of MAGESlam and converts it to a fossilized map
        // that can be used for offline queries of frame poses
        static std::unique_ptr<FossilizedMap> Fossilize(std::unique_ptr<MAGESlam> slam);

        ~MAGESlam();
    private:
        std::unique_ptr<Impl> m_impl;
    };
}


#ifndef __INTERPOLATOR_H__
#define __INTERPOLATOR_H__

#include <vector>
#include <gsl/gsl_math.h>
#include <gsl/gsl_spline.h>

namespace RHEHpt{

class Interpolator
{
	public:
		Interpolator (unsigned choice = 0);
		virtual ~Interpolator ();

		double operator()(unsigned order, double xp) const;

		void set_choice(unsigned choice){ _choice = choice; }

	private:
		unsigned _choice;
		gsl_interp_accel* _gsl_acc;

		/* matrix of gsl interpolators one row per _choice and one column per order */
		std::vector < std::vector < gsl_spline *> > _interpolators;

};

} /* close RHEHpt namespace* */

#endif /* __INTERPOLATOR_H__ */


#ifndef CWANNIER_DOS_VALUES_H
#define CWANNIER_DOS_VALUES_H

#include <stdbool.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_sort_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_eigen.h>
#include "HTightBinding.h"
#include "ctetra/dos.h"

double* DosValues(HTightBinding *Hrs, gsl_matrix *R, int na, int nb, int nc, double *Es, double num_dos, bool all_Es);

double* DosEnergyDerivValues(HTightBinding *Hrs, gsl_matrix *R, int na, int nb, int nc, double *Es, int num_dos, double num_electrons, double *fermi, double *dos_fermi, double *dos_deriv_fermi);

#endif // CWANNIER_DOS_VALUES_H


/*
# Program to run a Monte Carlo radiation transfer through the 2D
# simulations of GRB jets.
#
# Python code written by D. Lazzati at Oregonstate, C code written by Tyler Parsotan @ Oregon State
# ver 0.1 July 8, 2015
# ver 1.1 July 20, 2015: added record of number of scatterings, included
# 	all terms in weight. Should now give correct light curves.
# ver 1.2 July 21, 2015: added parameter file to keep track of input
# 	params of each simulation

# ver 2.0 July 22, 2015: corrected the problem that arises when there is
# 	no scattering in the time span of one frame. Fixed output arrays dimension.

# ver 2.1 July 25, 2015: fixed bug that did not make the number of
# 	scattering grow with the number of photons.

# ver 3.0 July 28, 2015: using scipy nearest neighbor interpolation to
# 	speed things up. Gained about factor 2

# ver 3.1 July 29, 2015: added radial spread of photon injection points
# ver 3.2 July 31, 2015: added Gamma to the weight of photons!!!

# ver 4.0 Aug 5, 2015: try to speed up by inverting cycle
# ver 4.1 Aug 8, 2015: add spherical test as an option
# ver 4.2 Aug 9, 2015: saving files appending rather than re-writing
# ver 4.3 Aug 11, 2015: corrected error in the calculation of the local temperature
# ver 4.4 Aug 13, 2015: added cylindrical test
# ver 4.5 Aug 18, 2015: fixd various problems pointed by the cylindrical test
# ver 4.6 Aug 21, 2015: corrected mean free path for large radii

# ver 5.0 Aug 25, 2015: corrected problem with high-T electrons and excess scatterings
# ver 5.1 Aug 25, 2015: cleaned-up coding
# ver 5.2 Sept 3, 2015: fixed problem with number of scatterings for multiple injections
 *
 * ver 6.0 Dec 28, 2016: rewrote the code in C, added checkpoint file so if the code is interrupted all the progress wont be lost, made the code only need to be compiled once for a given MC_XXX directory path
                                            so you just need to supply the sub directory of MC_XXX as a command line argument
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <math.h>
#include <gsl/gsl_rng.h>
//#include "mclib.h"
#include "mclib_3d.h"
#include <omp.h>

#define THISRUN "Science"
#define FILEPATH "/Users/Tylerparsotan/Documents/Box\ Sync/RIKEN_HYDRO_DATA/JP_HYDRODATA/"
#define FILEROOT "u"
#define MC_PATH "PHOTON_TEST/"
//#define MC_PATH "MC_16OI/Single_Photon_Cy_mc_total/"
#define MCPAR "riken_mc.par"

int main(int argc, char **argv)
{
    //compile each time a macro is changed

	// Define variables
	char flash_prefix[200]="";
	char mc_file[200]="" ;
    char this_run[200]=THISRUN;
    char *cyl="Cylindrical";
    char *sph="Spherical";
    char spect;//type of spectrum
    char restrt;//restart or not
    double fps, theta_jmin, theta_jmax ;//frames per second of sim, min opening angle of jet, max opening angle of jet in radians
    double inj_radius_small, inj_radius_large,  ph_weight_suggest ;//radius at chich photons are injected into sim
    int frm0_small, frm0_large,last_frm, frm2_small, frm2_large, j=0, min_photons, max_photons ;//frame starting from, last frame of sim, frame of last injection

    int num_thread=0, angle_count=0;
    int half_threads=floor((num_thread/2));
    int num_angles=0;
    int dim_switch=0;
    double *thread_theta=NULL; //saves ranges of thetas for each thread to go through
    double delta_theta=0;

    //new muliple threads injecting and propagating photons
    const gsl_rng_type *rng_t;
    gsl_rng **rng;
    gsl_rng_env_setup();
    rng_t = gsl_rng_ranlxs0;

    //want to break up simulation by angle and injection frame & have each thread save data in its own folder
    //have each thread check if its directory is made and if its restarting (delete evrything) or if its continuing with a previous simulation
    //the angle and the injection frames will be the names of mc_dir, therefore read mc.par first in MC_XXX directory

    //make strings of proper directories etc.
	snprintf(flash_prefix,sizeof(flash_prefix),"%s%s",FILEPATH,FILEROOT );
	//snprintf(mc_dir,sizeof(flash_prefix),"%s%s",FILEPATH,MC_PATH);
    //snprintf(mc_file,sizeof(flash_prefix),"%s%s",mc_dir, MCPAR);
    snprintf(mc_file,sizeof(flash_prefix),"%s%s%s",FILEPATH, MC_PATH,MCPAR);

    //printf(">> mc.py:  Reading mc.par\n");

    readMcPar(mc_file, &fps, &theta_jmin, &theta_jmax, &delta_theta, &inj_radius_small,&inj_radius_large, &frm0_small , &frm0_large ,&last_frm ,&frm2_small, &frm2_large, &ph_weight_suggest, &min_photons, &max_photons, &spect, &restrt, &num_thread, &dim_switch); //thetas that comes out is in degrees

    //printf("small: %d large: %d weights: %e, %c\n", min_photons, max_photons, ph_weight_suggest, restrt);
    if (num_thread==0)
    {
        num_thread=omp_get_max_threads(); //if user specifies 0 in mc.par, default to max number of threads possible
    }

    half_threads=floor((num_thread/2));
    //thread_theta=malloc(((half_threads)+1)*sizeof(double) );

    rng = (gsl_rng **) malloc((num_thread ) * sizeof(gsl_rng *));
     rng[0] = gsl_rng_alloc (rng_t); //initalize first random number generator to seed the others with random numbers

    for(j=1;j<num_thread;j++)
    {
        rng[j] = gsl_rng_alloc (rng_t);
        gsl_rng_set(rng[j],gsl_rng_get(rng[0]));
    }

    //divide up angles and frame injections among threads DONT WANT NUMBER OF THREADS TO BE ODD
    //assign ranges to array that hold them
    /*
    delta_theta=(theta_jmax-theta_jmin)/(half_threads);
    *(thread_theta+0)=theta_jmin;
    //printf("%e\n", *(thread_theta+0));

    for (j=1;j<(half_threads+1); j++)
    {
        *(thread_theta+j)=*(thread_theta+(j-1))+delta_theta;
        //printf("%e\n", *(thread_theta+j)*180/M_PI);
    }
    */

     //leave angles in degrees here
    num_angles=(int) (((theta_jmax-theta_jmin)/delta_theta)) ;//*(180/M_PI));
    thread_theta=malloc( num_angles *sizeof(double) );
    *(thread_theta+0)=theta_jmin;//*(180/M_PI);
    printf("%e\n", *(thread_theta+0));

    for (j=1;j<(num_angles); j++)
    {
        *(thread_theta+j)=*(thread_theta+(j-1))+delta_theta;
        printf("%e\n", *(thread_theta+j));
    }

    //printf("half_threads: %d\n", half_threads);
    //start parallel section with half the threads possible and assign each thread to its value of theta by rewriting its private value of theta min and max that was read from mcrat
    omp_set_nested(1); //allow for nested parallelization
    //omp_set_dynamic(0);
    //omp_set_num_threads(num_thread);
    //#pragma omp parallel firstprivate(theta_jmin_thread, theta_jmax_thread, mc_dir, phPtr, framestart, scatt_framestart, num_ph, restrt, time_now, st, dirp, file_count, mc_filename, mc_operation, dt_max)
    //printf("%d\n", omp_get_num_threads() );
    //    for (angle_count=(int) (theta_jmin); angle_count< (int) (theta_jmax+1)  ;angle_count=angle_count+delta_theta )

    #pragma omp parallel for num_threads(num_thread) private(angle_count)
    for (angle_count=0; angle_count< num_angles ;angle_count++ )
    {

        printf("%d\t%lf\n", omp_get_thread_num(), delta_theta );
        double inj_radius;
        int frm2, frm0;
        char mc_filename[200]="";
        char mc_filename_2[200]="";
        char mc_operation[200]="";
        char mc_dir[200]="" ;
        int file_count = 0;
        DIR * dirp;
        struct dirent * entry;
        struct stat st = {0};
        double theta_jmin_thread=0, theta_jmax_thread=0;

        theta_jmin_thread= (*(thread_theta+angle_count))*(M_PI/180);//(*(thread_theta+omp_get_thread_num() ));
        theta_jmax_thread= ((*(thread_theta+angle_count))+delta_theta)*(M_PI/180);//(*(thread_theta+omp_get_thread_num()+1 ));
        printf("Thread %d: %0.1lf, %0.1lf \n %d %d\n", omp_get_thread_num(),  theta_jmin_thread*180/M_PI,  theta_jmax_thread*180/M_PI, frm2_small, frm2_large );

        snprintf(mc_dir,sizeof(flash_prefix),"%s%s%0.1lf-%0.1lf/",FILEPATH,MC_PATH, theta_jmin_thread*180/M_PI, theta_jmax_thread*180/M_PI ); //have to add angle into this

        printf(">> Thread %d in  MCRaT: I am working on path: %s \n",omp_get_thread_num(), mc_dir  );

        if ((theta_jmin_thread >= 0) &&  (theta_jmax_thread <= (2*M_PI/180) )) //if within small angle (0-2 degrees) use _small inj_radius and frm2
        {
            inj_radius=inj_radius_small;
            frm2=frm2_small;
            frm0=frm0_small;
        }
        else
        {
            inj_radius=inj_radius_large;
            frm2=frm2_large;
            frm0=frm0_large;
        }
        printf("Thread %d: %0.1lf, %0.1lf \n %d %e %d\n", omp_get_thread_num(),  theta_jmin_thread*180/M_PI,  theta_jmax_thread*180/M_PI, frm2, inj_radius, frm0 );

        //want to also have another set of threads that each has differing ranges of frame injections therefore do nested parallelism here so each thread can read its own checkpoint file
        //#pragma omp parallel num_threads(2) firstprivate(restrt)
        {
            char flash_file[200]="";
            char log_file[200]="";
            FILE *fPtr=NULL; //pointer to log file for each thread
            double *xPtr=NULL,  *yPtr=NULL,  *rPtr=NULL,  *thetaPtr=NULL,  *velxPtr=NULL,  *velyPtr=NULL,  *densPtr=NULL,  *presPtr=NULL,  *gammaPtr=NULL,  *dens_labPtr=NULL;
            double *phiPtr=NULL, *velzPtr=NULL, *zPtr=NULL;
            double *szxPtr=NULL,*szyPtr=NULL, *tempPtr=NULL; //pointers to hold data from FLASH files
            int num_ph=0, array_num=0, ph_scatt_index=0, max_scatt=0, min_scatt=0,i=0; //number of photons produced in injection algorithm, number of array elleemnts from reading FLASH file, index of photon whch does scattering, generic counter
            double dt_max=0, thescatt=0, accum_time=0;
            double  gamma_infinity=0, time_now=0, time_step=0, avg_scatt=0; //gamma_infinity not used?
            double ph_dens_labPtr=0, ph_vxPtr=0, ph_vyPtr=0, ph_tempPtr=0, ph_vzPtr=0;// *ph_cosanglePtr=NULL ;
            double min_r=0, max_r=0;
            int frame=0, scatt_frame=0, frame_scatt_cnt=0, scatt_framestart=0, framestart=0;
            struct photon *phPtr=NULL; //pointer to array of photons

            //if (omp_get_thread_num()==0)
            //{
                //printf( "A:%d Im Thread: %d with ancestor %d working in %s\n", omp_get_num_threads(),  omp_get_thread_num(), omp_get_ancestor_thread_num(1), mc_dir);
            //}

            if (restrt=='c')
            {
                printf(">> mc.py:  Reading checkpoint\n");
                //#pragma omp critical
                {
                    readCheckpoint(mc_dir, &phPtr, frm0, &framestart, &scatt_framestart, &num_ph, &restrt, &time_now);

                /*
                for (i=0;i<num_ph;i++)
                {
                    printf("%e,%e,%e, %e,%e,%e, %e, %e\n",(phPtr+i)->p0, (phPtr+i)->p1, (phPtr+i)->p2, (phPtr+i)->p3, (phPtr+i)->r0, (phPtr+i)->r1, (phPtr+i)->r2, (phPtr+i)->num_scatt );
                }
                */
                if (restrt=='c')
                {
                    printf(">> Thread %d with ancestor %d: Starting from photons injected at frame: %d out of %d\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),framestart, frm2);
                    printf(">> Thread %d with ancestor %d: Continuing scattering %d photons from frame: %d\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),num_ph, scatt_framestart);
                    printf(">> Thread %d with ancestor %d: The time now is: %e\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),time_now);
                }
                else
                {
                    printf(">> Thread %d with ancestor %d: Continuing simulation by injecting photons at frame: %d out of %d\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),framestart, frm2); //starting with new photon injection is same as restarting sim
                }
                }
            }
            else if (stat(mc_dir, &st) == -1)
            {
                mkdir(mc_dir, 0777); //make the directory with full permissions

                framestart=frm0; //if restarting then start from parameters given in mc.par file
                scatt_framestart=frm0;
            }
            else
            {
                //remove everything from MC directory to ensure no corruption of data if theres other files there besides the mc.par file
                //for a checkpoint implementation, need to find the latest checkpoint file and read it and not delete the files
                #pragma omp critical
                {
                    printf(">> Thread %d with ancestor %d:  Cleaning directory \n",omp_get_thread_num(), omp_get_ancestor_thread_num(1));
                    dirp = opendir(mc_dir);
                    while ((entry = readdir(dirp)) != NULL)
                    {
                        if (entry->d_type == DT_REG) { /* If the entry is a regular file */
                             file_count++; //count how many files are in dorectory
                        }
                    }
                    printf("File count %d\n", file_count);

                    if (file_count>0)
                    {
                        for (i=0;i<=last_frm;i++)
                        {

                            snprintf(mc_filename,sizeof(mc_filename),"%s%s%d%s", mc_dir,"mcdata_",i,"_P0.dat");
                            if(( access( mc_filename, F_OK ) != -1 ) )
                            {
                                snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s%d%s","exec rm ", mc_dir,"mcdata_",i,"_*.dat"); //prepares string to remove *.dat in mc_dir
                                printf("%s\n",mc_operation);
                                system(mc_operation);

                                //snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s%d%s","exec rm ", mc_dir,"mcdata_",i,"_*");
                                //system(mc_operation);
                            }
                        }
                        //snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s","exec rm ", mc_dir,"mcdata_PW_*.dat"); //prepares string to remove *.dat in mc_dir
                        //system(mc_operation);

                        snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s","exec rm ", mc_dir,"mcdata_PW.dat"); //prepares string to remove *.dat in mc_dir
                        system(mc_operation);

                        //snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s","exec rm ", mc_dir,"mc_chkpt_*.dat"); //prepares string to remove *.dat in mc_dir
                        //system(mc_operation);

                        snprintf(mc_operation,sizeof(flash_prefix),"%s%s%s","exec rm ", mc_dir,"mc_output_*.log"); //prepares string to remove *.log in mc_dir
                        system(mc_operation);

                    }
                }
                framestart=frm0; //if restarting then start from parameters given in mc.par file
                scatt_framestart=frm0;

            }

            dt_max=1.0/fps;
            //#pragma omp barrier

            snprintf(log_file,sizeof(log_file),"%s%s",mc_dir,"mc_output.log" );
            printf("%s\n",log_file);
            fPtr=fopen(log_file, "w");

            fprintf(fPtr, "%d Im Thread: %d with ancestor %d Starting on Frame: %d scatt_framestart: %d\n", omp_get_num_threads(),  omp_get_thread_num(), omp_get_ancestor_thread_num(1), framestart, scatt_framestart);
            fflush(fPtr);
            //fclose(fPtr);
            //#pragma omp barrier
            //exit(0);
            //loop over frames
            //for a checkpoint implementation, start from the last saved "frame" value and go to the saved "frm2" value

            //#pragma omp for
            for (frame=framestart;frame<=frm2;frame++)
            {
                 if (restrt=='r')
                 {
                    time_now=frame/fps; //for a checkpoint implmentation, load the saved "time_now" value when reading the ckeckpoint file otherwise calculate it normally
                 }

                //printf(">> mc.py: Working on Frame %d\n", frame);
                fprintf(fPtr,"%d Im Thread: %d with ancestor %d Working on Frame: %d\n", omp_get_num_threads(),  omp_get_thread_num(), omp_get_ancestor_thread_num(1), frame);
                fflush(fPtr);

                if (restrt=='r')
                {

                    //exit(0);
                    //read in FLASH file
                    //for a checkpoint implmentation, dont need to read the file yet
                    if (dim_switch==0)
                    {
                        //put proper number at the end of the flash file
                        modifyFlashName(flash_file, flash_prefix, frame, dim_switch);
                        fprintf(fPtr,">> Im Thread: %d with ancestor %d: Opening FLASH file %s\n",omp_get_thread_num(), omp_get_ancestor_thread_num(1), flash_file);
                        fflush(fPtr);

                        #pragma omp critical
                        {
                            readAndDecimate(flash_file, inj_radius, fps, &xPtr,  &yPtr,  &szxPtr, &szyPtr, &rPtr,\
                                &thetaPtr, &velxPtr,  &velyPtr,  &densPtr,  &presPtr,  &gammaPtr,  &dens_labPtr, &tempPtr, &array_num, 1, min_r, max_r, fPtr);
                        }
                    }
                    else
                    {
                        read_hydro(FILEPATH, frame, inj_radius, &xPtr,  &yPtr, &zPtr,  &szxPtr, &szyPtr, &rPtr,\
                                &thetaPtr, &phiPtr, &velxPtr,  &velyPtr, &velzPtr,  &densPtr,  &presPtr,  &gammaPtr,  &dens_labPtr, &tempPtr, &array_num, 1, min_r, max_r, fps, fPtr);
                    }

                    //check for run type
                    if(strcmp(cyl, this_run)==0)
                    {
                        //printf("In cylindrical prep\n");
                        cylindricalPrep(gammaPtr, velxPtr, velyPtr, densPtr, dens_labPtr, presPtr, tempPtr, array_num);
                    }
                    else if (strcmp(sph, this_run)==0)
                    {
                        sphericalPrep(rPtr, xPtr, yPtr,gammaPtr, velxPtr, velyPtr, densPtr, dens_labPtr, presPtr, tempPtr, array_num );
                    }

                    //determine where to place photons and how many should go in a given place
                    //for a checkpoint implmentation, dont need to inject photons, need to load photons' last saved data
                    fprintf(fPtr,">>  Thread: %d with ancestor %d: Injecting photons\n",omp_get_thread_num(), omp_get_ancestor_thread_num(1));
                    fflush(fPtr);

                    if (dim_switch==0)
                    {
                        photonInjection(&phPtr, &num_ph, inj_radius, ph_weight_suggest, min_photons, max_photons,spect, array_num, fps, theta_jmin_thread, theta_jmax_thread, xPtr, yPtr, szxPtr, szyPtr,rPtr,thetaPtr, tempPtr, velxPtr, velyPtr,rng[omp_get_thread_num()] );
                    }
                    else
                    {
                        photonInjection3D(&phPtr, &num_ph, inj_radius, ph_weight_suggest, min_photons, max_photons,spect, array_num, fps, theta_jmin_thread, theta_jmax_thread, xPtr, yPtr, zPtr, szxPtr, szyPtr,rPtr,thetaPtr, phiPtr, tempPtr, velxPtr, velyPtr, velzPtr, rng[omp_get_thread_num()] );
                    }

                    //printf("%d\n",num_ph); //num_ph is one more photon than i actually have
                    /*
                    for (i=0;i<num_ph;i++)
                        printf("%e,%e,%e \n",(phPtr+i)->r0, (phPtr+i)->r1, (phPtr+i)->r2 );
                    */
                }

                //scatter photons all the way thoughout the jet
                //for a checkpoint implmentation, start from the last saved "scatt_frame" value eh start_frame=frame or start_frame=cont_frame
                if (restrt=='r')
                {
                    scatt_framestart=frame; //have to make sure that once the inner loop is done and the outer loop is incrememnted by one the inner loop starts at that new value and not the one read by readCheckpoint()
                }

                for (scatt_frame=scatt_framestart;scatt_frame<=last_frm;scatt_frame++)
                {
                    fprintf(fPtr,">>\n");
                    fprintf(fPtr,">> Thread %d with ancestor %d : Working on photons injected at frame: %d out of %d\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),frame, frm2);
                    fprintf(fPtr,">> Thread %d with ancestor %d: %s - Working on frame %d\n",omp_get_thread_num(), omp_get_ancestor_thread_num(1), THISRUN, scatt_frame);
                    fprintf(fPtr,">> Thread %d with ancestor %d: Opening file...\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1));
                    fflush(fPtr);

                    if (dim_switch==0)
                    {
                        //put proper number at the end of the flash file
                        modifyFlashName(flash_file, flash_prefix, scatt_frame, dim_switch);
                        #pragma omp critical
                        {
                            phMinMax(phPtr, num_ph, &min_r, &max_r);
                            readAndDecimate(flash_file, inj_radius, fps, &xPtr,  &yPtr,  &szxPtr, &szyPtr, &rPtr,\
                                &thetaPtr, &velxPtr,  &velyPtr,  &densPtr,  &presPtr,  &gammaPtr,  &dens_labPtr, &tempPtr, &array_num, 0, min_r, max_r, fPtr);
                        }
                    }
                    else
                    {
                        phMinMax(phPtr, num_ph, &min_r, &max_r);

                        read_hydro(FILEPATH, scatt_frame, inj_radius, &xPtr,  &yPtr, &zPtr,  &szxPtr, &szyPtr, &rPtr,\
                                &thetaPtr, &phiPtr, &velxPtr,  &velyPtr, &velzPtr,  &densPtr,  &presPtr,  &gammaPtr,  &dens_labPtr, &tempPtr, &array_num, 0, min_r, max_r, fps, fPtr);
                    }

                    //check for run type
                    if(strcmp(cyl, this_run)==0)
                    {
                        //printf("In cylindrical prep\n");
                        cylindricalPrep(gammaPtr, velxPtr, velyPtr, densPtr, dens_labPtr, presPtr, tempPtr, array_num);
                    }
                    else if (strcmp(sph, this_run)==0)
                    {
                        sphericalPrep(rPtr, xPtr, yPtr,gammaPtr, velxPtr, velyPtr, densPtr, dens_labPtr, presPtr, tempPtr, array_num );
                    }
                        //printf("The result of read and decimate are arrays with %d elements\n", array_num);

                    fprintf(fPtr,">> Thread %d with ancestor %d: propagating and scattering %d photons\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1),num_ph);
                    fflush(fPtr);

                    frame_scatt_cnt=0;
                    while (time_now<((scatt_frame+1)/fps))
                    {
                        //if simulation time is less than the simulation time of the next frame, keep scattering in this frame
                        //go through each photon and find blocks closest to each photon and properties of those blocks to calulate mean free path
                        //and choose the photon with the smallest mfp and calculate the timestep

                        ph_scatt_index=findNearestPropertiesAndMinMFP(phPtr, num_ph, array_num, &time_step, xPtr,  yPtr, zPtr, velxPtr,  velyPtr,  velzPtr, dens_labPtr, tempPtr,\
                            &ph_dens_labPtr, &ph_vxPtr, &ph_vyPtr, &ph_vzPtr, &ph_tempPtr, rng[omp_get_thread_num()], dim_switch);

                        //printf("In main: %e, %d, %e, %e\n", *(ph_num_scatt+ph_scatt_index), ph_scatt_index, time_step, time_now);
                        printf("In main: %e, %d, %e, %e\n",((phPtr+ph_scatt_index)->num_scatt), ph_scatt_index, time_step, time_now);

                         if (time_step<dt_max)
                        {

                            //update number of scatterings and time
                            //(*(ph_num_scatt+ph_scatt_index))+=1;
                            ((phPtr+ph_scatt_index)->num_scatt)+=1;
                            frame_scatt_cnt+=1;
                            time_now+=time_step;

                            updatePhotonPosition(phPtr, num_ph, time_step);

                            //scatter the photon
                            //printf("Passed Parameters: %e, %e, %e\n", (ph_vxPtr), (ph_vyPtr), (ph_tempPtr));

                            photonScatter( (phPtr+ph_scatt_index), (ph_vxPtr), (ph_vyPtr), ph_vzPtr, (ph_tempPtr), rng[omp_get_thread_num()] , dim_switch, fPtr);

                            //if (frame_scatt_cnt%1000 == 0)
                            {
                                fprintf(fPtr,"Scattering Number: %d\n", frame_scatt_cnt);
                                fprintf(fPtr,"The local temp is: %e\n", (ph_tempPtr));
                                fprintf(fPtr,"Average photon energy is: %e\n", averagePhotonEnergy(phPtr, num_ph)); //write function to average over the photons p0 and then do (*3e10/1.6e-9)
                                fflush(fPtr);
                            }

                        }
                        else
                        {
                            time_now+=dt_max;

                            //for each photon update its position based on its momentum

                            updatePhotonPosition(phPtr, num_ph, dt_max);
                        }

                        //printf("In main 2: %e, %d, %e, %e\n", ((phPtr+ph_scatt_index)->num_scatt), ph_scatt_index, time_step, time_now);

                    }

                //get scattering statistics
                phScattStats(phPtr, num_ph, &max_scatt, &min_scatt, &avg_scatt);

                fprintf(fPtr,"The number of scatterings in this frame is: %d\n", frame_scatt_cnt);
                fprintf(fPtr,"The last time step was: %lf.\nThe time now is: %lf\n", time_step,time_now);
                fprintf(fPtr,"The maximum number of scatterings for a photon is: %d\nThe minimum number of scattering for a photon is: %d\n", max_scatt, min_scatt);
                fprintf(fPtr,"The average number of scatterings thus far is: %lf\n", avg_scatt);
                fflush(fPtr);

                printPhotons(phPtr, num_ph,  scatt_frame , frame, mc_dir);
                exit(0);
                //for a checkpoint implmentation,save the checkpoint file here after every 5 frames or something
                //save the photons data, the scattering number data, the scatt_frame value, and the frame value
                //WHAT IF THE PROGRAM STOPS AFTER THE LAST SCATT_FRAME, DURING THE FIRST SCATT_FRAME OF NEW FRAME VARIABLE - save restrt variable as 'r'
                fprintf(fPtr, ">> Thread %d with ancestor %d: Making checkpoint file\n", omp_get_thread_num(), omp_get_ancestor_thread_num(1));
                fflush(fPtr);
                saveCheckpoint(mc_dir, frame, scatt_frame, num_ph, time_now, phPtr, last_frm);

                free(xPtr);free(yPtr);free(szxPtr);free(szyPtr);free(rPtr);free(thetaPtr);free(velxPtr);free(velyPtr);free(densPtr);free(presPtr);
                free(gammaPtr);free(dens_labPtr);free(tempPtr);
                xPtr=NULL; yPtr=NULL;  rPtr=NULL;thetaPtr=NULL;velxPtr=NULL;velyPtr=NULL;densPtr=NULL;presPtr=NULL;gammaPtr=NULL;dens_labPtr=NULL;
                szxPtr=NULL; szyPtr=NULL; tempPtr=NULL;
                }
                restrt='r';//set this to make sure that the next iteration of propogating photons doesnt use the values from the last reading of the checkpoint file
                free(phPtr);
                phPtr=NULL;

            }

        }//end omp parallel inner section

        //merge files from each worker thread within a directory
        //dirFileMerge(mc_dir, frm0, last_frm);

    } //end omp parallel section

    //gsl_rng_free (rand);
    //free rand number generator
    for (j=0;j<num_thread;j++)
    {
        gsl_rng_free(rng[j]);
    }
    free(rng);
    free(thread_theta);

	return 0;

}


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_drot (const int N, double *X, const int incX, double *Y, const int incY,
	    const double c, const double s)
{
#define BASE double
#include "source_rot.h"
#undef BASE
}


/**
 *
 * @file qwrapper_slange.c
 *
 *  PLASMA core_blas quark wrapper
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Julien Langou
 * @author Henricus Bouwmeester
 * @author Mathieu Faverge
 * @date 2010-11-15
 * @generated s Tue Jan  7 11:44:56 2014
 *
 **/
#include <lapacke.h>
#include "common.h"

/***************************************************************************//**
 *
 **/
void QUARK_CORE_slange(Quark *quark, Quark_Task_Flags *task_flags,
                       int norm, int M, int N,
                       const float *A, int LDA, int szeA,
                       int szeW, float *result)
{
    szeW = max(1, szeW);
    DAG_CORE_LANGE;
    QUARK_Insert_Task(quark, CORE_slange_quark, task_flags,
        sizeof(PLASMA_enum),                &norm,  VALUE,
        sizeof(int),                        &M,     VALUE,
        sizeof(int),                        &N,     VALUE,
        sizeof(float)*szeA,     A,             INPUT,
        sizeof(int),                        &LDA,   VALUE,
        sizeof(float)*szeW,                 NULL,          SCRATCH,
        sizeof(float),                      result,        OUTPUT,
        0);
}

/***************************************************************************//**
 *
 **/
void QUARK_CORE_slange_f1(Quark *quark, Quark_Task_Flags *task_flags,
                          PLASMA_enum norm, int M, int N,
                          const float *A, int LDA, int szeA,
                          int szeW, float *result,
                          float *fake, int szeF)
{
    szeW = max(1, szeW);
    DAG_CORE_LANGE;

    if ( result == fake ) {
        QUARK_Insert_Task(quark, CORE_slange_quark, task_flags,
            sizeof(PLASMA_enum),                &norm,  VALUE,
            sizeof(int),                        &M,     VALUE,
            sizeof(int),                        &N,     VALUE,
            sizeof(float)*szeA,     A,             INPUT,
            sizeof(int),                        &LDA,   VALUE,
            sizeof(float)*szeW,                 NULL,          SCRATCH,
            sizeof(float),                      result,        OUTPUT | GATHERV,
            0);
    } else {
        QUARK_Insert_Task(quark, CORE_slange_f1_quark, task_flags,
            sizeof(PLASMA_enum),                &norm,  VALUE,
            sizeof(int),                        &M,     VALUE,
            sizeof(int),                        &N,     VALUE,
            sizeof(float)*szeA,     A,             INPUT,
            sizeof(int),                        &LDA,   VALUE,
            sizeof(float)*szeW,                 NULL,          SCRATCH,
            sizeof(float),                      result,        OUTPUT,
            sizeof(float)*szeF,                 fake,          OUTPUT | GATHERV,
            0);
    }
}

/***************************************************************************//**
 *
 **/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_slange_quark = PCORE_slange_quark
#define CORE_slange_quark PCORE_slange_quark
#endif
void CORE_slange_quark(Quark *quark)
{
    float *normA;
    int norm;
    int M;
    int N;
    float *A;
    int LDA;
    float *work;

    quark_unpack_args_7(quark, norm, M, N, A, LDA, work, normA);
    *normA = LAPACKE_slange_work(
        LAPACK_COL_MAJOR,
        lapack_const(norm),
        M, N, A, LDA, work);
}

/***************************************************************************//**
 *
 **/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_slange_f1_quark = PCORE_slange_f1_quark
#define CORE_slange_f1_quark PCORE_slange_f1_quark
#endif
void CORE_slange_f1_quark(Quark *quark)
{
    float *normA;
    int norm;
    int M;
    int N;
    float *A;
    int LDA;
    float *work;
    float *fake;

    quark_unpack_args_8(quark, norm, M, N, A, LDA, work, normA, fake);
    *normA = LAPACKE_slange_work(
        LAPACK_COL_MAJOR,
        lapack_const(norm),
        M, N, A, LDA, work);
}