@@ -0,0 +1,91 @@ | |||||
#compiler =icpc | |||||
#CANTERA_DIR =/opt/scientific/cantera-2.3_intel_mkl | |||||
#IDA_DIR =/opt/scientific/sundials-3.1.1_intel_mkl | |||||
#EXE =lagrangianCombustion2 | |||||
#DESTDIR =~/bin | |||||
compiler =g++ | |||||
CANTERA_DIR =/opt/scientific/cantera-2.4_gnu_blas | |||||
IDA_DIR =/opt/scientific/sundials-3.1.1_gnu_lapack | |||||
EXE =lagrangianCombustion | |||||
DESTDIR =~/bin | |||||
CANTERA_INCLUDES=-I$(CANTERA_DIR)/include | |||||
GSL_INCLUDES =-I/usr/include/gsl | |||||
GSL_LIBS =-L/usr/lib -lgsl -lgslcblas | |||||
IDA_INCLUDES =-I$(IDA_DIR)/include | |||||
SUN_INCLUDES =-I$(IDA_DIR)/include | |||||
IDA_LIBS =-L$(IDA_DIR)/lib -lsundials_nvecopenmp \ | |||||
-lsundials_ida -lsundials_sunlinsollapackband | |||||
CANTERA_LIBS =-L$(CANTERA_DIR)/lib -lcantera_shared | |||||
RPATH =-Wl,-rpath=$(IDA_DIR)/lib,-rpath=$(CANTERA_DIR)/lib | |||||
RM=rm -f | |||||
compiler?=g++ | |||||
ifeq ($(compiler),g++) | |||||
CPPFLAGS= -Wall -O3 | |||||
CPP=g++ | |||||
endif | |||||
ifeq ($(compiler),icpc) | |||||
export GXX_INCLUDE=/usr/lib/gcc/x86_64-pc-linux-gnu/7.4.1/include/c++ | |||||
CPPFLAGS= -Wall -O3 -gxx-name=/usr/bin/g++-7 -std=c++11 | |||||
CPP=icpc | |||||
endif | |||||
OBJS = parse.o UserData.o gridRoutines.o residue.o solution.o main.o | |||||
all: $(EXE) | |||||
# pull in dependency info for *existing* .o files | |||||
-include $(OBJS:.o=.d) | |||||
parse.o: parse.cpp parse.h parse.hpp | |||||
$(CPP) $(CPPFLAGS) -c parse.cpp -o parse.o | |||||
$(CPP) -MM parse.cpp > parse.d | |||||
solution.o: solution.cpp solution.h | |||||
$(CPP) $(CPPFLAGS) $(CANTERA_INCLUDES) $(IDA_INCLUDES) \ | |||||
-c solution.cpp -o solution.o | |||||
$(CPP) -MM $(CANTERA_INCLUDES) $(IDA_INCLUDES) \ | |||||
solution.cpp > solution.d | |||||
residue.o: residue.cpp residue.h UserData.h gridRoutines.h | |||||
$(CPP) $(CPPFLAGS) $(CANTERA_INCLUDES) \ | |||||
$(IDA_INCLUDES) $(GSL_INCLUDES) -c residue.cpp \ | |||||
-o residue.o -fopenmp | |||||
$(CPP) -MM $(CANTERA_INCLUDES) \ | |||||
$(IDA_INCLUDES) $(GSL_INCLUDES) \ | |||||
residue.cpp > residue.d | |||||
gridRoutines.o: gridRoutines.cpp gridRoutines.h parse.h | |||||
$(CPP) $(CPPFLAGS) -c gridRoutines.cpp -o gridRoutines.o | |||||
$(CPP) -MM gridRoutines.cpp > gridRoutines.d | |||||
UserData.o: UserData.cpp UserData.h gridRoutines.h parse.h | |||||
$(CPP) $(CPPFLAGS) $(CANTERA_INCLUDES) \ | |||||
-c UserData.cpp -o UserData.o | |||||
$(CPP) -MM $(CANTERA_INCLUDES) \ | |||||
UserData.cpp > UserData.d | |||||
main.o: main.cpp UserData.h solution.h residue.h macros.h | |||||
$(CPP) $(CPPFLAGS) $(CANTERA_INCLUDES) $(IDA_INCLUDES) \ | |||||
-c main.cpp -o main.o | |||||
$(CPP) -MM $(CANTERA_INCLUDES) $(IDA_INCLUDES) \ | |||||
main.cpp > main.d | |||||
$(EXE): $(OBJS) | |||||
$(CPP) $(CPPFLAGS) $(IDA_INCLUDES) \ | |||||
$(CANTERA_INCLUDES) $(GSL_INCLUDES) $(RPATH) \ | |||||
$(OBJS) -o $(EXE) -fopenmp $(IDA_LIBS) \ | |||||
$(CANTERA_LIBS) $(GSL_LIBS) | |||||
.PHONY: install | |||||
install: | |||||
cp $(EXE) $(DESTDIR)/$(EXE) | |||||
.PHONY: clean | |||||
clean: | |||||
rm -f $(EXE) $(OBJS) *.d | |||||
@@ -0,0 +1,409 @@ | |||||
#include "UserData.h" | |||||
#include "parse.h" | |||||
void freeUserData(UserData data){ | |||||
if(data!=NULL){ | |||||
if(data->trmix!=NULL){ | |||||
delete data->trmix; | |||||
printf("Transport Deleted!\n"); | |||||
} | |||||
if(data->gas!=NULL){ | |||||
delete data->gas; | |||||
printf("Gas Deleted!\n"); | |||||
} | |||||
if(data->adaptiveGrid){ | |||||
if(data->grid->xOld!=NULL){ | |||||
delete[] data->grid->xOld; | |||||
printf("old grid array Deleted!\n"); | |||||
} | |||||
if(data->grid->x!=NULL){ | |||||
delete[] data->grid->x; | |||||
printf("current grid array Deleted!\n"); | |||||
} | |||||
if(data->grid!=NULL){ | |||||
free(data->grid); | |||||
printf("grid object Freed!\n"); | |||||
} | |||||
} | |||||
else{ | |||||
if(data->uniformGrid!=NULL){ | |||||
delete[] data->uniformGrid; | |||||
printf("uniformGrid deleted!\n"); | |||||
} | |||||
} | |||||
if(data->innerMassFractions!=NULL){ | |||||
delete[] data->innerMassFractions; | |||||
printf("innerMassFractions array Deleted!\n"); | |||||
} | |||||
if(data->output!=NULL){ | |||||
fclose(data->output); | |||||
printf("Output File Cleared from Memory!\n"); | |||||
} | |||||
if(data->gridOutput!=NULL){ | |||||
fclose(data->gridOutput); | |||||
printf("Grid Output File Cleared from Memory!\n"); | |||||
} | |||||
//if(data->ratesOutput!=NULL){ | |||||
// fclose(data->ratesOutput); | |||||
// printf("Rates Output File Cleared from Memory!\n"); | |||||
//} | |||||
if(data->globalOutput!=NULL){ | |||||
fclose(data->globalOutput); | |||||
printf("Global Output File Cleared from Memory!\n"); | |||||
} | |||||
} | |||||
free(data); /* Free the user data */ | |||||
printf("\n\n"); | |||||
} | |||||
UserData allocateUserData(FILE *input){ | |||||
UserData data; | |||||
data = (UserData) malloc(sizeof *data); | |||||
if(!data){ | |||||
printf("Allocation Failed!\n"); | |||||
return(NULL); | |||||
} | |||||
setSaneDefaults(data); | |||||
int ier; | |||||
ier=parseNumber<size_t>(input, "basePts" , MAXBUFLEN, &data->npts); | |||||
if(ier==-1 || data->npts<=0){ | |||||
printf("Enter non-zero basePts!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "domainLength", MAXBUFLEN, &data->domainLength); | |||||
if(ier==-1 || data->domainLength<=0.0e0){ | |||||
printf("domainLength error!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int>(input, "constantPressure" , MAXBUFLEN, &data->constantPressure); | |||||
if(ier==-1 || (data->constantPressure!=0 && data->constantPressure!=1)){ | |||||
printf("constantPressure error!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int>(input, "problemType" , MAXBUFLEN, &data->problemType); | |||||
if(ier==-1 || (data->problemType!=0 | |||||
&& data->problemType!=1 | |||||
&& data->problemType!=2 | |||||
&& data->problemType!=3)){ | |||||
printf("include valid problemType!\n"); | |||||
printf("0: premixed combustion with NO equilibrated ignition kernel\n"); | |||||
printf("1: premixed combustion WITH equilibrated ignition kernel\n"); | |||||
printf("2: arbitrary initial conditions\n"); | |||||
printf("3: Restart\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "dPdt" , MAXBUFLEN, &data->dPdt); | |||||
ier=parseNumber<int> (input, "reflectProblem" , MAXBUFLEN, &data->reflectProblem); | |||||
if(data->reflectProblem!=0 && data->reflectProblem!=1){ | |||||
printf("Invalid entry for reflectProblem! Can be only 1 or 0.\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "mdot" , MAXBUFLEN, &data->mdot); | |||||
ier=parseNumber<double>(input, "initialTemperature", MAXBUFLEN, | |||||
&data->initialTemperature); | |||||
if(ier==-1 || data->initialTemperature<=0.0e0){ | |||||
printf("Enter positive initialTemperature in K!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "initialPressure", MAXBUFLEN, | |||||
&data->initialPressure); | |||||
if(ier==-1 || data->initialTemperature<=0.0e0){ | |||||
printf("Enter positive initialPressure in atm!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "metric" , MAXBUFLEN, &data->metric); | |||||
if(data->metric!=0 && data->metric!=1 && data->metric!=2){ | |||||
printf("Invalid entry for metric!\n"); | |||||
printf("0: Cartesian\n"); | |||||
printf("1: Cylindrical\n"); | |||||
printf("2: Spherical\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "QDot", MAXBUFLEN, &data->maxQDot); | |||||
if(ier==-1 && data->problemType==0){ | |||||
printf("Need to specify QDot for problemType 0!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "kernelSize", MAXBUFLEN, &data->kernelSize); | |||||
if(ier==-1 && data->problemType==0){ | |||||
printf("Need to specify kernelSize for problemType 0!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "ignTime", MAXBUFLEN, &data->ignTime); | |||||
if(ier==-1 && data->problemType==0){ | |||||
printf("Need to specify ignTime for problemType 0!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "mixingWidth", MAXBUFLEN, | |||||
&data->mixingWidth); | |||||
if(ier==-1){ | |||||
printf("Need to specify mixingWidth!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "shift", MAXBUFLEN, &data->shift); | |||||
ier=parseNumber<double>(input, "firstRadius", MAXBUFLEN, &data->firstRadius); | |||||
ier=parseNumber<double>(input, "wallTemperature", MAXBUFLEN, &data->wallTemperature); | |||||
ier=parseNumber<int> (input, "dirichletInner" , MAXBUFLEN, | |||||
&data->dirichletInner); | |||||
if(data->dirichletInner!=0 && data->dirichletInner!=1){ | |||||
printf("dirichletInner can either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "dirichletOuter" , MAXBUFLEN, | |||||
&data->dirichletOuter); | |||||
if(data->dirichletOuter!=0 && data->dirichletOuter!=1){ | |||||
printf("dirichletOuter can either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "adaptiveGrid" , MAXBUFLEN, | |||||
&data->adaptiveGrid); | |||||
if(ier==-1 || (data->adaptiveGrid!=0 && data->adaptiveGrid!=1)){ | |||||
printf("specify adaptiveGrid as 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "moveGrid" , MAXBUFLEN, | |||||
&data->moveGrid); | |||||
if(ier==-1 || (data->moveGrid!=0 && data->moveGrid!=1)){ | |||||
printf("specify moveGrid as 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double> (input, "isotherm" , MAXBUFLEN, | |||||
&data->isotherm); | |||||
if(ier==-1){ | |||||
printf("specify temperature of isotherm!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double>(input, "gridOffset", MAXBUFLEN, &data->gridOffset); | |||||
ier=parseNumber<int> (input, "nSaves" , MAXBUFLEN, &data->nSaves); | |||||
if(data->nSaves<0 ){ | |||||
printf("nSaves must be greater than 0!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "writeRates" , MAXBUFLEN, | |||||
&data->writeRates); | |||||
if(data->writeRates!=0 && data->writeRates!=1){ | |||||
printf("writeRates must either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "writeEveryRegrid", MAXBUFLEN, | |||||
&data->writeEveryRegrid); | |||||
if(data->writeEveryRegrid!=0 && data->writeEveryRegrid!=1){ | |||||
printf("writeEveryRegrid must either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double> (input, "writeDeltaT", MAXBUFLEN, | |||||
&data->writeDeltaT); | |||||
ier=parseNumber<int> (input, "setConstraints" , MAXBUFLEN, | |||||
&data->setConstraints); | |||||
if(data->setConstraints!=0 && data->setConstraints!=1){ | |||||
printf("setConstraints must either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "suppressAlg" , MAXBUFLEN, | |||||
&data->suppressAlg); | |||||
if(data->setConstraints!=0 && data->suppressAlg!=1){ | |||||
printf("suppressAlg must either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<int> (input, "dryRun" , MAXBUFLEN, | |||||
&data->dryRun); | |||||
if(data->dryRun!=0 && data->dryRun!=1){ | |||||
printf("dryRun must either be 0 or 1!\n"); | |||||
return(NULL); | |||||
} | |||||
ier=parseNumber<double> (input, "finalTime" , MAXBUFLEN, | |||||
&data->finalTime); | |||||
ier=parseNumber<double> (input, "relativeTolerance" , MAXBUFLEN, | |||||
&data->relativeTolerance); | |||||
ier=parseNumber<double> (input, "radiusTolerance" , MAXBUFLEN, | |||||
&data->radiusTolerance); | |||||
ier=parseNumber<double> (input, "temperatureTolerance", MAXBUFLEN, | |||||
&data->temperatureTolerance); | |||||
ier=parseNumber<double> (input, "pressureTolerance", MAXBUFLEN, | |||||
&data->pressureTolerance); | |||||
ier=parseNumber<double> (input, "massFractionTolerance", MAXBUFLEN, | |||||
&data->massFractionTolerance); | |||||
ier=parseNumber<double> (input, "bathGasTolerance", MAXBUFLEN, | |||||
&data->bathGasTolerance); | |||||
char chem[MAXBUFLEN],mix[MAXBUFLEN],tran[MAXBUFLEN]; | |||||
ier=parseNumber<char>(input, "chemistryFile" , MAXBUFLEN, chem); | |||||
if(ier==-1){ | |||||
printf("Enter chemistryFile!\n"); | |||||
return(NULL); | |||||
}else{ | |||||
try{ | |||||
data->gas = new Cantera::IdealGasMix(chem); | |||||
data->nsp=data->gas->nSpecies(); //assign no: of species | |||||
} catch (Cantera::CanteraError& err) { | |||||
printf("Error:\n"); | |||||
printf("%s\n",err.what()); | |||||
return(NULL); | |||||
} | |||||
} | |||||
ier=parseNumber<char>(input, "transportModel", MAXBUFLEN, tran); | |||||
if(ier==-1){ | |||||
printf("Enter transportModel!\n"); | |||||
return(NULL); | |||||
}else{ | |||||
try{ | |||||
data->trmix = Cantera::newTransportMgr(tran, data->gas); | |||||
}catch (Cantera::CanteraError& err) { | |||||
printf("Error:\n"); | |||||
printf("%s\n",err.what()); | |||||
return(NULL); | |||||
} | |||||
} | |||||
ier=parseNumber<char>(input, "mixtureComposition", MAXBUFLEN, mix); | |||||
if(ier==-1){ | |||||
printf("Enter mixtureComposition!\n"); | |||||
return(NULL); | |||||
}else{ | |||||
if(data->gas!=NULL){ | |||||
try{ | |||||
data->gas->setState_TPX(data->initialTemperature, | |||||
data->initialPressure*Cantera::OneAtm, | |||||
mix); | |||||
}catch (Cantera::CanteraError& err) { | |||||
printf("Error:\n"); | |||||
printf("%s\n",err.what()); | |||||
return(NULL); | |||||
} | |||||
} | |||||
} | |||||
ier=parseNumber<int> (input, "nThreads" , MAXBUFLEN, &data->nThreads); | |||||
if(data->nThreads<0 ){ | |||||
printf("nThreads must be greater than 0!\n"); | |||||
return(NULL); | |||||
} | |||||
data->nr=0; | |||||
//data->np=data->nr+1; | |||||
data->nt=data->nr+1; | |||||
data->ny=data->nt+1; | |||||
data->np=data->ny+data->nsp; | |||||
data->nvar=data->nsp+3; //assign no: of variables (R,T,P,nsp species) | |||||
if(!data->adaptiveGrid){ | |||||
data->uniformGrid = new double [data->npts]; | |||||
data->neq=data->nvar*data->npts; | |||||
} | |||||
else{ | |||||
data->grid=(UserGrid) malloc(sizeof *data->grid); | |||||
ier=getGridSettings(input,data->grid); | |||||
if(ier==-1)return(NULL); | |||||
ier=initializeGrid(data->grid); | |||||
if(ier==-1)return(NULL); | |||||
ier=reGrid(data->grid, data->grid->position); | |||||
if(ier==-1)return(NULL); | |||||
data->npts=data->grid->nPts; | |||||
data->neq=data->nvar*data->npts; | |||||
} | |||||
data->output=fopen("output.dat","w"); | |||||
data->globalOutput=fopen("globalOutput.dat","w"); | |||||
data->gridOutput=fopen("grid.dat","w"); | |||||
//data->ratesOutput=fopen("rates.dat","w"); | |||||
data->innerMassFractions = new double [data->nsp]; | |||||
return(data); | |||||
} | |||||
void setSaneDefaults(UserData data){ | |||||
data->domainLength=1.0e-02; | |||||
data->constantPressure=1; | |||||
data->problemType=1; | |||||
data->dPdt=0.0e0; | |||||
data->reflectProblem=0; | |||||
data->mdot=0.0; | |||||
data->initialTemperature=300.0; | |||||
data->initialPressure=1.0; | |||||
data->metric=0; | |||||
data->ignTime=1e-09; | |||||
data->maxQDot=0.0e0; | |||||
data->maxTemperature=300.0e0; | |||||
data->mixingWidth=1e-04; | |||||
data->shift=3.0e-03; | |||||
data->firstRadius=1e-04; | |||||
data->wallTemperature=298.0e0; | |||||
data->dirichletInner=0; | |||||
data->dirichletOuter=0; | |||||
data->adaptiveGrid=0; | |||||
data->moveGrid=0; | |||||
data->gridOffset=0.0e0; | |||||
data->isotherm=1000.0; | |||||
data->nSaves=30; | |||||
data->writeRates=0; | |||||
data->writeEveryRegrid=0; | |||||
data->writeDeltaT=1e-04; | |||||
data->relativeTolerance=1e-06; | |||||
data->radiusTolerance=1e-08; | |||||
data->temperatureTolerance=1e-06; | |||||
data->pressureTolerance=1e-06; | |||||
data->massFractionTolerance=1e-09; | |||||
data->bathGasTolerance=1e-06; | |||||
data->finalTime=1e-02; | |||||
data->tNow=0.0e0; | |||||
data->setConstraints=0; | |||||
data->suppressAlg=1; | |||||
data->regrid=0; | |||||
data->gridDirection=1; | |||||
data->dryRun=0; | |||||
data->nThreads=1; | |||||
data->flamePosition[0]=0.0e0; | |||||
data->flamePosition[1]=0.0e0; | |||||
data->flameTime[0]=0.0e0; | |||||
data->flameTime[1]=0.0e0; | |||||
data->nTimeSteps=0; | |||||
} | |||||
@@ -0,0 +1,170 @@ | |||||
#ifndef CANTERA_DEF | |||||
#define CANTERA_DEF | |||||
#include <cantera/IdealGasMix.h> | |||||
#include <cantera/transport.h> | |||||
#endif | |||||
#include "gridRoutines.h" | |||||
#ifndef USER_DEF | |||||
#define USER_DEF | |||||
typedef struct UserDataTag{ | |||||
/*An ideal gas object from Cantera. Contains thermodynamic and kinetic | |||||
* info of all species.*/ | |||||
Cantera::IdealGasMix* gas; | |||||
/*A Transport object from Cantera. Contains all transport info of all | |||||
* species.*/ | |||||
Cantera::Transport* trmix; | |||||
/*Length of the domain (in meters):*/ | |||||
double domainLength; | |||||
/*Mass of gas in domain (in kg):*/ | |||||
double mass; | |||||
/*Parameter that indicates the symmetry of the problem;*/ | |||||
/*metric=0:Planar*/ | |||||
/*metric=1:Cylindrical*/ | |||||
/*metric=2:Spherical*/ | |||||
int metric; | |||||
/*No: of species:*/ | |||||
size_t nsp; | |||||
/*No: of equations:*/ | |||||
size_t neq; | |||||
/*No: of variables:*/ | |||||
size_t nvar; | |||||
/*Pointer indices (see "macros.h" for aliases that use these):*/ | |||||
/*Pointer index for temperature:*/ | |||||
size_t nt; | |||||
/*Pointer index for species:*/ | |||||
size_t ny; | |||||
/*Pointer index for spatial coordinate:*/ | |||||
size_t nr; | |||||
/*Pointer index for pressure:*/ | |||||
size_t np; | |||||
/*Species index of bath gas:*/ | |||||
size_t k_bath; | |||||
/*Species index of oxidizer:*/ | |||||
size_t k_oxidizer; | |||||
size_t k_OH; | |||||
size_t k_HO2; | |||||
/*User-defined mass flux (kg/m^2/s):*/ | |||||
double mdot; | |||||
/*Flag to solve isobaric/isochoric problem;*/ | |||||
/*constantPressure=1: isobaric*/ | |||||
/*constantPressure=0: isochoric*/ | |||||
int constantPressure; | |||||
/*User-defined dPdt (Pa/s), activates when problem is "isobaric":*/ | |||||
double dPdt; | |||||
/*Initial temperature of the gas (K):*/ | |||||
double initialTemperature; | |||||
/*Initial Pressure of the gas (atm):*/ | |||||
double initialPressure; | |||||
/*Classification of problem type;*/ | |||||
/*problemType=0: Mixture is premixed and spatially uniform initially. | |||||
* In order for mixture to ignite, an external heat source (finite | |||||
* maxQDot) must be used.*/ | |||||
/*problemType=1: Mixture is premixed but spatially non-uniform | |||||
* initially. Equilibrium products are contained within a hot kernel of | |||||
* size given by "shift" and a mixing length scale given by | |||||
* "mixingWidth".*/ | |||||
/*problemType=2: User specified initial condition. Use file | |||||
* "initialCondition.dat".*/ | |||||
int problemType; | |||||
/*Maximum External heat source (K/s):*/ | |||||
double maxQDot; | |||||
/*Ignition kernel size:*/ | |||||
double kernelSize; | |||||
double maxTemperature; | |||||
/*Maximum time for which the external heat source is applied (s):*/ | |||||
double ignTime; | |||||
/*Vector of Mass Fractions used to impose Robin Boundary Condition for | |||||
* species at the domain origin:*/ | |||||
double* innerMassFractions; | |||||
/*Value of temperature to be used if Dirichlet Boundary Conditions are | |||||
* imposed for temperature:*/ | |||||
double innerTemperature; | |||||
double wallTemperature; | |||||
/*Isotherm chosen to find the location of a "burning" front (K):*/ | |||||
double isotherm; | |||||
/*Interval of time integration:*/ | |||||
double finalTime; | |||||
/*Current time:*/ | |||||
double tNow; | |||||
/*Flag to reflect initial conditions across center of the domain:*/ | |||||
int reflectProblem; | |||||
/*Parameters for initial conditions in setting up profiles: | |||||
increasing function of x: g=0.5*(erf(x-3*w-shift)/w)+1) | |||||
decreasing function of x: f=1-g*/ | |||||
double mixingWidth; | |||||
double shift; | |||||
double firstRadius; | |||||
/*Flag to run program without time-integration i.e. simply layout the | |||||
* initial conditions and quit:*/ | |||||
int dryRun; | |||||
/*Relative Tolerance:*/ | |||||
double relativeTolerance; | |||||
/*Absolute Tolerance for spatial coordinate:*/ | |||||
double radiusTolerance; | |||||
/*Absolute Tolerance for Temperature:*/ | |||||
double temperatureTolerance; | |||||
/*Absolute Tolerance for Pressure:*/ | |||||
double pressureTolerance; | |||||
/*Absolute Tolerance for Mass Fractions:*/ | |||||
double massFractionTolerance; | |||||
/*Absolute Tolerance for bath gas mass fraction:*/ | |||||
double bathGasTolerance; | |||||
/*Flag to set constraints on Mass fractions so they don't acquire | |||||
* negative values:*/ | |||||
int setConstraints; | |||||
/*Flag to suppress error checking on algebraic variables:*/ | |||||
int suppressAlg; | |||||
/*Number of time-steps elapsed before saving the solution:*/ | |||||
int nSaves; | |||||
/*Flag to set write for every regrid:*/ | |||||
int writeEveryRegrid; | |||||
double writeDeltaT; | |||||
/*Solution output file:*/ | |||||
FILE* output; | |||||
/*Flag to write the rates (ydot) of solution components into the | |||||
* "ratesOutput" file:*/ | |||||
int writeRates; | |||||
/*Grid output file:*/ | |||||
FILE* gridOutput; | |||||
///*Rate of change (ydot) output file (see "writeRates"):*/ | |||||
//FILE* ratesOutput; | |||||
/*Global properties (mdot, radius of flame, etc.) output file:*/ | |||||
FILE* globalOutput; | |||||
/*Flag to adapt grid:*/ | |||||
int adaptiveGrid; | |||||
/*Flag to move grid:*/ | |||||
int moveGrid; | |||||
/*Flag to initiate regrid:*/ | |||||
int regrid; | |||||
/*Integer that specifies grid movement direction: | |||||
* gridDirection = -1: Move Left | |||||
* gridDirection = +1: Move Right*/ | |||||
int gridDirection; | |||||
/*Total number of points for grid:*/ | |||||
size_t npts; | |||||
double gridOffset; | |||||
UserGrid grid; | |||||
double* uniformGrid; | |||||
int dirichletInner,dirichletOuter; | |||||
int nThreads; | |||||
double clockStart; | |||||
/*These arrays are used to compute dr/dt, which in turn is used to | |||||
* compute the flame speed S_u:*/ | |||||
double flamePosition[2]; | |||||
double flameTime[2]; | |||||
size_t nTimeSteps; | |||||
} *UserData; | |||||
UserData allocateUserData(FILE *input); | |||||
void setSaneDefaults(UserData data); | |||||
void freeUserData(UserData data); | |||||
#endif | |||||
@@ -0,0 +1,244 @@ | |||||
#include "gridRoutines.h" | |||||
#include <stdio.h> | |||||
inline double l(const double* x, | |||||
const double* a, | |||||
const double* w, | |||||
const double* fac, | |||||
const int* refineLeft){ | |||||
if(*refineLeft==0){ | |||||
return(tanh(-*a*(*x+*w*100.0e0))); | |||||
}else{ | |||||
return(tanh(-*a*(*x-*w*(*fac)))); | |||||
} | |||||
} | |||||
inline double r(const double* x, | |||||
const double* a, | |||||
const double* w, | |||||
const double* fac, | |||||
const int* refineRight){ | |||||
if(*refineRight==0){ | |||||
return(tanh(*a*(*x-(1.0e0+*w*100.0e0)))); | |||||
}else{ | |||||
return(tanh(*a*(*x-(1.0e0-*w*(*fac))))); | |||||
} | |||||
} | |||||
inline double f(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w){ | |||||
return(tanh(-*a*(*x-(*c+*w))) | |||||
+tanh(-*a*((*x-1.0e0)-(*c+*w))) | |||||
+tanh(-*a*((*x+1.0e0)-(*c+*w)))); | |||||
} | |||||
inline double g(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w){ | |||||
return(tanh(*a*(*x-(*c-*w))) | |||||
+tanh(*a*((*x-1.0e0)-(*c-*w))) | |||||
+tanh(*a*((*x+1.0e0)-(*c-*w)))); | |||||
} | |||||
inline double rho(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w, | |||||
const double* mag, | |||||
const double* leftFac, | |||||
const double* rightFac, | |||||
const int* refineLeft, | |||||
const int* refineRight){ | |||||
return(((2.0e0+f(x,a,c,w) | |||||
+g(x,a,c,w) | |||||
+l(x,a,w,leftFac,refineLeft) | |||||
+r(x,a,w,rightFac,refineRight))*0.5e0) | |||||
*(*mag-1.0e0)+1.0e0); | |||||
} | |||||
size_t maxPoints(const size_t basePts, | |||||
const double* a, | |||||
const double* w, | |||||
const double* mag, | |||||
const double* leftFac, | |||||
const double* rightFac, | |||||
const int* refineLeft, | |||||
const int* refineRight){ | |||||
double dx=1.0e0/((double)(basePts)-1.0e0); | |||||
double y=0.0e0; | |||||
size_t i=0; | |||||
double r=0.0e0; | |||||
double t=0.5e0; | |||||
while(y<=1.0e0){ | |||||
r=rho(&y,a,&t,w,mag,leftFac,rightFac,refineLeft,refineRight); | |||||
y=y+(dx/r); | |||||
i++; | |||||
} | |||||
return(i); | |||||
} | |||||
void fillGrid(const size_t* basePts, | |||||
const size_t* nPts, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w, | |||||
const double* mag, | |||||
const double* leftFac, | |||||
const double* rightFac, | |||||
const int* refineLeft, | |||||
const int* refineRight, | |||||
double x[]){ | |||||
FILE* out;out=fopen("tmp.dat","w"); | |||||
double y=0.0e0; | |||||
double r=0.0e0; | |||||
double dx=1.0e0/((double)(*basePts)-1.0e0); | |||||
for(size_t j=0;j<*nPts;j++){ | |||||
r=rho(&y,a,c,w,mag,leftFac,rightFac,refineLeft,refineRight); | |||||
fprintf(out, "%15.15e\n",dx/r); | |||||
y=y+(dx/r); | |||||
} | |||||
fclose(out); | |||||
double dxp[*nPts-1]; | |||||
for (size_t j = 0; j < *nPts; j++) { | |||||
dxp[j]=0.0e0; | |||||
} | |||||
FILE* tmp;tmp=fopen("tmp.dat","r"); | |||||
char buf[MAXBUFLEN]; | |||||
size_t i=0; | |||||
while (fgets(buf,MAXBUFLEN, tmp)!=NULL){ | |||||
sscanf(buf, "%lf", &y); | |||||
dxp[i]=y; | |||||
i++; | |||||
} | |||||
fclose(tmp); | |||||
double sum=0.0e0; | |||||
double err=0.0e0; | |||||
double fix=0.0e0; | |||||
for(size_t j=0;j<*nPts-1;j++){ | |||||
sum+=dxp[j]; | |||||
} | |||||
err=1.0e0-sum; | |||||
printf("sum before correction: %15.6e\n",sum); | |||||
printf("err before correction: %15.6e\n",err); | |||||
fix=err/((double)(*nPts)); | |||||
sum=0.0e0; | |||||
for(size_t j=0;j<*nPts-1;j++){ | |||||
dxp[j]+=fix; | |||||
sum+=dxp[j]; | |||||
} | |||||
err=1.0e0-sum; | |||||
printf("sum after correction:%15.6e\n",sum); | |||||
printf("err after correction: %15.6e\n",err); | |||||
x[0]=0.0e0; | |||||
for(size_t j=0;j<*nPts-1;j++){ | |||||
x[j+1]=x[j]+dxp[j]; | |||||
} | |||||
x[*nPts-1]=1.0e0; | |||||
} | |||||
double safePosition(double c, double w){ | |||||
if(c<w){ | |||||
return(w); | |||||
} | |||||
else if(c>1.0e0-w){ | |||||
return(1.0e0-w); | |||||
} | |||||
else{ | |||||
return(c); | |||||
} | |||||
} | |||||
int reGrid(UserGrid grid, double position){ | |||||
printf("before regrid: %ld\n", grid->nPts); | |||||
double xx[grid->nPts]; | |||||
fillGrid(&grid->basePts, | |||||
&grid->nPts, | |||||
&grid->a, | |||||
&position, | |||||
&grid->w, | |||||
&grid->mag, | |||||
&grid->leftFac, | |||||
&grid->rightFac, | |||||
&grid->refineLeft, | |||||
&grid->refineRight, | |||||
xx); | |||||
for (size_t i = 0; i < grid->nPts; i++) { | |||||
grid->x[i]=xx[i]; | |||||
} | |||||
return(0); | |||||
} | |||||
void storeGrid(const double* x, double *y, const size_t nPts){ | |||||
for(size_t i=0;i<nPts;i++){ | |||||
y[i]=x[i]; | |||||
} | |||||
} | |||||
int initializeGrid(UserGrid grid){ | |||||
grid->nPts=maxPoints(grid->basePts, | |||||
&grid->a, | |||||
&grid->w, | |||||
&grid->mag, | |||||
&grid->leftFac, | |||||
&grid->rightFac, | |||||
&grid->refineLeft, | |||||
&grid->refineRight); | |||||
printf("nPts: %ld\n",grid->nPts); | |||||
grid->leastMove=grid->w; | |||||
grid->x = new double [grid->nPts]; | |||||
grid->xOld = new double [grid->nPts]; | |||||
for (size_t i = 0; i < grid->nPts; i++) { | |||||
grid->x[i]=0.0e0; | |||||
grid->xOld[i]=0.0e0; | |||||
} | |||||
return(0); | |||||
} | |||||
int getGridSettings(FILE *input, UserGrid grid){ | |||||
int ier=0; | |||||
ier=parseNumber<size_t>(input, "basePts" , MAXBUFLEN, &grid->basePts); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "gridDensitySlope", MAXBUFLEN, &grid->a); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "fineGridHalfWidth", MAXBUFLEN, &grid->w); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "gridRefinement", MAXBUFLEN, &grid->mag); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "leftRefineFactor", MAXBUFLEN, &grid->leftFac); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "rightRefineFactor", MAXBUFLEN, &grid->rightFac); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<int>(input, "refineLeft" , MAXBUFLEN, &grid->refineLeft); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<int>(input, "refineRight" , MAXBUFLEN, &grid->refineRight); | |||||
if(ier==-1)return(-1); | |||||
ier=parseNumber<double>(input, "position" , MAXBUFLEN, &grid->position); | |||||
if(ier==-1)return(-1); | |||||
return(0); | |||||
} | |||||
@@ -0,0 +1,82 @@ | |||||
#include "parse.h" | |||||
#ifndef GSL_DEF | |||||
#define GSL_DEF | |||||
#include <gsl/gsl_math.h> | |||||
#include <gsl/gsl_spline.h> | |||||
#endif | |||||
#ifndef GRID_DEF | |||||
#define GRID_DEF | |||||
typedef struct gridTag{ | |||||
size_t basePts; | |||||
size_t nPts; | |||||
double position; | |||||
double leastMove; | |||||
double a; | |||||
double w; | |||||
double mag; | |||||
double leftFac; | |||||
double rightFac; | |||||
int refineLeft; | |||||
int refineRight; | |||||
double* x; | |||||
double* xOld; | |||||
} *UserGrid; | |||||
inline double l(const double* x, | |||||
const double* a, | |||||
const double* w, | |||||
const double* fac, | |||||
const int* refineLeft); | |||||
inline double r(const double* x, | |||||
const double* a, | |||||
const double* w, | |||||
const double* fac, | |||||
const int* refineRight); | |||||
inline double f(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w); | |||||
inline double g(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w); | |||||
inline double rho(const double* x, | |||||
const double* a, | |||||
const double* c, | |||||
const double* w, | |||||
const double* mag, | |||||
const double* leftFac, | |||||
const double* rightFac, | |||||
const int* refineLeft, | |||||
const int* refineRight); | |||||
size_t maxPoints(const size_t basePts, | |||||
const double* a, | |||||
const double* w, | |||||
const double* mag, | |||||
const double* leftFac, | |||||
const double* rightFac, | |||||
const int* refineLeft, | |||||
const int* refineRight); | |||||
double safePosition(double c, double w); | |||||
int reGrid(UserGrid grid, double position); | |||||
void storeGrid(const double* x, double *y, const size_t nPts); | |||||
int initializeGrid(UserGrid grid); | |||||
int getGridSettings(FILE *input, UserGrid grid); | |||||
#endif |
@@ -0,0 +1,50 @@ | |||||
#Problem constants: | |||||
domainLength=10.16e-02 #in meters | |||||
constantPressure=0 #1=isobaric, 0=isochoric | |||||
dPdt=0.0e0 #Units: Pa/s | |||||
problemType=1 #0=heatsource to ignite(premix),1=premix, 2=custom initial condition | |||||
reflectProblem=0 #If 1, the initial conditions are reflected across the center of the domain. Useful for spherically imploding flames for instance. | |||||
mdot=0.0 | |||||
initialTemperature=300.0 #in Kelvin | |||||
initialPressure=1.0 #in atmospheres | |||||
chemistryFile=./ch4_1step.xml #File containing thermodynamic, kinetic, and transport info | |||||
transportModel=Mix #Transport model | |||||
mixtureComposition=CH4:0.45,O2:1.0,N2:3.76 #Mole Fractions! | |||||
metric=2 #0=planar,1=cylindrical,2=spherical | |||||
ignTime=5e-07 #Time over which energy is supplied in seconds | |||||
QDot=1e+14 #Power supplied in units of K/s | |||||
kernelSize=0e-03 | |||||
mixingWidth=2e-03 #mixing layer width in m (for diffusion problem) | |||||
shift=4e-03 #shift of mixing layer into domain (for diffusion problem) | |||||
dirichletInner=0 #Boundary conditions for scalars (T,Y) | |||||
dirichletOuter=1 | |||||
wallTemperature=300.0 | |||||
#Grid settings: | |||||
adaptiveGrid=1 | |||||
moveGrid=1 | |||||
gridOffset=0 | |||||
basePts=32 | |||||
gridDensitySlope=70.0e0 | |||||
fineGridHalfWidth=8e-03 | |||||
gridRefinement=1000.0e0; | |||||
leftRefineFactor=0.01 | |||||
rightRefineFactor=0.01 | |||||
refineLeft=1 | |||||
refineRight=1 | |||||
position=0.0 | |||||
isotherm=1000.0 | |||||
#Solver settings: | |||||
nSaves=100 #Save solution every nSaves timesteps | |||||
writeEveryRegrid=1 | |||||
writeRates=0 | |||||
relativeTolerance=1e-06 | |||||
radiusTolerance=1e-09 #absolute tolerance for radius | |||||
temperatureTolerance=1e-09 | |||||
pressureTolerance=1e-09 | |||||
massFractionTolerance=1e-09 | |||||
bathGasTolerance=1e-09 | |||||
finalTime=1.0e0 #in seconds | |||||
setConstraints=0 | |||||
suppressAlg=0 | |||||
nThreads=1 | |||||
dryRun=0 |
@@ -0,0 +1,63 @@ | |||||
#ifndef MACRO_DEF | |||||
#define MACRO_DEF | |||||
//#define SUNDIALS_DOUBLE_PRECISION 1 | |||||
//#define SUNDIALS_SINGLE_PRECISION 1 | |||||
#define ZERO RCONST(0.0) | |||||
#define HALF RCONST(0.5) | |||||
#define ONE RCONST(1.0) | |||||
#define TWO RCONST(2.0) | |||||
#define THREE RCONST(3.0) | |||||
#define FOUR RCONST(4.0) | |||||
#define TEN RCONST(10.0) | |||||
/* In order to keep begin the index numbers from 1 instead of 0, we define | |||||
* macros here. Also, we define macros to ease referencing various variables in | |||||
* the sundials nvector. | |||||
*/ | |||||
#define psi(i) psidata[i-1] | |||||
#define T(i) ydata[((i-1)*data->nvar)+data->nt] | |||||
#define Y(i,k) ydata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#define R(i) ydata[((i-1)*data->nvar)+data->nr] | |||||
#define P(i) ydata[((i-1)*data->nvar)+data->np] | |||||
#define Tdot(i) ydotdata[((i-1)*data->nvar)+data->nt] | |||||
#define Ydot(i,k) ydotdata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#define Rdot(i) ydotdata[((i-1)*data->nvar)+data->nr] | |||||
#define Pdot(i) ydotdata[((i-1)*data->nvar)+data->np] | |||||
#define Tres(i) resdata[((i-1)*data->nvar)+data->nt] | |||||
#define Yres(i,k) resdata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#define Rres(i) resdata[((i-1)*data->nvar)+data->nr] | |||||
#define Pres(i) resdata[((i-1)*data->nvar)+data->np] | |||||
#define Tid(i) iddata[((i-1)*data->nvar)+data->nt] | |||||
#define Yid(i,k) iddata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#define Rid(i) iddata[((i-1)*data->nvar)+data->nr] | |||||
#define Pid(i) iddata[((i-1)*data->nvar)+data->np] | |||||
#define Yav(i) Yav[i-1] | |||||
#define YAvg(i) YAvg[i-1] | |||||
#define YVmhalf(i) YVmhalf[i-1] | |||||
#define YVphalf(i) YVphalf[i-1] | |||||
#define X(i) X[i-1] | |||||
#define Xp(i) Xp[i-1] | |||||
#define Xgradhalf(i) Xgradhalf[i-1] | |||||
#define XLeft(i) XLeft[i-1] | |||||
#define XRight(i) XRight[i-1] | |||||
#define gradX(i) gradX[i-1] | |||||
#define wdot(i) wdot[i-1] | |||||
#define enthalpy(i) enthalpy[i-1] | |||||
#define energy(i) energy[i-1] | |||||
#define Cp(i) Cp[i-1] | |||||
#define atolT(i) atolvdata[((i-1)*data->nvar)+data->nt] | |||||
#define atolY(i,k) atolvdata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#define atolR(i) atolvdata[((i-1)*data->nvar)+data->nr] | |||||
#define atolP(i) atolvdata[((i-1)*data->nvar)+data->np] | |||||
#define constraintsY(i,k) constraintsdata[((i-1)*data->nvar)+data->ny+k-1] | |||||
#endif |
@@ -0,0 +1,338 @@ | |||||
/* | |||||
_____ ___ ____ ____ | |||||
|_ _/ _ \| _ \ / ___| | |||||
| || | | | |_) | | | |||||
| || |_| | _ <| |___ | |||||
|_| \___/|_| \_\\____| | |||||
*/ | |||||
#include "UserData.h" | |||||
#include "solution.h" | |||||
#include "residue.h" | |||||
#include "macros.h" | |||||
#include "timing.h" | |||||
#include <ida/ida.h> | |||||
#include <ida/ida_direct.h> | |||||
#include <sunmatrix/sunmatrix_band.h> | |||||
#include <sunlinsol/sunlinsol_lapackband.h> | |||||
//#include <ida/ida_band.h> | |||||
static int check_flag(void *flagvalue, | |||||
const char *funcname, | |||||
int opt); | |||||
void freeAtLast(void* mem, N_Vector *y, | |||||
N_Vector *ydot, | |||||
N_Vector *res, | |||||
N_Vector *id, | |||||
N_Vector *atolv, | |||||
N_Vector *constraints,UserData data); | |||||
int main(){ | |||||
FILE *input;input=fopen("input.dat","r"); | |||||
UserData data;data=NULL;data=allocateUserData(input); | |||||
fclose(input); | |||||
data->clockStart=get_wall_time(); | |||||
if(data==NULL){ | |||||
printf("check input file!\n"); | |||||
freeUserData(data); | |||||
return(-1); | |||||
} | |||||
long int ier,mu,ml,count,netf,ncfn,njevals,nrevals; | |||||
realtype tNow,*atolvdata,*constraintsdata,finalTime,tolsfac; | |||||
N_Vector y,ydot,id,res,atolv,constraints; | |||||
y=ydot=id=res=atolv=constraints=NULL; | |||||
ier=allocateSolution(data->neq,data->nThreads,&y,&ydot,&id,&res,&atolv,&constraints); | |||||
ier=setAlgebraicVariables(&id,data); | |||||
ier=setInitialCondition(&y,&ydot,data); | |||||
if(ier==-1)return(-1); | |||||
tNow=data->tNow; | |||||
finalTime=data->finalTime; | |||||
double* ydata; | |||||
double* ydotdata; | |||||
ydata = N_VGetArrayPointer_OpenMP(y); | |||||
ydotdata = N_VGetArrayPointer_OpenMP(ydot); | |||||
void *mem;mem=NULL;mem = IDACreate(); | |||||
ier = IDASetUserData(mem, data); | |||||
ier = IDASetId(mem, id); | |||||
ier = IDAInit(mem, residue, tNow, y, ydot); | |||||
// Atol array | |||||
atolvdata = N_VGetArrayPointer_OpenMP(atolv); | |||||
for (size_t i = 1; i <=data->npts; i++) { | |||||
atolT(i) = data->temperatureTolerance; | |||||
for (size_t k = 1; k <=data->nsp; k++) { | |||||
if(k!=data->k_bath){ | |||||
atolY(i,k) = data->massFractionTolerance; | |||||
} | |||||
else{ | |||||
atolY(i,k) = data->bathGasTolerance; | |||||
} | |||||
} | |||||
atolR(i) = data->radiusTolerance; | |||||
atolP(i) = data->pressureTolerance; | |||||
} | |||||
ier = IDASVtolerances(mem, data->relativeTolerance, atolv); | |||||
mu = 2*data->nvar; ml = mu; | |||||
SUNMatrix A; A=NULL; | |||||
A=SUNBandMatrix(data->neq,mu,ml,mu+ml); | |||||
SUNLinearSolver LS; LS=NULL; | |||||
//LS=SUNBandLinearSolver(y,A); | |||||
LS=SUNLapackBand(y,A); | |||||
ier=IDADlsSetLinearSolver(mem,LS,A); | |||||
//ier = IDABand(mem, data->neq, mu, ml); | |||||
constraintsdata = N_VGetArrayPointer_OpenMP(constraints); | |||||
if(data->setConstraints){ | |||||
for (size_t i = 1; i <=data->npts; i++) { | |||||
for (size_t k = 1; k <=data->nsp; k++) { | |||||
constraintsY(i,k) = ONE; | |||||
} | |||||
} | |||||
ier=IDASetConstraints(mem, constraints); | |||||
} | |||||
ier = IDASetSuppressAlg(mem, data->suppressAlg); | |||||
if(check_flag(&ier, "IDASetSuppressAlg", 1)) return(1); | |||||
//ier= IDASetMaxNumStepsIC(mem, 1); | |||||
//ier= IDASetMaxNumJacsIC(mem,8); | |||||
//ier= IDASetMaxNumItersIC(mem,100); | |||||
//ier= IDASetMaxBacksIC(mem,2000); | |||||
//ier = IDASetLineSearchOffIC(mem,SUNTRUE); | |||||
if(!data->dryRun){ | |||||
printf("Calculating Initial Conditions:\n"); | |||||
printf("Cross your fingers...\n"); | |||||
ier = IDACalcIC(mem, IDA_YA_YDP_INIT, 1e-05*finalTime); | |||||
//If at first IDACalcIC doesn't succeed, try, try, try again: | |||||
for (int i = 0; i < 10; i++) { | |||||
ier = IDACalcIC(mem, IDA_YA_YDP_INIT, (1e-01+pow(10,i)*finalTime)); | |||||
if(ier==0){ | |||||
break; | |||||
} | |||||
} | |||||
//...or else cry again :( | |||||
if(check_flag(&ier, "IDACalcIC", 1)){ | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(-1); | |||||
}else{ | |||||
printf("Initial (Consistent) Conditions Calculated!\n"); | |||||
} | |||||
ier = IDASetInitStep(mem,1e-12); | |||||
} | |||||
printSpaceTimeHeader(data); | |||||
printGlobalHeader(data); | |||||
printSpaceTimeOutput(tNow, &y, data->output, data); | |||||
printSpaceTimeOutput(tNow, &y, data->gridOutput, data); | |||||
if(!data->dryRun){ | |||||
count=0; | |||||
double dt=1e-08; | |||||
double t1=0.0e0; | |||||
double xOld=0.0e0; | |||||
double x=0.0e0; | |||||
double dx=0.0e0; | |||||
double dxMin=1.0e0; | |||||
double dxRatio=dx/dxMin; | |||||
double writeTime=tNow; | |||||
int move=0; | |||||
int kcur=0; | |||||
if(data->adaptiveGrid){ | |||||
dxMin=data->grid->leastMove; | |||||
//xOld=maxCurvPosition(ydata, data->nt, data->nvar, | |||||
// data->grid->x, data->npts); | |||||
xOld=isothermPosition(ydata, data->isotherm, data->nt, | |||||
data->nvar, data->grid->x, data->npts); | |||||
} | |||||
while (tNow<=finalTime) { | |||||
t1=tNow; | |||||
ier = IDASolve(mem, finalTime, &tNow, y, ydot, IDA_ONE_STEP); | |||||
if(check_flag(&ier, "IDASolve", 1)){ | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(-1); | |||||
} | |||||
dt=tNow-t1; | |||||
ier = IDAGetCurrentOrder(mem, &kcur); | |||||
if(data->adaptiveGrid==1 && data->moveGrid==1){ | |||||
//x=maxCurvPosition(ydata, data->nt, data->nvar, | |||||
// data->grid->x, data->npts); | |||||
x=isothermPosition(ydata, data->isotherm, data->nt, | |||||
data->nvar, data->grid->x, data->npts); | |||||
//x=maxGradPosition(ydata, data->nt, data->nvar, | |||||
// data->grid->x, data->npts); | |||||
dx=x-xOld; | |||||
if(dx*dxMin>0.0e0){ | |||||
move=1; | |||||
}else{ | |||||
move=-1; | |||||
} | |||||
//if(fabs(dx)>=dxMin && x+(double)(move)*0.5e0*dxMin<=1.0e0){ | |||||
dxRatio=fabs(dx/dxMin); | |||||
if(dxRatio>=1.0e0 && dxRatio<=2.0e0){ | |||||
printf("Regridding!\n"); | |||||
data->regrid=1; | |||||
//printSpaceTimeOutput(tNow, &y, data->gridOutput, data); | |||||
ier=reGrid(data->grid, x+(double)(move)*0.5e0*dxMin); | |||||
if(ier==-1){ | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(-1); | |||||
} | |||||
updateSolution(ydata, ydotdata, data->nvar, | |||||
data->grid->xOld,data->grid->x,data->npts); | |||||
storeGrid(data->grid->x,data->grid->xOld,data->npts); | |||||
xOld=x; | |||||
printf("Regrid Complete! Restarting Problem at %15.6e s\n",tNow); | |||||
ier = IDAReInit(mem, tNow, y, ydot); | |||||
if(check_flag(&ier, "IDAReInit", 1)){ | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(-1); | |||||
} | |||||
ier = IDASetInitStep(mem,1e-01*dt); | |||||
printf("Reinitialized! Calculating Initial Conditions:\n"); | |||||
printf("Cross your fingers...\n"); | |||||
ier = IDACalcIC(mem, IDA_YA_YDP_INIT, tNow+1e-01*dt); | |||||
if(check_flag(&ier, "IDACalcIC", 1)){ | |||||
ier = IDACalcIC(mem, IDA_YA_YDP_INIT, tNow+1e+01*dt); | |||||
} | |||||
//Every once in a while, for reasons | |||||
//that befuddle this mathematically | |||||
//lesser author, IDACalcIC fails. Here, | |||||
//I desperately try to make it converge | |||||
//again by sampling increasingly larger | |||||
//time-steps: | |||||
for (int i = 0; i < 10; i++) { | |||||
ier = IDACalcIC(mem, IDA_YA_YDP_INIT, tNow+(1e-01+pow(10,i)*dt)); | |||||
if(ier==0){ | |||||
break; | |||||
} | |||||
} | |||||
//Failure :( Back to the drawing board: | |||||
if(check_flag(&ier, "IDACalcIC", 1)){ | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(-1); | |||||
} | |||||
printf("Initial (Consistent) Conditions Calculated!\n"); | |||||
printf("------------------------------------------\n\n"); | |||||
//if(data->writeEveryRegrid){ | |||||
} | |||||
} | |||||
if(count%data->nSaves==0 && !data->writeEveryRegrid){ | |||||
printSpaceTimeOutput(tNow, &y, data->output, data); | |||||
//if(data->writeRates){ | |||||
// printSpaceTimeRates(tNow, ydot, data); | |||||
//} | |||||
} | |||||
/*Print global variables only if time-step is of high order!*/ | |||||
if(data->nTimeSteps==0){ | |||||
data->flamePosition[0]=0.0e0; | |||||
data->flamePosition[1]=0.0e0; | |||||
data->flameTime[0]=tNow; | |||||
data->flameTime[1]=tNow; | |||||
} | |||||
if(kcur>=2 ){ | |||||
printGlobalVariables(tNow,&y,&ydot,data); | |||||
} | |||||
if(tNow>writeTime){ | |||||
writeTime+=data->writeDeltaT; | |||||
printSpaceTimeOutput(tNow, &y, data->output, data); | |||||
FILE* fp; | |||||
fp=fopen("restart.bin","w"); | |||||
writeRestart(tNow, &y, &ydot, fp, data); | |||||
fclose(fp); | |||||
} | |||||
ier = IDAGetNumErrTestFails(mem, &netf); | |||||
ier = IDAGetNumNonlinSolvConvFails(mem, &ncfn); | |||||
ier = IDADlsGetNumJacEvals(mem, &njevals); | |||||
ier = IDADlsGetNumResEvals(mem, &nrevals); | |||||
printf("etf = %ld ," | |||||
"nlsf= %ld ," | |||||
"J=%ld ," | |||||
"R=%ld ," | |||||
"o=%d ,",netf, ncfn, njevals, nrevals, kcur); | |||||
printf("Time=%15.6e s,",tNow); | |||||
printf("frac: %15.6e\n",dxRatio); | |||||
count++; | |||||
data->nTimeSteps=count; | |||||
} | |||||
} | |||||
SUNLinSolFree(LS); | |||||
SUNMatDestroy(A); | |||||
freeAtLast(mem,&y,&ydot,&res,&id,&atolv,&constraints,data); | |||||
return(0); | |||||
} | |||||
void freeAtLast(void* mem, | |||||
N_Vector *y, | |||||
N_Vector *ydot, | |||||
N_Vector *res, | |||||
N_Vector *id, | |||||
N_Vector *atolv, | |||||
N_Vector *constraints,UserData data){ | |||||
IDAFree(&mem); | |||||
freeSolution(y,ydot,res,id,atolv,constraints); | |||||
freeUserData(data); | |||||
} | |||||
static int check_flag(void *flagvalue, const char *funcname, int opt) | |||||
{ | |||||
int *errflag; | |||||
/* Check if SUNDIALS function returned NULL pointer - no memory allocated */ | |||||
if (opt == 0 && flagvalue == NULL) { | |||||
fprintf(stderr, | |||||
"\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n", | |||||
funcname); | |||||
return(1); | |||||
} | |||||
/* Check if flag < 0 */ | |||||
else if (opt == 1) { | |||||
errflag = (int *) flagvalue; | |||||
if (*errflag < 0) { | |||||
fprintf(stderr, | |||||
"\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n", | |||||
funcname, *errflag); | |||||
return(1); | |||||
} | |||||
} | |||||
/* Check if function returned NULL pointer - no memory allocated */ | |||||
else if (opt == 2 && flagvalue == NULL) { | |||||
fprintf(stderr, | |||||
"\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n", | |||||
funcname); | |||||
return(1); | |||||
} | |||||
return(0); | |||||
} |
@@ -0,0 +1,20 @@ | |||||
#include "parse.h" | |||||
void getFromString (const char* buf, int* n){ | |||||
*n=atoi(buf); | |||||
printf("%d\n",*n); | |||||
} | |||||
void getFromString (const char* buf, size_t* n){ | |||||
*n=(size_t)(atoi(buf)); | |||||
printf("%lu\n",*n); | |||||
} | |||||
void getFromString (const char* buf, double* n){ | |||||
*n=(double)(atof(buf)); | |||||
printf("%15.6e\n",*n); | |||||
} | |||||
void getFromString (const char* buf, char* n){ | |||||
sscanf(buf,"%s",n); | |||||
printf("%s\n",n); | |||||
} |
@@ -0,0 +1,31 @@ | |||||
#ifndef PRINT_DEF | |||||
#define PRINT_DEF | |||||
#include <string.h> //for strings | |||||
#include <stdio.h> //for printf,scanf | |||||
#include <stdlib.h> //for atoi, atof | |||||
#endif | |||||
#ifndef PARSE_DEF | |||||
#define PARSE_DEF | |||||
#define MAXBUFLEN 200 | |||||
void getFromString (const char* buf, int* n); | |||||
void getFromString (const char* buf, size_t* n); | |||||
void getFromString (const char* buf, double* n); | |||||
void getFromString (const char* buf, char* n); | |||||
int parseString(FILE* input, const char* keyword, const size_t bufLen, char* n); | |||||
template<typename T> | |||||
int parseNumber(FILE* input, const char* keyword, const size_t bufLen, T* n); | |||||
template<typename T> | |||||
int parseArray(FILE* input, const char* keyword, const size_t bufLen, | |||||
const size_t arrLen, T y[]); | |||||
#include "parse.hpp" | |||||
#endif | |||||
@@ -0,0 +1,76 @@ | |||||
template<typename T> | |||||
int parseNumber(FILE* input, const char* keyword, const size_t bufLen, T* n){ | |||||
char buf[bufLen]; | |||||
char buf1[bufLen]; | |||||
char comment[1]; | |||||
char *ret; | |||||
while (fgets(buf,bufLen, input)!=NULL){ | |||||
comment[0]=buf[0]; | |||||
if(strncmp(comment,"#",1)==0){ | |||||
//printf("Comment!:%s\n",buf); | |||||
} | |||||
else{ | |||||
ret=strtok(buf,"="); | |||||
if(strcmp(ret,keyword)==0){ | |||||
/*offset buf by keyword size + 1 for the "="*/ | |||||
strncpy (buf1, buf+strlen(keyword)+1, bufLen); | |||||
printf("%30s: ",keyword); | |||||
getFromString(buf1,n); | |||||
rewind(input); | |||||
return(0); | |||||
} | |||||
} | |||||
} | |||||
rewind(input); | |||||
return(-1); | |||||
} | |||||
template<typename T> | |||||
int parseArray(FILE* input, const char* keyword, const size_t bufLen, | |||||
const size_t arrLen, T y[]){ | |||||
char buf[bufLen]; | |||||
char buf1[bufLen]; | |||||
char comment[1]; | |||||
char *ret; | |||||
while (fgets(buf,bufLen, input)!=NULL){ | |||||
comment[0]=buf[0]; | |||||
if(strncmp(comment,"#",1)==0){ | |||||
//printf("Comment!:%s\n",buf); | |||||
} | |||||
else{ | |||||
ret=strtok(buf,"="); | |||||
if(strcmp(ret,keyword)==0){ | |||||
/*offset buf by keyword size + 1 for the "="*/ | |||||
strncpy (buf1, buf+strlen(keyword)+1, bufLen); | |||||
printf("%30s:\n",keyword); | |||||
ret=strtok(buf1,","); | |||||
size_t j=0; | |||||
while(ret!=NULL){ | |||||
if(j<arrLen){ | |||||
//y[j]=atof(ret); | |||||
getFromString(ret,&y[j]); | |||||
} | |||||
ret=strtok(NULL,","); | |||||
j++; | |||||
} | |||||
rewind(input); | |||||
if(j!=arrLen){ | |||||
printf("Check no: of values entered for %s\n",keyword); | |||||
printf("%lu values required!\n",arrLen); | |||||
return(-1); | |||||
} | |||||
else{ | |||||
return(0); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
rewind(input); | |||||
return(-1); | |||||
} | |||||
@@ -0,0 +1,90 @@ | |||||
#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 <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 | |||||
#include "UserData.h" | |||||
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); | |||||
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); |
@@ -0,0 +1,90 @@ | |||||
#include "solution.h" | |||||
int allocateSolution(size_t neq, | |||||
int nThreads, | |||||
N_Vector *y, | |||||
N_Vector *ydot, | |||||
N_Vector *res, | |||||
N_Vector *id, | |||||
N_Vector *atolv, | |||||
N_Vector *constraints){ | |||||
*y = N_VNew_OpenMP(neq,nThreads); | |||||
if(*y==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(0.0e0), *y); | |||||
*ydot = N_VNew_OpenMP(neq,nThreads); | |||||
if(*ydot==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(0.0e0), *ydot); | |||||
*res = N_VNew_OpenMP(neq,nThreads); | |||||
if(*res==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(0.0e0), *res); | |||||
*id = N_VNew_OpenMP(neq,nThreads); | |||||
if(*id==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(1.0e0), *id); | |||||
*atolv = N_VNew_OpenMP(neq,nThreads); | |||||
if(*atolv==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(0.0e0), *atolv); | |||||
*constraints = N_VNew_OpenMP(neq,nThreads); | |||||
if(*constraints==NULL){ | |||||
printf("Allocation Failed!\n"); | |||||
return(1); | |||||
} | |||||
N_VConst((realtype)(0.0e0), *constraints); | |||||
return(0); | |||||
} | |||||
void freeSolution(N_Vector *y, | |||||
N_Vector *ydot, | |||||
N_Vector *res, | |||||
N_Vector *id, | |||||
N_Vector *atolv, | |||||
N_Vector *constraints){ | |||||
if(*y!=NULL){ | |||||
N_VDestroy_OpenMP(*y); | |||||
printf("y Destroyed!\n"); | |||||
} | |||||
if(*ydot!=NULL){ | |||||
N_VDestroy_OpenMP(*ydot); | |||||
printf("ydot Destroyed!\n"); | |||||
} | |||||
if(*res!=NULL){ | |||||
N_VDestroy_OpenMP(*res); | |||||
printf("res Destroyed!\n"); | |||||
} | |||||
if(*id!=NULL){ | |||||
N_VDestroy_OpenMP(*id); | |||||
printf("id Destroyed!\n"); | |||||
} | |||||
if(*atolv!=NULL){ | |||||
N_VDestroy_OpenMP(*atolv); | |||||
printf("atolv Destroyed!\n"); | |||||
} | |||||
if(*constraints!=NULL){ | |||||
N_VDestroy_OpenMP(*constraints); | |||||
printf("constraints Destroyed!\n"); | |||||
} | |||||
printf("\n\n"); | |||||
} |
@@ -0,0 +1,15 @@ | |||||
#ifndef PRINT_DEF | |||||
#define PRINT_DEF | |||||
#include <string.h> //for strings | |||||
#include <stdio.h> //for printf,scanf | |||||
#include <stdlib.h> //for atoi, atof | |||||
#endif | |||||
#ifndef SUNDIALS_DEF | |||||
#define SUNDIALS_DEF | |||||
#include <sundials/sundials_types.h> | |||||
#include <nvector/nvector_openmp.h> | |||||
#endif | |||||
int allocateSolution(size_t neq, int nThreads, N_Vector *y, N_Vector *ydot, N_Vector *res, N_Vector *id, N_Vector *atolv, N_Vector *constraints); | |||||
void freeSolution(N_Vector *y, N_Vector *ydot, N_Vector *res, N_Vector *id, N_Vector *atolv, N_Vector *constraints); |
@@ -0,0 +1,2 @@ | |||||
double get_wall_time(); | |||||
double get_cpu_time(); |
@@ -0,0 +1,45 @@ | |||||
// Windows | |||||
#ifdef _WIN32 | |||||
#include <Windows.h> | |||||
double get_wall_time(){ | |||||
LARGE_INTEGER time,freq; | |||||
if (!QueryPerformanceFrequency(&freq)){ | |||||
// Handle error | |||||
return 0; | |||||
} | |||||
if (!QueryPerformanceCounter(&time)){ | |||||
// Handle error | |||||
return 0; | |||||
} | |||||
return (double)time.QuadPart / freq.QuadPart; | |||||
} | |||||
double get_cpu_time(){ | |||||
FILETIME a,b,c,d; | |||||
if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){ | |||||
// Returns total user time. | |||||
// Can be tweaked to include kernel times as well. | |||||
return | |||||
(double)(d.dwLowDateTime | | |||||
((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001; | |||||
}else{ | |||||
// Handle error | |||||
return 0; | |||||
} | |||||
} | |||||
// Posix/Linux | |||||
#else | |||||
#include <time.h> | |||||
#include <sys/time.h> | |||||
double get_wall_time(){ | |||||
struct timeval time; | |||||
if (gettimeofday(&time,NULL)){ | |||||
// Handle error | |||||
return 0; | |||||
} | |||||
return (double)time.tv_sec + (double)time.tv_usec * .000001; | |||||
} | |||||
double get_cpu_time(){ | |||||
return (double)clock() / CLOCKS_PER_SEC; | |||||
} | |||||
#endif |