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 CHKERRTC(ierr) do {PetscCheckFalse(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; PetscErrorCode ierr; 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; ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Chemistry solver options","");CHKERRQ(ierr); ierr = PetscOptionsString("-chem","CHEMKIN input file","",chemfile,chemfile,sizeof(chemfile),NULL);CHKERRQ(ierr); ierr = PetscFileRetrieve(PETSC_COMM_WORLD,chemfile,lchemfile,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr); PetscCheckFalse(!found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot download %s and no local version %s",chemfile,lchemfile); ierr = PetscOptionsString("-thermo","NASA thermo input file","",thermofile,thermofile,sizeof(thermofile),NULL);CHKERRQ(ierr); ierr = PetscFileRetrieve(PETSC_COMM_WORLD,thermofile,lthermofile,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr); PetscCheckFalse(!found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot download %s and no local version %s",thermofile,lthermofile); user.pressure = 1.01325e5; /* Pascal */ ierr = PetscOptionsReal("-pressure","Pressure of reaction [Pa]","",user.pressure,&user.pressure,NULL);CHKERRQ(ierr); user.Tini = 1000; /* Kelvin */ ierr = PetscOptionsReal("-Tini","Initial temperature [K]","",user.Tini,&user.Tini,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-monitor_mass","Monitor the total mass at each timestep","",flg,&flg,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-monitor_temp","Monitor the temperature each timestep","",tflg,&tflg,NULL);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); /* tchem requires periodic table in current directory */ ierr = PetscFileRetrieve(PETSC_COMM_WORLD,periodic,lperiodic,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr); PetscCheckFalse(!found,PETSC_COMM_WORLD,PETSC_ERR_FILE_OPEN,"Cannot located required periodic table %s or local version %s",periodic,lperiodic); ierr = TC_initChem(lchemfile, lthermofile, 0, 1.0);CHKERRTC(ierr); TC_setThermoPres(user.pressure); user.Nspec = TC_getNspec(); user.Nreac = TC_getNreac(); /* Get names of all species in easy to use array */ ierr = PetscMalloc1((user.Nspec+1)*LENGTHOFSPECNAME,&names);CHKERRQ(ierr); ierr = PetscStrcpy(names,"Temp");CHKERRQ(ierr); TC_getSnames(user.Nspec,names+LENGTHOFSPECNAME); ierr = PetscMalloc1((user.Nspec+2),&snames);CHKERRQ(ierr); for (i=0; i .01) {ierr = PetscPrintf(PETSC_COMM_SELF,"%s %g\n",user.snames[i],(double)bmax[i]);CHKERRQ(ierr);} } ierr = VecRestoreArrayRead(max,&bmax);CHKERRQ(ierr); } } Vec y; ierr = MassFractionToMoleFraction(&user,X,&y);CHKERRQ(ierr); ierr = PrintSpecies(&user,y);CHKERRQ(ierr); ierr = VecDestroy(&y);CHKERRQ(ierr); */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Free work space. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ TC_reset(); ierr = PetscStrArrayDestroy(&user.snames);CHKERRQ(ierr); ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = VecDestroy(&X);CHKERRQ(ierr); ierr = VecDestroy(&lambda);CHKERRQ(ierr); ierr = TSDestroy(&ts);CHKERRQ(ierr); ierr = PetscFree3(user.tchemwork,user.Jdense,user.rows);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; } static PetscErrorCode FormRHSFunction(TS ts,PetscReal t,Vec X,Vec F,void *ptr) { User user = (User)ptr; PetscErrorCode ierr; PetscScalar *f; const PetscScalar *x; PetscFunctionBeginUser; ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); ierr = VecGetArray(F,&f);CHKERRQ(ierr); ierr = PetscArraycpy(user->tchemwork,x,user->Nspec+1);CHKERRQ(ierr); user->tchemwork[0] *= user->Tini; /* Dimensionalize */ ierr = TC_getSrc(user->tchemwork,user->Nspec+1,f);CHKERRTC(ierr); f[0] /= user->Tini; /* Non-dimensionalize */ ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); ierr = VecRestoreArray(F,&f);CHKERRQ(ierr); PetscFunctionReturn(0); } static PetscErrorCode FormRHSJacobian(TS ts,PetscReal t,Vec X,Mat Amat,Mat Pmat,void *ptr) { User user = (User)ptr; PetscErrorCode ierr; const PetscScalar *x; PetscInt M = user->Nspec+1,i; PetscFunctionBeginUser; ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); ierr = PetscArraycpy(user->tchemwork,x,user->Nspec+1);CHKERRQ(ierr); ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); user->tchemwork[0] *= user->Tini; /* Dimensionalize temperature (first row) because that is what Tchem wants */ ierr = TC_getJacTYN(user->tchemwork,user->Nspec,user->Jdense,1);CHKERRQ(ierr); 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; ierr = MatSetOption(Pmat,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr); ierr = MatSetOption(Pmat,MAT_IGNORE_ZERO_ENTRIES,PETSC_TRUE);CHKERRQ(ierr); ierr = MatZeroEntries(Pmat);CHKERRQ(ierr); ierr = MatSetValues(Pmat,M,user->rows,M,user->rows,user->Jdense,INSERT_VALUES);CHKERRQ(ierr); ierr = MatAssemblyBegin(Pmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(Pmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); if (Amat != Pmat) { ierr = MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); } PetscFunctionReturn(0); } PetscErrorCode FormInitialSolution(TS ts,Vec X,void *ctx) { PetscScalar *x; PetscErrorCode ierr; PetscInt i; Vec y; const PetscInt maxspecies = 10; PetscInt smax = maxspecies,mmax = maxspecies; char *names[maxspecies]; PetscReal molefracs[maxspecies],sum; PetscBool flg; PetscFunctionBeginUser; ierr = VecZeroEntries(X);CHKERRQ(ierr); ierr = VecGetArray(X,&x);CHKERRQ(ierr); x[0] = 1.0; /* Non-dimensionalized by user->Tini */ ierr = PetscOptionsGetStringArray(NULL,NULL,"-initial_species",names,&smax,&flg);CHKERRQ(ierr); PetscCheckFalse(smax < 2,PETSC_COMM_SELF,PETSC_ERR_USER,"Must provide at least two initial species"); ierr = PetscOptionsGetRealArray(NULL,NULL,"-initial_mole",molefracs,&mmax,&flg);CHKERRQ(ierr); PetscCheckFalse(smax != mmax,PETSC_COMM_SELF,PETSC_ERR_USER,"Must provide same number of initial species %D as initial moles %D",smax,mmax); sum = 0; for (i=0; iNspec,mof+1); ierr = VecRestoreArray(*molef,&mof);CHKERRQ(ierr); ierr = VecRestoreArrayRead(massf,&maf);CHKERRQ(ierr); 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) { PetscErrorCode ierr; const PetscScalar *mof; PetscScalar *maf; PetscFunctionBegin; ierr = VecDuplicate(molef,massf);CHKERRQ(ierr); ierr = VecGetArrayRead(molef,&mof);CHKERRQ(ierr); ierr = VecGetArray(*massf,&maf);CHKERRQ(ierr); maf[0] = mof[0]; /* copy over temperature */ TC_getMl2Ms((double*)mof+1,user->Nspec,maf+1); ierr = VecRestoreArrayRead(molef,&mof);CHKERRQ(ierr); ierr = VecRestoreArray(*massf,&maf);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode ComputeMassConservation(Vec x,PetscReal *mass,void* ctx) { PetscErrorCode ierr; PetscFunctionBegin; ierr = VecSum(x,mass);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MonitorMassConservation(TS ts,PetscInt step,PetscReal time,Vec x,void* ctx) { const PetscScalar *T; PetscReal mass; PetscErrorCode ierr; PetscFunctionBegin; ierr = ComputeMassConservation(x,&mass,ctx);CHKERRQ(ierr); ierr = VecGetArrayRead(x,&T);CHKERRQ(ierr); mass -= PetscAbsScalar(T[0]); ierr = VecRestoreArrayRead(x,&T);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Timestep %D time %g percent mass lost or gained %g\n",step,(double)time,(double)100.*(1.0 - mass));CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MonitorTempature(TS ts,PetscInt step,PetscReal time,Vec x,void* ctx) { User user = (User) ctx; const PetscScalar *T; PetscErrorCode ierr; PetscFunctionBegin; ierr = VecGetArrayRead(x,&T);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Timestep %D time %g temperature %g\n",step,(double)time,(double)T[0]*user->Tini);CHKERRQ(ierr); ierr = VecRestoreArrayRead(x,&T);CHKERRQ(ierr); PetscFunctionReturn(0); } /* Prints out each species with its name */ PETSC_UNUSED PetscErrorCode PrintSpecies(User user,Vec molef) { PetscErrorCode ierr; const PetscScalar *mof; PetscInt i,*idx,n = user->Nspec+1; PetscFunctionBegin; ierr = PetscMalloc1(n,&idx);CHKERRQ(ierr); for (i=0; isnames[idx[n-i-1]],mof[idx[n-i-1]]);CHKERRQ(ierr); } ierr = PetscFree(idx);CHKERRQ(ierr); ierr = VecRestoreArrayRead(molef,&mof);CHKERRQ(ierr); 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*/