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