@@ -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 |