From 4f0dfc3bdf09ae6cf9caf0b806af6fabf3002186 Mon Sep 17 00:00:00 2001 From: Will Bainbridge Date: Wed, 15 Sep 2021 12:06:07 +0100 Subject: [PATCH] chemistryModel: Change of state variable to mass fraction The chemistry model now solves a system of mass fractions, temperature and pressure, rather than a system of concentrations, temperature and pressure. The new form now accounts for the change in reaction rate associated with thermal expansion. Thermal expansion (or contraction) can dilute (or concentrate) the species concentrations, thereby reducing (or increasing) the reaction rates. Previously it was not possible to include this term because it was not computationally feasible to evaluate it in a system in which the state variable was concentration. The reaction rate interface has been simplified with respect to the generation of derivatives. Reactions are defined as k*C, where k is the reaction rate and C is the product of concentrations (raised to their stoichiomentric coefficients and/or specified powers). Reaction rate classes now provide two logical functions governing the derivatives of k; i.e., ddT (derivative w.r.t. temperature) and ddc (derivative w.r.t. concentration). Previously the reaction rate interface was closely related to the form of third-body reactions, which made it inconvenient to implement rates that were not very third-body-like. It is now possible to verify the implementations of the jacobian methods by comparison with finite-difference based evaluations of the rate methods. This has been done and a number of bugs have been found and fixed in the reaction rate classes. --- src/ODE/ODESystem/ODESystem.C | 34 +- .../basicChemistryModel/basicChemistryModel.C | 21 +- .../basicChemistryModel/basicChemistryModel.H | 16 + .../chemistryModel/chemistryModel.C | 481 +++++++++++------- .../chemistryModel/chemistryModel.H | 54 +- .../chemistryModel/chemistryModelI.H | 20 +- .../chemistryModel/tabulation/ISAT/ISAT.C | 70 +-- .../chemistryModel/tabulation/ISAT/ISAT.H | 6 +- .../ISAT/chemPointISAT/chemPointISAT.H | 2 +- .../chemistryTabulationMethod.C | 2 +- .../chemistryTabulationMethod.H | 6 +- .../chemistryTabulationMethodNew.C | 2 +- .../noChemistryTabulation.C | 2 +- .../noChemistryTabulation.H | 2 +- .../chemistryModel/chemistrySolver/ode/ode.C | 4 +- ...uxLimitedLangmuirHinshelwoodReactionRate.H | 19 +- ...xLimitedLangmuirHinshelwoodReactionRateI.H | 21 +- .../IrreversibleReaction.C | 20 +- .../IrreversibleReaction.H | 28 +- .../NonEquilibriumReversibleReaction.C | 24 +- .../NonEquilibriumReversibleReaction.H | 25 +- .../reaction/Reactions/Reaction/Reaction.C | 354 ++++++------- .../reaction/Reactions/Reaction/Reaction.H | 96 ++-- .../Reactions/ReactionProxy/ReactionProxy.C | 17 +- .../Reactions/ReactionProxy/ReactionProxy.H | 21 +- .../ReversibleReaction/ReversibleReaction.C | 26 +- .../ReversibleReaction/ReversibleReaction.H | 25 +- .../ArrheniusReactionRate.H | 25 +- .../ArrheniusReactionRateI.H | 21 +- .../ChemicallyActivatedReactionRate.H | 29 +- .../ChemicallyActivatedReactionRateI.H | 170 ++++--- .../FallOffReactionRate/FallOffReactionRate.H | 30 +- .../FallOffReactionRateI.H | 132 +++-- .../JanevReactionRate/JanevReactionRate.H | 23 +- .../JanevReactionRate/JanevReactionRateI.H | 21 +- .../LandauTellerReactionRate.H | 23 +- .../LandauTellerReactionRateI.H | 21 +- .../LangmuirHinshelwoodReactionRate.H | 23 +- .../LangmuirHinshelwoodReactionRateI.H | 73 +-- .../MichaelisMentenReactionRate.H | 25 +- .../MichaelisMentenReactionRateI.H | 28 +- .../LindemannFallOffFunction.H | 14 +- .../LindemannFallOffFunctionI.H | 6 +- .../SRIFallOffFunction/SRIFallOffFunction.H | 14 +- .../SRIFallOffFunction/SRIFallOffFunctionI.H | 57 ++- .../TroeFallOffFunction/TroeFallOffFunction.H | 14 +- .../TroeFallOffFunctionI.H | 157 +++--- .../powerSeries/powerSeriesReactionRate.H | 23 +- .../powerSeries/powerSeriesReactionRateI.H | 21 +- .../thirdBodyArrheniusReactionRate.H | 27 +- .../thirdBodyArrheniusReactionRateI.H | 50 +- .../thirdBodyEfficiencies.H | 12 +- .../thirdBodyEfficienciesI.H | 17 +- .../reaction/specieCoeffs/specieCoeffs.C | 4 +- .../reaction/specieCoeffs/specieCoeffs.H | 121 +++-- .../reaction/specieExponent/specieExponent.H | 154 ++++++ .../reaction/specieExponent/specieExponentI.H | 174 +++++++ 57 files changed, 1595 insertions(+), 1312 deletions(-) create mode 100644 src/thermophysicalModels/specie/reaction/specieExponent/specieExponent.H create mode 100644 src/thermophysicalModels/specie/reaction/specieExponent/specieExponentI.H diff --git a/src/ODE/ODESystem/ODESystem.C b/src/ODE/ODESystem/ODESystem.C index 54ee308b96..0e4e465baf 100644 --- a/src/ODE/ODESystem/ODESystem.C +++ b/src/ODE/ODESystem/ODESystem.C @@ -57,8 +57,15 @@ void Foam::ODESystem::check jacobian(x, y, li, dfdx1, d2fdxdyAnalytic); // Compare derivatives - Info<< "[derivatives] dfdx = " << dfdx0 << nl; - Info<< "[ jacobian] dfdx = " << dfdx1 << nl; + Info<< "[derivatives] dfdx = ( "; + forAll(dfdx0, i) { Info<< dfdx0[i] << ' '; } + Info<< ")" << nl; + Info<< "[ jacobian] dfdx = ( "; + forAll(dfdx1, i) { Info<< dfdx1[i] << ' '; } + Info<< ")" << nl; + Info<< "[ ratio] dfdx = ( "; + forAll(dfdx1, i) { Info<< dfdx1[i]/stabilise(dfdx0[i], rootVSmall) << ' '; } + Info<< ")" << nl; // Construct a Jacobian using the finite differences and the derivatives // method @@ -83,10 +90,25 @@ void Foam::ODESystem::check for (label i = 0; i < nEqns(); ++ i) { - Info<< "[derivatives] d2fdxdy[" << i << "] = " - << UList(d2fdxdyFiniteDifference[i], nEqns()) << nl; - Info<< "[ jacobian] d2fdxdy[" << i << "] = " - << UList(d2fdxdyAnalytic[i], nEqns()) << nl; + UList FD(d2fdxdyFiniteDifference[i], nEqns()); + Info<< "[derivatives] d2fdxdy[" << i << "] = ( "; + forAll(FD, i) { Info<< FD[i] << ' '; } + Info<< ")" << nl; + } + for (label i = 0; i < nEqns(); ++ i) + { + UList A(d2fdxdyAnalytic[i], nEqns()); + Info<< "[ jacobian] d2fdxdy[" << i << "] = ( "; + forAll(A, i) { Info<< A[i] << ' '; } + Info<< ")" << nl; + } + for (label i = 0; i < nEqns(); ++ i) + { + UList FD(d2fdxdyFiniteDifference[i], nEqns()); + UList A(d2fdxdyAnalytic[i], nEqns()); + Info<< "[ ratio] d2fdxdy[" << i << "] = ( "; + forAll(A, i) { Info<< A[i]/stabilise(FD[i], rootVSmall) << ' '; } + Info<< ")" << nl; } } diff --git a/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.C b/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.C index 12a9b113bf..b704bb790c 100644 --- a/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.C +++ b/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.C @@ -25,7 +25,25 @@ License #include "basicChemistryModel.H" -/* * * * * * * * * * * * * * * private static data * * * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */ + +namespace Foam +{ + template<> + const char* NamedEnum::names[] = + { + "fast", + "exact" + }; +} + + +const Foam::NamedEnum +< + Foam::basicChemistryModel::jacobianType, + 2 +> Foam::basicChemistryModel::jacobianTypeNames_; + namespace Foam { @@ -33,6 +51,7 @@ namespace Foam defineRunTimeSelectionTable(basicChemistryModel, thermo); } + // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // void Foam::basicChemistryModel::correct() diff --git a/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.H b/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.H index c87cb1e9ff..7550254be2 100644 --- a/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.H +++ b/src/thermophysicalModels/chemistryModel/basicChemistryModel/basicChemistryModel.H @@ -54,6 +54,22 @@ class basicChemistryModel : public IOdictionary { +public: + + // Public Enumerations + + //- Enumeration for the type of Jacobian to be calculated by the + // chemistry model + enum class jacobianType + { + fast, + exact + }; + + //- Jacobian type names + static const NamedEnum jacobianTypeNames_; + + protected: // Protected data diff --git a/src/thermophysicalModels/chemistryModel/chemistryModel/chemistryModel.C b/src/thermophysicalModels/chemistryModel/chemistryModel/chemistryModel.C index 0d680b50ca..92e0f95329 100644 --- a/src/thermophysicalModels/chemistryModel/chemistryModel/chemistryModel.C +++ b/src/thermophysicalModels/chemistryModel/chemistryModel/chemistryModel.C @@ -39,16 +39,22 @@ Foam::chemistryModel::chemistryModel basicChemistryModel(thermo), ODESystem(), log_(this->lookupOrDefault("log", false)), - Y_(this->thermo().composition().Y()), + jacobianType_ + ( + this->found("jacobian") + ? jacobianTypeNames_.read(this->lookup("jacobian")) + : jacobianType::fast + ), + Yvf_(this->thermo().composition().Y()), mixture_(refCast>(this->thermo())), specieThermos_(mixture_.specieThermos()), reactions_(mixture_.species(), specieThermos_, this->mesh(), *this), - nSpecie_(Y_.size()), - nReaction_(reactions_.size()), - Treact_(basicChemistryModel::template lookupOrDefault("Treact", 0)), + nSpecie_(Yvf_.size()), RR_(nSpecie_), + Y_(nSpecie_), c_(nSpecie_), - dcdt_(nSpecie_), + YTpWork_(scalarField(nSpecie_ + 2)), + YTpYTpWork_(scalarSquareMatrix(nSpecie_ + 2)), cTos_(nSpecie_, -1), sToc_(nSpecie_), mechRedPtr_ @@ -81,7 +87,7 @@ Foam::chemistryModel::chemistryModel ( IOobject ( - "RR." + Y_[fieldi].name(), + "RR." + Yvf_[fieldi].name(), this->mesh().time().timeName(), this->mesh(), IOobject::NO_READ, @@ -94,7 +100,7 @@ Foam::chemistryModel::chemistryModel } Info<< "chemistryModel: Number of species = " << nSpecie_ - << " and reactions = " << nReaction_ << endl; + << " and reactions = " << nReaction() << endl; // When the mechanism reduction method is used, the 'active' flag for every // species should be initialised (by default 'active' is true) @@ -102,11 +108,11 @@ Foam::chemistryModel::chemistryModel { const basicSpecieMixture& composition = this->thermo().composition(); - forAll(Y_, i) + forAll(Yvf_, i) { typeIOobject header ( - Y_[i].name(), + Yvf_[i].name(), this->mesh().time().timeName(), this->mesh(), IOobject::NO_READ @@ -137,101 +143,95 @@ Foam::chemistryModel::~chemistryModel() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template -void Foam::chemistryModel::omega -( - const scalar p, - const scalar T, - const scalarField& c, // Contains all species even when mechRed is active - const label li, - scalarField& dcdt -) const -{ - if (mechRedActive_) - { - forAll(sToc_, si) - { - dcdt_[sToc_[si]] = 0; - } - - forAll(reactions_, i) - { - if (!mechRed_.reactionDisabled(i)) - { - const Reaction& R = reactions_[i]; - - R.omega(p, T, c, li, dcdt_); - } - } - - forAll(sToc_, si) - { - dcdt[si] = dcdt_[sToc_[si]]; - } - } - else - { - dcdt = Zero; - - forAll(reactions_, i) - { - const Reaction& R = reactions_[i]; - R.omega(p, T, c, li, dcdt); - } - } -} - - template void Foam::chemistryModel::derivatives ( const scalar time, - const scalarField& c, + const scalarField& YTp, const label li, - scalarField& dcdt + scalarField& dYTpdt ) const { - const scalar T = c[nSpecie_]; - const scalar p = c[nSpecie_ + 1]; - if (mechRedActive_) { forAll(sToc_, i) { - c_[sToc_[i]] = max(c[i], 0); + Y_[sToc_[i]] = max(YTp[i], 0); } } else { - forAll(c_, i) + forAll(Y_, i) { - c_[i] = max(c[i], 0); + Y_[i] = max(YTp[i], 0); } } + const scalar T = YTp[nSpecie_]; + const scalar p = YTp[nSpecie_ + 1]; + + // Evaluate the mixture density + scalar rhoM = 0; + for (label i=0; i void Foam::chemistryModel::jacobian ( const scalar t, - const scalarField& c, + const scalarField& YTp, const label li, - scalarField& dcdt, + scalarField& dYTpdt, scalarSquareMatrix& J ) const { - // If the mechanism reduction is active, the computed Jacobian - // is compact (size of the reduced set of species) - // but according to the information of the complete set - // (i.e. for the third-body efficiencies) - if (mechRedActive_) { forAll(sToc_, i) { - c_[sToc_[i]] = max(c[i], 0); + Y_[sToc_[i]] = max(YTp[i], 0); } } else { forAll(c_, i) { - c_[i] = max(c[i], 0); + Y_[i] = max(YTp[i], 0); } } - const scalar T = c[nSpecie_]; - const scalar p = c[nSpecie_ + 1]; + const scalar T = YTp[nSpecie_]; + const scalar p = YTp[nSpecie_ + 1]; - dcdt = Zero; - J = Zero; + // Evaluate the specific volumes and mixture density + scalarField& v = YTpWork_[0]; + for (label i=0; i& R = reactions_[ri]; - scalar omegaI, kfwd, kbwd; - R.dwdc + reactions_[ri].ddNdtByVdcTp ( p, T, c_, li, - J, - dcdt, - omegaI, - kfwd, - kbwd, - mechRedActive_, - cTos_ - ); - R.dwdT - ( - p, - T, - c_, - li, - omegaI, - kfwd, - kbwd, - J, + dYTpdt, + ddNdtByVdcTp, mechRedActive_, cTos_, - nSpecie_ + 0, + nSpecie_, + YTpWork_[1], + YTpWork_[2] ); } } + // Reactions return dNdtByV, so we need to convert the result to dYdt + for (label i=0; i::tc() const for (label i=0; i::Qdot() const scalarField& Qdot = tQdot.ref(); - forAll(Y_, i) + forAll(Yvf_, i) { forAll(Qdot, celli) { @@ -522,7 +614,7 @@ Foam::chemistryModel::calculateRR for (label i=0; i::calculate() const scalarField& T = this->thermo().T(); const scalarField& p = this->thermo().p(); + scalarField& dNdtByV = YTpWork_[0]; + reactionEvaluationScope scope(*this); forAll(rho, celli) @@ -576,15 +670,33 @@ void Foam::chemistryModel::calculate() for (label i=0; i::solve return deltaTMin; } - tmp trho(this->thermo().rho0()); - const scalarField& rho = trho(); + tmp trhovf(this->thermo().rho()); + const volScalarField& rhovf = trhovf(); + tmp trho0vf(this->thermo().rho0()); + const volScalarField& rho0vf = trho0vf(); - const scalarField& T = this->thermo().T().oldTime(); - const scalarField& p = this->thermo().p().oldTime(); + const volScalarField& T0vf = this->thermo().T().oldTime(); + const volScalarField& p0vf = this->thermo().p().oldTime(); reactionEvaluationScope scope(*this); - scalarField c0(nSpecie_); + scalarField Y0(nSpecie_); // Composition vector (Yi, T, p, deltaT) scalarField phiq(nEqns() + 1); scalarField Rphiq(nEqns() + 1); - forAll(rho, celli) + forAll(rho0vf, celli) { - const scalar rhoi = rho[celli]; - scalar pi = p[celli]; - scalar Ti = T[celli]; + const scalar rho = rhovf[celli]; + const scalar rho0 = rho0vf[celli]; + + scalar p = p0vf[celli]; + scalar T = T0vf[celli]; for (label i=0; i::solve // Retrieved solution stored in Rphiq for (label i=0; i::solve { if (mechRedActive_) { + for (label i=0; i::solve // Solve the reduced set of ODE solve ( - pi, - Ti, - sc_, + p, + T, + sY_, celli, dt, deltaTChem_[celli] @@ -709,13 +841,12 @@ Foam::scalar Foam::chemistryModel::solve for (label i=0; i::solve // the stored points (either expand or add) if (tabulation_.tabulates()) { - forAll(c_, i) + forAll(Y_, i) { - Rphiq[i] = c_[i]/rhoi*specieThermos_[i].W(); + Rphiq[i] = Y_[i]; } - Rphiq[Rphiq.size()-3] = Ti; - Rphiq[Rphiq.size()-2] = pi; + Rphiq[Rphiq.size()-3] = T; + Rphiq[Rphiq.size()-2] = p; Rphiq[Rphiq.size()-1] = deltaT[celli]; - tabulation_.add(phiq, Rphiq, celli, rhoi, deltaT[celli]); + tabulation_.add(phiq, Rphiq, celli, rho0, deltaT[celli]); } // When operations are done and if mechanism reduction is active, @@ -745,19 +876,17 @@ Foam::scalar Foam::chemistryModel::solve // to the total number of species (stored in the mechRed object) if (mechRedActive_) { - nSpecie_ = mechRed_.nSpecie(); + setNSpecie(mechRed_.nSpecie()); } - deltaTMin = min(deltaTChem_[celli], deltaTMin); - deltaTChem_[celli] = - min(deltaTChem_[celli], deltaTChemMax_); + deltaTMin = min(deltaTChem_[celli], deltaTMin); + deltaTChem_[celli] = min(deltaTChem_[celli], deltaTChemMax_); } // Set the RR vector (used in the solver) for (label i=0; i& Y_; + const PtrList& Yvf_; //- Reference to the multi component mixture const multiComponentMixture& mixture_; @@ -145,24 +148,27 @@ class chemistryModel //- Number of species label nSpecie_; - //- Number of reactions - label nReaction_; - - //- Temperature below which the reaction rates are assumed 0 - scalar Treact_; - //- List of reaction rate per specie [kg/m^3/s] PtrList RR_; + //- Temporary mass fraction field + mutable scalarField Y_; + + //- Temporary simplified mechanism mass fraction field + DynamicField sY_; + //- Temporary concentration field mutable scalarField c_; - //- Temporary rate-of-change of concentration field - mutable scalarField dcdt_; - //- Temporary simplified mechanism concentration field DynamicField sc_; + //- Specie-temperature-pressure workspace fields + mutable FixedList YTpWork_; + + //- Specie-temperature-pressure workspace matrices + mutable FixedList YTpYTpWork_; + //- Temporary map from complete to simplified concentration fields // c -> sc List