#ifndef SUNDIALS_DEF
#define SUNDIALS_DEF
#include <sundials/sundials_types.h>
#include <nvector/nvector_openmp.h>
#endif

#ifndef PRINT_DEF
#define PRINT_DEF
#include <string.h>	//for strings
#include <string>
#include <cstring>
#include <stdio.h>	//for printf,scanf
#include <stdlib.h>	//for atoi, atof
#endif

#ifndef CANTERA_DEF
#define CANTERA_DEF
#include <cantera/IdealGasMix.h>
#include <cantera/transport.h>
#endif

#ifndef COOLPROP_DEF
#define COOLPROP_DEF
#include <CoolProp.h>   //for gas-phase thermodynamic properties
//#include <HumidAirProp.h>
//#include <CPState.h>
#endif

#include "UserData.h"
#include <vector> //add the vector module

void REGRID(double* ydata,double* ydotdata,UserData data);

void INTERPO(double* y,double* ydot,const size_t nvar,size_t nPts,const double XNEW[], const double XOLD[]);

double maxTemperaturePosition(const double* y,const size_t nt,const size_t nvar,const double* x ,size_t nPts);

double maxTemperature(const double* y,const size_t nt, const size_t nvar, size_t nPts); 

int maxTemperatureIndex(const double* y,const size_t nt,const size_t nvar ,size_t nPts);

double maxCurvPositionR(const double* y, const size_t nt, 
	               const size_t nvar, const size_t nr, size_t nPts);

int maxCurvIndexR(const double* y, const size_t nt, 
	               const size_t nvar, const size_t nr, size_t nPts);

double maxGradPosition(const double* y, const size_t nt, 
	               const size_t nvar, const double* x, size_t nPts);

int maxGradIndex(const double* y, const size_t nt, 
	         const size_t nvar, const double* x, size_t nPts);

double maxCurvPosition(const double* y, const size_t nt, 
	               const size_t nvar, const double* x, size_t nPts);

int maxCurvIndex(const double* y, const size_t nt, 
	               const size_t nvar, const double* x, size_t nPts);

double isothermPosition(const double* y, const double T, const size_t nt, 
	                const size_t nvar, const double* x, const size_t nPts);

int setAlgebraicVariables(N_Vector *id,UserData data,const double* ydata);

inline double calc_area(double x,int* i);

void updateSolution(double* y, double* ydot, const size_t nvar,
		    const double xOld[],const double xNew[],const size_t npts);

void readInitialCondition(FILE* input, double* ydata, const size_t nvar, const size_t nr, const size_t nPts);

double systemMass(double* ydata, UserData data);

int initializePsiGrid(double* ydata, double* psidata, UserData data);

int setInitialCondition(N_Vector* y, 
	    		N_Vector* ydot, 
            		UserData data);


inline void setGas(UserData data, double *ydata, size_t gridPoint);

void getTransport(UserData data, 
		  double *ydata, 
		  size_t gridPoint,
		  double *rho,
		  double *lambda,
		  double *YV);

int residue(double t, 
	    N_Vector y, 
	    N_Vector ydot, 
	    N_Vector res, 
            void *user_data);

void trackFlameOH(N_Vector y,UserData data);
void trackFlame(N_Vector y,UserData data);
size_t BathGasIndex(UserData data);
size_t oxidizerIndex(UserData data);

inline double Qdot(double* t, 
	           double* x, 
	           double* ignTime, 
	           double* kernelSize, 
	           double* maxQdot);

void printSpaceTimeHeader(UserData data);
void printSpaceTimeOutput(double t, N_Vector* y, FILE* output, UserData data);
void printSpaceTimeRates(double t, N_Vector ydot, UserData data);
void printGlobalHeader(UserData data);
void printGlobalVariables(double t, N_Vector* y, N_Vector* ydot, UserData data);
void printSpaceTimeOutputInterpolated(double t, N_Vector y, UserData data);

void writeRestart(double t, N_Vector* y, N_Vector* ydot, FILE* output, UserData data);
void readRestart(N_Vector* y, N_Vector* ydot, FILE* input, UserData data);

void getTimescale(UserData data, N_Vector* y);
void printTimescaleHeader(UserData data);
void printTimescaleOutput(double t,N_Vector* y,FILE* output,UserData data);
void floorSmallValue(UserData data, N_Vector* y);
void resetTolerance(UserData data, N_Vector* y,N_Vector* atolv);

void getReactions(UserData data,N_Vector* y,FILE* output);
void getSpecies(UserData data,N_Vector* y,FILE* output);

double getLiquidRho(double dropMole[],double temp,double pres);
double getLiquidCp(double dropMole[],double temp,double pres);
double getLiquidHv(double dropMole[],double temp,double pres);
double getLiquidMaxT(double dropMole[],double pres);