static const char help[] = "Integrate chemistry using TChem.\n"; #include #if defined(PETSC_HAVE_TCHEM) #if defined(MAX) #undef MAX #endif #if defined(MIN) #undef MIN #endif # include # include #else # error TChem is required for this example. Reconfigure PETSc using --download-tchem. #endif /* See extchem.example.1 for how to run an example See also h2_10sp.inp for another example Determine sensitivity of final temperature on each variables initial conditions -ts_dt 1.e-5 -ts_type cn -ts_adjoint_solve -ts_adjoint_view_solution draw The solution for component i = 0 is the temperature. The solution, i > 0, is the mass fraction, massf[i], of species i, i.e. mass of species i/ total mass of all species The mole fraction molef[i], i > 0, is the number of moles of a species/ total number of moles of all species Define M[i] = mass per mole of species i then molef[i] = massf[i]/(M[i]*(sum_j massf[j]/M[j])) FormMoleFraction(User,massf,molef) converts the mass fraction solution of each species to the mole fraction of each species. These are other data sets for other possible runs https://www-pls.llnl.gov/data/docs/science_and_technology/chemistry/combustion/n_heptane_v3.1_therm.dat https://www-pls.llnl.gov/data/docs/science_and_technology/chemistry/combustion/nc7_ver3.1_mech.txt */ typedef struct _User *User; struct _User { PetscReal pressure; int Nspec; int Nreac; PetscReal Tini; double *tchemwork; double *Jdense; /* Dense array workspace where Tchem computes the Jacobian */ PetscInt *rows; char **snames; }; static PetscErrorCode PrintSpecies(User,Vec); static PetscErrorCode MassFractionToMoleFraction(User,Vec,Vec*); static PetscErrorCode MoleFractionToMassFraction(User,Vec,Vec*); static PetscErrorCode FormRHSFunction(TS,PetscReal,Vec,Vec,void*); static PetscErrorCode FormRHSJacobian(TS,PetscReal,Vec,Mat,Mat,void*); static PetscErrorCode FormInitialSolution(TS,Vec,void*); static PetscErrorCode ComputeMassConservation(Vec,PetscReal*,void*); static PetscErrorCode MonitorMassConservation(TS,PetscInt,PetscReal,Vec,void*); static PetscErrorCode MonitorTempature(TS,PetscInt,PetscReal,Vec,void*); #define PetscCallTC(ierr) do {PetscCheck(!ierr,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in TChem library, return code %d",ierr);} while (0) int main(int argc,char **argv) { TS ts; /* time integrator */ TSAdapt adapt; Vec X,lambda; /* solution vector */ Mat J; /* Jacobian matrix */ PetscInt steps; PetscReal ftime,dt; char chemfile[PETSC_MAX_PATH_LEN],thermofile[PETSC_MAX_PATH_LEN],lchemfile[PETSC_MAX_PATH_LEN],lthermofile[PETSC_MAX_PATH_LEN],lperiodic[PETSC_MAX_PATH_LEN]; const char *periodic = "file://${PETSC_DIR}/${PETSC_ARCH}/share/periodictable.dat"; struct _User user; /* user-defined work context */ TSConvergedReason reason; char **snames,*names; PetscInt i; TSTrajectory tj; PetscBool flg = PETSC_FALSE,tflg = PETSC_FALSE,found; PetscCall(PetscInitialize(&argc,&argv,(char*)0,help)); PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Chemistry solver options",""); PetscCall(PetscOptionsString("-chem","CHEMKIN input file","",chemfile,chemfile,sizeof(chemfile),NULL)); PetscCall(PetscFileRetrieve(PETSC_COMM_WORLD,chemfile,lchemfile,PETSC_MAX_PATH_LEN,&found)); PetscCheck(found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot download %s and no local version %s",chemfile,lchemfile); PetscCall(PetscOptionsString("-thermo","NASA thermo input file","",thermofile,thermofile,sizeof(thermofile),NULL)); PetscCall(PetscFileRetrieve(PETSC_COMM_WORLD,thermofile,lthermofile,PETSC_MAX_PATH_LEN,&found)); PetscCheck(found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot download %s and no local version %s",thermofile,lthermofile); user.pressure = 1.01325e5; /* Pascal */ PetscCall(PetscOptionsReal("-pressure","Pressure of reaction [Pa]","",user.pressure,&user.pressure,NULL)); user.Tini = 1000; /* Kelvin */ PetscCall(PetscOptionsReal("-Tini","Initial temperature [K]","",user.Tini,&user.Tini,NULL)); PetscCall(PetscOptionsBool("-monitor_mass","Monitor the total mass at each timestep","",flg,&flg,NULL)); PetscCall(PetscOptionsBool("-monitor_temp","Monitor the temperature each timestep","",tflg,&tflg,NULL)); PetscOptionsEnd(); /* tchem requires periodic table in current directory */ PetscCall(PetscFileRetrieve(PETSC_COMM_WORLD,periodic,lperiodic,PETSC_MAX_PATH_LEN,&found)); PetscCheck(found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot located required periodic table %s or local version %s",periodic,lperiodic); PetscCallTC(TC_initChem(lchemfile, lthermofile, 0, 1.0)); TC_setThermoPres(user.pressure); user.Nspec = TC_getNspec(); user.Nreac = TC_getNreac(); /* Get names of all species in easy to use array */ PetscCall(PetscMalloc1((user.Nspec+1)*LENGTHOFSPECNAME,&names)); PetscCall(PetscStrcpy(names,"Temp")); TC_getSnames(user.Nspec,names+LENGTHOFSPECNAME); PetscCall(PetscMalloc1((user.Nspec+2),&snames)); for (i=0; i .01) PetscCall(PetscPrintf(PETSC_COMM_SELF,"%s %g\n",user.snames[i],(double)bmax[i])); } PetscCall(VecRestoreArrayRead(max,&bmax)); } } Vec y; PetscCall(MassFractionToMoleFraction(&user,X,&y)); PetscCall(PrintSpecies(&user,y)); PetscCall(VecDestroy(&y)); */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Free work space. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ TC_reset(); PetscCall(PetscStrArrayDestroy(&user.snames)); PetscCall(MatDestroy(&J)); PetscCall(VecDestroy(&X)); PetscCall(VecDestroy(&lambda)); PetscCall(TSDestroy(&ts)); PetscCall(PetscFree3(user.tchemwork,user.Jdense,user.rows)); PetscCall(PetscFinalize()); return 0; } static PetscErrorCode FormRHSFunction(TS ts,PetscReal t,Vec X,Vec F,void *ptr) { User user = (User)ptr; PetscScalar *f; const PetscScalar *x; PetscFunctionBeginUser; PetscCall(VecGetArrayRead(X,&x)); PetscCall(VecGetArray(F,&f)); PetscCall(PetscArraycpy(user->tchemwork,x,user->Nspec+1)); user->tchemwork[0] *= user->Tini; /* Dimensionalize */ PetscCallTC(TC_getSrc(user->tchemwork,user->Nspec+1,f)); f[0] /= user->Tini; /* Non-dimensionalize */ PetscCall(VecRestoreArrayRead(X,&x)); PetscCall(VecRestoreArray(F,&f)); PetscFunctionReturn(0); } static PetscErrorCode FormRHSJacobian(TS ts,PetscReal t,Vec X,Mat Amat,Mat Pmat,void *ptr) { User user = (User)ptr; const PetscScalar *x; PetscInt M = user->Nspec+1,i; PetscFunctionBeginUser; PetscCall(VecGetArrayRead(X,&x)); PetscCall(PetscArraycpy(user->tchemwork,x,user->Nspec+1)); PetscCall(VecRestoreArrayRead(X,&x)); user->tchemwork[0] *= user->Tini; /* Dimensionalize temperature (first row) because that is what Tchem wants */ PetscCall(TC_getJacTYN(user->tchemwork,user->Nspec,user->Jdense,1)); for (i=0; iJdense[i + 0*M] /= user->Tini; /* Non-dimensionalize first column */ for (i=0; iJdense[0 + i*M] /= user->Tini; /* Non-dimensionalize first row */ for (i=0; irows[i] = i; PetscCall(MatSetOption(Pmat,MAT_ROW_ORIENTED,PETSC_FALSE)); PetscCall(MatSetOption(Pmat,MAT_IGNORE_ZERO_ENTRIES,PETSC_TRUE)); PetscCall(MatZeroEntries(Pmat)); PetscCall(MatSetValues(Pmat,M,user->rows,M,user->rows,user->Jdense,INSERT_VALUES)); PetscCall(MatAssemblyBegin(Pmat,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(Pmat,MAT_FINAL_ASSEMBLY)); if (Amat != Pmat) { PetscCall(MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY)); } PetscFunctionReturn(0); } PetscErrorCode FormInitialSolution(TS ts,Vec X,void *ctx) { PetscScalar *x; PetscInt i; Vec y; const PetscInt maxspecies = 10; PetscInt smax = maxspecies,mmax = maxspecies; char *names[maxspecies]; PetscReal molefracs[maxspecies],sum; PetscBool flg; PetscFunctionBeginUser; PetscCall(VecZeroEntries(X)); PetscCall(VecGetArray(X,&x)); x[0] = 1.0; /* Non-dimensionalized by user->Tini */ PetscCall(PetscOptionsGetStringArray(NULL,NULL,"-initial_species",names,&smax,&flg)); PetscCheck(smax >= 2,PETSC_COMM_SELF,PETSC_ERR_USER,"Must provide at least two initial species"); PetscCall(PetscOptionsGetRealArray(NULL,NULL,"-initial_mole",molefracs,&mmax,&flg)); PetscCheck(smax == mmax,PETSC_COMM_SELF,PETSC_ERR_USER,"Must provide same number of initial species %" PetscInt_FMT " as initial moles %" PetscInt_FMT,smax,mmax); sum = 0; for (i=0; i= 0,PETSC_COMM_SELF,PETSC_ERR_USER,"Could not find species %s",names[i]); PetscCall(PetscPrintf(PETSC_COMM_SELF,"Species %" PetscInt_FMT ": %s %g\n",i,names[i],(double)molefracs[i])); x[1+ispec] = molefracs[i]; } for (i=0; iNspec,mof+1); PetscCall(VecRestoreArray(*molef,&mof)); PetscCall(VecRestoreArrayRead(massf,&maf)); PetscFunctionReturn(0); } /* Converts the input vector which is in mole fractions to mass fractions (used by tchem) */ PetscErrorCode MoleFractionToMassFraction(User user,Vec molef,Vec *massf) { const PetscScalar *mof; PetscScalar *maf; PetscFunctionBegin; PetscCall(VecDuplicate(molef,massf)); PetscCall(VecGetArrayRead(molef,&mof)); PetscCall(VecGetArray(*massf,&maf)); maf[0] = mof[0]; /* copy over temperature */ TC_getMl2Ms((double*)mof+1,user->Nspec,maf+1); PetscCall(VecRestoreArrayRead(molef,&mof)); PetscCall(VecRestoreArray(*massf,&maf)); PetscFunctionReturn(0); } PetscErrorCode ComputeMassConservation(Vec x,PetscReal *mass,void* ctx) { PetscFunctionBegin; PetscCall(VecSum(x,mass)); PetscFunctionReturn(0); } PetscErrorCode MonitorMassConservation(TS ts,PetscInt step,PetscReal time,Vec x,void* ctx) { const PetscScalar *T; PetscReal mass; PetscFunctionBegin; PetscCall(ComputeMassConservation(x,&mass,ctx)); PetscCall(VecGetArrayRead(x,&T)); mass -= PetscAbsScalar(T[0]); PetscCall(VecRestoreArrayRead(x,&T)); PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Timestep %" PetscInt_FMT " time %g percent mass lost or gained %g\n",step,(double)time,(double)(100.*(1.0 - mass)))); PetscFunctionReturn(0); } PetscErrorCode MonitorTempature(TS ts,PetscInt step,PetscReal time,Vec x,void* ctx) { User user = (User) ctx; const PetscScalar *T; PetscFunctionBegin; PetscCall(VecGetArrayRead(x,&T)); PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Timestep %" PetscInt_FMT " time %g temperature %g\n",step,(double)time,(double)(T[0]*user->Tini))); PetscCall(VecRestoreArrayRead(x,&T)); PetscFunctionReturn(0); } /* Prints out each species with its name */ PETSC_UNUSED PetscErrorCode PrintSpecies(User user,Vec molef) { const PetscScalar *mof; PetscInt i,*idx,n = user->Nspec+1; PetscFunctionBegin; PetscCall(PetscMalloc1(n,&idx)); for (i=0; isnames[idx[n-i-1]],(double)PetscRealPart(mof[idx[n-i-1]]))); } PetscCall(PetscFree(idx)); PetscCall(VecRestoreArrayRead(molef,&mof)); PetscFunctionReturn(0); } /*TEST build: requires: tchem test: args: -chem http://combustion.berkeley.edu/gri_mech/version30/files30/grimech30.dat -thermo http://combustion.berkeley.edu/gri_mech/version30/files30/thermo30.dat -initial_species CH4,O2,N2,AR -initial_mole 0.0948178320887,0.189635664177,0.706766236705,0.00878026702874 -Tini 1500 -Tini 1500 -ts_arkimex_fully_implicit -ts_max_snes_failures -1 -ts_adapt_dt_max 1e-4 -ts_arkimex_type 4 -ts_max_time .005 requires: !single filter: grep -v iterations TEST*/