TDACChemistryModel: New chemistry model providing Tabulation of Dynamic Adaptive Chemistry

Provides efficient integration of complex laminar reaction chemistry,
combining the advantages of automatic dynamic specie and reaction
reduction with ISAT (in situ adaptive tabulation).  The advantages grow
as the complexity of the chemistry increases.

References:
    Contino, F., Jeanmart, H., Lucchini, T., & D’Errico, G. (2011).
    Coupling of in situ adaptive tabulation and dynamic adaptive chemistry:
    An effective method for solving combustion in engine simulations.
    Proceedings of the Combustion Institute, 33(2), 3057-3064.

    Contino, F., Lucchini, T., D'Errico, G., Duynslaegher, C.,
    Dias, V., & Jeanmart, H. (2012).
    Simulations of advanced combustion modes using detailed chemistry
    combined with tabulation and mechanism reduction techniques.
    SAE International Journal of Engines,
    5(2012-01-0145), 185-196.

    Contino, F., Foucher, F., Dagaut, P., Lucchini, T., D’Errico, G., &
    Mounaïm-Rousselle, C. (2013).
    Experimental and numerical analysis of nitric oxide effect on the
    ignition of iso-octane in a single cylinder HCCI engine.
    Combustion and Flame, 160(8), 1476-1483.

    Contino, F., Masurier, J. B., Foucher, F., Lucchini, T., D’Errico, G., &
    Dagaut, P. (2014).
    CFD simulations using the TDAC method to model iso-octane combustion
    for a large range of ozone seeding and temperature conditions
    in a single cylinder HCCI engine.
    Fuel, 137, 179-184.

Two tutorial cases are currently provided:
    + tutorials/combustion/chemFoam/ic8h18_TDAC
    + tutorials/combustion/reactingFoam/laminar/counterFlowFlame2D_GRI_TDAC

the first of which clearly demonstrates the advantage of dynamic
adaptive chemistry providing ~10x speedup,

the second demonstrates ISAT on the modest complex GRI mechanisms for
methane combustion, providing a speedup of ~4x.

More tutorials demonstrating TDAC on more complex mechanisms and cases
will be provided soon in addition to documentation for the operation and
settings of TDAC.  Also further updates to the TDAC code to improve
consistency and integration with the rest of OpenFOAM and further
optimize operation can be expected.

Original code providing all algorithms for chemistry reduction and
tabulation contributed by Francesco Contino, Tommaso Lucchini, Gianluca
D’Errico, Hervé Jeanmart, Nicolas Bourgeois and Stéphane Backaert.

Implementation updated, optimized and integrated into OpenFOAM-dev by
Henry G. Weller, CFD Direct Ltd with the help of Francesco Contino.
This commit is contained in:
Henry Weller
2016-07-17 15:13:54 +01:00
parent 2d54b1d42b
commit 1d57269680
125 changed files with 45393 additions and 185 deletions

View File

@ -16,7 +16,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -16,7 +16,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -17,7 +17,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -17,7 +17,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -16,7 +16,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -16,7 +16,7 @@ tmp<fv::convectionScheme<scalar>> mvConvection
forAll(Y, i)
{
if (i != inertIndex)
if (i != inertIndex && composition.active(i))
{
volScalarField& Yi = Y[i];

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2015-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -142,6 +142,12 @@ Foam::MultiComponentPhaseModel<BasePhaseModel>::YiEqn
this->name()
)
)
|| (
!this->thermo_->composition().active
(
this->thermo_->composition().species()[Yi.member()]
)
)
)
{
return tmp<fvScalarMatrix>();

View File

@ -57,6 +57,7 @@ cleanCase()
rm -rf processor* > /dev/null 2>&1
rm -rf postProcessing > /dev/null 2>&1
rm -rf TDAC > /dev/null 2>&1
rm -rf probes* > /dev/null 2>&1
rm -rf forces* > /dev/null 2>&1
rm -rf graphs* > /dev/null 2>&1

View File

@ -6,6 +6,9 @@ chemistryModel/psiChemistryModel/psiChemistryModels.C
chemistryModel/rhoChemistryModel/rhoChemistryModel.C
chemistryModel/rhoChemistryModel/rhoChemistryModels.C
chemistryModel/TDACChemistryModel/reduction/makeChemistryReductionMethods.C
chemistryModel/TDACChemistryModel/tabulation/makeChemistryTabulationMethods.C
chemistrySolver/chemistrySolver/makeChemistrySolvers.C
LIB = $(FOAM_LIBBIN)/libchemistryModel

View File

@ -0,0 +1,843 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "TDACChemistryModel.H"
#include "UniformField.H"
#include "clockTime.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::TDACChemistryModel<CompType, ThermoType>::TDACChemistryModel
(
const fvMesh& mesh,
const word& phaseName
)
:
chemistryModel<CompType, ThermoType>(mesh, phaseName),
NsDAC_(this->nSpecie_),
completeC_(this->nSpecie_,0.0),
reactionsDisabled_(this->reactions_.size(), false),
completeToSimplifiedIndex_(this->nSpecie_,-1),
simplifiedToCompleteIndex_(this->nSpecie_),
specieComp_(this->nSpecie_)
{
basicMultiComponentMixture& composition = this->thermo().composition();
// Store the species composition according to the species index
speciesTable speciesTab = composition.species();
const HashTable<List<specieElement>>& specComp =
dynamicCast<const reactingMixture<ThermoType>&>(this->thermo())
.specieComposition();
forAll(specieComp_,i)
{
specieComp_[i] = specComp[this->Y()[i].name()];
}
mechRed_ = chemistryReductionMethod<CompType, ThermoType>::New
(
*this,
*this
);
// When the mechanism reduction method is used, the 'active' flag for every
// species should be initialized (by default 'active' is true)
if (mechRed_->active())
{
forAll(this->Y(), i)
{
IOobject header
(
this->Y()[i].name(),
mesh.time().timeName(),
mesh,
IOobject::NO_READ
);
// Check if the species file is provided, if not set inactive
// and NO_WRITE
if (!header.headerOk())
{
composition.setInactive(i);
this->Y()[i].writeOpt() = IOobject::NO_WRITE;
}
}
}
tabulation_ = chemistryTabulationMethod<CompType, ThermoType>::New
(
*this,
*this
);
if (mechRed_->log())
{
cpuReduceFile_ = logFile("cpu_reduce.out");
nActiveSpeciesFile_ = logFile("nActiveSpecies.out");
}
if (tabulation_->log())
{
cpuAddFile_ = logFile("cpu_add.out");
cpuRetrieveFile_ = logFile("cpu_retrieve.out");
}
if (mechRed_->log() || tabulation_->log())
{
cpuSolveFile_ = logFile("cpu_solve.out");
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::TDACChemistryModel<CompType, ThermoType>::~TDACChemistryModel()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::TDACChemistryModel<CompType, ThermoType>::omega
(
const scalarField& c, // Contains all species even when mechRed is active
const scalar T,
const scalar p,
scalarField& dcdt
) const
{
const bool reduced = mechRed_->active();
scalar pf, cf, pr, cr;
label lRef, rRef;
dcdt = Zero;
forAll(this->reactions_, i)
{
if (!reactionsDisabled_[i])
{
const Reaction<ThermoType>& R = this->reactions_[i];
scalar omegai = omega
(
R, c, T, p, pf, cf, lRef, pr, cr, rRef
);
forAll(R.lhs(), s)
{
label si = R.lhs()[s].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sl = R.lhs()[s].stoichCoeff;
dcdt[si] -= sl*omegai;
}
forAll(R.rhs(), s)
{
label si = R.rhs()[s].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sr = R.rhs()[s].stoichCoeff;
dcdt[si] += sr*omegai;
}
}
}
}
template<class CompType, class ThermoType>
Foam::scalar Foam::TDACChemistryModel<CompType, ThermoType>::omega
(
const Reaction<ThermoType>& R,
const scalarField& c, // Contains all species even when mechRed is active
const scalar T,
const scalar p,
scalar& pf,
scalar& cf,
label& lRef,
scalar& pr,
scalar& cr,
label& rRef
) const
{
const scalar kf = R.kf(p, T, c);
const scalar kr = R.kr(kf, p, T, c);
const label Nl = R.lhs().size();
const label Nr = R.rhs().size();
label slRef = 0;
lRef = R.lhs()[slRef].index;
pf = kf;
for (label s=1; s<Nl; s++)
{
const label si = R.lhs()[s].index;
if (c[si] < c[lRef])
{
const scalar exp = R.lhs()[slRef].exponent;
pf *= pow(max(0.0, c[lRef]), exp);
lRef = si;
slRef = s;
}
else
{
const scalar exp = R.lhs()[s].exponent;
pf *= pow(max(0.0, c[si]), exp);
}
}
cf = max(0.0, c[lRef]);
{
const scalar exp = R.lhs()[slRef].exponent;
if (exp < 1)
{
if (cf > SMALL)
{
pf *= pow(cf, exp - 1);
}
else
{
pf = 0;
}
}
else
{
pf *= pow(cf, exp - 1);
}
}
label srRef = 0;
rRef = R.rhs()[srRef].index;
// Find the matrix element and element position for the rhs
pr = kr;
for (label s=1; s<Nr; s++)
{
const label si = R.rhs()[s].index;
if (c[si] < c[rRef])
{
const scalar exp = R.rhs()[srRef].exponent;
pr *= pow(max(0.0, c[rRef]), exp);
rRef = si;
srRef = s;
}
else
{
const scalar exp = R.rhs()[s].exponent;
pr *= pow(max(0.0, c[si]), exp);
}
}
cr = max(0.0, c[rRef]);
{
const scalar exp = R.rhs()[srRef].exponent;
if (exp < 1)
{
if (cr>SMALL)
{
pr *= pow(cr, exp - 1);
}
else
{
pr = 0;
}
}
else
{
pr *= pow(cr, exp - 1);
}
}
return pf*cf - pr*cr;
}
template<class CompType, class ThermoType>
void Foam::TDACChemistryModel<CompType, ThermoType>::derivatives
(
const scalar time,
const scalarField& c,
scalarField& dcdt
) const
{
const bool reduced = mechRed_->active();
const scalar T = c[this->nSpecie_];
const scalar p = c[this->nSpecie_ + 1];
if (reduced)
{
// When using DAC, the ODE solver submit a reduced set of species the
// complete set is used and only the species in the simplified mechanism
// are updated
this->c_ = completeC_;
// Update the concentration of the species in the simplified mechanism
// the other species remain the same and are used only for third-body
// efficiencies
for (label i=0; i<NsDAC_; i++)
{
this->c_[simplifiedToCompleteIndex_[i]] = max(0.0, c[i]);
}
}
else
{
for (label i=0; i<this->nSpecie(); i++)
{
this->c_[i] = max(0.0, c[i]);
}
}
omega(this->c_, T, p, dcdt);
// Constant pressure
// dT/dt = ...
scalar rho = 0;
for (label i=0; i<this->c_.size(); i++)
{
const scalar W = this->specieThermo_[i].W();
rho += W*this->c_[i];
}
scalar cp = 0;
for (label i=0; i<this->c_.size(); i++)
{
// cp function returns [J/(kmol K)]
cp += this->c_[i]*this->specieThermo_[i].cp(p, T);
}
cp /= rho;
// When mechanism reduction is active
// dT is computed on the reduced set since dcdt is null
// for species not involved in the simplified mechanism
scalar dT = 0;
for (label i=0; i<this->nSpecie_; i++)
{
label si;
if (reduced)
{
si = simplifiedToCompleteIndex_[i];
}
else
{
si = i;
}
// ha function returns [J/kmol]
const scalar hi = this->specieThermo_[si].ha(p, T);
dT += hi*dcdt[i];
}
dT /= rho*cp;
dcdt[this->nSpecie_] = -dT;
// dp/dt = ...
dcdt[this->nSpecie_ + 1] = 0;
}
template<class CompType, class ThermoType>
void Foam::TDACChemistryModel<CompType, ThermoType>::jacobian
(
const scalar t,
const scalarField& c,
scalarSquareMatrix& dfdc
) const
{
const bool reduced = mechRed_->active();
// If the mechanism reduction is active, the computed Jacobian
// is compact (size of the reduced set of species)
// but according to the informations of the complete set
// (i.e. for the third-body efficiencies)
const scalar T = c[this->nSpecie_];
const scalar p = c[this->nSpecie_ + 1];
if (reduced)
{
this->c_ = completeC_;
for (label i=0; i<NsDAC_; i++)
{
this->c_[simplifiedToCompleteIndex_[i]] = max(0.0, c[i]);
}
}
else
{
forAll(this->c_, i)
{
this->c_[i] = max(c[i], 0.0);
}
}
dfdc = Zero;
forAll(this->reactions_, ri)
{
if (!reactionsDisabled_[ri])
{
const Reaction<ThermoType>& R = this->reactions_[ri];
const scalar kf0 = R.kf(p, T, this->c_);
const scalar kr0 = R.kr(kf0, p, T, this->c_);
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
if (reduced)
{
sj = completeToSimplifiedIndex_[sj];
}
scalar kf = kf0;
forAll(R.lhs(), i)
{
const label si = R.lhs()[i].index;
const scalar el = R.lhs()[i].exponent;
if (i == j)
{
if (el < 1)
{
if (this->c_[si] > SMALL)
{
kf *= el*pow(this->c_[si] + VSMALL, el - 1);
}
else
{
kf = 0;
}
}
else
{
kf *= el*pow(this->c_[si], el - 1);
}
}
else
{
kf *= pow(this->c_[si], el);
}
}
forAll(R.lhs(), i)
{
label si = R.lhs()[i].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sl = R.lhs()[i].stoichCoeff;
dfdc(si, sj) -= sl*kf;
}
forAll(R.rhs(), i)
{
label si = R.rhs()[i].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sr = R.rhs()[i].stoichCoeff;
dfdc(si, sj) += sr*kf;
}
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
if (reduced)
{
sj = completeToSimplifiedIndex_[sj];
}
scalar kr = kr0;
forAll(R.rhs(), i)
{
const label si = R.rhs()[i].index;
const scalar er = R.rhs()[i].exponent;
if (i == j)
{
if (er < 1)
{
if (this->c_[si] > SMALL)
{
kr *= er*pow(this->c_[si] + VSMALL, er - 1);
}
else
{
kr = 0;
}
}
else
{
kr *= er*pow(this->c_[si], er - 1);
}
}
else
{
kr *= pow(this->c_[si], er);
}
}
forAll(R.lhs(), i)
{
label si = R.lhs()[i].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sl = R.lhs()[i].stoichCoeff;
dfdc(si, sj) += sl*kr;
}
forAll(R.rhs(), i)
{
label si = R.rhs()[i].index;
if (reduced)
{
si = completeToSimplifiedIndex_[si];
}
const scalar sr = R.rhs()[i].stoichCoeff;
dfdc(si, sj) -= sr*kr;
}
}
}
}
// Calculate the dcdT elements numerically
const scalar delta = 1e-3;
omega(this->c_, T + delta, p, this->dcdt_);
for (label i=0; i<this->nSpecie_; i++)
{
dfdc(i, this->nSpecie_) = this->dcdt_[i];
}
omega(this->c_, T - delta, p, this->dcdt_);
for (label i=0; i<this->nSpecie_; i++)
{
dfdc(i, this->nSpecie_) =
0.5*(dfdc(i, this->nSpecie_) - this->dcdt_[i])/delta;
}
dfdc(this->nSpecie_, this->nSpecie_) = 0;
dfdc(this->nSpecie_ + 1, this->nSpecie_) = 0;
}
template<class CompType, class ThermoType>
void Foam::TDACChemistryModel<CompType, ThermoType>::jacobian
(
const scalar t,
const scalarField& c,
scalarField& dcdt,
scalarSquareMatrix& dfdc
) const
{
jacobian(t, c, dfdc);
const scalar T = c[this->nSpecie_];
const scalar p = c[this->nSpecie_ + 1];
// Note: Uses the c_ field initialized by the call to jacobian above
omega(this->c_, T, p, dcdt);
}
template<class CompType, class ThermoType>
template<class DeltaTType>
Foam::scalar Foam::TDACChemistryModel<CompType, ThermoType>::solve
(
const DeltaTType& deltaT
)
{
const bool reduced = mechRed_->active();
basicMultiComponentMixture& composition = this->thermo().composition();
// CPU time analysis
const clockTime clockTime_= clockTime();
clockTime_.timeIncrement();
scalar reduceMechCpuTime_ = 0;
scalar addNewLeafCpuTime_ = 0;
scalar solveChemistryCpuTime_ = 0;
scalar searchISATCpuTime_ = 0;
// Average number of active species
scalar nActiveSpecies = 0;
scalar nAvg = 0;
CompType::correct();
scalar deltaTMin = GREAT;
if (!this->chemistry_)
{
return deltaTMin;
}
const volScalarField rho
(
IOobject
(
"rho",
this->time().timeName(),
this->mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
this->thermo().rho()
);
const scalarField& T = this->thermo().T();
const scalarField& p = this->thermo().p();
scalarField c(this->nSpecie_);
scalarField c0(this->nSpecie_);
// Composition vector (Yi, T, p)
scalarField phiq(this->nEqns());
scalarField Rphiq(this->nEqns());
forAll(rho, celli)
{
const scalar rhoi = rho[celli];
scalar pi = p[celli];
scalar Ti = T[celli];
for (label i=0; i<this->nSpecie_; i++)
{
c[i] = rhoi*this->Y_[i][celli]/this->specieThermo_[i].W();
c0[i] = c[i];
phiq[i] = this->Y()[i][celli];
}
phiq[this->nSpecie()]=Ti;
phiq[this->nSpecie()+1]=pi;
// Initialise time progress
scalar timeLeft = deltaT[celli];
// Not sure if this is necessary
Rphiq = Zero;
clockTime_.timeIncrement();
// When tabulation is active (short-circuit evaluation for retrieve)
// It first tries to retrieve the solution of the system with the
// information stored through the tabulation method
if (tabulation_->active() && tabulation_->retrieve(phiq, Rphiq))
{
// Retrieved solution stored in Rphiq
for (label i=0; i<this->nSpecie(); i++)
{
c[i] = rhoi*Rphiq[i]/this->specieThermo_[i].W();
}
searchISATCpuTime_ += clockTime_.timeIncrement();
}
// This position is reached when tabulation is not used OR
// if the solution is not retrieved.
// In the latter case, it adds the information to the tabulation
// (it will either expand the current data or add a new stored poin).
else
{
clockTime_.timeIncrement();
if (reduced)
{
// Reduce mechanism change the number of species (only active)
mechRed_->reduceMechanism(c, Ti, pi);
nActiveSpecies += mechRed_->NsSimp();
nAvg++;
}
reduceMechCpuTime_ += clockTime_.timeIncrement();
// Calculate the chemical source terms
while (timeLeft > SMALL)
{
scalar dt = timeLeft;
if (reduced)
{
// completeC_ used in the overridden ODE methods
// to update only the active species
completeC_ = c;
// Solve the reduced set of ODE
this->solve
(
simplifiedC_, Ti, pi, dt, this->deltaTChem_[celli]
);
for (label i=0; i<NsDAC_; i++)
{
c[simplifiedToCompleteIndex_[i]] = simplifiedC_[i];
}
}
else
{
this->solve(c, Ti, pi, dt, this->deltaTChem_[celli]);
}
timeLeft -= dt;
}
solveChemistryCpuTime_ += clockTime_.timeIncrement();
// If tabulation is used, we add the information computed here to
// the stored points (either expand or add)
if (tabulation_->active())
{
forAll(c, i)
{
Rphiq[i] = c[i]/rhoi*this->specieThermo_[i].W();
}
Rphiq[Rphiq.size()-2] = Ti;
Rphiq[Rphiq.size()-1] = pi;
tabulation_->add(phiq, Rphiq, rhoi);
}
addNewLeafCpuTime_ += clockTime_.timeIncrement();
// When operations are done and if mechanism reduction is active,
// the number of species (which also affects nEqns) is set back
// to the total number of species (stored in the mechRed object)
if (reduced)
{
this->nSpecie_ = mechRed_->nSpecie();
}
deltaTMin = min(this->deltaTChem_[celli], deltaTMin);
}
// Set the RR vector (used in the solver)
for (label i=0; i<this->nSpecie_; i++)
{
this->RR_[i][celli] =
(c[i] - c0[i])*this->specieThermo_[i].W()/deltaT[celli];
}
}
if (mechRed_->log() || tabulation_->log())
{
cpuSolveFile_()
<< this->time().timeOutputValue()
<< " " << solveChemistryCpuTime_ << endl;
}
if (mechRed_->log())
{
cpuReduceFile_()
<< this->time().timeOutputValue()
<< " " << reduceMechCpuTime_ << endl;
}
if (tabulation_->active())
{
// Every time-step, look if the tabulation should be updated
tabulation_->update();
// Write the performance of the tabulation
tabulation_->writePerformance();
if (tabulation_->log())
{
cpuRetrieveFile_()
<< this->time().timeOutputValue()
<< " " << searchISATCpuTime_ << endl;
cpuAddFile_()
<< this->time().timeOutputValue()
<< " " << addNewLeafCpuTime_ << endl;
}
}
if (reduced && nAvg && mechRed_->log())
{
// Write average number of species
nActiveSpeciesFile_()
<< this->time().timeOutputValue()
<< " " << nActiveSpecies/nAvg << endl;
}
if (Pstream::parRun())
{
List<bool> active(composition.active());
Pstream::listCombineGather(active, orEqOp<bool>());
Pstream::listCombineScatter(active);
forAll(active, i)
{
if (active[i])
{
composition.setActive(i);
}
}
}
forAll(this->Y(), i)
{
if (composition.active(i))
{
this->Y()[i].writeOpt() = IOobject::AUTO_WRITE;
}
}
return deltaTMin;
}
template<class CompType, class ThermoType>
Foam::scalar Foam::TDACChemistryModel<CompType, ThermoType>::solve
(
const scalar deltaT
)
{
// Don't allow the time-step to change more than a factor of 2
return min
(
this->solve<UniformField<scalar>>(UniformField<scalar>(deltaT)),
2*deltaT
);
}
template<class CompType, class ThermoType>
Foam::scalar Foam::TDACChemistryModel<CompType, ThermoType>::solve
(
const scalarField& deltaT
)
{
return this->solve<scalarField>(deltaT);
}
// ************************************************************************* //

View File

@ -0,0 +1,280 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::TDACChemistryModel
Description
Extends chemistryModel by adding the TDAC method.
References:
\verbatim
Contino, F., Jeanmart, H., Lucchini, T., & DErrico, G. (2011).
Coupling of in situ adaptive tabulation and dynamic adaptive chemistry:
An effective method for solving combustion in engine simulations.
Proceedings of the Combustion Institute, 33(2), 3057-3064.
Contino, F., Lucchini, T., D'Errico, G., Duynslaegher, C.,
Dias, V., & Jeanmart, H. (2012).
Simulations of advanced combustion modes using detailed chemistry
combined with tabulation and mechanism reduction techniques.
SAE International Journal of Engines,
5(2012-01-0145), 185-196.
Contino, F., Foucher, F., Dagaut, P., Lucchini, T., DErrico, G., &
Mounaïm-Rousselle, C. (2013).
Experimental and numerical analysis of nitric oxide effect on the
ignition of iso-octane in a single cylinder HCCI engine.
Combustion and Flame, 160(8), 1476-1483.
Contino, F., Masurier, J. B., Foucher, F., Lucchini, T., DErrico, G., &
Dagaut, P. (2014).
CFD simulations using the TDAC method to model iso-octane combustion
for a large range of ozone seeding and temperature conditions
in a single cylinder HCCI engine.
Fuel, 137, 179-184.
\endverbatim
SourceFiles
TDACChemistryModelI.H
TDACChemistryModel.C
\*---------------------------------------------------------------------------*/
#ifndef TDACChemistryModel_H
#define TDACChemistryModel_H
#include "chemistryModel.H"
#include "chemistryReductionMethod.H"
#include "chemistryTabulationMethod.H"
#include "OFstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class TDACChemistryModel Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class TDACChemistryModel
:
public chemistryModel<CompType, ThermoType>
{
// Private member data
// Mechanism reduction
label NsDAC_;
scalarField completeC_;
scalarField simplifiedC_;
Field<bool> reactionsDisabled_;
Field<label> completeToSimplifiedIndex_;
DynamicList<label> simplifiedToCompleteIndex_;
List<List<specieElement>> specieComp_;
autoPtr<chemistryReductionMethod<CompType, ThermoType>> mechRed_;
// Tabulation
autoPtr<chemistryTabulationMethod<CompType, ThermoType>> tabulation_;
// Log file for the average time spent reducing the chemistry
autoPtr<OFstream> cpuReduceFile_;
// Write average number of species
autoPtr<OFstream> nActiveSpeciesFile_;
//- Log file for the average time spent adding tabulated data
autoPtr<OFstream> cpuAddFile_;
//- Log file for the average time spent retrieving tabulated data
autoPtr<OFstream> cpuRetrieveFile_;
//- Log file for average time spent solving the chemistry
autoPtr<OFstream> cpuSolveFile_;
// Private Member Functions
//- Disallow copy constructor
TDACChemistryModel(const TDACChemistryModel&);
//- Disallow default bitwise assignment
void operator=(const TDACChemistryModel&);
//- Solve the reaction system for the given time step
// of given type and return the characteristic time
// Variable number of species added
template<class DeltaTType>
scalar solve(const DeltaTType& deltaT);
public:
//- Runtime type information
TypeName("TDACChemistryModel");
// Constructors
//- Construct from mesh
TDACChemistryModel
(
const fvMesh& mesh,
const word& phaseName
);
//- Destructor
virtual ~TDACChemistryModel();
// Member Functions
//- Create and return a TDAC log file of the given name
inline autoPtr<OFstream> logFile(const word& name) const;
inline PtrList<volScalarField>& Y();
//- dc/dt = omega, rate of change in concentration, for each species
virtual void omega
(
const scalarField& c,
const scalar T,
const scalar p,
scalarField& dcdt
) const;
//- Return the reaction rate for reaction r and the reference
// species and charateristic times
virtual scalar omega
(
const Reaction<ThermoType>& r,
const scalarField& c,
const scalar T,
const scalar p,
scalar& pf,
scalar& cf,
label& lRef,
scalar& pr,
scalar& cr,
label& rRef
) const;
// Chemistry model functions (overriding functions in
// chemistryModel to use the private solve function)
//- Solve the reaction system for the given time step
// and return the characteristic time
virtual scalar solve(const scalar deltaT);
//- Solve the reaction system for the given time step
// and return the characteristic time
virtual scalar solve(const scalarField& deltaT);
// ODE functions (overriding functions in chemistryModel to take into
// account the variable number of species)
virtual void derivatives
(
const scalar t,
const scalarField& c,
scalarField& dcdt
) const;
//- Pure jacobian function for tabulation
void jacobian
(
const scalar t,
const scalarField& c,
scalarSquareMatrix& dfdc
) const;
virtual void jacobian
(
const scalar t,
const scalarField& c,
scalarField& dcdt,
scalarSquareMatrix& dfdc
) const;
virtual void solve
(
scalarField& c,
scalar& T,
scalar& p,
scalar& deltaT,
scalar& subDeltaT
) const = 0;
// Mechanism reduction access functions
inline void setNsDAC(const label newNsDAC);
inline void setNSpecie(const label newNs);
inline scalarField& completeC();
inline scalarField& simplifiedC();
inline Field<bool>& reactionsDisabled();
inline bool active(const label i) const;
inline void setActive(const label i);
inline DynamicList<label>& simplifiedToCompleteIndex();
inline Field<label>& completeToSimplifiedIndex();
inline const Field<label>& completeToSimplifiedIndex() const;
inline List<List<specieElement>>& specieComp();
inline autoPtr<chemistryReductionMethod<CompType, ThermoType>>&
mechRed();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "TDACChemistryModelI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "TDACChemistryModel.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,152 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
inline Foam::autoPtr<Foam::OFstream>
Foam::TDACChemistryModel<CompType, ThermoType>::logFile(const word& name) const
{
mkDir(this->mesh().time().path()/"TDAC");
return autoPtr<OFstream>
(
new OFstream
(
this->mesh().time().path()/"TDAC"/name
)
);
}
template<class CompType, class ThermoType>
inline Foam::PtrList<Foam::volScalarField>&
Foam::TDACChemistryModel<CompType, ThermoType>::Y()
{
return this->Y_;
}
template<class CompType, class ThermoType>
inline Foam::autoPtr<Foam::chemistryReductionMethod<CompType, ThermoType>>&
Foam::TDACChemistryModel<CompType, ThermoType>::mechRed()
{
return mechRed_;
}
template<class CompType, class ThermoType>
inline void Foam::TDACChemistryModel<CompType, ThermoType>::setActive
(
const label i
)
{
this->thermo().composition().setActive(i);
}
template<class CompType, class ThermoType>
inline bool Foam::TDACChemistryModel<CompType, ThermoType>::active
(
const label i
) const
{
return this->thermo().composition().active(i);
}
template<class CompType, class ThermoType>
inline void
Foam::TDACChemistryModel<CompType, ThermoType>::setNsDAC(const label newNsDAC)
{
NsDAC_ = newNsDAC;
}
template<class CompType, class ThermoType>
inline void
Foam::TDACChemistryModel<CompType, ThermoType>::setNSpecie(const label newNs)
{
this->nSpecie_ = newNs;
}
template<class CompType, class ThermoType>
inline Foam::DynamicList<Foam::label>&
Foam::TDACChemistryModel<CompType, ThermoType>::simplifiedToCompleteIndex()
{
return simplifiedToCompleteIndex_;
}
template<class CompType, class ThermoType>
inline Foam::Field<Foam::label>&
Foam::TDACChemistryModel<CompType, ThermoType>::completeToSimplifiedIndex()
{
return completeToSimplifiedIndex_;
}
template<class CompType, class ThermoType>
inline const Foam::Field<Foam::label>&
Foam::TDACChemistryModel<CompType, ThermoType>::
completeToSimplifiedIndex() const
{
return completeToSimplifiedIndex_;
}
template<class CompType, class ThermoType>
inline Foam::Field<bool>&
Foam::TDACChemistryModel<CompType, ThermoType>::reactionsDisabled()
{
return reactionsDisabled_;
}
template<class CompType, class ThermoType>
inline Foam::scalarField&
Foam::TDACChemistryModel<CompType, ThermoType>::completeC()
{
return completeC_;
}
template<class CompType, class ThermoType>
inline Foam::scalarField&
Foam::TDACChemistryModel<CompType, ThermoType>::simplifiedC()
{
return simplifiedC_;
}
template<class CompType, class ThermoType>
inline Foam::List<Foam::List<Foam::specieElement>>&
Foam::TDACChemistryModel<CompType, ThermoType>::specieComp()
{
return specieComp_;
}
// ************************************************************************* //

View File

@ -0,0 +1,746 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "DAC.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DAC<CompType, ThermoType>::DAC
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry),
searchInitSet_(this->coeffsDict_.subDict("initialSet").size()),
zprime_(0),
nbCLarge_(3),
sC_(this->nSpecie_,0),
sH_(this->nSpecie_,0),
sO_(this->nSpecie_,0),
sN_(this->nSpecie_,0),
CO2Id_(-1),
COId_(-1),
HO2Id_(-1),
H2OId_(-1),
NOId_(-1),
automaticSIS_(true),
phiTol_(this->tolerance()),
NOxThreshold_(1800),
CO2Name_
(
dict.subDict("reduction").lookupOrDefault<word>
(
"CO2Name","CO2"
)
),
COName_
(
dict.subDict("reduction").lookupOrDefault<word>
(
"COName","CO"
)
),
HO2Name_
(
dict.subDict("reduction").lookupOrDefault<word>
(
"HO2Name","HO2"
)
),
H2OName_
(
dict.subDict("reduction").lookupOrDefault<word>
(
"H2OName","H2O"
)
),
NOName_
(
dict.subDict("reduction").lookupOrDefault<word>
(
"NOName","NO"
)
),
forceFuelInclusion_(false)
{
label j=0;
dictionary initSet = this->coeffsDict_.subDict("initialSet");
for (label i=0; i<chemistry.nSpecie(); i++)
{
if (initSet.found(chemistry.Y()[i].name()))
{
searchInitSet_[j++] = i;
}
}
if (j<searchInitSet_.size())
{
FatalErrorInFunction
<< searchInitSet_.size()-j
<< " species in the intial set is not in the mechanism "
<< initSet
<< exit(FatalError);
}
if (this->coeffsDict_.found("automaticSIS"))
{
automaticSIS_.readIfPresent("automaticSIS", this->coeffsDict_);
}
if (this->coeffsDict_.found("forceFuelInclusion"))
{
forceFuelInclusion_.readIfPresent
(
"forceFuelInclusion",this->coeffsDict_
);
}
if (this->coeffsDict_.found("phiTol"))
{
phiTol_ = readScalar(this->coeffsDict_.lookup("phiTol"));
}
if (this->coeffsDict_.found("NOxThreshold"))
{
NOxThreshold_ = readScalar(this->coeffsDict_.lookup("NOxThreshold"));
}
const List<List<specieElement>>& specieComposition =
chemistry.specieComp();
for (label i=0; i<this->nSpecie_; i++)
{
const List<specieElement>& curSpecieComposition =
specieComposition[i];
// For all elements in the current species
forAll(curSpecieComposition, j)
{
const specieElement& curElement =
curSpecieComposition[j];
if (curElement.name() == "C")
{
sC_[i] = curElement.nAtoms();
}
else if (curElement.name() == "H")
{
sH_[i] = curElement.nAtoms();
}
else if (curElement.name() == "O")
{
sO_[i] = curElement.nAtoms();
}
else if (curElement.name() == "N")
{
sN_[i] = curElement.nAtoms();
}
else
{
Info<< "element not considered"<<endl;
}
}
if (this->chemistry_.Y()[i].name() == CO2Name_)
{
CO2Id_ = i;
}
else if (this->chemistry_.Y()[i].name() == COName_)
{
COId_ = i;
}
else if (this->chemistry_.Y()[i].name() == HO2Name_)
{
HO2Id_ = i;
}
else if (this->chemistry_.Y()[i].name() == H2OName_)
{
H2OId_ = i;
}
else if (this->chemistry_.Y()[i].name() == NOName_)
{
NOId_ = i;
}
}
if ((CO2Id_==-1 || COId_==-1 || HO2Id_==-1 || H2OId_==-1) && automaticSIS_)
{
FatalErrorInFunction
<< "The name of the species used in automatic SIS are not found in "
<< " the mechanism. You should either set the name for CO2, CO, H2O"
<< " and HO2 properly or set automaticSIS to off "
<< exit(FatalError);
}
// To compute zprime, the fuel species should be specified.
// According to the given mass fraction, an equivalent O/C ratio is computed
if (automaticSIS_)
{
dictionary fuelDict;
if (this->coeffsDict_.found("fuelSpecies"))
{
fuelDict = this->coeffsDict_.subDict("fuelSpecies");
fuelSpecies_ = fuelDict.toc();
if (fuelSpecies_.size() == 0)
{
FatalErrorInFunction
<< "With automatic SIS, the fuel species should be "
<< "specified in the fuelSpecies subDict"
<< exit(FatalError);
}
}
else
{
FatalErrorInFunction
<< "With automatic SIS, the fuel species should be "
<< "specified in the fuelSpecies subDict"
<< exit(FatalError);
}
if (this->coeffsDict_.found("nbCLarge"))
{
nbCLarge_ = readLabel(fuelDict.lookup("nbCLarge"));
}
fuelSpeciesID_.setSize(fuelSpecies_.size());
fuelSpeciesProp_.setSize(fuelSpecies_.size());
scalar Mmtot(0.0);
forAll(fuelSpecies_, i)
{
fuelSpeciesProp_[i] = readScalar(fuelDict.lookup(fuelSpecies_[i]));
for (label j=0; j<this->nSpecie_; j++)
{
if (this->chemistry_.Y()[j].name() == fuelSpecies_[i])
{
fuelSpeciesID_[i] = j;
break;
}
}
scalar curMm =
this->chemistry_.specieThermo()[fuelSpeciesID_[i]].W();
Mmtot += fuelSpeciesProp_[i]/curMm;
}
Mmtot = 1.0/Mmtot;
scalar nbC(0.0);
scalar nbO(0.0);
forAll(fuelSpecies_, i)
{
label curID = fuelSpeciesID_[i];
scalar curMm = this->chemistry_.specieThermo()[curID].W();
nbC += fuelSpeciesProp_[i]*Mmtot/curMm*sC_[curID];
nbO += fuelSpeciesProp_[i]*Mmtot/curMm*sO_[curID];
}
zprime_ = nbO/nbC;
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DAC<CompType, ThermoType>::~DAC()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::DAC<CompType, ThermoType>::reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
scalarField& completeC(this->chemistry_.completeC());
scalarField c1(this->chemistry_.nEqns(), 0.0);
for(label i=0; i<this->nSpecie_; i++)
{
c1[i] = c[i];
completeC[i] = c[i];
}
c1[this->nSpecie_] = T;
c1[this->nSpecie_+1] = p;
// Compute the rAB matrix
RectangularMatrix<scalar> rABNum(this->nSpecie_,this->nSpecie_,0.0);
scalarField PA(this->nSpecie_,0.0);
scalarField CA(this->nSpecie_,0.0);
// Number of initialized rAB for each lines
Field<label> NbrABInit(this->nSpecie_,0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
scalar pf, cf, pr, cr;
label lRef, rRef;
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
// for each reaction compute omegai
scalar omegai = this->chemistry_.omega
(
R, c1, T, p, pf, cf, lRef, pr, cr, rRef
);
// Then for each pair of species composing this reaction,
// compute the rAB matrix (separate the numerator and
// denominator)
// While computing the rAB for all the species involved in the reaction
// we should consider that one can write a reaction A+B=2C as A+B=C+C
// In this case, the following algorithm only take once the effect
// of the species. It stores the species encountered in the reaction but
// use another list to see if this species has already been used
DynamicList<scalar> wA(R.lhs().size()+R.rhs().size());
DynamicList<label> wAID(R.lhs().size()+R.rhs().size());
forAll(R.lhs(), s) // Compute rAB for all species in the left hand side
{
label ss = R.lhs()[s].index;
scalar sl = -R.lhs()[s].stoichCoeff; // vAi = v''-v' => here -v'
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
// Disable for self reference (by definition rAA=0)
deltaBi[ss] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// Disable to avoid counting it more than once
deltaBi[curIndex] = false;
// Test if this rAB is not initialized
if (rABPos(ss, curIndex)==-1)
{
// It starts at rABPos(ss, sj)=0
rABPos(ss, curIndex) = NbrABInit[ss];
NbrABInit[ss]++;
// to avoid overflow
rABNum(ss, rABPos(ss, curIndex)) = sl*omegai;
// store the other specie involved
rABOtherSpec(ss, rABPos(ss, curIndex)) = curIndex;
}
else
{
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
forAll(R.rhs(), s) // Compute rAB for all species in the right hand side
{
label ss = R.rhs()[s].index;
scalar sl = R.rhs()[s].stoichCoeff; // vAi = v''-v' => here v''
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
// Disable for self reference (by definition rAA=0)
deltaBi[ss] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// Disable to avoid counting it more than once
deltaBi[curIndex] = false;
// Test if this rAB is not initialized
if (rABPos(ss, curIndex) == -1)
{
// it starts at rABPos(ss, sj)=0
rABPos(ss, curIndex) = NbrABInit[ss];
NbrABInit[ss]++;
rABNum(ss, rABPos(ss, curIndex)) = sl*omegai;
rABOtherSpec(ss, rABPos(ss, curIndex)) = curIndex;
}
else
{
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
wAID.shrink();
// Now that every species of the reactions has been visited, we can
// compute the production and consumption rate. This way, it avoids
// getting wrong results when species are present in both lhs and rhs
forAll(wAID, id)
{
if (wA[id] > 0.0)
{
if (PA[wAID[id]] == 0.0)
{
PA[wAID[id]] = wA[id];
}
else
{
PA[wAID[id]] += wA[id];
}
}
else
{
if (CA[wAID[id]] == 0.0)
{
CA[wAID[id]] = -wA[id];
}
else
{
CA[wAID[id]] += -wA[id];
}
}
}
}
// rii = 0.0 by definition
scalar phiLarge(0.0);
scalar phiProgress(0.0);
if (automaticSIS_)
{
// Compute the progress equivalence ratio
// and the equivalence ratio for fuel decomposition
label nElements = 4; // 4 main elements (C, H, O, N)
// Total number of C, H and O (in this order)
scalarList Na(nElements,0.0);
scalarList Nal(nElements,0.0); // for large hydrocarbons
for (label i=0; i<this->nSpecie_; i++)
{
// Complete combustion products are not considered
if
(
this->chemistry_.Y()[i].name() == "CO2"
|| this->chemistry_.Y()[i].name() == "H2O"
)
{
continue;
}
Na[0] += sC_[i]*c[i];
Na[1] += sH_[i]*c[i];
Na[2] += sO_[i]*c[i];
if (sC_[i]>nbCLarge_ || this->chemistry_.Y()[i].name() == "O2")
{
Nal[0] += sC_[i]*c[i];
Nal[1] += sH_[i]*c[i];
Nal[2] += sO_[i]*c[i];
}
}
// 2C(-CO2) + H(-H2O)/2 - z'C(-CO2)
// Progress equivalence ratio = ----------------------------------
// O(-CO2-H2O) - z' C(-CO2)
// where minus means that this species is not considered for the number
// of atoms and z' is the ratio of the number of O and C in the fuel(s)
phiProgress = (2*Na[0]+Na[1]/2-zprime_*Na[0])/(Na[2]-zprime_*Na[0]);
// 2Cl + Hl/2
// Equivalence ratio for fuel decomposition = ----------
// Ol(+O2)
phiLarge = (2*Nal[0]+Nal[1]/2)/Nal[2];
}
// Using the rAB matrix (numerator and denominator separated)
// compute the R value according to the search initiating set
scalarField Rvalue(this->nSpecie_,0.0);
label speciesNumber = 0;
// Set all species to inactive and activate them according
// to rAB and initial set
for (label i=0; i<this->nSpecie_; i++)
{
this->activeSpecies_[i] = false;
}
// Initialize the FIFOStack for search set
FIFOStack<label> Q;
const labelList& SIS(searchInitSet_);
// If automaticSIS is on, the search initiating set is selected according to
// phiProgress and phiLarge
if (automaticSIS_)
{
if (phiLarge >= phiTol_ && phiProgress >= phiTol_)
{
// When phiLarge and phiProgress >= phiTol then
// CO, HO2 and fuel are in the SIS
Q.push(COId_);
speciesNumber++;
this->activeSpecies_[COId_] = true;
Rvalue[COId_] = 1.0;
Q.push(HO2Id_);
speciesNumber++;
this->activeSpecies_[HO2Id_] = true;
Rvalue[HO2Id_] = 1.0;
forAll(fuelSpeciesID_,i)
{
Q.push(fuelSpeciesID_[i]);
speciesNumber++;
this->activeSpecies_[fuelSpeciesID_[i]] = true;
Rvalue[fuelSpeciesID_[i]] = 1.0;
}
}
else if (phiLarge < phiTol_ && phiProgress >= phiTol_)
{
// When phiLarge < phiTol and phiProgress >= phiTol then
// CO, HO2 are in the SIS
Q.push(COId_);
speciesNumber++;
this->activeSpecies_[COId_] = true;
Rvalue[COId_] = 1.0;
Q.push(HO2Id_);
speciesNumber++;
this->activeSpecies_[HO2Id_] = true;
Rvalue[HO2Id_] = 1.0;
if (forceFuelInclusion_)
{
forAll(fuelSpeciesID_,i)
{
Q.push(fuelSpeciesID_[i]);
speciesNumber++;
this->activeSpecies_[fuelSpeciesID_[i]] = true;
Rvalue[fuelSpeciesID_[i]] = 1.0;
}
}
}
else
{
// When phiLarge and phiProgress< phiTol then
// CO2, H2O are in the SIS
Q.push(CO2Id_);
speciesNumber++;
this->activeSpecies_[CO2Id_] = true;
Rvalue[CO2Id_] = 1.0;
Q.push(H2OId_);
speciesNumber++;
this->activeSpecies_[H2OId_] = true;
Rvalue[H2OId_] = 1.0;
if (forceFuelInclusion_)
{
forAll(fuelSpeciesID_,i)
{
Q.push(fuelSpeciesID_[i]);
speciesNumber++;
this->activeSpecies_[fuelSpeciesID_[i]] = true;
Rvalue[fuelSpeciesID_[i]] = 1.0;
}
}
}
if (T>NOxThreshold_ && NOId_!=-1)
{
Q.push(NOId_);
speciesNumber++;
this->activeSpecies_[NOId_] = true;
Rvalue[NOId_] = 1.0;
}
}
else // No automaticSIS => all species of the SIS are added
{
for (label i=0; i<SIS.size(); i++)
{
label q = SIS[i];
this->activeSpecies_[q] = true;
speciesNumber++;
Q.push(q);
Rvalue[q] = 1.0;
}
}
// Execute the main loop for R-value
while (!Q.empty())
{
label u = Q.pop();
scalar Den = max(PA[u],CA[u]);
if (Den!=0.0)
{
for (label v=0; v<NbrABInit[u]; v++)
{
label otherSpec = rABOtherSpec(u, v);
scalar rAB = mag(rABNum(u, v))/Den;
if (rAB>1)
{
Info<< "Badly Conditioned rAB : " << rAB
<< "species involved : "<<u << "," << otherSpec << endl;
rAB=1.0;
}
// The direct link is weaker than the user-defined tolerance
if (rAB >= this->tolerance())
{
scalar Rtemp = Rvalue[u]*rAB;
// a link analysed previously is stronger
// the (composed) link is stronger than the user-defined
// tolerance
if ((Rvalue[otherSpec]<Rtemp) && (Rtemp>=this->tolerance()))
{
Q.push(otherSpec);
Rvalue[otherSpec] = Rtemp;
if (!this->activeSpecies_[otherSpec])
{
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
}
}
}
}
}
}
// Put a flag on the reactions containing at least one removed species
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
this->chemistry_.reactionsDisabled()[i] = false;
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
if (!this->activeSpecies_[ss])
{
// Flag the reaction to disable it
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
if (!this->chemistry_.reactionsDisabled()[i])
{
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
if (!this->activeSpecies_[ss])
{
// Flag the reaction to disable it
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
}
}
this->NsSimp_ = speciesNumber;
scalarField& simplifiedC(this->chemistry_.simplifiedC());
simplifiedC.setSize(this->NsSimp_+2);
DynamicList<label>& s2c(this->chemistry_.simplifiedToCompleteIndex());
s2c.setSize(this->NsSimp_);
Field<label>& c2s(this->chemistry_.completeToSimplifiedIndex());
label j = 0;
for (label i=0; i<this->nSpecie_; i++)
{
if (this->activeSpecies_[i])
{
s2c[j] = i;
simplifiedC[j] = c[i];
c2s[i] = j++;
if (!this->chemistry_.active(i))
{
this->chemistry_.setActive(i);
}
}
else
{
c2s[i] = -1;
}
}
simplifiedC[this->NsSimp_] = T;
simplifiedC[this->NsSimp_+1] = p;
this->chemistry_.setNsDAC(this->NsSimp_);
// Change temporary Ns in chemistryModel
// to make the function nEqns working
this->chemistry_.setNSpecie(this->NsSimp_);
}
// ************************************************************************* //

View File

@ -0,0 +1,172 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::DAC
Description
The Dynamic Adaptive Chemistry (DAC) method [1] simplify the chemistry
using the matrix rAB defined by (DRGEP algorithm [2])
|sum_i=1->Nr vAi wi dBi|
rAB = --------------------------- ,
max(PA, CA)
PA = sum_i=1->Nr (max (0, vAi wi)) -> production of species A
CA = sum_i=1->Nr (max (0, -vAi wi)) -> consumption of species A
where i is the reaction index, Nr the number of reactions, vAi is the net
stoechiometric coefficient of species A in the ith reaction (vAi = v''-v')
, wi is the progress variable of reaction i and dBi equals 1 if reaction i
involves B and O otherwise.
rAB show the error introduced to the production rates of A when B and all
the reactions including it are removed. It is computed as in [3] so that
the algorithm is O(Nr).
DAC uses a initial set of species that represents the major parts of the
combustion mechanism, i.e. H2/O2, fuel decomposition and CO2 production.
Usualy, it includes the fuel, HO2 and CO. Then it computes the dependance
of these set to the other species. This is done by introducing R-value
defined by
R_V0 (V) = max_SP(product(rij)),
where SP is the set of all possible paths leading from V0 to V and
product(rij) is the chain product of the weights of the edges along the
given path. The R-value for the initial set species is 1.
When the R-value of a species is larger than a user-defined tolerance
then the species is included in the simplified mechanism. Otherwise,
the species is removed along with all the reactions including it.
During this process, instead of looking over all species like described
in [1], the algorithm implemented here creates dynamic list to retain
the initialized edges only (see [3]).
References:
\verbatim
[1] Liang, L., Stevens, J. G., & Farrell, J. T. (2009).
A dynamic adaptive chemistry scheme for reactive flow computations.
Proceedings of the Combustion Institute, 32(1), 527-534.
[2] Pepiot-Desjardins, P., & Pitsch, H. (2008).
An efficient error-propagation-based reduction method for large
chemical kinetic mechanisms.
Combustion and Flame, 154(1), 67-81.
[3] Lu, T., & Law, C. K. (2006).
Linear time reduction of large kinetic mechanisms with directed
relation graph: n-Heptane and iso-octane.
Combustion and Flame, 144(1), 24-36.
\endverbatim
SourceFiles
DAC.C
\*---------------------------------------------------------------------------*/
#ifndef DAC_H
#define DAC_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class DAC Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class DAC
:
public chemistryReductionMethod<CompType, ThermoType>
{
// Private data
//- List of label for the search initiating set
labelList searchInitSet_;
scalar zprime_;
label nbCLarge_;
List<label> sC_,sH_,sO_,sN_;
label CO2Id_,COId_,HO2Id_,H2OId_,NOId_;
Switch automaticSIS_;
scalar phiTol_;
scalar NOxThreshold_;
wordList fuelSpecies_;
scalarField fuelSpeciesProp_;
List<label> fuelSpeciesID_;
word CO2Name_, COName_, HO2Name_, H2OName_, NOName_;
Switch forceFuelInclusion_;
public:
//- Runtime type information
TypeName("DAC");
// Constructors
//- Construct from components
DAC
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~DAC();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "DAC.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,347 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "DRG.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DRG<CompType, ThermoType>::DRG
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry),
searchInitSet_(this->coeffsDict_.subDict("initialSet").size())
{
label j=0;
dictionary initSet = this->coeffsDict_.subDict("initialSet");
for (label i=0; i<chemistry.nSpecie(); i++)
{
if (initSet.found(chemistry.Y()[i].name()))
{
searchInitSet_[j++] = i;
}
}
if (j<searchInitSet_.size())
{
FatalErrorInFunction
<< searchInitSet_.size()-j
<< " species in the intial set is not in the mechanism "
<< initSet
<< exit(FatalError);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DRG<CompType, ThermoType>::~DRG()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::DRG<CompType, ThermoType>::reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
scalarField c1(this->nSpecie_+2, 0.0);
for(label i=0; i<this->nSpecie_; i++)
{
c1[i] = c[i];
}
c1[this->nSpecie_] = T;
c1[this->nSpecie_+1] = p;
// Compute the rAB matrix
RectangularMatrix<scalar> rABNum(this->nSpecie_,this->nSpecie_,0.0);
scalarField rABDen(this->nSpecie_,0.0);
// Number of initialized rAB for each lines
Field<label> NbrABInit(this->nSpecie_,0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
scalar pf, cf, pr, cr;
label lRef, rRef;
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
// For each reaction compute omegai
scalar omegai = this->chemistry_.omega
(
R, c1, T, p, pf, cf, lRef, pr, cr, rRef
);
// Then for each pair of species composing this reaction,
// compute the rAB matrix (separate the numerator and
// denominator)
DynamicList<scalar> wA(R.lhs().size()+R.rhs().size());
DynamicList<label> wAID(R.lhs().size()+R.rhs().size());
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
scalar sl = -R.lhs()[s].stoichCoeff;
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
break;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
scalar sl = R.rhs()[s].stoichCoeff;
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
break;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
// Now that all nuAi*wi are computed, without counting twice species
// present in both rhs and lhs, we can update the denominator and
// numerator for the rAB
wAID.shrink();
forAll(wAID, id)
{
label curID = wAID[id];
// Absolute value of aggregated value
scalar curwA = ((wA[id]>=0) ? wA[id] : -wA[id]);
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
// Disable for self reference (by definition rAA=0)
deltaBi[curID] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// Disable to avoid counting it more than once
deltaBi[curIndex] = false;
// Test if this rAB is not initialized
if (rABPos(curID, curIndex)==-1)
{
rABPos(curID, curIndex) = NbrABInit[curID];
NbrABInit[curID]++;
rABNum(curID, rABPos(curID, curIndex)) = curwA;
rABOtherSpec(curID, rABPos(curID, curIndex)) = curIndex;
}
else
{
rABNum(curID, rABPos(curID, curIndex)) += curwA;
}
}
}
if (rABDen[curID] == 0.0)
{
rABDen[curID] = curwA;
}
else
{
rABDen[curID] +=curwA;
}
}
}
// rii = 0.0 by definition
label speciesNumber = 0;
// Set all species to inactive and activate them according
// to rAB and initial set
for (label i=0; i<this->nSpecie_; i++)
{
this->activeSpecies_[i] = false;
}
FIFOStack<label> Q;
// Initialize the list of active species with the search initiating set
// (SIS)
for (label i=0; i<searchInitSet_.size(); i++)
{
label q = searchInitSet_[i];
this->activeSpecies_[q] = true;
speciesNumber++;
Q.push(q);
}
// Depth first search with rAB
while (!Q.empty())
{
label u = Q.pop();
scalar Den = rABDen[u];
if (Den > VSMALL)
{
for (label v=0; v<NbrABInit[u]; v++)
{
label otherSpec = rABOtherSpec(u, v);
scalar rAB = rABNum(u, v)/Den;
if (rAB>1)
{
Info<< "Badly Conditioned rAB : " << rAB
<< "species involved : " << u << "," << otherSpec
<< endl;
rAB = 1;
}
// Do a DFS on B only if rAB is above the tolerance and if the
// species was not searched before
if
(
rAB >= this->tolerance()
&& !this->activeSpecies_[otherSpec]
)
{
Q.push(otherSpec);
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
}
}
}
}
// Put a flag on the reactions containing at least one removed species
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
this->chemistry_.reactionsDisabled()[i] = false;
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
// The species is inactive then the reaction is removed
if (!this->activeSpecies_[ss])
{
// Flag the reaction to disable it
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
// If the reaction has not been disabled yet
if (!this->chemistry_.reactionsDisabled()[i])
{
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
}
}
this->NsSimp_ = speciesNumber;
this->chemistry_.simplifiedC().setSize(this->NsSimp_+2);
this->chemistry_.simplifiedToCompleteIndex().setSize(this->NsSimp_);
label j = 0;
for (label i=0; i<this->nSpecie_; i++)
{
if (this->activeSpecies_[i])
{
this->chemistry_.simplifiedToCompleteIndex()[j] = i;
this->chemistry_.simplifiedC()[j] = c[i];
this->chemistry_.completeToSimplifiedIndex()[i] = j++;
if (!this->chemistry_.active(i))
{
this->chemistry_.setActive(i);
}
}
else
{
this->chemistry_.completeToSimplifiedIndex()[i] = -1;
}
}
this->chemistry_.simplifiedC()[this->NsSimp_] = T;
this->chemistry_.simplifiedC()[this->NsSimp_+1] = p;
this->chemistry_.setNsDAC(this->NsSimp_);
// Change temporary Ns in chemistryModel
// to make the function nEqns working
this->chemistry_.setNSpecie(this->NsSimp_);
}
// ************************************************************************* //

View File

@ -0,0 +1,108 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::DRG
Description
Implementation of the Directed Relation Graph (DRG) method
SourceFiles
DRG.C
\*---------------------------------------------------------------------------*/
#ifndef DRG_H
#define DRG_H
#include "chemistryReductionMethod.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class DRG Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class DRG
:
public chemistryReductionMethod<CompType, ThermoType>
{
// Private data
//- List of label for the search initiating set
labelList searchInitSet_;
public:
//- Runtime type information
TypeName("DRG");
// Constructors
//- Construct from components
DRG
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
// Destructor
virtual ~DRG();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "DRG.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,746 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "DRGEP.H"
#include "SortableListDRGEP.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DRGEP<CompType, ThermoType>::DRGEP
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry),
searchInitSet_(this->coeffsDict_.subDict("initialSet").size()),
sC_(this->nSpecie_,0),
sH_(this->nSpecie_,0),
sO_(this->nSpecie_,0),
sN_(this->nSpecie_,0),
NGroupBased_(50)
{
label j=0;
dictionary initSet = this->coeffsDict_.subDict("initialSet");
for (label i=0; i<chemistry.nSpecie(); i++)
{
if (initSet.found(chemistry.Y()[i].name()))
{
searchInitSet_[j++]=i;
}
}
if (j<searchInitSet_.size())
{
FatalErrorInFunction
<< searchInitSet_.size()-j
<< " species in the intial set is not in the mechanism "
<< initSet
<< exit(FatalError);
}
if (this->coeffsDict_.found("NGroupBased"))
{
NGroupBased_ = readLabel(this->coeffsDict_.lookup("NGroupBased"));
}
const List<List<specieElement>>& specieComposition =
this->chemistry_.specieComp();
for (label i=0; i<this->nSpecie_; i++)
{
const List<specieElement>& curSpecieComposition =
specieComposition[i];
// for all elements in the current species
forAll(curSpecieComposition, j)
{
const specieElement& curElement =
curSpecieComposition[j];
if (curElement.name() == "C")
{
sC_[i] = curElement.nAtoms();
}
else if (curElement.name() == "H")
{
sH_[i] = curElement.nAtoms();
}
else if (curElement.name() == "O")
{
sO_[i] = curElement.nAtoms();
}
else if (curElement.name() == "N")
{
sN_[i] = curElement.nAtoms();
}
else
{
Info<< "element not considered"<< endl;
}
}
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::DRGEP<CompType, ThermoType>::~DRGEP()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::DRGEP<CompType, ThermoType>::
reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
scalarField& completeC(this->chemistry_.completeC());
scalarField c1(this->chemistry_.nEqns(), 0.0);
for (label i=0; i<this->nSpecie_; i++)
{
c1[i] = c[i];
completeC[i] = c[i];
}
c1[this->nSpecie_] = T;
c1[this->nSpecie_+1] = p;
// Compute the rAB matrix
RectangularMatrix<scalar> rABNum(this->nSpecie_,this->nSpecie_,0.0);
scalarField PA(this->nSpecie_,0.0);
scalarField CA(this->nSpecie_,0.0);
// Number of initialized rAB for each lines
Field<label> NbrABInit(this->nSpecie_,0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
scalar pf, cf, pr, cr;
label lRef, rRef;
scalarField omegaV(this->chemistry_.reactions().size());
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
// for each reaction compute omegai
scalar omegai = this->chemistry_.omega
(
R, c1, T, p, pf, cf, lRef, pr, cr, rRef
);
omegaV[i] = omegai;
// then for each pair of species composing this reaction,
// compute the rAB matrix (separate the numerator and
// denominator)
DynamicList<scalar> wA(R.lhs().size()+R.rhs().size());
DynamicList<label> wAID(R.lhs().size()+R.rhs().size());
forAll(R.lhs(), s)// compute rAB for all species in the left hand side
{
label ss = R.lhs()[s].index;
scalar sl = -R.lhs()[s].stoichCoeff; // vAi = v''-v' => here -v'
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
// Disable for self reference (by definition rAA=0)
deltaBi[ss] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// disable to avoid counting it more than once
deltaBi[curIndex] = false;
// test if this rAB is not initialized
if (rABPos(ss, curIndex)==-1)
{
rABPos(ss, curIndex) = NbrABInit[ss];
NbrABInit[ss]++;
rABNum(ss, rABPos(ss, curIndex)) = sl*omegai;
rABOtherSpec(ss, rABPos(ss, curIndex)) = curIndex;
}
else
{
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
// Compute rAB for all species in the right hand side
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
scalar sl = R.rhs()[s].stoichCoeff; // vAi = v''-v' => here v''
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
// Disable for self reference (by definition rAA=0)
deltaBi[ss] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// disable to avoid counting it more than once
deltaBi[curIndex] = false;
// test if this rAB is not initialized
if (rABPos(ss, curIndex)==-1)
{
rABPos(ss, curIndex) = NbrABInit[ss];
NbrABInit[ss]++;
rABNum(ss, rABPos(ss, curIndex)) = sl*omegai;
rABOtherSpec(ss, rABPos(ss, curIndex)) = curIndex;
}
else
{
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
wAID.shrink();
// Now that every species of the reactions has been visited, we can
// compute the production and consumption rate. This way, it avoids
// getting wrong results when species are present in both lhs and rhs
forAll(wAID, id)
{
if (wA[id] > 0.0)
{
if (PA[wAID[id]] == 0.0)
{
PA[wAID[id]] = wA[id];
}
else
{
PA[wAID[id]] += wA[id];
}
}
else
{
if (CA[wAID[id]] == 0.0)
{
CA[wAID[id]] = -wA[id];
}
else
{
CA[wAID[id]] += -wA[id];
}
}
}
}
// rii = 0.0 by definition
// Compute the production rate of each element Pa
label nElements = 4; // 4 main elements (C, H, O, N)
scalarList Pa(nElements,0.0);
scalarList Ca(nElements,0.0);
// for (label q=0; q<SIS.size(); q++)
for (label i=0; i<this->nSpecie_; i++)
{
Pa[0] += sC_[i]*max(0.0,(PA[i]-CA[i]));
Ca[0] += sC_[i]*max(0.0,-(PA[i]-CA[i]));
Pa[1] += sH_[i]*max(0.0,(PA[i]-CA[i]));
Ca[1] += sH_[i]*max(0.0,-(PA[i]-CA[i]));
Pa[2] += sO_[i]*max(0.0,(PA[i]-CA[i]));
Ca[2] += sO_[i]*max(0.0,-(PA[i]-CA[i]));
Pa[3] += sN_[i]*max(0.0,(PA[i]-CA[i]));
Ca[3] += sN_[i]*max(0.0,-(PA[i]-CA[i]));
}
// Using the rAB matrix (numerator and denominator separated)
// compute the R value according to the search initiating set
scalarField Rvalue(this->nSpecie_,0.0);
label speciesNumber = 0;
List<bool> disabledSpecies(this->nSpecie_,false);
// set all species to inactive and activate them according
// to rAB and initial set
for (label i=0; i<this->nSpecie_; i++)
{
this->activeSpecies_[i] = false;
}
// Initialize the FIFOStack for search set
FIFOStack<label> Q;
const labelList& SIS(this->searchInitSet_);
DynamicList<label> QStart(SIS.size());
DynamicList<scalar> alphaQ(SIS.size());
// Compute the alpha coefficient and initialize the R value of the species
// in the SIS
for (label i=0; i<SIS.size(); i++)
{
label q = SIS[i];
// compute alpha
scalar alphaA(0.0);
// C
if (Pa[0] > VSMALL)
{
scalar alphaTmp = (sC_[q]*mag(PA[q]-CA[q])/Pa[0]);
if (alphaTmp > alphaA)
{
alphaA = alphaTmp;
}
}
// H
if (Pa[1] > VSMALL)
{
scalar alphaTmp = (sH_[q]*mag(PA[q]-CA[q])/Pa[1]);
if (alphaTmp > alphaA)
{
alphaA = alphaTmp;
}
}
// O
if (Pa[2] > VSMALL)
{
scalar alphaTmp = (sO_[q]*mag(PA[q]-CA[q])/Pa[2]);
if (alphaTmp > alphaA)
{
alphaA = alphaTmp;
}
}
// N
if (Pa[3] > VSMALL)
{
scalar alphaTmp = (sN_[q]*mag(PA[q]-CA[q])/Pa[3]);
if (alphaTmp > alphaA)
{
alphaA = alphaTmp;
}
}
if (alphaA > this->tolerance())
{
this->activeSpecies_[q] = true;
speciesNumber++;
Q.push(q);
QStart.append(q);
alphaQ.append(1.0);
Rvalue[q] = 1.0;
}
else
{
Rvalue[q] = alphaA;
}
}
// if all species from the SIS has been removed
// force the use of the species with maximum Rvalue
if (Q.empty())
{
scalar Rmax=0.0;
label specID=-1;
forAll(SIS, i)
{
if (Rvalue[SIS[i]] > Rmax)
{
Rmax = Rvalue[SIS[i]];
specID=SIS[i];
}
}
Q.push(specID);
QStart.append(specID);
alphaQ.append(1.0);
speciesNumber++;
Rvalue[specID] = 1.0;
this->activeSpecies_[specID] = true;
}
// Execute the main loop for R-value
while (!Q.empty())
{
label u = Q.pop();
scalar Den = max(PA[u],CA[u]);
if (Den > VSMALL)
{
for (label v=0; v<NbrABInit[u]; v++)
{
label otherSpec = rABOtherSpec(u, v);
scalar rAB = mag(rABNum(u, v))/Den;
if (rAB>1)
{
Info<< "Badly Conditioned rAB : " << rAB
<< "species involved : "<<u << "," << otherSpec << endl;
rAB=1.0;
}
scalar Rtemp = Rvalue[u]*rAB;
// a link analysed previously is stronger
if (Rvalue[otherSpec] < Rtemp)
{
Rvalue[otherSpec] = Rtemp;
// the (composed) link is stronger than the tolerance
if (Rtemp >= this->tolerance())
{
Q.push(otherSpec);
if (!this->activeSpecies_[otherSpec])
{
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
}
}
}
}
}
}
// Group-based reduction
// number of species disabled in the first step
label NDisabledSpecies(this->nSpecie_-speciesNumber);
// while the number of removed species is greater than NGroupBased, the rAB
// are reevaluated according to the group based definition for each loop the
// temporary disabled species (in the first reduction) are sorted to disable
// definitely the NGroupBased species with lower R then these R value a
// reevaluated taking into account these disabled species
while(NDisabledSpecies > NGroupBased_)
{
// keep track of disabled species using sortablelist to extract only
// NGroupBased lower R value
SortableListDRGEP<scalar> Rdisabled(NDisabledSpecies);
labelList Rindex(NDisabledSpecies);
label nD = 0;
forAll(disabledSpecies, i)
{
// if just disabled and not in a previous loop
if (!this->activeSpecies_[i] && !disabledSpecies[i])
{
// Note: non-reached species will be removed first (Rvalue=0)
Rdisabled[nD] = Rvalue[i];
Rindex[nD++] = i;
}
}
// sort the Rvalue to obtain the NGroupBased lower R value
Rdisabled.partialSort(NGroupBased_);
labelList tmpIndex(Rdisabled.indices());
// disable definitely NGroupBased species in this loop
for (label i=0; i<NGroupBased_; i++)
{
disabledSpecies[Rindex[tmpIndex[i]]] = true;
}
NDisabledSpecies -= NGroupBased_;
// reevaluate the rAB according to the group-based definition rAB{S} [1]
// only update the numerator
forAll(NbrABInit, i)
{
for (label v=0; v<NbrABInit[i]; v++)
{
rABNum(i, v) = 0.0;
}
}
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
scalar omegai = omegaV[i];
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
scalar sl = -R.lhs()[s].stoichCoeff; // vAi = v''-v' => here -v'
List<bool> deltaBi(this->nSpecie_, false);
bool alreadyDisabled(false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
if (disabledSpecies[sj])
{
alreadyDisabled=true;
}
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
if (disabledSpecies[sj])
{
alreadyDisabled=true;
}
}
deltaBi[ss] = false;
if (alreadyDisabled)
{
// if one of the species in this reaction is disabled, all
// species connected to species ss are modified
for (label v=0; v<NbrABInit[ss]; v++)
{
rABNum(ss, v) += sl*omegai;
}
}
else
{
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
// disable to avoid counting it more than once
deltaBi[curIndex] = false;
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
}
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
scalar sl = R.rhs()[s].stoichCoeff; // vAi = v''-v' => here v''
List<bool> deltaBi(this->nSpecie_, false);
bool alreadyDisabled(false);
FIFOStack<label> usedIndex;
forAll(R.lhs(), j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
if (disabledSpecies[sj])
{
alreadyDisabled=true;
}
}
forAll(R.rhs(), j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
if (disabledSpecies[sj])
{
alreadyDisabled=true;
}
}
deltaBi[ss] = false;
if (alreadyDisabled)
{
// if one of the species in this reaction is disabled, all
// species connected to species ss are modified
for (label v=0; v<NbrABInit[ss]; v++)
{
rABNum(ss, v) += sl*omegai;
}
}
else
{
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
deltaBi[curIndex] = false;
rABNum(ss, rABPos(ss, curIndex)) += sl*omegai;
}
}
}
}
}
forAll(QStart, qi)
{
label u = QStart[qi];
Q.push(u);
}
while (!Q.empty())
{
label u = Q.pop();
scalar Den = max(PA[u],CA[u]);
if (Den!=0.0)
{
for (label v=0; v<NbrABInit[u]; v++)
{
label otherSpec = rABOtherSpec(u, v);
if (!disabledSpecies[otherSpec])
{
scalar rAB = mag(rABNum(u, v))/Den;
if (rAB>1.0)
{
Info<< "Badly Conditioned rAB : " << rAB
<< "species involved : "
<<this->chemistry_.Y()[u].name() << ","
<< this->chemistry_.Y()[otherSpec].name()
<< endl;
rAB=1.0;
}
scalar Rtemp = Rvalue[u]*rAB;
// a link analysed previously is stronger
if (Rvalue[otherSpec] < Rtemp)
{
Rvalue[otherSpec] = Rtemp;
if (Rtemp >= this->tolerance())
{
Q.push(otherSpec);
if (!this->activeSpecies_[otherSpec])
{
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
NDisabledSpecies--;
}
}
}
}
}
}
}
}
// End of group-based reduction
// Put a flag on the reactions containing at least one removed species
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
this->chemistry_.reactionsDisabled()[i] = false;
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
if (!this->chemistry_.reactionsDisabled()[i])
{
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
}
}
this->NsSimp_ = speciesNumber;
scalarField& simplifiedC(this->chemistry_.simplifiedC());
simplifiedC.setSize(this->NsSimp_+2);
DynamicList<label>& s2c(this->chemistry_.simplifiedToCompleteIndex());
s2c.setSize(this->NsSimp_);
Field<label>& c2s(this->chemistry_.completeToSimplifiedIndex());
label j = 0;
for (label i=0; i<this->nSpecie_; i++)
{
if (this->activeSpecies_[i])
{
s2c[j] = i;
simplifiedC[j] = c[i];
c2s[i] = j++;
if (!this->chemistry_.active(i))
{
this->chemistry_.setActive(i);
}
}
else
{
c2s[i] = -1;
}
}
simplifiedC[this->NsSimp_] = T;
simplifiedC[this->NsSimp_+1] = p;
this->chemistry_.setNsDAC(this->NsSimp_);
// change temporary Ns in chemistryModel
// to make the function nEqns working
this->chemistry_.setNSpecie(this->NsSimp_);
}
// ************************************************************************* //

View File

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::DRGEP
Description
The DRGEP algorithm [1] is based on
|sum_i=1->Nr vAi wi dBi|
rAB = --------------------------- ,
max(PA, CA)
PA = sum_i=1->Nr (max (0, vAi wi)) -> production of species A
CA = sum_i=1->Nr (max (0, -vAi wi)) -> consumption of species A
where i is the reaction index, Nr the number of reactions, vAi is the net
stoechiometric coefficient of species A in the ith reaction (vAi = v''-v')
, wi is the progress variable of reaction i and dBi equals 1 if reaction i
involves B and O otherwise.
rAB show the error introduced to the production rates of A when B and all
the reactions including it are removed. It is computed as in [2] so that
the algorithm is O(Nr).
DAC uses a initial set of species that represents the major parts of the
combustion mechanism, i.e. H2/O2, fuel decomposition and CO2 production.
Usualy, it includes the fuel, HO2 and CO. Then it computes the dependance
of these set to the other species. This is done by introducing R-value
defined by
R_V0 (V) = max_SP(product(rij)) ,
where SP is the set of all possible paths leading from V0 to V and
product(rij) is the chain product of the weights of the edges along the
given path. The R-value for the initial set species is 1.
When the R-value of a species is larger than a user-defined tolerance
then the species is included in the simplified mechanism. Otherwise,
the species is removed along with all the reactions including it.
During this process, instead of looking over all species like described
in [1], the algorithm implemented here creates dynamic list to retain
the initialized edges only (see [2]).
To avoid using the target species when they are not contributing yet or
anymore to the system, a coefficient based on the exchange of element is
introduced:
NTa |PT - CT|
alphaTa = ----------------
Pa
Pa = sum_speciesS NSa max(0, PS-CS)
where 'a' refers to different elements present in the system
(namely C, H, O and N for conventionail hydrocarbon combustion),
NTa is the number of element a in species T.
When this coefficient alpha is below the specified threshold, the species is
removed from the search initiating set. In the original paper from
Pepiot-Desjardins et al.[2], this coefficient is further transformed to
compute a global normalized scaling coefficient but here as it is dynamicly
computed, alpha is not introduced in the calculation of R.
References:
\verbatim
[1] Pepiot-Desjardins, P., & Pitsch, H. (2008).
An efficient error-propagation-based reduction method for large
chemical kinetic mechanisms.
Combustion and Flame, 154(1), 67-81.
[2] Lu, T., & Law, C. K. (2006).
Linear time reduction of large kinetic mechanisms with directed
relation graph: n-Heptane and iso-octane.
Combustion and Flame, 144(1), 24-36.
\endverbatim
SourceFiles
DRGEP.C
\*---------------------------------------------------------------------------*/
#ifndef DRGEP_H
#define DRGEP_H
#include "chemistryReductionMethod.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class ode Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class DRGEP
:
public chemistryReductionMethod<CompType, ThermoType>
{
// Private data
//- List of label for the search initiating set
labelList searchInitSet_;
List<label> sC_,sH_,sO_,sN_;
label NGroupBased_;
public:
//- Runtime type information
TypeName("DRGEP");
// Constructors
//- Construct from components
DRGEP
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~DRGEP();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "DRGEP.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,153 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "OSspecific.H"
#include <algorithm>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template <class Type>
Foam::SortableListDRGEP<Type>::SortableListDRGEP(const List<Type>& values)
:
List<Type>(values),
indices_(values.size())
{
sort();
}
template <class Type>
Foam::SortableListDRGEP<Type>::SortableListDRGEP(const label size)
:
List<Type>(size),
indices_(size)
{}
template <class Type>
Foam::SortableListDRGEP<Type>::SortableListDRGEP
(
const label size,
const Type& val
)
:
List<Type>(size, val),
indices_(size)
{}
template <class Type>
Foam::SortableListDRGEP<Type>::SortableListDRGEP
(
const SortableListDRGEP<Type>& lst
)
:
List<Type>(lst),
indices_(lst.indices())
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template <class Type>
void Foam::SortableListDRGEP<Type>::setSize(const label newSize)
{
List<Type>::setSize(newSize);
indices_.setSize(newSize);
}
template <class Type>
void Foam::SortableListDRGEP<Type>::sort()
{
forAll(indices_, i)
{
indices_[i] = i;
}
Foam::sort(indices_, less(*this));
List<Type> tmpValues(this->size());
forAll(indices_, i)
{
tmpValues[i] = this->operator[](indices_[i]);
}
List<Type>::transfer(tmpValues);
}
template <class Type>
void Foam::SortableListDRGEP<Type>::partialSort(int M)
{
forAll(indices_, i)
{
indices_[i] = i;
}
std::partial_sort
(
indices_.begin(),
indices_.begin()+M,
indices_.end(),
less(*this)
);
}
template <class Type>
void Foam::SortableListDRGEP<Type>::stableSort()
{
forAll(indices_, i)
{
indices_[i] = i;
}
Foam::stableSort(indices_, less(*this));
List<Type> tmpValues(this->size());
forAll(indices_, i)
{
tmpValues[i] = this->operator[](indices_[i]);
}
List<Type>::transfer(tmpValues);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template <class Type>
void
Foam::SortableListDRGEP<Type>::operator=(const SortableListDRGEP<Type>& rhs)
{
List<Type>::operator=(rhs);
indices_ = rhs.indices();
}
// ************************************************************************* //

View File

@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::SortableListDRGEP
Description
A list that is sorted upon construction or when explicitly requested
with the sort() method.
SourceFiles
SortableListDRGEP.C
\*---------------------------------------------------------------------------*/
#ifndef SortableListDRGEP_H
#define SortableListDRGEP_H
#include "labelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class SortableListDRGEP Declaration
\*---------------------------------------------------------------------------*/
template <class Type>
class SortableListDRGEP
:
public List<Type>
{
// Private data
//- Original indices
labelList indices_;
public:
// Public classes
//- Less function class used by the sort function
class less
{
const UList<Type>& values_;
public:
less(const UList<Type>& values)
:
values_(values)
{}
bool operator()(const label a, const label b)
{
return values_[a] < values_[b];
}
};
// Constructors
//- Construct from List, sorting the elements. Starts with indices set
// to index in argument
explicit SortableListDRGEP(const List<Type>&);
//- Construct given size. Sort later on.
explicit SortableListDRGEP(const label size);
//- Construct given size and initial value. Sort later on.
SortableListDRGEP(const label size, const Type&);
//- Construct as copy.
SortableListDRGEP(const SortableListDRGEP<Type>&);
// Member Functions
//- Return the list of sorted indices. Updated every sort.
const labelList& indices() const
{
return indices_;
}
//- Size the list. If grow can cause undefined indices (until next sort)
void setSize(const label);
//- Sort the list (if changed after construction time)
void sort();
//- Partial sort the list (if changed after construction time)
void partialSort(int M);
//- Sort the list (if changed after construction time)
void stableSort();
// Member Operators
void operator=(const SortableListDRGEP<Type>&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "SortableListDRGEP.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,568 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "EFA.H"
#include "SortableListEFA.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::EFA<CompType, ThermoType>::EFA
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry),
sC_(this->nSpecie_,0),
sH_(this->nSpecie_,0),
sO_(this->nSpecie_,0),
sN_(this->nSpecie_,0),
sortPart_(0.05)
{
const List<List<specieElement>>& specieComposition =
this->chemistry_.specieComp();
for (label i=0; i<this->nSpecie_; i++)
{
const List<specieElement>& curSpecieComposition =
specieComposition[i];
// for all elements in the current species
forAll(curSpecieComposition, j)
{
const specieElement& curElement =
curSpecieComposition[j];
if (curElement.name() == "C")
{
sC_[i] = curElement.nAtoms();
}
else if (curElement.name() == "H")
{
sH_[i] = curElement.nAtoms();
}
else if (curElement.name() == "O")
{
sO_[i] = curElement.nAtoms();
}
else if (curElement.name() == "N")
{
sN_[i] = curElement.nAtoms();
}
else
{
Info<< "element not considered"<< endl;
}
}
}
if (this->coeffsDict_.found("sortPart"))
{
sortPart_ = readScalar(this->coeffsDict_.lookup("sortPart"));
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::EFA<CompType, ThermoType>::~EFA()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::EFA<CompType, ThermoType>::reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
scalarField& completeC(this->chemistry_.completeC());
scalarField c1(this->chemistry_.nEqns(), 0.0);
for (label i=0; i<this->nSpecie_; i++)
{
c1[i] = c[i];
completeC[i] = c[i];
}
c1[this->nSpecie_] = T;
c1[this->nSpecie_+1] = p;
// Number of initialized rAB for each lines
Field<label> NbrABInit(this->nSpecie_,0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
RectangularMatrix<scalar> CFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
RectangularMatrix<scalar> HFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
RectangularMatrix<scalar> OFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
RectangularMatrix<scalar> NFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
scalar CFlux(0.0), HFlux(0.0), OFlux(0.0), NFlux(0.0);
label nbPairs(0);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
scalar pf, cf, pr, cr;
label lRef, rRef;
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
// for each reaction compute omegai
this->chemistry_.omega
(
R, c1, T, p, pf, cf, lRef, pr, cr, rRef
);
scalar fr = mag(pf*cf)+mag(pr*cr);
scalar NCi(0.0),NHi(0.0),NOi(0.0),NNi(0.0);
forAll(R.lhs(),s)
{
label curIndex = R.lhs()[s].index;
scalar stoicCoeff = R.lhs()[s].stoichCoeff;
NCi += sC_[curIndex]*stoicCoeff;
NHi += sH_[curIndex]*stoicCoeff;
NOi += sO_[curIndex]*stoicCoeff;
NNi += sN_[curIndex]*stoicCoeff;
}
// element conservation means that total number of element is
// twice the number on the left
NCi *=2;
NHi *=2;
NOi *=2;
NNi *=2;
// then for each source/sink pairs, compute the element flux
forAll(R.lhs(), Ai)// compute the element flux
{
label A = R.lhs()[Ai].index;
scalar Acoeff = R.lhs()[Ai].stoichCoeff;
forAll(R.rhs(), Bi)
{
label B = R.rhs()[Bi].index;
scalar Bcoeff = R.rhs()[Bi].stoichCoeff;
// if a pair in the reversed way has not been initialized
if (rABPos(B, A)==-1)
{
label otherS = rABPos(A, B);
if (otherS==-1)
{
rABPos(A, B) = NbrABInit[A]++;
otherS = rABPos(A, B);
nbPairs++;
rABOtherSpec(A, otherS) = B;
}
if (NCi>VSMALL)
{
CFluxAB(A, otherS) +=
fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
}
if (NHi>VSMALL)
{
HFluxAB(A, otherS) +=
fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
}
if (NOi>VSMALL)
{
OFluxAB(A, otherS) +=
fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
}
if (NNi>VSMALL)
{
NFluxAB(A, otherS) +=
fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
}
}
// If a pair BA is initialized,
// add the element flux to this pair
else
{
label otherS = rABPos(B, A);
if (NCi>VSMALL)
{
CFluxAB(B, otherS) +=
fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
}
if (NHi>VSMALL)
{
HFluxAB(B, otherS) +=
fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
}
if (NOi>VSMALL)
{
OFluxAB(B, otherS) +=
fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
}
if (NNi>VSMALL)
{
NFluxAB(B, otherS) +=
fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
}
}
if (NCi>VSMALL)
{
CFlux += fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
}
if (NHi>VSMALL)
{
HFlux += fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
}
if (NOi>VSMALL)
{
OFlux += fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
}
if (NNi>VSMALL)
{
NFlux += fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
}
}
}
}
// Select species according to the total flux cutoff (1-tolerance)
// of the flux is included
label speciesNumber = 0;
for (label i=0; i<this->nSpecie_; i++)
{
this->activeSpecies_[i] = false;
}
if (CFlux > VSMALL)
{
SortableListEFA<scalar> pairsFlux(nbPairs);
labelList source(nbPairs);
labelList sink(nbPairs);
label nP(0);
for (int A=0; A<this->nSpecie_ ; A++)
{
for (int j=0; j<NbrABInit[A]; j++)
{
label pairIndex = nP++;
pairsFlux[pairIndex] = 0.0;
label B = rABOtherSpec(A, j);
pairsFlux[pairIndex] += CFluxAB(A, j);
source[pairIndex] = A;
sink[pairIndex] = B;
}
}
// Sort in descending orders the source/sink pairs until the cutoff is
// reached. The sorting is done on part of the pairs because a small
// part of these pairs are responsible for a large part of the element
// flux
scalar cumFlux(0.0);
scalar threshold((1-this->tolerance())*CFlux);
label startPoint(0);
label nbToSort(static_cast<label> (nbPairs*sortPart_));
nbToSort = max(nbToSort,1);
bool cumRespected(false);
while(!cumRespected)
{
if (startPoint >= nbPairs)
{
FatalErrorInFunction
<< "startPoint outside number of pairs without reaching"
<< "100% flux"
<< exit(FatalError);
}
label nbi = min(nbToSort, nbPairs-startPoint);
pairsFlux.partialSort(nbi, startPoint);
const labelList& idx = pairsFlux.indices();
for (int i=0; i<nbi; i++)
{
cumFlux += pairsFlux[idx[startPoint+i]];
if (!this->activeSpecies_[source[idx[startPoint+i]]])
{
this->activeSpecies_[source[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (!this->activeSpecies_[sink[idx[startPoint+i]]])
{
this->activeSpecies_[sink[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (cumFlux >= threshold)
{
cumRespected = true;
break;
}
}
startPoint += nbToSort;
}
}
if (HFlux > VSMALL)
{
SortableListEFA<scalar> pairsFlux(nbPairs);
labelList source(nbPairs);
labelList sink(nbPairs);
label nP(0);
for (int A=0; A<this->nSpecie_ ; A++)
{
for (int j=0; j<NbrABInit[A]; j++)
{
label pairIndex = nP++;
pairsFlux[pairIndex] = 0.0;
label B = rABOtherSpec(A, j);
pairsFlux[pairIndex] += HFluxAB(A, j);
source[pairIndex] = A;
sink[pairIndex] = B;
}
}
scalar cumFlux(0.0);
scalar threshold((1-this->tolerance())*HFlux);
label startPoint(0);
label nbToSort(static_cast<label> (nbPairs*sortPart_));
nbToSort = max(nbToSort,1);
bool cumRespected(false);
while(!cumRespected)
{
if (startPoint >= nbPairs)
{
FatalErrorInFunction
<< "startPoint outside number of pairs without reaching"
<< "100% flux"
<< exit(FatalError);
}
label nbi = min(nbToSort, nbPairs-startPoint);
pairsFlux.partialSort(nbi, startPoint);
const labelList& idx = pairsFlux.indices();
for (int i=0; i<nbi; i++)
{
cumFlux += pairsFlux[idx[startPoint+i]];
if (!this->activeSpecies_[source[idx[startPoint+i]]])
{
this->activeSpecies_[source[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (!this->activeSpecies_[sink[idx[startPoint+i]]])
{
this->activeSpecies_[sink[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (cumFlux >= threshold)
{
cumRespected = true;
break;
}
}
startPoint += nbToSort;
}
}
if (OFlux > VSMALL)
{
SortableListEFA<scalar> pairsFlux(nbPairs);
labelList source(nbPairs);
labelList sink(nbPairs);
label nP(0);
for (int A=0; A<this->nSpecie_ ; A++)
{
for (int j=0; j<NbrABInit[A]; j++)
{
label pairIndex = nP++;
pairsFlux[pairIndex] = 0.0;
label B = rABOtherSpec(A, j);
pairsFlux[pairIndex] += OFluxAB(A, j);
source[pairIndex] = A;
sink[pairIndex] = B;
}
}
scalar cumFlux(0.0);
scalar threshold((1-this->tolerance())*OFlux);
label startPoint(0);
label nbToSort(static_cast<label> (nbPairs*sortPart_));
nbToSort = max(nbToSort,1);
bool cumRespected(false);
while(!cumRespected)
{
if (startPoint >= nbPairs)
{
FatalErrorInFunction
<< "startPoint outside number of pairs without reaching"
<< "100% flux"
<< exit(FatalError);
}
label nbi = min(nbToSort, nbPairs-startPoint);
pairsFlux.partialSort(nbi, startPoint);
const labelList& idx = pairsFlux.indices();
for (int i=0; i<nbi; i++)
{
cumFlux += pairsFlux[idx[startPoint+i]];
if (!this->activeSpecies_[source[idx[startPoint+i]]])
{
this->activeSpecies_[source[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (!this->activeSpecies_[sink[idx[startPoint+i]]])
{
this->activeSpecies_[sink[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (cumFlux >= threshold)
{
cumRespected = true;
break;
}
}
startPoint += nbToSort;
}
}
if (NFlux > VSMALL)
{
SortableListEFA<scalar> pairsFlux(nbPairs);
labelList source(nbPairs);
labelList sink(nbPairs);
label nP(0);
for (int A=0; A<this->nSpecie_ ; A++)
{
for (int j=0; j<NbrABInit[A]; j++)
{
label pairIndex = nP++;
pairsFlux[pairIndex] = 0.0;
label B = rABOtherSpec(A, j);
pairsFlux[pairIndex] += NFluxAB(A, j);
source[pairIndex] = A;
sink[pairIndex] = B;
}
}
scalar cumFlux(0.0);
scalar threshold((1-this->tolerance())*NFlux);
label startPoint(0);
label nbToSort(static_cast<label> (nbPairs*sortPart_));
nbToSort = max(nbToSort,1);
bool cumRespected(false);
while(!cumRespected)
{
if (startPoint >= nbPairs)
{
FatalErrorInFunction
<< "startPoint outside number of pairs without reaching"
<< "100% flux"
<< exit(FatalError);
}
label nbi = min(nbToSort, nbPairs-startPoint);
pairsFlux.partialSort(nbi, startPoint);
const labelList& idx = pairsFlux.indices();
for (int i=0; i<nbi; i++)
{
cumFlux += pairsFlux[idx[startPoint+i]];
if (!this->activeSpecies_[source[idx[startPoint+i]]])
{
this->activeSpecies_[source[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (!this->activeSpecies_[sink[idx[startPoint+i]]])
{
this->activeSpecies_[sink[idx[startPoint+i]]] = true;
speciesNumber++;
}
if (cumFlux >= threshold)
{
cumRespected = true;
break;
}
}
startPoint += nbToSort;
}
}
// Put a flag on the reactions containing at least one removed species
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
this->chemistry_.reactionsDisabled()[i] = false;
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
if (!this->chemistry_.reactionsDisabled()[i])
{
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
}
}
this->NsSimp_ = speciesNumber;
scalarField& simplifiedC(this->chemistry_.simplifiedC());
simplifiedC.setSize(this->NsSimp_+2);
DynamicList<label>& s2c(this->chemistry_.simplifiedToCompleteIndex());
s2c.setSize(this->NsSimp_);
Field<label>& c2s(this->chemistry_.completeToSimplifiedIndex());
label j = 0;
for (label i=0; i<this->nSpecie_; i++)
{
if (this->activeSpecies_[i])
{
s2c[j] = i;
simplifiedC[j] = c[i];
c2s[i] = j++;
if (!this->chemistry_.active(i))
{
this->chemistry_.setActive(i);
}
}
else
{
c2s[i] = -1;
}
}
simplifiedC[this->NsSimp_] = T;
simplifiedC[this->NsSimp_+1] = p;
this->chemistry_.setNsDAC(this->NsSimp_);
// change temporary Ns in chemistryModel
// to make the function nEqns working
this->chemistry_.setNSpecie(this->NsSimp_);
}
// ************************************************************************* //

View File

@ -0,0 +1,105 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::EFA
Description
SourceFiles
EFA.C
\*---------------------------------------------------------------------------*/
#ifndef EFA_H
#define EFA_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class ode Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class EFA
:
public chemistryReductionMethod<CompType, ThermoType>
{
// Private data
List<label> sC_,sH_,sO_,sN_;
scalar sortPart_;
public:
//- Runtime type information
TypeName("EFA");
// Constructors
//- Construct from components
EFA
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~EFA();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "EFA.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,155 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "OSspecific.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template <class Type>
Foam::SortableListEFA<Type>::SortableListEFA(const List<Type>& values)
:
List<Type>(values),
indices_(values.size())
{
sort();
}
template <class Type>
Foam::SortableListEFA<Type>::SortableListEFA(const label size)
:
List<Type>(size),
indices_(size)
{
forAll(indices_, i)
{
indices_[i] = i;
}
}
template <class Type>
Foam::SortableListEFA<Type>::SortableListEFA(const label size, const Type& val)
:
List<Type>(size, val),
indices_(size)
{
forAll(indices_, i)
{
indices_[i] = i;
}
}
template <class Type>
Foam::SortableListEFA<Type>::SortableListEFA(const SortableListEFA<Type>& lst)
:
List<Type>(lst),
indices_(lst.indices())
{
forAll(indices_, i)
{
indices_[i] = i;
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template <class Type>
void Foam::SortableListEFA<Type>::setSize(const label newSize)
{
List<Type>::setSize(newSize);
indices_.setSize(newSize);
}
template <class Type>
void Foam::SortableListEFA<Type>::sort()
{
forAll(indices_, i)
{
indices_[i] = i;
}
Foam::sort(indices_, less(*this));
List<Type> tmpValues(this->size());
forAll(indices_, i)
{
tmpValues[i] = this->operator[](indices_[i]);
}
List<Type>::transfer(tmpValues);
}
template <class Type>
void Foam::SortableListEFA<Type>::partialSort(int M, int start)
{
std::partial_sort
(
indices_.begin()+start,
indices_.begin()+start+M,
indices_.end(),
more(*this)
);
}
template <class Type>
void Foam::SortableListEFA<Type>::stableSort()
{
forAll(indices_, i)
{
indices_[i] = i;
}
Foam::stableSort(indices_, less(*this));
List<Type> tmpValues(this->size());
forAll(indices_, i)
{
tmpValues[i] = this->operator[](indices_[i]);
}
List<Type>::transfer(tmpValues);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template <class Type>
void Foam::SortableListEFA<Type>::operator=(const SortableListEFA<Type>& rhs)
{
List<Type>::operator=(rhs);
indices_ = rhs.indices();
}
// ************************************************************************* //

View File

@ -0,0 +1,141 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::SortableListEFA
Description
A list that is sorted upon construction or when explicitly requested
with the sort() method.
SourceFiles
SortableListEFA.C
\*---------------------------------------------------------------------------*/
#ifndef SortableListEFA_H
#define SortableListEFA_H
#include "labelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class SortableListEFA Declaration
\*---------------------------------------------------------------------------*/
template <class Type>
class SortableListEFA
:
public List<Type>
{
// Private data
//- Original indices
labelList indices_;
public:
// Public classes
//- Less function class used by the sort function
class more
{
const UList<Type>& values_;
public:
more(const UList<Type>& values)
:
values_(values)
{}
bool operator()(const label a, const label b)
{
return values_[a] > values_[b];
}
};
// Constructors
//- Construct from List, sorting the elements. Starts with indices set
// to index in argument
explicit SortableListEFA(const List<Type>&);
//- Construct given size. Sort later on.
explicit SortableListEFA(const label size);
//- Construct given size and initial value. Sort later on.
SortableListEFA(const label size, const Type&);
//- Construct as copy.
SortableListEFA(const SortableListEFA<Type>&);
// Member Functions
//- Return the list of sorted indices. Updated every sort.
const labelList& indices() const
{
return indices_;
}
//- Size the list. If grow can cause undefined indices (until next sort)
void setSize(const label);
//- Sort the list (if changed after construction time)
void sort();
//- Partial sort the list (if changed after construction time)
void partialSort(int M, int start);
//- Sort the list (if changed after construction time)
void stableSort();
// Member Operators
void operator=(const SortableListEFA<Type>&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "SortableListEFA.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,442 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "PFA.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::PFA<CompType, ThermoType>::PFA
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry),
searchInitSet_(this->coeffsDict_.subDict("initialSet").size())
{
label j=0;
dictionary initSet = this->coeffsDict_.subDict("initialSet");
for (label i=0; i<chemistry.nSpecie(); i++)
{
if (initSet.found(chemistry.Y()[i].name()))
{
searchInitSet_[j++] = i;
}
}
if (j<searchInitSet_.size())
{
FatalErrorInFunction
<< searchInitSet_.size()-j
<< " species in the intial set is not in the mechanism "
<< initSet
<< abort(FatalError);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::PFA<CompType, ThermoType>::~PFA()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::PFA<CompType, ThermoType>::reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
scalarField& completeC(this->chemistry_.completeC());
scalarField c1(this->chemistry_.nEqns(), 0.0);
for (label i=0; i<this->nSpecie_; i++)
{
c1[i] = c[i];
completeC[i] = c[i];
}
c1[this->nSpecie_] = T;
c1[this->nSpecie_+1] = p;
// Compute the rAB matrix
RectangularMatrix<scalar> PAB(this->nSpecie_,this->nSpecie_,0.0);
RectangularMatrix<scalar> CAB(this->nSpecie_,this->nSpecie_,0.0);
scalarField PA(this->nSpecie_,0.0);
scalarField CA(this->nSpecie_,0.0);
// Number of initialized rAB for each lines
Field<label> NbrABInit(this->nSpecie_,0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
scalar pf, cf, pr, cr;
label lRef, rRef;
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
// for each reaction compute omegai
scalar omegai = this->chemistry_.omega
(
R, c1, T, p, pf, cf, lRef, pr, cr, rRef
);
// then for each pair of species composing this reaction,
// compute the rAB matrix (separate the numerator and
// denominator)
DynamicList<scalar> wA(R.lhs().size()+R.rhs().size());
DynamicList<label> wAID(R.lhs().size()+R.rhs().size());
forAll(R.lhs(), s)// compute rAB for all species in the left hand side
{
label ss = R.lhs()[s].index;
scalar sl = -R.lhs()[s].stoichCoeff; // vAi = v''-v' => here -v'
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
break;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
forAll(R.rhs(), s) // compute rAB for all species in the right hand side
{
label ss = R.rhs()[s].index;
scalar sl = R.rhs()[s].stoichCoeff; // vAi = v''-v' => here v''
bool found(false);
forAll(wAID, id)
{
if (ss==wAID[id])
{
wA[id] += sl*omegai;
found = true;
break;
}
}
if (!found)
{
wA.append(sl*omegai);
wAID.append(ss);
}
}
wAID.shrink();
forAll(wAID, id)
{
label curID = wAID[id];
scalar curwA = wA[id];
List<bool> deltaBi(this->nSpecie_, false);
FIFOStack<label> usedIndex;
forAll(R.lhs(),j)
{
label sj = R.lhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
forAll(R.rhs(),j)
{
label sj = R.rhs()[j].index;
usedIndex.push(sj);
deltaBi[sj] = true;
}
deltaBi[curID] = false;
while(!usedIndex.empty())
{
label curIndex = usedIndex.pop();
if (deltaBi[curIndex])
{
deltaBi[curIndex] = false;
if (rABPos(curID, curIndex)==-1)
{
rABPos(curID, curIndex) = NbrABInit[curID];
rABOtherSpec(curID, NbrABInit[curID]) = curIndex;
if (curwA > 0.0)
{
PAB(curID, NbrABInit[curID]) = curwA;
}
else
{
CAB(curID, NbrABInit[curID]) = -curwA;
}
NbrABInit[curID]++;
}
else
{
if (curwA > 0.0)
{
PAB(curID, rABPos(curID, curIndex)) += curwA;
}
else
{
CAB(curID, rABPos(curID, curIndex)) += -curwA;
}
}
}
}
// Now that every species of the reactions has been visited, we can
// compute the production and consumption rate. It avoids getting
// wrong results when species are present in both lhs and rhs
if (curwA > 0.0)
{
if (PA[curID] == 0.0)
{
PA[curID] = curwA;
}
else
{
PA[curID] += curwA;
}
}
else
{
if (CA[curID] == 0.0)
{
CA[curID] = -curwA;
}
else
{
CA[curID] += -curwA;
}
}
}
}
// rii = 0.0 by definition
// Compute second generation link strength
// For all species A look at all rAri of the connected species ri and
// compute rriB with all the connected species of ri, B different of A. If
// a new species is connected, add it to the list of connected species. It
// is a connection of second generation and it will be aggregated in the
// final step to evaluate the total connection strength (or path flux).
// Compute rsecond=rAri*rriB with A!=ri!=B
RectangularMatrix<scalar> PAB2nd(this->nSpecie_,this->nSpecie_,0.0);
RectangularMatrix<scalar> CAB2nd(this->nSpecie_,this->nSpecie_,0.0);
// Number of initialized rAB for each lines
Field<label> NbrABInit2nd(this->nSpecie_, 0);
// Position of the initialized rAB, -1 when not initialized
RectangularMatrix<label> rABPos2nd(this->nSpecie_, this->nSpecie_, -1);
// Index of the other species involved in the rABNum
RectangularMatrix<label> rABOtherSpec2nd
(
this->nSpecie_, this->nSpecie_, -1
);
forAll(NbrABInit, A)
{
for (int i=0; i<NbrABInit[A]; i++)
{
label ri = rABOtherSpec(A, i);
scalar maxPACA = max(PA[ri],CA[ri]);
if (maxPACA > VSMALL)
{
for (int j=0; j<NbrABInit[ri]; j++)
{
label B = rABOtherSpec(ri, j);
if (B != A) // if B!=A and also !=ri by definition
{
if (rABPos2nd(A, B)==-1)
{
rABPos2nd(A, B) = NbrABInit2nd[A]++;
rABOtherSpec2nd(A, rABPos2nd(A, B)) = B;
PAB2nd(A, rABPos2nd(A, B)) =
PAB(A, i)*PAB(ri, j)/maxPACA;
CAB2nd(A, rABPos2nd(A, B)) =
CAB(A, i)*CAB(ri, j)/maxPACA;
}
else
{
PAB2nd(A, rABPos2nd(A, B)) +=
PAB(A, i)*PAB(ri, j)/maxPACA;
CAB2nd(A, rABPos2nd(A, B)) +=
CAB(A, i)*CAB(ri, j)/maxPACA;
}
}
}
}
}
}
// Using the rAB matrix (numerator and denominator separated)
label speciesNumber = 0;
// set all species to inactive and activate them according
// to rAB and initial set
for (label i=0; i<this->nSpecie_; i++)
{
this->activeSpecies_[i] = false;
}
// Initialize the FIFOStack for search set
const labelList& SIS(this->searchInitSet_);
FIFOStack<label> Q;
for (label i=0; i<SIS.size(); i++)
{
label q = SIS[i];
this->activeSpecies_[q] = true;
speciesNumber++;
Q.push(q);
}
// Execute the main loop for R-value
while (!Q.empty())
{
label u = Q.pop();
scalar Den = max(PA[u],CA[u]);
if (Den!=0.0)
{
// first generation
for (label v=0; v<NbrABInit[u]; v++)
{
label otherSpec = rABOtherSpec(u, v);
scalar rAB = (PAB(u, v)+CAB(u, v))/Den; // first generation
label id2nd = rABPos2nd(u, otherSpec);
if (id2nd !=-1)// if there is a second generation link
{
rAB += (PAB2nd(u, id2nd)+CAB2nd(u, id2nd))/Den;
}
// the link is stronger than the user-defined tolerance
if
(
rAB >= this->tolerance()
&& !this->activeSpecies_[otherSpec]
)
{
Q.push(otherSpec);
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
}
}
// second generation link only (for those without first link)
for (label v=0; v<NbrABInit2nd[u]; v++)
{
label otherSpec = rABOtherSpec2nd(u, v);
scalar rAB = (PAB2nd(u, v)+CAB2nd(u, v))/Den;
// the link is stronger than the user-defined tolerance
if
(
rAB >= this->tolerance()
&& !this->activeSpecies_[otherSpec]
)
{
Q.push(otherSpec);
this->activeSpecies_[otherSpec] = true;
speciesNumber++;
}
}
}
}
// Put a flag on the reactions containing at least one removed species
forAll(this->chemistry_.reactions(), i)
{
const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
this->chemistry_.reactionsDisabled()[i] = false;
forAll(R.lhs(), s)
{
label ss = R.lhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
if (!this->chemistry_.reactionsDisabled()[i])
{
forAll(R.rhs(), s)
{
label ss = R.rhs()[s].index;
if (!this->activeSpecies_[ss])
{
this->chemistry_.reactionsDisabled()[i] = true;
break;
}
}
}
}
this->NsSimp_ = speciesNumber;
scalarField& simplifiedC(this->chemistry_.simplifiedC());
simplifiedC.setSize(this->NsSimp_+2);
DynamicList<label>& s2c(this->chemistry_.simplifiedToCompleteIndex());
s2c.setSize(this->NsSimp_);
Field<label>& c2s(this->chemistry_.completeToSimplifiedIndex());
label j = 0;
for (label i=0; i<this->nSpecie_; i++)
{
if (this->activeSpecies_[i])
{
s2c[j] = i;
simplifiedC[j] = c[i];
c2s[i] = j++;
if (!this->chemistry_.active(i))
{
this->chemistry_.setActive(i);
}
}
else
{
c2s[i] = -1;
}
}
simplifiedC[this->NsSimp_] = T;
simplifiedC[this->NsSimp_+1] = p;
this->chemistry_.setNsDAC(this->NsSimp_);
// change temporary Ns in chemistryModel
// to make the function nEqns working
this->chemistry_.setNSpecie(this->NsSimp_);
}
// ************************************************************************* //

View File

@ -0,0 +1,107 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::PFA
Description
Path flux analysis
SourceFiles
PFA.C
\*---------------------------------------------------------------------------*/
#ifndef PFA_H
#define PFA_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class ode Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class PFA
:
public chemistryReductionMethod<CompType, ThermoType>
{
// Private data
//- List of label for the search initiating set
labelList searchInitSet_;
public:
//- Runtime type information
TypeName("PFA");
// Constructors
//- Construct from components
PFA
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~PFA();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "PFA.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "chemistryReductionMethod.H"
#include "TDACChemistryModel.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethod<CompType, ThermoType>::chemistryReductionMethod
(
const Foam::IOdictionary& dict,
Foam::TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
dict_(dict),
coeffsDict_(dict.subDict("reduction")),
active_(coeffsDict_.lookupOrDefault<Switch>("active", false)),
log_(coeffsDict_.lookupOrDefault<Switch>("log", false)),
chemistry_(chemistry),
activeSpecies_(chemistry.nSpecie(), false),
NsSimp_(chemistry.nSpecie()),
nSpecie_(chemistry.nSpecie()),
tolerance_(coeffsDict_.lookupOrDefault<scalar>("tolerance", 1e-4))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethod<CompType, ThermoType>::
~chemistryReductionMethod()
{}
// ************************************************************************* //

View File

@ -0,0 +1,177 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethod
Description
An abstract class for methods of chemical mechanism reduction
SourceFiles
chemistryReductionMethod.C
\*---------------------------------------------------------------------------*/
#ifndef chemistryReductionMethod_H
#define chemistryReductionMethod_H
#include "IOdictionary.H"
#include "Switch.H"
#include "scalarField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
template<class CompType, class ThermoType>
class TDACChemistryModel;
/*---------------------------------------------------------------------------*\
Class chemistrySolver Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class chemistryReductionMethod
{
protected:
const IOdictionary& dict_;
//- Dictionary that store the algorithm data
const dictionary coeffsDict_;
//- Is mechanism reduction active?
Switch active_;
//- Switch to select performance logging
Switch log_;
TDACChemistryModel<CompType, ThermoType>& chemistry_;
//- List of active species (active = true)
List<bool> activeSpecies_;
//- Number of active species
label NsSimp_;
//- Number of species
const label nSpecie_;
//- Tolerance for the mechanism reduction algorithm
scalar tolerance_;
public:
//- Runtime type information
TypeName("chemistryReductionMethod");
// Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
chemistryReductionMethod,
dictionary,
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
),
(dict, chemistry)
);
// Constructors
//- Construct from components
chemistryReductionMethod
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
// Selector
static autoPtr<chemistryReductionMethod<CompType, ThermoType>> New
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~chemistryReductionMethod();
// Member Functions
//- Is mechanism reduction active?
inline bool active() const;
//- Is performance data logging enabled?
inline bool log() const;
//- Return the active species
inline const List<bool>& activeSpecies() const;
//- Return the number of active species
inline label NsSimp();
//- Return the initial number of species
inline label nSpecie();
//- Return the tolerance
inline scalar tolerance() const;
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
) = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "chemistryReductionMethodI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "chemistryReductionMethod.C"
#include "chemistryReductionMethodNew.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethod
Description
An abstract class for reducing chemical mechanism
SourceFiles
chemistryReductionMethod.C
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
inline bool
Foam::chemistryReductionMethod<CompType, ThermoType>::active() const
{
return active_;
}
template<class CompType, class ThermoType>
inline bool
Foam::chemistryReductionMethod<CompType, ThermoType>::log() const
{
return active_ && log_;
}
template<class CompType, class ThermoType>
inline const Foam::List<bool>&
Foam::chemistryReductionMethod<CompType, ThermoType>::activeSpecies() const
{
return activeSpecies_;
}
template<class CompType, class ThermoType>
inline Foam::label
Foam::chemistryReductionMethod<CompType, ThermoType>::NsSimp()
{
return NsSimp_;
}
template<class CompType, class ThermoType>
inline Foam::label
Foam::chemistryReductionMethod<CompType, ThermoType>::nSpecie()
{
return nSpecie_;
}
template<class CompType, class ThermoType>
inline Foam::scalar
Foam::chemistryReductionMethod<CompType, ThermoType>::tolerance() const
{
return tolerance_;
}
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "chemistryReductionMethod.H"
#include "Time.H"
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::autoPtr<Foam::chemistryReductionMethod<CompType, ThermoType>>
Foam::chemistryReductionMethod<CompType, ThermoType>::New
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
{
IOdictionary thermoDict
(
IOobject
(
"thermophysicalProperties",
dict.db().time().constant(),
dict.db(),
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE,
false
)
);
word thermoTypeName;
if (thermoDict.isDict("thermoType"))
{
const dictionary& thermoTypeDict(thermoDict.subDict("thermoType"));
thermoTypeName =
word(thermoTypeDict.lookup("transport")) + '<'
+ word(thermoTypeDict.lookup("thermo")) + '<'
+ word(thermoTypeDict.lookup("equationOfState")) + '<'
+ word(thermoTypeDict.lookup("specie")) + ">>,"
+ word(thermoTypeDict.lookup("energy")) + ">";
}
else
{
FatalIOErrorInFunction(thermoDict)
<< "thermoType is in the old format and must be upgraded"
<< exit(FatalIOError);
}
dictionary MRdict(dict.subDict("reduction"));
word chemistryReductionMethodTypeName =
word(MRdict.lookup("method")) + '<'
+ word(dict.subDict("chemistryType").lookup("chemistryThermo")) + ','
+ thermoTypeName + '>';
typename dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(chemistryReductionMethodTypeName);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorInFunction
<< "Unknown chemistryReductionMethodType type "
<< chemistryReductionMethodTypeName
<< endl << endl
<< "Valid chemistryReductionMethodType types are :" << endl
<< dictionaryConstructorTablePtr_->toc()
<< exit(FatalError);
}
return autoPtr<chemistryReductionMethod<CompType, ThermoType>>
(
cstrIter()(dict, chemistry)
);
}
// ************************************************************************* //

View File

@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "makeChemistryReductionMethods.H"
#include "thermoPhysicsTypes.H"
#include "psiChemistryModel.H"
#include "rhoChemistryModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Chemistry solvers based on sensibleEnthalpy
makeChemistryReductionMethods(psiChemistryModel, constGasHThermoPhysics);
makeChemistryReductionMethods(psiChemistryModel, gasHThermoPhysics);
makeChemistryReductionMethods
(
psiChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryReductionMethods
(
psiChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryReductionMethods(psiChemistryModel, icoPoly8HThermoPhysics);
makeChemistryReductionMethods(rhoChemistryModel, constGasHThermoPhysics);
makeChemistryReductionMethods(rhoChemistryModel, gasHThermoPhysics);
makeChemistryReductionMethods
(
rhoChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryReductionMethods
(
rhoChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryReductionMethods(rhoChemistryModel, icoPoly8HThermoPhysics);
// Chemistry solvers based on sensibleInternalEnergy
makeChemistryReductionMethods(psiChemistryModel, constGasEThermoPhysics);
makeChemistryReductionMethods(psiChemistryModel, gasEThermoPhysics);
makeChemistryReductionMethods
(
psiChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryReductionMethods
(
psiChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryReductionMethods(psiChemistryModel, icoPoly8EThermoPhysics);
makeChemistryReductionMethods(rhoChemistryModel, constGasEThermoPhysics);
makeChemistryReductionMethods(rhoChemistryModel, gasEThermoPhysics);
makeChemistryReductionMethods
(
rhoChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryReductionMethods
(
rhoChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryReductionMethods(rhoChemistryModel, icoPoly8EThermoPhysics);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef makeChemistryReductionMethods_H
#define makeChemistryReductionMethods_H
#include "chemistryReductionMethod.H"
#include "noChemistryReduction.H"
#include "DAC.H"
#include "DRG.H"
#include "DRGEP.H"
#include "EFA.H"
#include "PFA.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#define makeChemistryReductionMethod(SS, Comp, Thermo) \
\
typedef chemistryReductionMethods::SS<Comp, Thermo> SS##Comp##Thermo; \
\
defineTemplateTypeNameAndDebugWithName \
( \
SS##Comp##Thermo, \
(#SS"<" + word(Comp::typeName_()) \
+ "," + Thermo::typeName() + ">").c_str(), \
0 \
); \
\
chemistryReductionMethod<Comp, Thermo>:: \
adddictionaryConstructorToTable<SS##Comp##Thermo> \
add##chemistryReductionMethods##SS##Comp##Thermo##ConstructorToTable_;
#define makeChemistryReductionMethods(CompChemModel, Thermo) \
\
typedef chemistryReductionMethod<CompChemModel, Thermo> \
chemistryReductionMethod##CompChemModel##Thermo; \
\
defineTemplateTypeNameAndDebugWithName \
( \
chemistryReductionMethod##CompChemModel##Thermo, \
"chemistryReductionMethod<"#CompChemModel","#Thermo">", \
0 \
); \
\
defineTemplateRunTimeSelectionTable \
( \
chemistryReductionMethod##CompChemModel##Thermo, \
dictionary \
); \
\
makeChemistryReductionMethod \
( \
none, \
CompChemModel, \
Thermo \
); \
\
makeChemistryReductionMethod \
( \
DAC, \
CompChemModel, \
Thermo \
); \
\
makeChemistryReductionMethod \
( \
DRG, \
CompChemModel, \
Thermo \
); \
\
makeChemistryReductionMethod \
( \
DRGEP, \
CompChemModel, \
Thermo \
); \
\
makeChemistryReductionMethod \
( \
EFA, \
CompChemModel, \
Thermo \
); \
\
makeChemistryReductionMethod \
( \
PFA, \
CompChemModel, \
Thermo \
); \
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "noChemistryReduction.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::none<CompType, ThermoType>::none
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryReductionMethod<CompType, ThermoType>(dict, chemistry)
{
this->active_ = false;
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryReductionMethods::none<CompType, ThermoType>::~none()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryReductionMethods::none<CompType, ThermoType>::
reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
)
{
NotImplemented;
}
// ************************************************************************* //

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryReductionMethods::none
Description
SourceFiles
noChemistryReduction.C
\*---------------------------------------------------------------------------*/
#ifndef none_H
#define none_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryReductionMethods
{
/*---------------------------------------------------------------------------*\
Class none Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class none
:
public chemistryReductionMethod<CompType, ThermoType>
{
public:
//- Runtime type information
TypeName("none");
// Constructors
//- Construct from components
none
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~none();
// Member Functions
//- Reduce the mechanism
virtual void reduceMechanism
(
const scalarField &c,
const scalar T,
const scalar p
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryReductionMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "noChemistryReduction.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,622 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ISAT.H"
#include "LUscalarMatrix.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::ISAT
(
const dictionary& chemistryProperties,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryTabulationMethod<CompType, ThermoType>
(
chemistryProperties,
chemistry
),
chemisTree_(chemistry, this->coeffsDict_),
scaleFactor_(chemistry.nEqns(), 1.0),
runTime_(chemistry.time()),
chPMaxLifeTime_
(
this->coeffsDict_.lookupOrDefault
(
"chPMaxLifeTime",
(runTime_.endTime().value()-runTime_.startTime().value())
/runTime_.deltaT().value()
)
),
maxGrowth_(this->coeffsDict_.lookupOrDefault("maxGrowth", INT_MAX)),
checkEntireTreeInterval_
(
this->coeffsDict_.lookupOrDefault("checkEntireTreeInterval", INT_MAX)
),
maxDepthFactor_
(
this->coeffsDict_.lookupOrDefault
(
"maxDepthFactor",
(chemisTree_.maxNLeafs() - 1)
/(log(scalar(chemisTree_.maxNLeafs()))/log(2.0))
)
),
minBalanceThreshold_
(
this->coeffsDict_.lookupOrDefault
(
"minBalanceThreshold",0.1*chemisTree_.maxNLeafs()
)
),
MRURetrieve_(this->coeffsDict_.lookupOrDefault("MRURetrieve", false)),
maxMRUSize_(this->coeffsDict_.lookupOrDefault("maxMRUSize", 0)),
lastSearch_(NULL),
growPoints_(this->coeffsDict_.lookupOrDefault("growPoints", true)),
nRetrieved_(0),
nGrowth_(0),
nAdd_(0),
cleaningRequired_(false)
{
if (this->active_)
{
dictionary scaleDict(this->coeffsDict_.subDict("scaleFactor"));
label Ysize = this->chemistry_.Y().size();
scalar otherScaleFactor = readScalar(scaleDict.lookup("otherSpecies"));
for (label i=0; i<Ysize; i++)
{
if (!scaleDict.found(this->chemistry_.Y()[i].name()))
{
scaleFactor_[i] = otherScaleFactor;
}
else
{
scaleFactor_[i] =
readScalar
(
scaleDict.lookup(this->chemistry_.Y()[i].name())
);
}
}
scaleFactor_[Ysize] = readScalar(scaleDict.lookup("Temperature"));
scaleFactor_[Ysize+1] = readScalar(scaleDict.lookup("Pressure"));
}
if (this->log())
{
nRetrievedFile_ = chemistry.logFile("found_isat.out");
nGrowthFile_ = chemistry.logFile("growth_isat.out");
nAddFile_ = chemistry.logFile("add_isat.out");
sizeFile_ = chemistry.logFile("size_isat.out");
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::~ISAT()
{}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::addToMRU
(
chemPointISAT<CompType, ThermoType>* phi0
)
{
if (maxMRUSize_ > 0 && MRURetrieve_)
{
// First search if the chemPoint is already in the list
bool isInList = false;
typename SLList <chemPointISAT<CompType, ThermoType>*>::iterator iter =
MRUList_.begin();
for ( ; iter != MRUList_.end(); ++iter)
{
if (iter() == phi0)
{
isInList = true;
break;
}
}
// If it is in the list, then move it to front
if (isInList)
{
if (iter() != MRUList_.first())
{
// iter hold the position of the element to move
MRUList_.remove(iter);
// Insert the element in front of the list
MRUList_.insert(phi0);
}
}
else // chemPoint not yet in the list, iter is last
{
if (MRUList_.size() == maxMRUSize_)
{
if (iter() == MRUList_.last())
{
MRUList_.remove(iter);
MRUList_.insert(phi0);
}
else
{
FatalErrorInFunction
<< "wrong MRUList construction"
<< exit(FatalError);
}
}
else
{
MRUList_.insert(phi0);
}
}
}
}
template<class CompType, class ThermoType>
void Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::calcNewC
(
chemPointISAT<CompType, ThermoType>* phi0,
const scalarField& phiq,
scalarField& Rphiq
)
{
label nEqns = this->chemistry_.nEqns(); // Full set of species
bool mechRedActive = this->chemistry_.mechRed()->active();
Rphiq = phi0->Rphi();
scalarField dphi(phiq-phi0->phi());
const scalarSquareMatrix& gradientsMatrix = phi0->A();
List<label>& completeToSimplified(phi0->completeToSimplifiedIndex());
// Rphiq[i] = Rphi0[i]+A(i, j)dphi[j]
// where Aij is dRi/dphi_j
for (label i=0; i<nEqns-2; i++)
{
if (mechRedActive)
{
label si = completeToSimplified[i];
// The species is active
if (si != -1)
{
for (label j=0; j<nEqns-2; j++)
{
label sj = completeToSimplified[j];
if (sj != -1)
{
Rphiq[i] += gradientsMatrix(si, sj)*dphi[j];
}
}
Rphiq[i] +=
gradientsMatrix(si, phi0->nActiveSpecies())*dphi[nEqns-2];
Rphiq[i] +=
gradientsMatrix(si, phi0->nActiveSpecies()+1)*dphi[nEqns-1];
// As we use an approximation of A, Rphiq should be checked for
// negative values
Rphiq[i] = max(0.0,Rphiq[i]);
}
// The species is not active A(i, j) = I(i, j)
else
{
Rphiq[i] += dphi[i];
Rphiq[i] = max(0.0,Rphiq[i]);
}
}
else // Mechanism reduction is not active
{
for (label j=0; j<nEqns; j++)
{
Rphiq[i] += gradientsMatrix(i, j)*dphi[j];
}
// As we use a first order gradient matrix, Rphiq should be checked
// for negative values
Rphiq[i] = max(0.0,Rphiq[i]);
}
}
}
template<class CompType, class ThermoType>
bool Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::grow
(
chemPointISAT<CompType, ThermoType>* phi0,
const scalarField& phiq,
const scalarField& Rphiq
)
{
// If the pointer to the chemPoint is NULL, the function stops
if (!phi0)
{
return false;
}
// Raise a flag when the chemPoint used has been grown more than the
// allowed number of time
if (!phi0->toRemove() && phi0->nGrowth() > maxGrowth_)
{
cleaningRequired_ = true;
phi0->toRemove() = true;
}
// If the solution RphiQ is still within the tolerance we try to grow it
// in some cases this might result in a failure and the grow function of
// the chemPoint returns false
if (phi0->checkSolution(phiq, Rphiq))
{
return phi0->grow(phiq);
}
// The actual solution and the approximation given by ISAT are too different
else
{
return false;
}
}
template<class CompType, class ThermoType>
bool
Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::cleanAndBalance()
{
bool treeModified(false);
// Check all chemPoints to see if we need to delete some of the chemPoints
// according to the ellapsed time and number of growths
chemPointISAT<CompType, ThermoType>* x = chemisTree_.treeMin();
while(x != NULL)
{
chemPointISAT<CompType, ThermoType>* xtmp =
chemisTree_.treeSuccessor(x);
// timeOutputValue returns timeToUserTime(value()), therefore, it should
// be compare with timeToUserTime(deltaT)
scalar elapsedTime = runTime_.timeOutputValue() - x->timeTag();
scalar maxElapsedTime =
chPMaxLifeTime_
* runTime_.timeToUserTime(runTime_.deltaTValue());
if ((elapsedTime > maxElapsedTime) || (x->nGrowth() > maxGrowth_))
{
chemisTree_.deleteLeaf(x);
treeModified = true;
}
x = xtmp;
}
// Check if the tree should be balanced according to criterion:
// -the depth of the tree bigger than a*log2(size), log2(size) being the
// ideal depth (e.g. 4 leafs can be stored in a tree of depth 2)
if
(
chemisTree_.size() > minBalanceThreshold_
&& chemisTree_.depth() >
maxDepthFactor_*log(scalar(chemisTree_.size()))/log(2.0)
)
{
chemisTree_.balance();
MRUList_.clear();
treeModified = true;
}
// Return a bool to specify if the tree structure has been modified and is
// now below the user specified limit (true if not full)
return (treeModified && !chemisTree_.isFull());
}
template<class CompType, class ThermoType>
void Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::computeA
(
scalarSquareMatrix& A,
const scalarField& Rphiq,
const scalar rhoi
)
{
scalar dt = runTime_.deltaTValue();
bool mechRedActive = this->chemistry_.mechRed()->active();
label speciesNumber = this->chemistry_.nSpecie();
scalarField Rcq(this->chemistry_.nEqns());
for (label i=0; i<speciesNumber; i++)
{
label s2c = i;
if (mechRedActive)
{
s2c = this->chemistry_.simplifiedToCompleteIndex()[i];
}
Rcq[i] = rhoi*Rphiq[s2c]/this->chemistry_.specieThermo()[s2c].W();
}
Rcq[speciesNumber] = Rphiq[Rphiq.size()-2];
Rcq[speciesNumber+1] = Rphiq[Rphiq.size()-1];
// Aaa is computed implicitely,
// A is given by A = C(psi0, t0+dt), where C is obtained through solving
// d/dt C(psi0,t) = J(psi(t))C(psi0,t)
// If we solve it implicitely:
// (C(psi0, t0+dt) - C(psi0,t0))/dt = J(psi(t0+dt))C(psi0,t0+dt)
// The Jacobian is thus computed according to the mapping
// C(psi0,t0+dt)*(I-dt*J(psi(t0+dt))) = C(psi0, t0)
// A = C(psi0,t0)/(I-dt*J(psi(t0+dt)))
// where C(psi0,t0) = I
this->chemistry_.jacobian(runTime_.value(), Rcq, A);
// The jacobian is computed according to the molar concentration
// the following conversion allows the code to use A with mass fraction
for (label i=0; i<speciesNumber; i++)
{
label si = i;
if (mechRedActive)
{
si = this->chemistry_.simplifiedToCompleteIndex()[i];
}
for (label j=0; j<speciesNumber; j++)
{
label sj = j;
if (mechRedActive)
{
sj = this->chemistry_.simplifiedToCompleteIndex()[j];
}
A(i, j) *=
-dt*this->chemistry_.specieThermo()[si].W()
/this->chemistry_.specieThermo()[sj].W();
}
A(i, i) += 1;
// Columns for pressure and temperature
A(i, speciesNumber) *=
-dt*this->chemistry_.specieThermo()[si].W()/rhoi;
A(i, speciesNumber+1) *=
-dt*this->chemistry_.specieThermo()[si].W()/rhoi;
}
// For temperature and pressure, only unity on the diagonal
A(speciesNumber, speciesNumber) = 1;
A(speciesNumber+1, speciesNumber+1) = 1;
// Inverse of (I-dt*J(psi(t0+dt)))
LUscalarMatrix LUA(A);
LUA.inv(A);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
bool Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::retrieve
(
const Foam::scalarField& phiq,
scalarField& Rphiq
)
{
bool retrieved(false);
chemPointISAT<CompType, ThermoType>* phi0;
// If the tree is not empty
if (chemisTree_.size())
{
chemisTree_.binaryTreeSearch(phiq, chemisTree_.root(), phi0);
// lastSearch keeps track of the chemPoint we obtain by the regular
// binary tree search
lastSearch_ = phi0;
if (phi0->inEOA(phiq))
{
retrieved = true;
}
// After a successful secondarySearch, phi0 store a pointer to the
// found chemPoint
else if (chemisTree_.secondaryBTSearch(phiq, phi0))
{
retrieved = true;
}
else if (MRURetrieve_)
{
typename SLList
<
chemPointISAT<CompType, ThermoType>*
>::iterator iter = MRUList_.begin();
for ( ; iter != MRUList_.end(); ++iter)
{
phi0 = iter();
if (phi0->inEOA(phiq))
{
retrieved = true;
break;
}
}
}
}
// The tree is empty, retrieved is still false
else
{
// There is no chempoints that we can try to grow
lastSearch_ = NULL;
}
if (retrieved)
{
scalar elapsedTime =
runTime_.timeOutputValue() - phi0->timeTag();
scalar maxElapsedTime =
chPMaxLifeTime_
* runTime_.timeToUserTime(runTime_.deltaTValue());
// Raise a flag when the chemPoint has been used more than the allowed
// number of time steps
if (elapsedTime > maxElapsedTime && !phi0->toRemove())
{
cleaningRequired_ = true;
phi0->toRemove() = true;
}
lastSearch_->lastTimeUsed() = runTime_.timeOutputValue();
addToMRU(phi0);
calcNewC(phi0,phiq, Rphiq);
nRetrieved_++;
return true;
}
else
{
// This point is reached when every retrieve trials have failed
// or if the tree is empty
return false;
}
}
template<class CompType, class ThermoType>
bool Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::add
(
const scalarField& phiq,
const scalarField& Rphiq,
const scalar rho
)
{
// If lastSearch_ holds a valid pointer to a chemPoint AND the growPoints_
// option is on, the code first tries to grow the point hold by lastSearch_
if (lastSearch_ && growPoints_)
{
if (grow(lastSearch_,phiq, Rphiq))
{
nGrowth_++;
// the structure of the tree is not modified, return false
return false;
}
}
bool treeCleanedOrCleared(false);
// If the code reach this point, it is either because lastSearch_ is not
// valid, OR because growPoints_ is not on, OR because the grow operation
// has failed. In the three cases, a new point is added to the tree.
if (chemisTree().isFull())
{
// If cleanAndBalance operation do not result in a reduction of the tree
// size, the last possibility is to delete completely the tree.
// It can be partially rebuild with the MRU list if this is used.
if (!cleanAndBalance())
{
DynamicList<chemPointISAT<CompType, ThermoType>*> tempList;
if (maxMRUSize_>0)
{
// Create a copy of each chemPointISAT of the MRUList_ before
// they are deleted
typename SLList
<
chemPointISAT<CompType, ThermoType>*
>::iterator iter = MRUList_.begin();
for ( ; iter != MRUList_.end(); ++iter)
{
tempList.append
(
new chemPointISAT<CompType, ThermoType>(*iter())
);
}
}
chemisTree().clear();
// Pointers to chemPoint are not valid anymore, clear the list
MRUList_.clear();
// Construct the tree without giving a reference to attach to it
// since the structure has been completely discarded
chemPointISAT<CompType, ThermoType>* nulPhi = 0;
forAll(tempList, i)
{
chemisTree().insertNewLeaf
(
tempList[i]->phi(),
tempList[i]->Rphi(),
tempList[i]->A(),
scaleFactor(),
this->tolerance(),
scaleFactor_.size(),
nulPhi
);
deleteDemandDrivenData(tempList[i]);
}
}
// The structure has been changed, it will force the binary tree to
// perform a new search and find the most appropriate point still stored
lastSearch_ = NULL;
// Either cleanAndBalance has changed the tree or it has been cleared
// in any case treeCleanedOrCleared should be set to true
treeCleanedOrCleared = true;
}
// Compute the A matrix needed to store the chemPoint.
label ASize = this->chemistry_.nEqns(); // Reduced when mechRed is active
scalarSquareMatrix A(ASize, Zero);
computeA(A, Rphiq, rho);
chemisTree().insertNewLeaf
(
phiq,
Rphiq,
A,
scaleFactor(),
this->tolerance(),
scaleFactor_.size(),
lastSearch_ // lastSearch_ may be NULL (handled by binaryTree)
);
nAdd_++;
return treeCleanedOrCleared;
}
template<class CompType, class ThermoType>
void
Foam::chemistryTabulationMethods::ISAT<CompType, ThermoType>::writePerformance()
{
if (this->log())
{
nRetrievedFile_()
<< runTime_.timeOutputValue() << " " << nRetrieved_ << endl;
nRetrieved_ = 0;
nGrowthFile_()
<< runTime_.timeOutputValue() << " " << nGrowth_ << endl;
nGrowth_ = 0;
nAddFile_()
<< runTime_.timeOutputValue() << " " << nAdd_ << endl;
nAdd_ = 0;
sizeFile_()
<< runTime_.timeOutputValue() << " " << this->size() << endl;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,256 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryTabulationMethods::ISAT
Description
Implementation of the ISAT (In-situ adaptive tabulation), for chemistry
calculation.
Reference:
\verbatim
Pope, S. B. (1997).
Computationally efficient implementation of combustion chemistry using
in situ adaptive tabulation.
Combustion Theory and Modelling, 1, 41-63.
\endverbatim
\*---------------------------------------------------------------------------*/
#ifndef ISAT_H
#define ISAT_H
#include "binaryTree.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace chemistryTabulationMethods
{
/*---------------------------------------------------------------------------*\
Class ISAT Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class ISAT
:
public chemistryTabulationMethod<CompType, ThermoType>
{
// Private data
//- List of the stored 'points' organized in a binary tree
binaryTree<CompType, ThermoType> chemisTree_;
//- List of scale factors for species, temperature and pressure
scalarField scaleFactor_;
const Time& runTime_;
//- Lifetime (number of time steps) of a stored point
label chPMaxLifeTime_;
//- Maximum number of growths before removing from the tree
label maxGrowth_;
//- Check the binary tree for leafs to remove every interval
label checkEntireTreeInterval_;
//- Factor that multiply the ideal depth of a binary tree to decide
// wheter to try to balance of not
scalar maxDepthFactor_;
//- Minimal size before trying to balance the tree
label minBalanceThreshold_;
//- After a failed primary retrieve, look in the MRU list
Switch MRURetrieve_;
//- Most Recently Used (MRU) list of chemPoint
SLList<chemPointISAT<CompType, ThermoType>*> MRUList_;
//- Maximum size of the MRU list
label maxMRUSize_;
//- Store a pointer to the last chemPointISAT found
chemPointISAT<CompType, ThermoType>* lastSearch_;
//- Switch to allow growth (on by default)
Switch growPoints_;
// Statistics on ISAT usage
label nRetrieved_;
label nGrowth_;
label nAdd_;
autoPtr<OFstream> nRetrievedFile_;
autoPtr<OFstream> nGrowthFile_;
autoPtr<OFstream> nAddFile_;
autoPtr<OFstream> sizeFile_;
bool cleaningRequired_;
// Private Member Functions
//- Disallow default bitwise copy construct
ISAT(const ISAT&);
//- Add a chemPoint to the MRU list
void addToMRU(chemPointISAT<CompType, ThermoType>* phi0);
//- Compute and return the mapping of the composition phiq
// Input : phi0 the nearest chemPoint used in the linear interpolation
// phiq the composition of the query point for which we want to
// compute the mapping
// Rphiq the mapping of the new composition point (given as empty)
// Output: void (the mapping is stored in the Rphiq array)
// Rphiq = Rphi0 + A * (phiq-phi0)
void calcNewC
(
chemPointISAT<CompType, ThermoType>* phi0,
const scalarField& phiq,
scalarField& Rphiq
);
//- Check if the composition of the query point phiq lies in the
// ellipsoid of accuracy approximating the region of accuracy of the
// stored chemPoint phi0
// Input : phi0 the nearest chemPoint used in the linear interpolation
// phiq the composition of the query point for which we want to
// compute the mapping
// Output: true if phiq is in the EOA, false if not
bool grow
(
chemPointISAT<CompType, ThermoType>* phi0,
const scalarField& phiq,
const scalarField& Rphiq
);
//- Clean and balance the tree
bool cleanAndBalance();
//- Functions to construct the gradients matrix
// When mecanism reduction is active, the A matrix is given by
// Aaa Aad
// A = ( Ada Add ), where the sub gradient matrices are:
// (Aaa) active species according to active species, (Aad) active
// species according to disabled species, (Ada) disabled species
// according to active species, and (Add) disabled species according to
// disabled species.
// The current implementation computes Aaa with the Jacobian of the
// reduced set of species. Aad = 0, Ada = 0, and Add = I.
// To be implemented: add options to compute the A matrix for different
// strategies
void computeA
(
scalarSquareMatrix& A,
const scalarField& Rphiq,
const scalar rho
);
public:
//- Runtime type information
TypeName("ISAT");
// Constructors
//- Construct from dictionary
ISAT
(
const dictionary& chemistryProperties,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
// Destructor
virtual ~ISAT();
// Member Functions
inline binaryTree<CompType, ThermoType>& chemisTree()
{
return chemisTree_;
}
inline const scalarField& scaleFactor() const
{
return scaleFactor_;
}
//- Return the size of the binary tree
virtual inline label size()
{
return chemisTree_.size();
}
virtual void writePerformance();
//- Find the closest stored leaf of phiQ and store the result in
// RphiQ or return false.
virtual bool retrieve
(
const Foam::scalarField& phiq,
scalarField& Rphiq
);
//- Add information to the tabulation.
// This function can grow an existing point or add a new leaf to the
// binary tree Input : phiq the new composition to store Rphiq the
// mapping of the new composition point
virtual bool add
(
const scalarField& phiq,
const scalarField& Rphiq,
const scalar rho
);
virtual bool update()
{
return cleanAndBalance();
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryTabulationMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ISAT.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,180 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "binaryNode.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::binaryNode<CompType, ThermoType>::binaryNode
(
)
:
leafLeft_(NULL),
leafRight_(NULL),
nodeLeft_(NULL),
nodeRight_(NULL),
parent_(NULL)
{}
template<class CompType, class ThermoType>
Foam::binaryNode<CompType, ThermoType>::binaryNode
(
chemPointISAT<CompType, ThermoType>* elementLeft,
chemPointISAT<CompType, ThermoType>* elementRight,
binaryNode<CompType, ThermoType>* parent
)
:
leafLeft_(elementLeft),
leafRight_(elementRight),
nodeLeft_(NULL),
nodeRight_(NULL),
parent_(parent),
v_(elementLeft->completeSpaceSize(),0.0)
{
calcV(elementLeft, elementRight, v_);
a_ = calcA(elementLeft, elementRight);
}
template<class CompType, class ThermoType>
Foam::binaryNode<CompType, ThermoType>::binaryNode
(
binaryNode<CompType, ThermoType> *bn
)
:
leafLeft_(bn->leafLeft()),
leafRight_(bn->leafRight()),
nodeLeft_(bn->nodeLeft()),
nodeRight_(bn->nodeRight()),
parent_(bn->parent()),
v_(bn->v()),
a_(bn->a())
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void
Foam::binaryNode<CompType, ThermoType>::calcV
(
chemPointISAT<CompType, ThermoType>*& elementLeft,
chemPointISAT<CompType, ThermoType>*& elementRight,
scalarField& v
)
{
// LT is the transpose of the L matrix
scalarSquareMatrix& LT = elementLeft->LT();
bool mechReductionActive = elementLeft->chemistry().mechRed()->active();
// difference of composition in the full species domain
scalarField phiDif(elementRight->phi() - elementLeft->phi());
const scalarField& scaleFactor(elementLeft->scaleFactor());
scalar epsTol = elementLeft->tolerance();
// v = LT.T()*LT*phiDif
for (label i=0; i<elementLeft->completeSpaceSize(); i++)
{
label si = i;
bool outOfIndexI = true;
if (mechReductionActive)
{
if (i<elementLeft->completeSpaceSize()-2)
{
si = elementLeft->completeToSimplifiedIndex()[i];
outOfIndexI = (si==-1);
}
else// temperature and pressure
{
outOfIndexI = false;
label dif = i-(elementLeft->completeSpaceSize()-2);
si = elementLeft->nActiveSpecies()+dif;
}
}
if (!mechReductionActive || (mechReductionActive && !(outOfIndexI)))
{
v[i]=0.0;
for (label j=0; j<elementLeft->completeSpaceSize(); j++)
{
label sj = j;
bool outOfIndexJ = true;
if (mechReductionActive)
{
if (j<elementLeft->completeSpaceSize()-2)
{
sj = elementLeft->completeToSimplifiedIndex()[j];
outOfIndexJ = (sj==-1);
}
else
{
outOfIndexJ = false;
label dif = j-(elementLeft->completeSpaceSize()-2);
sj = elementLeft->nActiveSpecies()+dif;
}
}
if
(
!mechReductionActive
||(mechReductionActive && !(outOfIndexJ))
)
{
// since L is a lower triangular matrix k=0->min(i, j)
for (label k=0; k<=min(si, sj); k++)
{
v[i] += LT(k, si)*LT(k, sj)*phiDif[j];
}
}
}
}
else
{
// when it is an inactive species the diagonal element of LT is
// 1/(scaleFactor*epsTol)
v[i] = phiDif[i]/sqr(scaleFactor[i]*epsTol);
}
}
}
template<class CompType, class ThermoType>
Foam::scalar Foam::binaryNode<CompType, ThermoType>::calcA
(
chemPointISAT<CompType, ThermoType>* elementLeft,
chemPointISAT<CompType, ThermoType>* elementRight
)
{
scalar a = 0.0;
scalarField phih((elementLeft->phi()+elementRight->phi())/2);
label completeSpaceSize = elementLeft->completeSpaceSize();
for (label i=0; i<completeSpaceSize; i++)
{
a += v_[i]*phih[i];
}
return a;
}
// ************************************************************************* //

View File

@ -0,0 +1,207 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::binaryNode
Description
Node of the binary tree
SourceFile
binaryNode.C
\*---------------------------------------------------------------------------*/
#ifndef BINARY_NODE_H
#define BINARY_NODE_H
#include "chemPointISAT.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class binaryNode Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class binaryNode
{
public:
//- Element on the left
chemPointISAT<CompType, ThermoType>* leafLeft_;
//- Element on the right
chemPointISAT<CompType, ThermoType>* leafRight_;
//- Node which follows on the left
binaryNode<CompType, ThermoType>* nodeLeft_;
//- Node which follows on the right
binaryNode<CompType, ThermoType>* nodeRight_;
//- Parent node
binaryNode<CompType, ThermoType>* parent_;
scalarField v_;
scalar a_;
//- Compute vector v:
// Let E be the ellipsoid which covers the region of accuracy of
// the left leaf (previously defined). E is described by
// E={phi| ||L^T.(phi-phi0)|| <= 1}, (see chemPoint for more details).
// let E' be the tranformation of E in a space where E' is a hypersphere
// centered at the origin, in this space y=L^T.(phi-phi0) and then
// E'={y| ||y||<=1}
// let u be the unit vector joining the center of E' and the newly added
// composition point in the transformed space
// (y2=L^T.(phiq-phi0)),u = y2/||y2|
// Then the hyperplane separating the two points is defined as the
// perpendicular bisector of the segment linking 0 to y2
// H' = {y| u^T.(y-yh) = 0},
// where yh = y2/2.
// In the orginal composition space, the hyperplane H is defined by
// H = {y| v^T(phi-phih) = 0},
// where phih = phi0 + L^-T.yh = (phi0 + phiq) / 2 and v is
// L.L^T (phiq-phi0)
// v = -------------------- .
// ||L.L^T (phiq-phi0)||
//
// Note : v is not normalised in this implementation since it is used
// on both side of an equality to know if one should go on the
// left or the right in the binary tree
// Parameter:
// elementLeft : chemPoint of the left element
// elementRight: chemPoint of the right element
// v : empty scalar field to store v
// Returnq: void (v is stored in the empty scalarField)
void calcV
(
chemPointISAT<CompType, ThermoType>*& elementLeft,
chemPointISAT<CompType, ThermoType>*& elementRight,
scalarField& v
);
//- Compute a the product v^T.phih, with phih = (phi0 + phiq)/2.
// When travelling in the binary tree,
// to know in which part of the composition space the query point 'phi'
// belongs to, v^T.phi is performed. If the result is "> a" then it belongs
// to the right part (where phiq is), otherwise it belongs to the left
// part (where phi0 is).
scalar calcA
(
chemPointISAT<CompType, ThermoType>* elementLeft,
chemPointISAT<CompType, ThermoType>* elementRight
);
// Constructors
//- Construct null
binaryNode();
//- Construct from components
binaryNode
(
chemPointISAT<CompType, ThermoType>* elementLeft,
chemPointISAT<CompType, ThermoType>* elementRight,
binaryNode<CompType, ThermoType>* parent
);
//- Construct from another binary node
binaryNode
(
binaryNode<CompType, ThermoType> *bn
);
// Member functions
//- Access
inline chemPointISAT<CompType, ThermoType>*& leafLeft()
{
return leafLeft_;
}
inline chemPointISAT<CompType, ThermoType>*& leafRight()
{
return leafRight_;
}
inline binaryNode<CompType, ThermoType>*& nodeLeft()
{
return nodeLeft_;
}
inline binaryNode<CompType, ThermoType>*& nodeRight()
{
return nodeRight_;
}
inline binaryNode<CompType, ThermoType>*& parent()
{
return parent_;
}
//- Topology
inline const scalarField& v() const
{
return v_;
}
inline scalarField& v()
{
return v_;
}
inline const scalar& a() const
{
return a_;
}
inline scalar& a()
{
return a_;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "binaryNode.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,821 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "binaryTree.H"
#include "SortableList.H"
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::insertNode
(
chP*& phi0,
bn*& newNode
)
{
if (phi0 == phi0->node()->leafRight())// phi0 is on the right
{
phi0->node()->leafRight() = NULL;
phi0->node()->nodeRight() = newNode;
return;
}
else if (phi0 == phi0->node()->leafLeft())// phi0 is on the left
{
phi0->node()->leafLeft() = NULL;
phi0->node()->nodeLeft() = newNode;
return;
}
// if we reach this point, there is an issue with the adressing
FatalErrorInFunction
<< "trying to insert a node with a wrong pointer to a chemPoint"
<< exit(FatalError);
}
template<class CompType, class ThermoType>
bool Foam::binaryTree<CompType, ThermoType>::inSubTree
(
const scalarField& phiq,
bn* y,
chP* x
)
{
if ((n2ndSearch_ < max2ndSearch_) && (y!=NULL))
{
scalar vPhi=0.0;
const scalarField& v = y->v();
const scalar a = y->a();
// compute v*phi
for (label i=0; i<phiq.size(); i++)
{
vPhi += phiq[i]*v[i];
}
if (vPhi<=a)// on the left side of the node
{
if (y->nodeLeft() == NULL)// left is a chemPoint
{
n2ndSearch_++;
if (y->leafLeft()->inEOA(phiq))
{
x=y->leafLeft();
return true;
}
}
else// the left side is a node
{
if (inSubTree(phiq, y->nodeLeft(),x))
{
return true;
}
}
// not on the left side, try the right side
if ((n2ndSearch_ < max2ndSearch_) && y->nodeRight() == NULL)
{
n2ndSearch_++;
// we reach the end of the subTree we can return the result
if (y->leafRight()->inEOA(phiq))
{
x=y->leafRight();
return true;
}
else
{
x=NULL;
return false;
}
}
else// test for n2ndSearch is done in the call of inSubTree
{
return inSubTree(phiq, y->nodeRight(),x);
}
}
else // on right side (symetric of above)
{
if (y->nodeRight() == NULL)
{
n2ndSearch_++;
if (y->leafRight()->inEOA(phiq))
{
return true;
}
}
else// the right side is a node
{
if (inSubTree(phiq, y->nodeRight(),x))
{
x=y->leafRight();
return true;
}
}
// if we reach this point, the retrieve has
// failed on the right side, explore the left side
if ((n2ndSearch_ < max2ndSearch_) && y->nodeLeft() == NULL)
{
n2ndSearch_++;
if (y->leafLeft()->inEOA(phiq))
{
x=y->leafLeft();
return true;
}
else
{
x=NULL;
return false;
}
}
else
{
return inSubTree(phiq, y->nodeLeft(),x);
}
}
}
else
{
return false;
}
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::deleteSubTree(bn* subTreeRoot)
{
if (subTreeRoot != NULL)
{
deleteDemandDrivenData(subTreeRoot->leafLeft());
deleteDemandDrivenData(subTreeRoot->leafRight());
deleteSubTree(subTreeRoot->nodeLeft());
deleteSubTree(subTreeRoot->nodeRight());
deleteDemandDrivenData(subTreeRoot);
}
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::transplant(bn* u, bn* v)
{
if (v != NULL)
{
// u is root_
if (u->parent() == NULL)
{
root_ = v;
}
// u is on the left of its parent
else if (u == u->parent()->nodeLeft())
{
u->parent()->nodeLeft() = v;
}
// u is ont the right of its parent
else if (u == u->parent()->nodeRight())
{
u->parent()->nodeRight() = v;
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial node"
<< exit(FatalError);
}
v->parent() = u->parent();
}
else
{
FatalErrorInFunction
<< "trying to transplant a NULL node"
<< exit(FatalError);
}
}
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::chemPSibling(bn* y)
{
if (y->parent()!=NULL)
{
if (y == y->parent()->nodeLeft())// y is on the left, return right side
{
// might return NULL if the right side is a node
return y->parent()->leafRight();
}
else if (y == y->parent()->nodeRight())
{
return y->parent()->leafLeft();
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial node"
<< exit(FatalError);
return NULL;
}
}
// the binaryNode is root_ and has no sibling
return NULL;
}
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::chemPSibling(chP* x)
{
if (size_>1)
{
if (x == x->node()->leafLeft())
{
// x is on the left, return right side
// might return NULL if the right side is a node
return x->node()->leafRight();
}
else if (x == x->node()->leafRight())
{
// x is on the right, return left side
return x->node()->leafLeft();
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial leaf"
<< exit(FatalError);
return NULL;
}
}
// there is only one leaf attached to the root_, no sibling
return NULL;
}
template<class CompType, class ThermoType>
Foam::binaryNode<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::nodeSibling(bn* y)
{
if (y->parent()!=NULL)
{
if (y == y->parent()->nodeLeft())
{
// y is on the left, return right side
return y->parent()->nodeRight();
}
else if (y == y->parent()->nodeRight())
{
return y->parent()->nodeLeft();
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial node"
<< exit(FatalError);
return NULL;
}
}
return NULL;
}
template<class CompType, class ThermoType>
Foam::binaryNode<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::nodeSibling(chP* x)
{
if (size_>1)
{
if (x == x->node()->leafLeft())
{
// x is on the left, return right side
return x->node()->nodeRight();
}
else if (x == x->node()->leafRight())
{
// x is on the right, return left side
return x->node()->nodeLeft();
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial leaf"
<< exit(FatalError);
return NULL;
}
}
return NULL;
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::deleteAllNode(bn* subTreeRoot)
{
if (subTreeRoot != NULL)
{
deleteAllNode(subTreeRoot->nodeLeft());
deleteAllNode(subTreeRoot->nodeRight());
deleteDemandDrivenData(subTreeRoot);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::binaryTree<CompType, ThermoType>::binaryTree
(
TDACChemistryModel<CompType, ThermoType>& chemistry,
dictionary coeffsDict
)
:
chemistry_(chemistry),
root_(NULL),
maxNLeafs_(readLabel(coeffsDict.lookup("maxNLeafs"))),
size_(0),
n2ndSearch_(0),
max2ndSearch_(coeffsDict.lookupOrDefault("max2ndSearch",0)),
coeffsDict_(coeffsDict)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::label Foam::binaryTree<CompType, ThermoType>::depth(bn* subTreeRoot)
{
// when we reach the leaf, we return 0
if (subTreeRoot == NULL)
{
return 0;
}
else
{
return 1+max
(
depth(subTreeRoot->nodeLeft()),
depth(subTreeRoot->nodeRight())
);
}
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::insertNewLeaf
(
const scalarField& phiq,
const scalarField& Rphiq,
const scalarSquareMatrix& A,
const scalarField& scaleFactor,
const scalar& epsTol,
const label nCols,
chP*& phi0
)
{
if (size_ == 0) // no points are stored
{
// create an empty binary node and point root_ to it
root_ = new bn();
// create the new chemPoint which holds the composition point
// phiq and the data to initialize the EOA
chP* newChemPoint =
new chP
(
chemistry_,
phiq,
Rphiq,
A,
scaleFactor,
epsTol,
nCols,
coeffsDict_,
root_
);
root_->leafLeft()=newChemPoint;
}
else // at least one point stored
{
// no reference chemPoint, a BT search is required
if (phi0 == NULL)
{
binaryTreeSearch(phiq, root_,phi0);
}
// access to the parent node of the chemPoint
bn* parentNode = phi0->node();
// create the new chemPoint which holds the composition point
// phiq and the data to initialize the EOA
chP* newChemPoint =
new chP
(
chemistry_,
phiq,
Rphiq,
A,
scaleFactor,
epsTol,
nCols,
coeffsDict_
);
// insert new node on the parent node in the position of the
// previously stored leaf (phi0)
// the new node contains phi0 on the left and phiq on the right
// the hyper plane is computed in the binaryNode constructor
bn* newNode;
if (size_>1)
{
newNode = new bn(phi0, newChemPoint, parentNode);
// make the parent of phi0 point to the newly created node
insertNode(phi0, newNode);
}
else // size_ == 1 (because not equal to 0)
{
// when size is 1, the binaryNode is without hyperplane
deleteDemandDrivenData(root_);
newNode = new bn(phi0, newChemPoint, NULL);
root_ = newNode;
}
phi0->node()=newNode;
newChemPoint->node()=newNode;
}
size_++;
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::binaryTreeSearch
(
const scalarField& phiq,
bn* node,
chP*& nearest
)
{
if (size_ > 1)
{
scalar vPhi=0.0;
const scalarField& v = node->v();
const scalar& a = node->a();
// compute v*phi
for (label i=0; i<phiq.size(); i++) vPhi += phiq[i]*v[i];
if (vPhi > a) // on right side (side of the newly added point)
{
if (node->nodeRight()!=NULL)
{
binaryTreeSearch(phiq, node->nodeRight(), nearest);
}
else // the terminal node is reached, store leaf on the right
{
nearest = node->leafRight();
return;
}
}
else // on left side (side of the previously stored point)
{
if (node->nodeLeft()!=NULL)
{
binaryTreeSearch(phiq, node->nodeLeft(), nearest);
}
else // the terminal node is reached, return element on right
{
nearest = node->leafLeft();
return;
}
}
}
// only one point stored (left element of the root)
else if (size_ == 1)
{
nearest = root_->leafLeft();
}
else // no point stored
{
nearest = NULL;
}
}
template<class CompType, class ThermoType>
bool Foam::binaryTree<CompType, ThermoType>::secondaryBTSearch
(
const scalarField& phiq,
chP*& x
)
{
// initialize n2ndSearch_
n2ndSearch_ = 0;
if ((n2ndSearch_ < max2ndSearch_) && (size_ > 1))
{
chP* xS = chemPSibling(x);
if (xS != NULL)
{
n2ndSearch_++;
if (xS->inEOA(phiq))
{
x=xS;
return true;
}
}
else if (inSubTree(phiq, nodeSibling(x),x))
{
return true;
}
// if we reach this point, no leafs were found at this depth or lower
// we move upward in the tree
bn* y = x->node();
while((y->parent()!= NULL) && (n2ndSearch_ < max2ndSearch_))
{
xS = chemPSibling(y);
if (xS != NULL)
{
n2ndSearch_++;
if (xS->inEOA(phiq))
{
x=xS;
return true;
}
}
else if (inSubTree(phiq, nodeSibling(y),x))
{
return true;
}
y=y->parent();
}
// if we reach this point it is either because
// we did not find another covering EOA in the entire tree or
// we reach the maximum number of secondary search
return false;
}
else
{
return false;
}
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::deleteLeaf(chP*& phi0)
{
if (size_ == 1) // only one point is stored
{
deleteDemandDrivenData(phi0);
deleteDemandDrivenData(root_);
}
else if (size_ > 1)
{
bn* z = phi0->node();
bn* x;
chP* siblingPhi0 = chemPSibling(phi0);
if (siblingPhi0 != NULL)// the sibling of phi0 is a chemPoint
{
// z was root (only two chemPoints in the tree)
if (z->parent() == NULL)
{
root_ = new bn();
root_->leafLeft()=siblingPhi0;
siblingPhi0->node()=root_;
}
else if (z==z->parent()->nodeLeft())
{
z->parent()->leafLeft() = siblingPhi0;
z->parent()->nodeLeft() = NULL;
siblingPhi0->node() = z->parent();
}
else if (z == z->parent()->nodeRight())
{
z->parent()->leafRight() = siblingPhi0;
z->parent()->nodeRight() = NULL;
siblingPhi0->node() = z->parent();
}
else
{
FatalErrorInFunction
<< "wrong addressing of the initial leaf"
<< exit(FatalError);
}
}
else
{
x = nodeSibling(phi0);
if (x !=NULL)
{
transplant(z, x);
}
else
{
FatalErrorInFunction
<< "inconsistent structure of the tree, no leaf and no node"
<< exit(FatalError);
}
}
deleteDemandDrivenData(phi0);
deleteDemandDrivenData(z);
}
size_--;
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::balance()
{
scalarField mean(chemistry_.nEqns(),0.0);
//1) walk through the entire tree by starting with the tree's most left
// chemPoint
chP* x=treeMin();
List<chP*> chemPoints(size_);
label chPi=0;
//2) compute the mean composition
while(x!=NULL)
{
const scalarField& phij = x->phi();
mean += phij;
chemPoints[chPi++] = x;
x=treeSuccessor(x);
}
mean /= size_;
//3) compute the variance for each space direction
List<scalar> variance(chemistry_.nEqns(),0.0);
forAll(chemPoints, j)
{
const scalarField& phij = chemPoints[j]->phi();
forAll(variance, vi)
{
variance[vi] += sqr(phij[vi]-mean[vi]);
}
}
//4) analyze what is the direction of the maximal variance
scalar maxVariance(-1.0);
label maxDir(-1);
forAll(variance, vi)
{
if (maxVariance < variance[vi])
{
maxVariance = variance[vi];
maxDir = vi;
}
}
// maxDir indicates the direction of maximum variance
// we create the new root node by taking the two extreme points
// in this direction if these extreme points were not deleted in the
// cleaning that come before the balance function they are still important
// and the tree should therefore take them into account
SortableList<scalar> phiMaxDir(chemPoints.size(),0.0);
forAll(chemPoints, j)
{
phiMaxDir[j] = chemPoints[j]->phi()[maxDir];
}
phiMaxDir.sort();
// delete reference to all node since the tree is reshaped
deleteAllNode();
root_=NULL;
// add the node for the two extremum
bn* newNode = new bn
(
chemPoints[phiMaxDir.indices()[0]],
chemPoints[phiMaxDir.indices()[phiMaxDir.size()-1]],
NULL
);
root_ = newNode;
chemPoints[phiMaxDir.indices()[0]]->node() = newNode;
chemPoints[phiMaxDir.indices()[phiMaxDir.size()-1]]->node() = newNode;
for (label cpi=1; cpi<chemPoints.size()-1; cpi++)
{
chP* phi0;
binaryTreeSearch
(
chemPoints[phiMaxDir.indices()[cpi]]->phi(),
root_,
phi0
);
// add the chemPoint
bn* nodeToAdd =
new bn(phi0,chemPoints[phiMaxDir.indices()[cpi]], phi0->node());
// make the parent of phi0 point to the newly created node
insertNode(phi0, nodeToAdd);
phi0->node()=nodeToAdd;
chemPoints[phiMaxDir.indices()[cpi]]->node()=nodeToAdd;
}
}
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::treeMin(bn* subTreeRoot)
{
if (subTreeRoot!=NULL)
{
while(subTreeRoot->nodeLeft() != NULL)
{
subTreeRoot = subTreeRoot->nodeLeft();
}
return subTreeRoot->leafLeft();
}
else
{
return NULL;
}
}
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>*
Foam::binaryTree<CompType, ThermoType>::treeSuccessor(chP* x)
{
if (size_>1)
{
if (x == x->node()->leafLeft())
{
if (x->node()->nodeRight() == NULL)
{
return x->node()->leafRight();
}
else
{
return treeMin(x->node()->nodeRight());
}
}
else if (x == x->node()->leafRight())
{
bn* y = x->node();
while((y->parent() !=NULL))
{
if (y == y->parent()->nodeLeft())
{
if (y->parent()->nodeRight() == NULL)
{
return y->parent()->leafRight();
}
else
{
return treeMin(y->parent()->nodeRight());
}
}
y=y->parent();
}
// when we reach this point, y points to the root and
// never entered in the if loop (coming from the right)
// so we are at the tree maximum and there is no successor
return NULL;
}
else
{
FatalErrorInFunction
<< "inconsistent structure of the tree, no leaf and no node"
<< exit(FatalError);
return NULL;
}
}
return NULL;
}
template<class CompType, class ThermoType>
void Foam::binaryTree<CompType, ThermoType>::clear()
{
// recursively delete the element in the subTree
deleteSubTree();
// reset root node (should already be NULL)
root_=NULL;
// reset size_
size_=0;
}
template<class CompType, class ThermoType>
bool Foam::binaryTree<CompType, ThermoType>::isFull()
{
return size_ >= maxNLeafs_;
}
// ************************************************************************* //

View File

@ -0,0 +1,250 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::binaryTree
Description
Data storage of the chemistryOnLineLibrary according to a binary
tree structure.
0 (root node)
/ \
0 0
/ \ / \
L R L 0
/ \
L R
L: leafLeft_
R: leafRight_
\*---------------------------------------------------------------------------*/
#ifndef binaryTree_H
#define binaryTree_H
#include "binaryNode.H"
#include "chemPointISAT.H"
namespace Foam
{
template<class CompType, class ThermoType>
class TDACChemistryModel;
template<class CompType, class ThermoType>
class binaryTree
{
public:
typedef binaryNode<CompType, ThermoType> bn;
typedef chemPointISAT<CompType, ThermoType> chP;
private:
//- Reference to the chemistryModel
TDACChemistryModel<CompType, ThermoType>& chemistry_;
//- Root node of the binary tree
bn *root_;
//- Maximum number of elements in the binary tree
label maxNLeafs_;
//- Size of the BST (= number of chemPoint stored)
label size_;
//- Secondary retrieve search variables
label n2ndSearch_;
label max2ndSearch_;
//- Insert new node at the position of phi0
// phi0 should be already attached to another node or the pointer to it
// will be lost
void insertNode
(
chP*& phi0,
bn*& newNode
);
//- Perform a search in the subtree starting from the subtree node y
// This search continue to use the hyperplan to walk the tree
// If covering EOA is found return true and x points to the chemPoint
bool inSubTree
(
const scalarField& phiq,
bn* y,
chP* x
);
void deleteSubTree(binaryNode<CompType, ThermoType>* subTreeRoot);
inline void deleteSubTree()
{
deleteSubTree(root_);
}
//- Replace the binaryNode u with v
void transplant(bn* u, bn* v);
chP* chemPSibling(bn* y);
chP* chemPSibling(chP* x);
bn* nodeSibling(bn* y);
bn* nodeSibling(chP* x);
void deleteAllNode(bn* subTreeRoot);
dictionary coeffsDict_;
public:
//- Constructors
//- Construct from dictionary and chemistryOnLineLibrary
binaryTree
(
TDACChemistryModel<CompType, ThermoType>& chemistry,
dictionary coeffsDict
);
//- Member functions
inline label size()
{
return size_;
}
//- Computes iteratively the depth of the subTree
label depth(bn* subTreeRoot);
inline label depth()
{
return depth(root_);
}
inline bn* root()
{
return root_;
}
inline label maxNLeafs()
{
return maxNLeafs_;
}
// Insert a new leaf starting from the parent node of phi0
// Parameters: phi0 the leaf to replace by a node
// phiq the new composition to store
// Rphiq the mapping of the new composition point
// A the mapping gradient matrix
// B the matrix used to initialize the EOA
// nCols the size of the matrix
// Returns: void
// Description :
//1) Create a new leaf with the data to initialize the EOA and to
// retrieve the mapping by linear interpolation (the EOA is
// initialize in the chemPoint constructor)
//2) Get the parent node of phi0 and connect a new node in place of the
// leaf of phi0. This new node is constructed with phi0 on the left
// and phiq on the right (the hyperplane is computed inside the
// binaryNode constructor)
void insertNewLeaf
(
const scalarField& phiq,
const scalarField& Rphiq,
const scalarSquareMatrix& A,
const scalarField& scaleFactor,
const scalar& epsTol,
const label nCols,
chP*& phi0
);
// Search the binaryTree until the nearest leaf of a specified
// leaf is found.
void binaryTreeSearch
(
const scalarField& phiq,
bn* node,
chP*& nearest
);
// Perform a secondary binary tree search starting from a failed
// chemPoint x, with a depth-first search algorithm
// If another candidate is found return true and x points to the chemP
bool secondaryBTSearch(const scalarField& phiq, chP*& x);
//- Delete a leaf from the binary tree and reshape the binary tree for
// the following binary tree search
// Return the index in the nodeList of the removed node
// (-1 when no node)
void deleteLeaf(chP*& phi0);
//- Cheap balance function
// This function just roughly separate the space in two parts
// with a hyperplane which separate the two extreme chemPoint in the
// direction of the maximum the variance
// Then, it repopulate the tree with this hyperplane stored at the root
// and by inserting the chemPoint in increasing order of value in that
// direction
void balance();
inline void deleteAllNode()
{
deleteAllNode(root_);
}
chP* treeMin(bn* subTreeRoot);
inline chP* treeMin()
{
return treeMin(root_);
}
chP* treeSuccessor(chP* x);
//- Removes every entries of the tree and delete the associated objects
void clear();
//- ListFull
bool isFull();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "binaryTree.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,985 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "chemPointISAT.H"
#include <limits>
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
// Defined as static to be able to dynamicly change it during simulations
// (all chemPoints refer to the same object)
template<class CompType, class ThermoType>
Foam::scalar Foam::chemPointISAT<CompType, ThermoType>::tolerance_;
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class CompType, class ThermoType>
void Foam::chemPointISAT<CompType, ThermoType>::qrDecompose
(
const label nCols,
scalarSquareMatrix& R
)
{
scalarField c(nCols);
scalarField d(nCols);
scalar scale, sigma, sum;
for (label k=0; k<nCols-1; k++)
{
scale = 0.0;
for (label i=k; i<nCols; i++)
{
scale=max(scale, fabs(R(i, k)));
}
if (scale == 0.0)
{
c[k] = d[k] = 0.0;
}
else
{
for (label i=k; i<nCols; i++)
{
R(i, k) /= scale;
}
sum = 0.0;
for (label i=k; i<nCols; i++)
{
sum += sqr(R(i, k));
}
sigma = sign(R(k, k))*sqrt(sum);
R(k, k) += sigma;
c[k] = sigma*R(k, k);
d[k] = -scale*sigma;
for (label j=k+1; j<nCols; j++)
{
sum=0.0;
for ( label i=k; i<nCols; i++)
{
sum += R(i, k)*R(i, j);
}
scalar tau = sum/c[k];
for ( label i=k; i<nCols; i++)
{
R(i, j) -= tau*R(i, k);
}
}
}
}
d[nCols-1] = R(nCols-1, nCols-1);
// form R
for (label i=0; i<nCols; i++)
{
R(i, i) = d[i];
for ( label j=0; j<i; j++)
{
R(i, j)=0.0;
}
}
}
template<class CompType, class ThermoType>
void Foam::chemPointISAT<CompType, ThermoType>::qrUpdate
(
scalarSquareMatrix& R,
const label n,
const Foam::scalarField &u,
const Foam::scalarField &v
)
{
label k, i;
scalarField w(u);
for (k=n-1;k>=0;k--)
{
if (w[k] != 0.0)
{
break;
}
}
if (k < 0)
{
k=0;
}
for (i=k-1;i>=0;i--)
{
rotate(R, i, w[i],-w[i+1], n);
if (w[i] == 0.0)
{
w[i] = fabs(w[i+1]);
}
else if (fabs(w[i]) > fabs(w[i+1]))
{
w[i] = fabs(w[i])*sqrt(1.0+sqr(w[i+1]/w[i]));
}
else
{
w[i] = fabs(w[i+1])*sqrt(1.0+sqr(w[i]/w[i+1]));
}
}
for (i=0;i<n;i++)
{
R(0, i) += w[0]*v[i];
}
for (i=0;i<k;i++)
{
rotate(R, i, R(i, i),-R(i+1, i), n);
}
}
template<class CompType, class ThermoType>
void Foam::chemPointISAT<CompType, ThermoType>::rotate
(
scalarSquareMatrix& R,
const label i,
const scalar a,
const scalar b,
label n
)
{
label j;
scalar c, fact, s, w, y;
if (a == 0.0)
{
c=0.0;
s=(b >= 0.0 ? 1.0 : -1.0);
}
else if (fabs(a) > fabs(b))
{
fact = b/a;
c=sign(a)/sqrt(1.0+(fact*fact));
s=fact*c;
}
else
{
fact=a/b;
s=sign(b)/sqrt(1.0+(fact*fact));
c=fact*s;
}
for (j=i;j<n;j++)
{
y=R(i, j);
w=R(i+1, j);
R(i, j)=c*y-s*w;
R(i+1, j)=s*y+c*w;
}
}
template<class CompType, class ThermoType>
void Foam::chemPointISAT<CompType, ThermoType>::svd
(
scalarSquareMatrix& A,
label m,
label n,
scalarDiagonalMatrix& d,
scalarSquareMatrix& V
)
{
// UPDATED VERSION NR3
bool flag;
label i, its, j, jj, k, l, nm;
scalar anorm, c, f, g, h, s, scale, x, y, z;
scalarField rv1(n);
scalar eps = std::numeric_limits<scalar>::epsilon();
g = scale = anorm = 0.0;
// Householder reduction to bidiagonal form
for ( i = 0; i<n; i++)
{
l=i+2; // change from i+1 to i+2
rv1[i] = scale*g;
g=s=scale=0.0;
if (i < m)
{
for (k=i;k<m;k++)
{
scale += fabs(A(k, i));
}
if (scale != 0.0)
{
for ( k=i;k<m;k++)
{
A(k, i) /= scale;
s += A(k, i)*A(k, i);
}
f = A(i, i);
g = -sign(f)*sqrt(s);
h = f*g-s;
A(i, i)=f-g;
for (j=l-1;j<n;j++)
{
for (s=0.0,k=i;k<m;k++)
{
s += A(k, i)*A(k, j);
}
f = s/h;
for (k=i; k<m;k++)
{
A(k, j) += f*A(k, i);
}
}
for (k=i; k<m;k++)
{
A(k, i) *= scale;
}
}
}
d[i] = scale * g;
g=s=scale=0.0;
if (i+1 <= m && i+1 != n)
{
for (k=l-1; k<n; k++)
{
scale += fabs(A(i, k));
}
if (scale != 0.0)
{
for (k=l-1; k<n; k++)
{
A(i, k) /= scale;
s += A(i, k)*A(i, k);
}
f = A(i, l-1);
g = -sign(f)*sqrt(s);
h = f*g-s;
A(i, l-1) = f-g;
for (k=l-1; k<n; k++)
{
rv1[k] = A(i, k)/h;
}
for (j=l-1; j<m; j++)
{
for (s=0.0,k=l-1; k<n; k++)
{
s += A(j, k)*A(i, k);
}
for (k=l-1; k<n; k++)
{
A(j, k) += s*rv1[k];
}
}
for (k=l-1; k<n; k++)
{
A(i, k) *= scale;
}
}
}
anorm = max(anorm, (fabs(d[i])+fabs(rv1[i])));
}
// Accumulation of right-hand transformations
for (i=n-1; i>=0; i--)
{
if (i < n-1)
{
if (g != 0.0)
{
for (j=l; j<n; j++)
{
V(j, i) = (A(i, j)/A(i, l))/g;
}
for (j=l; j<n; j++)
{
for (s=0.0,k=l; k<n; k++)
{
s += A(i, k)*V(k, j);
}
for (k=l; k<n; k++)
{
V(k, j) += s*V(k, i);
}
}
}
for (j=l; j<n; j++)
{
V(i, j)=V(j, i)=0.0;
}
}
V(i, i) = 1.0;
g = rv1[i];
l = i;
}
// Accumulation of left-hand transformations
for (i = min(m, n)-1; i>=0; i--)
{
l=i+1;
g=d[i];
for (j=l; j<n; j++)
{
A(i, j) = 0.0;
}
if (g != 0.0)
{
g = 1.0/g;
for (j=l; j<n; j++)
{
for (s=0.0, k=l; k<m; k++)
{
s+= A(k, i)*A(k, j);
}
f = (s/A(i, i))*g;
for (k=i; k<m; k++)
{
A(k, j) += f*A(k, i);
}
}
for (j=i; j<m; j++)
{
A(j, i) *= g;
}
}
else
{
for (j=i; j<m; j++)
{
A(j, i)=0.0;
}
}
++A(i, i);
}
// Diagonalization of the bidiagonal form :
// Loop over singular values, and over allowed iteration
for (k=n-1; k>=0; k--)
{
for (its=0; its<30; its++)
{
flag=true;
// Test for splitting (rv1[1] always zero)
for (l=k; l>=0; l--)
{
nm = l-1;
if (l == 0 || fabs(rv1[l]) <= eps*anorm)
{
flag = false;
break;
}
if (fabs(d[nm]) <= eps*anorm)
{
break;
}
}
// Cancellation of rv1[l], if l>1
if (flag)
{
c = 0.0;
s = 1.0;
for (i=l; i<k+1; i++)
{
f = s*rv1[i];
rv1[i] = c*rv1[i];
if (fabs(f) <= eps*anorm)
{
break;
}
g = d[i];
h = pythag(f, g);
d[i] = h;
h = 1.0/h;
c = g*h;
s = -f*h;
for (j=0; j<m; j++)
{
y = A(j, nm);
z = A(j, i);
A(j, nm) = y*c + z*s;
A(j, i) = z*c - y*s;
}
}
}
z = d[k];
if (l == k) // Convergence
{
if (z < 0.0) // Singular value is made nonnegative
{
d[k] = -z;
for (j=0; j<n; j++)
{
V(j, k) = -V(j, k);
}
}
break;
}
if (its == 34)
{
WarningInFunction
<< "no convergence in 35 SVD iterations"
<< endl;
}
x = d[l];
nm = k-1;
y = d[nm];
g = rv1[nm];
h = rv1[k];
f = ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
g = pythag(f,1.0);
f = ((x-z)*(x+z)+h*((y/(f+sign(f)*g))-h))/x;
c=s=1.0;
// Next QR transformation
for (j=l; j<=nm; j++)
{
i = j+1;
g = rv1[i];
y = d[i];
h = s*g;
g = c*g;
z = pythag(f, h);
rv1[j] = z;
c = f/z;
s = h/z;
f = x*c + g*s;
g = g*c - x*s;
h = y*s;
y *= c;
for (jj=0; jj<n; jj++)
{
x = V(jj, j);
z = V(jj, i);
V(jj, j) = x*c + z*s;
V(jj, i) = z*c - x*s;
}
z = pythag(f, h);
d[j] = z;
if (z)
{
z = 1.0/z;
c = f*z;
s = h*z;
}
f = c*g + s*y;
x = c*y - s*g;
for (jj=0; jj<m; jj++)
{
y = A(jj, j);
z = A(jj, i);
A(jj, j) = y*c + z*s;
A(jj, i) = z*c - y*s;
}
}
rv1[l] = 0.0;
rv1[k] = f;
d[k] = x;
}
}
}
// pythag function used in svd
// compute (a^2+b^2)^1/2 without descrutive underflow or overflow
template<class CompType, class ThermoType>
Foam::scalar
Foam::chemPointISAT<CompType, ThermoType>::pythag(scalar a, scalar b)
{
scalar absa, absb;
absa = fabs(a);
absb = fabs(b);
if (absa > absb)
{
return absa*sqrt(1.0+sqr(absb/absa));
}
else
{
return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+sqr(absa/absb)));
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>::chemPointISAT
(
TDACChemistryModel<CompType, ThermoType>& chemistry,
const scalarField& phi,
const scalarField& Rphi,
const scalarSquareMatrix& A,
const scalarField& scaleFactor,
const scalar& tolerance,
const label& completeSpaceSize,
const dictionary& coeffsDict,
binaryNode<CompType, ThermoType>* node
)
:
chemistry_(chemistry),
phi_(phi),
Rphi_(Rphi),
A_(A),
scaleFactor_(scaleFactor),
node_(node),
completeSpaceSize_(completeSpaceSize),
nGrowth_(0),
nActiveSpecies_(chemistry.mechRed()->NsSimp()),
completeToSimplifiedIndex_(completeSpaceSize-2),
simplifiedToCompleteIndex_(nActiveSpecies_),
timeTag_(chemistry_.time().timeOutputValue()),
lastTimeUsed_(chemistry_.time().timeOutputValue()),
toRemove_(false),
maxNumNewDim_(coeffsDict.lookupOrDefault("maxNumNewDim",0)),
printProportion_(coeffsDict.lookupOrDefault("printProportion",false))
{
tolerance_=tolerance;
bool isMechRedActive = chemistry_.mechRed()->active();
if (isMechRedActive)
{
for (label i=0; i<completeSpaceSize-2; i++)
{
completeToSimplifiedIndex_[i] =
chemistry.completeToSimplifiedIndex()[i];
}
for (label i=0; i<nActiveSpecies_; i++)
{
simplifiedToCompleteIndex_[i] =
chemistry.simplifiedToCompleteIndex()[i];
}
}
label reduOrCompDim = completeSpaceSize;
if (isMechRedActive)
{
reduOrCompDim = nActiveSpecies_+2;
}
// SVD decomposition A= U*D*V^T
scalarSquareMatrix Atmp(A);// A computed in ISAT.C
scalarSquareMatrix B(reduOrCompDim, Zero);
DiagonalMatrix<scalar> diag(reduOrCompDim, Zero);
svd(Atmp, reduOrCompDim, reduOrCompDim, diag, B);
// replace the value of vector diag by max(diag, 1/2), first ISAT paper,
// Pope
for (label i=0; i<reduOrCompDim; i++)
{
diag[i] = max(diag[i], 0.5);
}
// rebuild A with max length, tol and scale factor before QR decomposition
scalarSquareMatrix Atilde(reduOrCompDim, reduOrCompDim);
// result stored in Atilde
multiply(Atilde, Atmp, diag, B.T());
for (label i=0; i<reduOrCompDim; i++)// on species loop
{
for (label j=0; j<reduOrCompDim; j++)// species, T and p loop
{
label compi=i;
if (isMechRedActive)
{
compi = simplifiedToCompleteIndex(i);
}
// SF*A/tolerance
// (where SF is diagonal with inverse of scale factors)
// SF*A is the same as dividing each line by the scale factor
// corresponding to the species of this line
Atilde(i, j) /= (tolerance*scaleFactor[compi]);
}
}
// The object LT_ (the transpose of the Q) describe the EOA, since we have
// A^T B^T B A that should be factorized into L Q^T Q L^T and is set in the
// qrDecompose function
LT_ = scalarSquareMatrix(Atilde);
qrDecompose(reduOrCompDim, LT_);
}
template<class CompType, class ThermoType>
Foam::chemPointISAT<CompType, ThermoType>::chemPointISAT
(
Foam::chemPointISAT<CompType, ThermoType>& p
)
:
chemistry_(p.chemistry()),
phi_(p.phi()),
Rphi_(p.Rphi()),
LT_(p.LT()),
A_(p.A()),
scaleFactor_(p.scaleFactor()),
node_(p.node()),
completeSpaceSize_(p.completeSpaceSize()),
nGrowth_(p.nGrowth()),
nActiveSpecies_(p.nActiveSpecies()),
completeToSimplifiedIndex_(p.completeToSimplifiedIndex()),
simplifiedToCompleteIndex_(p.simplifiedToCompleteIndex()),
timeTag_(p.timeTag()),
lastTimeUsed_(p.lastTimeUsed()),
toRemove_(p.toRemove()),
maxNumNewDim_(p.maxNumNewDim())
{
tolerance_ = p.tolerance();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
bool Foam::chemPointISAT<CompType, ThermoType>::inEOA(const scalarField& phiq)
{
scalarField dphi(phiq-phi());
bool isMechRedActive = chemistry_.mechRed()->active();
label dim = (isMechRedActive) ? nActiveSpecies_ : completeSpaceSize()-2;
scalar epsTemp=0.0;
List<scalar> propEps(completeSpaceSize(),0.0);
for (label i=0; i<completeSpaceSize()-2; i++)
{
scalar temp(0.0);
// When mechanism reduction is inactive OR on active species multiply L
// by dphi to get the distance in the active species direction else (for
// inactive species), just multiply the diagonal element and dphi
if
(
!(isMechRedActive)
||(isMechRedActive && completeToSimplifiedIndex_[i]!=-1)
)
{
label si=(isMechRedActive) ? completeToSimplifiedIndex_[i] : i;
for (label j=si; j<dim; j++)// LT is upper triangular
{
label sj=(isMechRedActive) ? simplifiedToCompleteIndex_[j] : j;
temp += LT_(si, j)*dphi[sj];
}
temp += LT_(si, nActiveSpecies_)*dphi[completeSpaceSize()-2];
temp += LT_(si, nActiveSpecies_+1)*dphi[completeSpaceSize()-1];
}
else
{
temp = dphi[i]/(tolerance_*scaleFactor_[i]);
}
epsTemp += sqr(temp);
if (printProportion_)
{
propEps[i] = temp;
}
}
// Temperature
epsTemp +=
sqr
(
LT_(dim, dim)*dphi[completeSpaceSize()-2]
+LT_(dim, dim+1)*dphi[completeSpaceSize()-1]
);
// Pressure
epsTemp += sqr(LT_(dim+1, dim+1)*dphi[completeSpaceSize()-1]);
if (printProportion_)
{
propEps[completeSpaceSize()-2] =
sqr
(
LT_(dim, dim)*dphi[completeSpaceSize()-2]
+ LT_(dim, dim+1)*dphi[completeSpaceSize()-1]
);
propEps[completeSpaceSize()-1] =
sqr(LT_(dim+1, dim+1)*dphi[completeSpaceSize()-1]);
}
if (sqrt(epsTemp) > 1.0+tolerance_)
{
if (printProportion_)
{
scalar max=-1.0;
label maxIndex=-1;
for (label i=0; i<completeSpaceSize(); i++)
{
if(max < propEps[i])
{
max = propEps[i];
maxIndex = i;
}
}
word propName;
if (maxIndex >= completeSpaceSize()-2)
{
if(maxIndex == completeSpaceSize()-2)
{
propName = "T";
}
else if(maxIndex == completeSpaceSize()-1)
{
propName = "p";
}
}
else
{
propName = chemistry_.Y()[maxIndex].name();
}
Info<< "Direction maximum impact to error in ellipsoid: "
<< propName << endl;
Info<< "Proportion to the total error on the retrieve: "
<< max / (epsTemp+SMALL) << endl;
}
return false;
}
else
{
return true;
}
}
template<class CompType, class ThermoType>
bool Foam::chemPointISAT<CompType, ThermoType>::checkSolution
(
const scalarField& phiq,
const scalarField& Rphiq
)
{
scalar eps2 = 0.0;
scalarField dR(Rphiq - Rphi());
scalarField dphi(phiq - phi());
const scalarField& scaleFactorV(scaleFactor());
const scalarSquareMatrix& Avar(A());
bool isMechRedActive = chemistry_.mechRed()->active();
scalar dRl = 0.0;
label dim = completeSpaceSize()-2;
if (isMechRedActive)
{
dim = nActiveSpecies_;
}
// Since we build only the solution for the species, T and p are not
// included
for (label i=0; i<completeSpaceSize()-2; i++)
{
dRl = 0.0;
if (isMechRedActive)
{
label si = completeToSimplifiedIndex_[i];
// If this species is active
if (si!=-1)
{
for (label j=0; j<dim; j++)
{
label sj=simplifiedToCompleteIndex_[j];
dRl += Avar(si, j)*dphi[sj];
}
dRl += Avar(si, nActiveSpecies_)*dphi[completeSpaceSize()-2];
dRl += Avar(si, nActiveSpecies_+1)*dphi[completeSpaceSize()-1];
}
else
{
dRl = dphi[i];
}
}
else
{
for (label j=0; j<completeSpaceSize(); j++)
{
dRl += Avar(i, j)*dphi[j];
}
}
eps2 += sqr((dR[i]-dRl)/scaleFactorV[i]);
}
eps2 = sqrt(eps2);
if (eps2 > tolerance())
{
return false;
}
else
{
// if the solution is in the ellipsoid of accuracy
return true;
}
}
template<class CompType, class ThermoType>
bool Foam::chemPointISAT<CompType, ThermoType>::grow(const scalarField& phiq)
{
scalarField dphi(phiq - phi());
label dim = completeSpaceSize();
label initNActiveSpecies(nActiveSpecies_);
bool isMechRedActive = chemistry_.mechRed()->active();
if (isMechRedActive)
{
label activeAdded(0);
DynamicList<label> dimToAdd(0);
// check if the difference of active species is lower than the maximum
// number of new dimensions allowed
for (label i=0; i<completeSpaceSize()-2; i++)
{
// first test if the current chemPoint has an inactive species
// corresponding to an active one in the query point
if
(
completeToSimplifiedIndex_[i] == -1
&& chemistry_.completeToSimplifiedIndex()[i]!=-1
)
{
activeAdded++;
dimToAdd.append(i);
}
// then test if an active species in the current chemPoint
// corresponds to an inactive on the query side
if
(
completeToSimplifiedIndex_[i]!=-1
&& chemistry_.completeToSimplifiedIndex()[i] == -1
)
{
activeAdded++;
// we don't need to add a new dimension but we count it to have
// control on the difference through maxNumNewDim
}
// finally test if both points have inactive species but
// with a dphi!=0
if
(
completeToSimplifiedIndex_[i] == -1
&& chemistry_.completeToSimplifiedIndex()[i] == -1
&& dphi[i] != 0.0
)
{
activeAdded++;
dimToAdd.append(i);
}
}
// if the number of added dimension is too large, growth fail
if (activeAdded > maxNumNewDim_)
{
return false;
}
// the number of added dimension to the current chemPoint
nActiveSpecies_ += dimToAdd.size();
simplifiedToCompleteIndex_.setSize(nActiveSpecies_);
forAll(dimToAdd, i)
{
label si = nActiveSpecies_ - dimToAdd.size() + i;
// add the new active species
simplifiedToCompleteIndex_[si] = dimToAdd[i];
completeToSimplifiedIndex_[dimToAdd[i]] = si;
}
// update LT and A :
//-add new column and line for the new active species
//-transfer last two lines of the previous matrix (p and T) to the end
// (change the diagonal position)
//-set all element of the new lines and columns to zero except diagonal
// (=1/(tolerance*scaleFactor))
if (nActiveSpecies_ > initNActiveSpecies)
{
scalarSquareMatrix LTvar = LT_; // take a copy of LT_
scalarSquareMatrix Avar = A_; // take a copy of A_
LT_ = scalarSquareMatrix(nActiveSpecies_+2, Zero);
A_ = scalarSquareMatrix(nActiveSpecies_+2, Zero);
// write the initial active species
for (label i=0; i<initNActiveSpecies; i++)
{
for (label j=0; j<initNActiveSpecies; j++)
{
LT_(i, j) = LTvar(i, j);
A_(i, j) = Avar(i, j);
}
}
// write the columns for temperature and pressure
for (label i=0; i<initNActiveSpecies; i++)
{
for (label j=1; j>=0; j--)
{
LT_(i, nActiveSpecies_+j)=LTvar(i, initNActiveSpecies+j);
A_(i, nActiveSpecies_+j)=Avar(i, initNActiveSpecies+j);
LT_(nActiveSpecies_+j, i)=LTvar(initNActiveSpecies+j, i);
A_(nActiveSpecies_+j, i)=Avar(initNActiveSpecies+j, i);
}
}
// end with the diagonal elements for temperature and pressure
LT_(nActiveSpecies_, nActiveSpecies_)=
LTvar(initNActiveSpecies, initNActiveSpecies);
A_(nActiveSpecies_, nActiveSpecies_)=
Avar(initNActiveSpecies, initNActiveSpecies);
LT_(nActiveSpecies_+1, nActiveSpecies_+1)=
LTvar(initNActiveSpecies+1, initNActiveSpecies+1);
A_(nActiveSpecies_+1, nActiveSpecies_+1)=
Avar(initNActiveSpecies+1, initNActiveSpecies+1);
for (label i=initNActiveSpecies; i<nActiveSpecies_;i++)
{
LT_(i, i)=
1.0
/ (tolerance_*scaleFactor_[simplifiedToCompleteIndex_[i]]);
A_(i, i)=1.0;
}
}
dim = nActiveSpecies_+2;
}
// beginning of grow algorithm
scalarField phiTilde(dim, 0.0);
scalar normPhiTilde = 0.0;
// p' = L^T.(p-phi)
for (label i=0; i<dim; i++)
{
for (label j=i; j<dim-2; j++)// LT is upper triangular
{
label sj = j;
if (isMechRedActive)
{
sj=simplifiedToCompleteIndex_[j];
}
phiTilde[i] += LT_(i, j)*dphi[sj];
}
phiTilde[i] += LT_(i, dim-2)*dphi[completeSpaceSize()-2];
phiTilde[i] += LT_(i, dim-1)*dphi[completeSpaceSize()-1];
normPhiTilde += sqr(phiTilde[i]);
}
scalar invSqrNormPhiTilde = 1.0/normPhiTilde;
normPhiTilde = sqrt(normPhiTilde);
// gamma = (1/|p'| - 1)/|p'|^2
scalar gamma = (1/normPhiTilde - 1)*invSqrNormPhiTilde;
scalarField u(gamma*phiTilde);
scalarField v(dim,0.0);
for ( label i=0; i<dim; i++)
{
for (register label j=0; j<=i;j++)
{
v[i] += phiTilde[j]*LT_(j, i);
}
}
qrUpdate(LT_,dim, u, v);
nGrowth_++;
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,460 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemPointISAT
Description
Leaf of the binary tree.
The chemPoint stores the composition 'phi', the mapping of this
composition Rphi, the mapping gradient matrix A and the matrix describing
the Ellipsoid Of Accuracy (EOA).
1)When the chemPoint is created the region of accuracy is approximated by
an ellipsoid E centered in 'phi' (obtained with the constant):
E = {x| ||L^T.(x-phi)|| <= 1},
with x a point in the composition space and L^T the transpose of an upper
triangular matrix describing the EOA (see below: "Computation of L" ).
2)To RETRIEVE the mapping from the chemPoint phi, the query point phiq has to
be in the EOA of phi. It follows that, dphi=phiq-phi and to test if phiq
is in the ellipsoid there are two methods. First, compare r=||dphi|| with
rmin and rmax. If r < rmin, phiq is in the EOA. If r > rmax, phiq is out of
the EOA. This operations is O(completeSpaceSize) and is performed first.
If rmin < r < rmax, then the second method is used:
||L^T.dphi|| <= 1 to be in the EOA.
If phiq is in the EOA, Rphiq is obtained by linear interpolation:
Rphiq= Rphi + A.dphi.
3)If phiq is not in the EOA, then the mapping is computed. But as the EOA
is a conservative approximation of the region of accuracy surrounding the
point phi, we could expand it by comparing the computed results with the
one obtained by linear interpolation. The error epsGrow is calculated:
epsGrow = ||B.(dR - dRl)||,
with dR = Rphiq - Rphi, dRl = A.dphi and B the diagonal scale factor
matrix.
If epsGrow <= tolerance, the EOA is too conservative and a GROW is perforned
otherwise, the newly computed mapping is associated to the initial
composition and added to the tree.
4)To GROW the EOA, we expand it to include the previous EOA and the query
point phiq. The rank-one matrix method is used. The EOA is transformed
to a hypersphere centered at the origin. Then it is expanded to include
the transformed point phiq' on its boundary. Then the inverse transformation
give the modified matrix L' (see below: "Grow the EOA").
Computation of L :
In [1], the EOA of the constant approximation is given by
E = {x| ||B.A/tolerance.(x-phi)|| <= 1},
with B a scale factor diagonal matrix, A the mapping gradient matrix and
tolerance the absolute tolerance. If we take the QR decomposition of
(B.A)/tolerance= Q.R, with Q an orthogonal matrix and R an upper triangular
matrix such that the EOA is described by
(phiq-phi0)^T.R^T.R.(phiq-phi0) <= 1
L^T = R, both Cholesky decomposition of A^T.B^T.B.A/tolerance^2
This representation of the ellipsoid is used in [2] and in order to avoid
large value of semi-axe length in certain direction, a Singular Value
Decomposition (SVD) is performed on the L matrix:
L = UDV^T,
with the orthogonal matrix U giving the directions of the principal axes
and 1/di the inverse of the element of the diagonal matrix D giving the
length of the principal semi-axes. To avoid very large value of those
length,
di' = max(di, 1/(alphaEOA*sqrt(tolerance))), with alphaEOA = 0.1 (see [2])
di' = max(di, 1/2), see [1]. The latter will be used in this implementation.
And L' = UD'V^T, with D' the diagonal matrix with the modified di'.
Grow the EOA :
More details about the minimum-volume ellipsoid covering an ellispoid E and
a point p are found in [3]. Here is the main steps to obtain the modified
matrix L' describind the new ellipsoid.
1) calculate the point p' in the transformed space :
p' = L^T.(p-phi)
2) compute the rank-one decomposition:
G = I + gamma.p'.p'^T,
with gamma = (1/|p'|-1)*1/|p'|^2
3) compute L':
L' = L.G.
References:
\verbatim
[1] Pope, S. B. (1997).
Computationally efficient implementation of combustion chemistry using
in situ adaptive tabulation.
Combustion Theory and Modelling, 1, 41-63.
[2] Lu, L., & Pope, S. B. (2009).
An improved algorithm for in situ adaptive tabulation.
Journal of Computational Physics, 228(2), 361-386.
[3] Pope, S. B. (2008).
Algorithms for ellipsoids.
Cornell University Report No. FDA, 08-01.
\endverbatim
\*---------------------------------------------------------------------------*/
#ifndef chemPointISAT_H
#define chemPointISAT_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
class binaryNode;
template<class CompType, class ThermoType>
class TDACChemistryModel;
/*---------------------------------------------------------------------------*\
Class chemPointISAT Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class chemPointISAT
{
// Private data
//- Pointer to the chemistryModel object
TDACChemistryModel<CompType, ThermoType>& chemistry_;
//- Vector storing the composition, temperature and pressure
scalarField phi_;
//- Vector storing the mapping of the composition phi
scalarField Rphi_;
//- LT the transpose of the L matrix describing the Ellipsoid Of
// Accuracy use List of Lists to be able to change size if DAC is used
scalarSquareMatrix LT_;
//- A the mapping gradient matrix
scalarSquareMatrix A_;
//- Vector storing the scale factor
scalarField scaleFactor_;
//- Reference to the node in the binary tree holding this chemPoint
binaryNode<CompType, ThermoType>* node_;
//- The size of the composition space (size of the vector phi)
label completeSpaceSize_;
//- Number of times the element has been grown
label nGrowth_;
//- Tolerance for the Ellipsoid of accuracy
static scalar tolerance_;
//- Number of active species stored in the chemPoint
label nActiveSpecies_;
// Vectors that store the index conversion between the simplified
// and the complete chemical mechanism
List<label> completeToSimplifiedIndex_;
List<label> simplifiedToCompleteIndex_;
scalar timeTag_;
scalar lastTimeUsed_;
bool toRemove_;
label maxNumNewDim_;
Switch printProportion_;
//- QR decomposition of a matrix
// Input : nCols cols number
// R the matrix to decompose
// QT an empty matrix that stores the transpose of the Q matrix
// R is returned in the given R matrix
// which is used to store the ellipsoid of accuracy
void qrDecompose
(
const label nCols,
scalarSquareMatrix& R
);
//- QR update of the matrix A
void qrUpdate
(
scalarSquareMatrix& R,
const label n,
const scalarField &u,
const scalarField &v
);
void rotate
(
scalarSquareMatrix& R,
const label i,
const scalar a,
const scalar b,
label n
);
//- Singular Value Decomposition (SVD) for a square matrix
// needed to compute the the length of the hyperellipsoid semi-axes
// SVD decompose a matrix A into:
// A = U * D * V^T ,
// with the singular value in the diagonal matrix D and U and V
// orthogonal A (scalarMatrix) the square matrix to apply the
// decomposition on m (label) the number of line of the matrix A
// n (label) the size of the matrix A
// Output: U (scalarMatrix) replace A
// V (scalarMatrix) not the transpose V^T
// d (scalarField) the diagonal element of matrix D
void svd
(
scalarSquareMatrix& A,
label m,
label n,
scalarDiagonalMatrix& d,
scalarSquareMatrix& V
);
//- Function used in svd function
scalar pythag(scalar a, scalar b);
public:
// Constructors
//- Construct from components
chemPointISAT
(
TDACChemistryModel<CompType, ThermoType>& chemistry,
const scalarField& phi,
const scalarField& Rphi,
const scalarSquareMatrix& A,
const scalarField& scaleFactor,
const scalar& tolerance,
const label& completeSpaceSize,
const dictionary& coeffsDict,
binaryNode<CompType, ThermoType>* node = NULL
);
//- Construct from another chemPoint and reference to a binary node
chemPointISAT
(
const chemPointISAT<CompType, ThermoType>& p,
binaryNode<CompType, ThermoType>* node
);
//- Construct from another chemPoint
chemPointISAT
(
chemPointISAT<CompType, ThermoType>& p
);
// Member functions
//- Access to the TDACChemistryModel
inline TDACChemistryModel<CompType, ThermoType>& chemistry()
{
return chemistry_;
}
inline label nGrowth()
{
return nGrowth_;
}
inline label& completeSpaceSize()
{
return completeSpaceSize_;
}
inline const scalarField& phi() const
{
return phi_;
}
inline const scalarField& Rphi() const
{
return Rphi_;
}
inline const scalarField& scaleFactor()
{
return scaleFactor_;
}
inline const scalar& tolerance()
{
return tolerance_;
}
static void changeTolerance(scalar newTol)
{
tolerance_ = newTol;
}
inline binaryNode<CompType, ThermoType>*& node()
{
return node_;
}
inline const scalarSquareMatrix& A() const
{
return A_;
}
inline scalarSquareMatrix& A()
{
return A_;
}
inline const scalarSquareMatrix& LT() const
{
return LT_;
}
inline scalarSquareMatrix& LT()
{
return LT_;
}
inline label nActiveSpecies()
{
return nActiveSpecies_;
}
inline List<label>& completeToSimplifiedIndex()
{
return completeToSimplifiedIndex_;
}
inline List<label>& simplifiedToCompleteIndex()
{
return simplifiedToCompleteIndex_;
}
inline label simplifiedToCompleteIndex(label i)
{
if (i < nActiveSpecies_)
{
return simplifiedToCompleteIndex_[i];
}
else if (i == nActiveSpecies_)
{
return completeSpaceSize_-2;
}
else if (i == nActiveSpecies_+1)
{
return completeSpaceSize_-1;
}
else
{
return -1;
}
}
inline const scalar& timeTag()
{
return timeTag_;
}
inline scalar& lastTimeUsed()
{
return lastTimeUsed_;
}
inline bool& toRemove()
{
return toRemove_;
}
inline label& maxNumNewDim()
{
return maxNumNewDim_;
}
// ISAT functions
//- To RETRIEVE the mapping from the stored chemPoint phi, the query
// point phiq has to be in the EOA of phi.
// To test if phiq is in the ellipsoid:
// ||L^T.dphi|| <= 1
bool inEOA(const scalarField& phiq);
//- More details about the minimum-volume ellipsoid covering an
// ellispoid E and a point p are found in [1].
// Here is the main steps to obtain the
// modified matrix L' describind the new ellipsoid.
// 1) calculate the point p' in the transformed space :
// p' = L^T.(p-phi)
// 2) compute the rank-one decomposition:
// G = I + gamma.p'.p'^T,
// with gamma = (1/|p'|-1)*1/|p'|^2
// 3) compute L':
// L'L'^T = (L.G)(L.G)^T,
// L'^T is then obtained by QR decomposition of (L.G)^T = G^T.L^T
// [1] Stephen B. Pope, "Algorithms for ellipsoids", FDA 08-01,
// Cornell University, 2008
bool grow(const scalarField& phiq);
//- If phiq is not in the EOA, then the mapping is computed.
// But as the EOA is a conservative approximation of the region of
// accuracy surrounding the point phi, we could expand it by
// comparing thecomputed results with the one obtained by linear
// interpolation. The error eps is calculated:
// eps = ||B.(dR - dRl)||,
// with dR = Rphiq - Rphi, dRl = A.dphi and B the diagonal scale
// factor matrix.
// If eps <= tolerance, the EOA is too conservative and a GROW is
// performed,
// otherwise, the newly computed mapping is associated to the
// initial composition and added to the tree.
bool checkSolution
(
const scalarField& phiq,
const scalarField& Rphiq
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "chemPointISAT.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,55 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "chemistryTabulationMethod.H"
#include "TDACChemistryModel.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethod<CompType, ThermoType>::chemistryTabulationMethod
(
const dictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
dict_(dict),
coeffsDict_(dict.subDict("tabulation")),
active_(coeffsDict_.lookupOrDefault<Switch>("active", false)),
log_(coeffsDict_.lookupOrDefault<Switch>("log", false)),
chemistry_(chemistry),
tolerance_(coeffsDict_.lookupOrDefault<scalar>("tolerance", 1e-4))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethod<CompType, ThermoType>::
~chemistryTabulationMethod()
{}
// ************************************************************************* //

View File

@ -0,0 +1,184 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryTabulationMethod
Description
An abstract class for chemistry tabulation.
SourceFiles
chemistryTabulationMethod.C
\*---------------------------------------------------------------------------*/
#ifndef chemistryTabulationMethod_H
#define chemistryTabulationMethod_H
#include "IOdictionary.H"
#include "scalarField.H"
#include "Switch.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
class TDACChemistryModel;
/*---------------------------------------------------------------------------*\
Class chemistryTabulationMethod Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class chemistryTabulationMethod
{
protected:
const dictionary& dict_;
const dictionary coeffsDict_;
//- Is tabulation active?
Switch active_;
//- Switch to select performance logging
Switch log_;
TDACChemistryModel<CompType, ThermoType>& chemistry_;
scalar tolerance_;
public:
//- Runtime type information
TypeName("chemistryTabulationMethod");
// Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
chemistryTabulationMethod,
dictionary,
(
const dictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
),
(dict, chemistry)
);
// Constructors
//- Construct from components
chemistryTabulationMethod
(
const dictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
// Selectors
static autoPtr<chemistryTabulationMethod> New
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
//- Destructor
virtual ~chemistryTabulationMethod();
// Member Functions
inline bool active()
{
return active_;
}
inline bool log()
{
return active_ && log_;
}
inline scalar tolerance() const
{
return tolerance_;
}
virtual label size() = 0;
virtual void writePerformance() = 0;
// Retrieve function: (only virtual here)
// Try to retrieve a stored point close enough (according to tolerance)
// to a stored point. If successful, it returns true and store the
// results in RphiQ, i.e. the result of the integration of phiQ
virtual bool retrieve
(
const scalarField& phiQ,
scalarField& RphiQ
) = 0;
// Add function: (only virtual here)
// Add information to the tabulation algorithm. Give the reference for
// future retrieve (phiQ) and the corresponding result (RphiQ).
virtual bool add
(
const scalarField& phiQ,
const scalarField& RphiQ,
const scalar rho
) = 0;
// Update function: (only virtual here)
// The underlying structure of the tabulation is updated/cleaned
// to increase the performance of the retrieve
virtual bool update() = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "chemistryTabulationMethod.C"
#include "chemistryTabulationMethodNew.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "chemistryTabulationMethod.H"
#include "Time.H"
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::autoPtr<Foam::chemistryTabulationMethod<CompType, ThermoType>>
Foam::chemistryTabulationMethod<CompType, ThermoType>::New
(
const IOdictionary& dict,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
{
IOdictionary thermoDict
(
IOobject
(
"thermophysicalProperties",
dict.db().time().constant(),
dict.db(),
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE,
false
)
);
word thermoTypeName;
if (thermoDict.isDict("thermoType"))
{
const dictionary& thermoTypeDict(thermoDict.subDict("thermoType"));
thermoTypeName =
word(thermoTypeDict.lookup("transport")) + '<'
+ word(thermoTypeDict.lookup("thermo")) + '<'
+ word(thermoTypeDict.lookup("equationOfState")) + '<'
+ word(thermoTypeDict.lookup("specie")) + ">>,"
+ word(thermoTypeDict.lookup("energy")) + ">";
}
else
{
FatalIOErrorInFunction(thermoDict)
<< "thermoType is in the old format and must be upgraded"
<< exit(FatalIOError);
}
dictionary tabdict(dict.subDict("tabulation"));
word chemistryTabulationMethodName =
word(tabdict.lookup("method")) + '<'
+ word(dict.subDict("chemistryType").lookup("chemistryThermo")) + ','
+ thermoTypeName + '>';
typename dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(chemistryTabulationMethodName);
if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorInFunction
<< "Unknown chemistryTabulationMethodType type "
<< chemistryTabulationMethodName
<< endl << endl
<< "Valid chemistryTabulationMethodType types are :" << endl
<< dictionaryConstructorTablePtr_->toc()
<< exit(FatalError);
}
return autoPtr<chemistryTabulationMethod<CompType, ThermoType>>
(
cstrIter()(dict, chemistry)
);
}
// ************************************************************************* //

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "makeChemistryTabulationMethods.H"
#include "thermoPhysicsTypes.H"
#include "psiChemistryModel.H"
#include "rhoChemistryModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Chemistry solvers based on sensibleEnthalpy
makeChemistryTabulationMethods(psiChemistryModel, constGasHThermoPhysics);
makeChemistryTabulationMethods(psiChemistryModel, gasHThermoPhysics);
makeChemistryTabulationMethods
(
psiChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryTabulationMethods
(
psiChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryTabulationMethods(psiChemistryModel, icoPoly8HThermoPhysics);
makeChemistryTabulationMethods(rhoChemistryModel, constGasHThermoPhysics);
makeChemistryTabulationMethods(rhoChemistryModel, gasHThermoPhysics);
makeChemistryTabulationMethods
(
rhoChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryTabulationMethods
(
rhoChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryTabulationMethods(rhoChemistryModel, icoPoly8HThermoPhysics);
// Chemistry solvers based on sensibleInternalEnergy
makeChemistryTabulationMethods(psiChemistryModel, constGasEThermoPhysics);
makeChemistryTabulationMethods(psiChemistryModel, gasEThermoPhysics);
makeChemistryTabulationMethods
(
psiChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryTabulationMethods
(
psiChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryTabulationMethods(psiChemistryModel, icoPoly8EThermoPhysics);
makeChemistryTabulationMethods(rhoChemistryModel, constGasEThermoPhysics);
makeChemistryTabulationMethods(rhoChemistryModel, gasEThermoPhysics);
makeChemistryTabulationMethods
(
rhoChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryTabulationMethods
(
rhoChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryTabulationMethods(rhoChemistryModel, icoPoly8EThermoPhysics);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,89 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef makeChemistryTabulationMethods_H
#define makeChemistryTabulationMethods_H
#include "chemistryTabulationMethod.H"
#include "noChemistryTabulation.H"
#include "ISAT.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#define makeChemistryTabulationMethod(SS, Comp, Thermo) \
\
typedef chemistryTabulationMethods::SS<Comp, Thermo> SS##Comp##Thermo; \
\
defineTemplateTypeNameAndDebugWithName \
( \
SS##Comp##Thermo, \
(#SS"<" + word(Comp::typeName_()) \
+ "," + Thermo::typeName() + ">").c_str(), \
0 \
); \
\
chemistryTabulationMethod<Comp, Thermo>:: \
adddictionaryConstructorToTable<SS##Comp##Thermo> \
add##chemistryTabulationMethods##SS##Comp##Thermo##ConstructorToTable_;
#define makeChemistryTabulationMethods(CompChemModel, Thermo) \
\
typedef chemistryTabulationMethod<CompChemModel, Thermo> \
chemistryTabulationMethod##CompChemModel##Thermo; \
\
defineTemplateTypeNameAndDebugWithName \
( \
chemistryTabulationMethod##CompChemModel##Thermo, \
"chemistryTabulationMethod<"#CompChemModel","#Thermo">", \
0 \
); \
\
defineTemplateRunTimeSelectionTable \
( \
chemistryTabulationMethod##CompChemModel##Thermo, \
dictionary \
); \
\
makeChemistryTabulationMethod \
( \
none, \
CompChemModel, \
Thermo \
); \
\
makeChemistryTabulationMethod \
( \
ISAT, \
CompChemModel, \
Thermo \
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "noChemistryTabulation.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethods::none<CompType, ThermoType>::none
(
const dictionary& chemistryProperties,
TDACChemistryModel<CompType, ThermoType>& chemistry
)
:
chemistryTabulationMethod<CompType, ThermoType>
(
chemistryProperties,
chemistry
)
{
this->active_ = false;
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::chemistryTabulationMethods::none<CompType, ThermoType>::~none()
{}
// ************************************************************************* //

View File

@ -0,0 +1,141 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::chemistryTabulationMethods::none
Description
\*---------------------------------------------------------------------------*/
#ifndef chemistryTabulationMethod_none_H
#define chemistryTabulationMethod_none_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "chemistryTabulationMethod.H"
namespace Foam
{
namespace chemistryTabulationMethods
{
/*---------------------------------------------------------------------------*\
Class none Declaration
\*---------------------------------------------------------------------------*/
template<class CompType, class ThermoType>
class none
:
public chemistryTabulationMethod<CompType, ThermoType>
{
// Private Member Functions
//- Disallow default bitwise copy construct
none(const none&);
public:
//- Runtime type information
TypeName("none");
// Constructors
//- Construct from dictionary
none
(
const dictionary& chemistryProperties,
TDACChemistryModel<CompType, ThermoType>& chemistry
);
// Destructor
virtual ~none();
// Member Functions
//- Return the size of the binary tree
virtual label size()
{
NotImplemented;
return 0;
}
virtual void writePerformance()
{
NotImplemented;
}
//- Find the closest stored leaf of phiQ and store the result in
// RphiQ or return false.
virtual bool retrieve
(
const Foam::scalarField& phiq,
scalarField& Rphiq
)
{
NotImplemented;
return false;
}
// Add information to the tabulation.This function can grow an
// existing point or add a new leaf to the binary tree Input : phiq
// the new composition to store Rphiq the mapping of the new
// composition point
virtual bool add
(
const scalarField& phiq,
const scalarField& Rphiq,
const scalar rho
)
{
NotImplemented;
return false;
}
virtual bool update()
{
NotImplemented;
return false;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace chemistryTabulationMethods
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "noChemistryTabulation.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012-2015 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2012-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -103,11 +103,25 @@ Foam::autoPtr<ChemistryModel> Foam::basicChemistryModel::New
<< exit(FatalIOError);
}
Switch isTDAC(chemistryTypeDict.lookupOrDefault("TDAC", false));
// Construct the name of the chemistry type from the components
if (isTDAC)
{
chemistryTypeName =
word(chemistryTypeDict.lookup("chemistrySolver")) + '<'
+ "TDACChemistryModel<"
+ word(chemistryTypeDict.lookup("chemistryThermo")) + ','
+ thermoTypeName + ">";
+ thermoTypeName + ">>";
}
else
{
chemistryTypeName =
word(chemistryTypeDict.lookup("chemistrySolver")) + '<'
+ "chemistryModel<"
+ word(chemistryTypeDict.lookup("chemistryThermo")) + ','
+ thermoTypeName + ">>";
}
typename ChemistryModel::fvMeshConstructorTable::iterator cstrIter =
ChemistryModel::fvMeshConstructorTablePtr_->find(chemistryTypeName);

View File

@ -53,7 +53,9 @@ Foam::chemistryModel<CompType, ThermoType>::chemistryModel
nSpecie_(Y_.size()),
nReaction_(reactions_.size()),
Treact_(CompType::template lookupOrDefault<scalar>("Treact", 0.0)),
RR_(nSpecie_)
RR_(nSpecie_),
c_(nSpecie_),
dcdt_(nSpecie_)
{
// create the fields for the chemistry sources
forAll(RR_, fieldi)
@ -92,19 +94,18 @@ Foam::chemistryModel<CompType, ThermoType>::~chemistryModel()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CompType, class ThermoType>
Foam::tmp<Foam::scalarField>
Foam::chemistryModel<CompType, ThermoType>::omega
void Foam::chemistryModel<CompType, ThermoType>::omega
(
const scalarField& c,
const scalar T,
const scalar p
const scalar p,
scalarField& dcdt
) const
{
scalar pf, cf, pr, cr;
label lRef, rRef;
tmp<scalarField> tom(new scalarField(nEqns(), 0.0));
scalarField& om = tom.ref();
dcdt = Zero;
forAll(reactions_, i)
{
@ -119,18 +120,16 @@ Foam::chemistryModel<CompType, ThermoType>::omega
{
const label si = R.lhs()[s].index;
const scalar sl = R.lhs()[s].stoichCoeff;
om[si] -= sl*omegai;
dcdt[si] -= sl*omegai;
}
forAll(R.rhs(), s)
{
const label si = R.rhs()[s].index;
const scalar sr = R.rhs()[s].stoichCoeff;
om[si] += sr*omegai;
dcdt[si] += sr*omegai;
}
}
return tom;
}
@ -171,14 +170,8 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::omega
label& rRef
) const
{
scalarField c2(nSpecie_, 0.0);
for (label i = 0; i < nSpecie_; i++)
{
c2[i] = max(0.0, c[i]);
}
const scalar kf = R.kf(p, T, c2);
const scalar kr = R.kr(kf, p, T, c2);
const scalar kf = R.kf(p, T, c);
const scalar kr = R.kr(kf, p, T, c);
pf = 1.0;
pr = 1.0;
@ -278,14 +271,19 @@ template<class CompType, class ThermoType>
void Foam::chemistryModel<CompType, ThermoType>::derivatives
(
const scalar time,
const scalarField &c,
const scalarField& c,
scalarField& dcdt
) const
{
const scalar T = c[nSpecie_];
const scalar p = c[nSpecie_ + 1];
dcdt = omega(c, T, p);
for (label i = 0; i < nSpecie_; i++)
{
c_[i] = max(0.0, c[i]);
}
omega(c_, T, p, dcdt);
// constant pressure
// dT/dt = ...
@ -294,13 +292,13 @@ void Foam::chemistryModel<CompType, ThermoType>::derivatives
for (label i = 0; i < nSpecie_; i++)
{
const scalar W = specieThermo_[i].W();
cSum += c[i];
rho += W*c[i];
cSum += c_[i];
rho += W*c_[i];
}
scalar cp = 0.0;
for (label i=0; i<nSpecie_; i++)
{
cp += c[i]*specieThermo_[i].cp(p, T);
cp += c_[i]*specieThermo_[i].cp(p, T);
}
cp /= rho;
@ -331,29 +329,22 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
const scalar T = c[nSpecie_];
const scalar p = c[nSpecie_ + 1];
scalarField c2(nSpecie_, 0.0);
forAll(c2, i)
forAll(c_, i)
{
c2[i] = max(c[i], 0.0);
c_[i] = max(c[i], 0.0);
}
for (label i=0; i<nEqns(); i++)
{
for (label j=0; j<nEqns(); j++)
{
dfdc(i, j) = 0.0;
}
}
dfdc = Zero;
// Length of the first argument must be nSpecie()
dcdt = omega(c2, T, p);
// Length of the first argument must be nSpecie_
omega(c_, T, p, dcdt);
forAll(reactions_, ri)
{
const Reaction<ThermoType>& R = reactions_[ri];
const scalar kf0 = R.kf(p, T, c2);
const scalar kr0 = R.kr(kf0, p, T, c2);
const scalar kf0 = R.kf(p, T, c_);
const scalar kr0 = R.kr(kf0, p, T, c_);
forAll(R.lhs(), j)
{
@ -367,9 +358,9 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
{
if (el < 1.0)
{
if (c2[si] > SMALL)
if (c_[si] > SMALL)
{
kf *= el*pow(c2[si] + VSMALL, el - 1.0);
kf *= el*pow(c_[si] + VSMALL, el - 1.0);
}
else
{
@ -378,12 +369,12 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
}
else
{
kf *= el*pow(c2[si], el - 1.0);
kf *= el*pow(c_[si], el - 1.0);
}
}
else
{
kf *= pow(c2[si], el);
kf *= pow(c_[si], el);
}
}
@ -391,13 +382,13 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
{
const label si = R.lhs()[i].index;
const scalar sl = R.lhs()[i].stoichCoeff;
dfdc[si][sj] -= sl*kf;
dfdc(si, sj) -= sl*kf;
}
forAll(R.rhs(), i)
{
const label si = R.rhs()[i].index;
const scalar sr = R.rhs()[i].stoichCoeff;
dfdc[si][sj] += sr*kf;
dfdc(si, sj) += sr*kf;
}
}
@ -413,9 +404,9 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
{
if (er < 1.0)
{
if (c2[si] > SMALL)
if (c_[si] > SMALL)
{
kr *= er*pow(c2[si] + VSMALL, er - 1.0);
kr *= er*pow(c_[si] + VSMALL, er - 1.0);
}
else
{
@ -424,12 +415,12 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
}
else
{
kr *= er*pow(c2[si], er - 1.0);
kr *= er*pow(c_[si], er - 1.0);
}
}
else
{
kr *= pow(c2[si], er);
kr *= pow(c_[si], er);
}
}
@ -437,26 +428,34 @@ void Foam::chemistryModel<CompType, ThermoType>::jacobian
{
const label si = R.lhs()[i].index;
const scalar sl = R.lhs()[i].stoichCoeff;
dfdc[si][sj] += sl*kr;
dfdc(si, sj) += sl*kr;
}
forAll(R.rhs(), i)
{
const label si = R.rhs()[i].index;
const scalar sr = R.rhs()[i].stoichCoeff;
dfdc[si][sj] -= sr*kr;
dfdc(si, sj) -= sr*kr;
}
}
}
// Calculate the dcdT elements numerically
const scalar delta = 1.0e-3;
const scalarField dcdT0(omega(c2, T - delta, p));
const scalarField dcdT1(omega(c2, T + delta, p));
for (label i = 0; i < nEqns(); i++)
omega(c_, T + delta, p, dcdt_);
for (label i=0; i<nSpecie_; i++)
{
dfdc[i][nSpecie()] = 0.5*(dcdT1[i] - dcdT0[i])/delta;
dfdc(i, nSpecie_) = dcdt_[i];
}
omega(c_, T - delta, p, dcdt_);
for (label i=0; i<nSpecie_; i++)
{
dfdc(i, nSpecie_) = 0.5*(dfdc(i, nSpecie_) - dcdt_[i])/delta;
}
dfdc(nSpecie_, nSpecie_) = 0;
dfdc(nSpecie_ + 1, nSpecie_) = 0;
}
@ -513,21 +512,20 @@ Foam::chemistryModel<CompType, ThermoType>::tc() const
scalar rhoi = rho[celli];
scalar Ti = T[celli];
scalar pi = p[celli];
scalarField c(nSpecie_);
scalar cSum = 0.0;
for (label i=0; i<nSpecie_; i++)
{
scalar Yi = Y_[i][celli];
c[i] = rhoi*Yi/specieThermo_[i].W();
cSum += c[i];
c_[i] = rhoi*Yi/specieThermo_[i].W();
cSum += c_[i];
}
forAll(reactions_, i)
{
const Reaction<ThermoType>& R = reactions_[i];
omega(R, c, Ti, pi, pf, cf, lRef, pr, cr, rRef);
omega(R, c_, Ti, pi, pf, cf, lRef, pr, cr, rRef);
forAll(R.rhs(), s)
{
@ -679,17 +677,16 @@ Foam::chemistryModel<CompType, ThermoType>::calculateRR
const scalar Ti = T[celli];
const scalar pi = p[celli];
scalarField c(nSpecie_, 0.0);
for (label i=0; i<nSpecie_; i++)
{
const scalar Yi = Y_[i][celli];
c[i] = rhoi*Yi/specieThermo_[i].W();
c_[i] = rhoi*Yi/specieThermo_[i].W();
}
const scalar w = omegaI
(
reactionI,
c,
c_,
Ti,
pi,
pf,
@ -739,18 +736,17 @@ void Foam::chemistryModel<CompType, ThermoType>::calculate()
const scalar Ti = T[celli];
const scalar pi = p[celli];
scalarField c(nSpecie_, 0.0);
for (label i=0; i<nSpecie_; i++)
{
const scalar Yi = Y_[i][celli];
c[i] = rhoi*Yi/specieThermo_[i].W();
c_[i] = rhoi*Yi/specieThermo_[i].W();
}
const scalarField dcdt(omega(c, Ti, pi));
omega(c_, Ti, pi, dcdt_);
for (label i=0; i<nSpecie_; i++)
{
RR_[i][celli] = dcdt[i]*specieThermo_[i].W();
RR_[i][celli] = dcdt_[i]*specieThermo_[i].W();
}
}
}
@ -789,7 +785,6 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::solve
const scalarField& T = this->thermo().T();
const scalarField& p = this->thermo().p();
scalarField c(nSpecie_);
scalarField c0(nSpecie_);
forAll(rho, celli)
@ -803,8 +798,8 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::solve
for (label i=0; i<nSpecie_; i++)
{
c[i] = rhoi*Y_[i][celli]/specieThermo_[i].W();
c0[i] = c[i];
c_[i] = rhoi*Y_[i][celli]/specieThermo_[i].W();
c0[i] = c_[i];
}
// Initialise time progress
@ -814,7 +809,7 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::solve
while (timeLeft > SMALL)
{
scalar dt = timeLeft;
this->solve(c, Ti, pi, dt, this->deltaTChem_[celli]);
this->solve(c_, Ti, pi, dt, this->deltaTChem_[celli]);
timeLeft -= dt;
}
@ -823,7 +818,7 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::solve
for (label i=0; i<nSpecie_; i++)
{
RR_[i][celli] =
(c[i] - c0[i])*specieThermo_[i].W()/deltaT[celli];
(c_[i] - c0[i])*specieThermo_[i].W()/deltaT[celli];
}
}
else
@ -864,18 +859,4 @@ Foam::scalar Foam::chemistryModel<CompType, ThermoType>::solve
}
template<class CompType, class ThermoType>
void Foam::chemistryModel<CompType, ThermoType>::solve
(
scalarField &c,
scalar& T,
scalar& p,
scalar& deltaT,
scalar& subDeltaT
) const
{
NotImplemented;
}
// ************************************************************************* //

View File

@ -64,23 +64,23 @@ class chemistryModel
{
// Private Member Functions
//- Solve the reaction system for the given time step
// of given type and return the characteristic time
template<class DeltaTType>
scalar solve(const DeltaTType& deltaT);
//- Disallow copy constructor
chemistryModel(const chemistryModel&);
//- Disallow default bitwise assignment
void operator=(const chemistryModel&);
//- Solve the reaction system for the given time step
// of given type and return the characteristic time
template<class DeltaTType>
scalar solve(const DeltaTType& deltaT);
protected:
typedef ThermoType thermoType;
// Private data
// Protected data
//- Reference to the field of specie mass fractions
PtrList<volScalarField>& Y_;
@ -103,6 +103,12 @@ protected:
//- List of reaction rate per specie [kg/m3/s]
PtrList<DimensionedField<scalar, volMesh>> RR_;
//- Temporary concentration field
mutable scalarField c_;
//- Temporary rate-of-change of concentration field
mutable scalarField dcdt_;
// Protected Member Functions
@ -148,11 +154,12 @@ public:
inline scalar& Treact();
//- dc/dt = omega, rate of change in concentration, for each species
virtual tmp<scalarField> omega
virtual void omega
(
const scalarField& c,
const scalar T,
const scalar p
const scalar p,
scalarField& dcdt
) const;
//- Return the reaction rate for reaction r and the reference
@ -259,7 +266,7 @@ public:
scalar& p,
scalar& deltaT,
scalar& subDeltaT
) const;
) const = 0;
};

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -33,6 +33,7 @@ Description
#include "psiChemistryModel.H"
#include "chemistryModel.H"
#include "TDACChemistryModel.H"
#include "thermoPhysicsTypes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -75,6 +76,43 @@ namespace Foam
icoPoly8HThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
constGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
gasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
icoPoly8HThermoPhysics
);
// Chemistry moldels based on sensibleInternalEnergy
makeChemistryModel
(
@ -110,6 +148,42 @@ namespace Foam
psiChemistryModel,
icoPoly8EThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
constGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
gasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
psiChemistryModel,
icoPoly8EThermoPhysics
);
}
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -33,6 +33,7 @@ Description
#include "rhoChemistryModel.H"
#include "chemistryModel.H"
#include "TDACChemistryModel.H"
#include "thermoPhysicsTypes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -76,6 +77,42 @@ namespace Foam
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
constGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
gasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
constIncompressibleGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
incompressibleGasHThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
icoPoly8HThermoPhysics
);
// Chemistry moldels based on sensibleInternalEnergy
makeChemistryModel
(
@ -111,6 +148,42 @@ namespace Foam
rhoChemistryModel,
icoPoly8EThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
constGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
gasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
constIncompressibleGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
incompressibleGasEThermoPhysics
);
makeChemistryModel
(
TDACChemistryModel,
rhoChemistryModel,
icoPoly8EThermoPhysics
);
}
// ************************************************************************* //

View File

@ -29,6 +29,7 @@ License
#include "chemistrySolver.H"
#include "chemistryModel.H"
#include "TDACChemistryModel.H"
#include "noChemistrySolver.H"
#include "EulerImplicit.H"
@ -38,13 +39,14 @@ License
#define makeChemistrySolverType(SS, Comp, Thermo) \
\
typedef SS<chemistryModel<Comp, Thermo>> SS##Comp##Thermo; \
typedef SS<chemistryModel<Comp, Thermo> > SS##Comp##Thermo; \
typedef SS<TDACChemistryModel<Comp, Thermo> > TDAC##SS##Comp##Thermo; \
\
defineTemplateTypeNameAndDebugWithName \
( \
SS##Comp##Thermo, \
(#SS"<" + word(Comp::typeName_()) \
+ "," + Thermo::typeName() + ">").c_str(), \
(#SS"<chemistryModel<" + word(Comp::typeName_()) \
+ "," + Thermo::typeName() + ">>").c_str(), \
0 \
); \
\
@ -53,6 +55,21 @@ License
Comp, \
SS##Comp##Thermo, \
fvMesh \
); \
\
defineTemplateTypeNameAndDebugWithName \
( \
TDAC##SS##Comp##Thermo, \
(#SS"<TDACChemistryModel<" + word(Comp::typeName_()) \
+ "," + Thermo::typeName() + ">>").c_str(), \
0 \
); \
\
addToRunTimeSelectionTable \
( \
Comp, \
TDAC##SS##Comp##Thermo, \
fvMesh \
);

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -32,7 +32,6 @@ namespace Foam
defineTypeNameAndDebug(basicMultiComponentMixture, 0);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::basicMultiComponentMixture::basicMultiComponentMixture
@ -44,46 +43,28 @@ Foam::basicMultiComponentMixture::basicMultiComponentMixture
)
:
species_(specieNames),
active_(species_.size(), true),
Y_(species_.size())
{
forAll(species_, i)
{
IOobject header
(
IOobject::groupName(species_[i], phaseName),
mesh.time().timeName(),
mesh,
IOobject::NO_READ
);
word YdefaultName(IOobject::groupName("Ydefault", phaseName));
// Check if field exists and can be read
if (header.headerOk())
{
Y_.set
(
i,
new volScalarField
(
IOobject
(
IOobject::groupName(species_[i], phaseName),
mesh.time().timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
)
);
}
else
{
volScalarField Ydefault
(
IOobject
(
"Ydefault",
mesh.time().timeName(),
YdefaultName,
exists(mesh.time().path()/mesh.time().timeName()/YdefaultName)
? mesh.time().timeName()
: (
exists
(
mesh.time().path()/mesh.time().constant()/YdefaultName
)
? mesh.time().constant()
: Time::timeName(0)
),
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE
@ -101,14 +82,13 @@ Foam::basicMultiComponentMixture::basicMultiComponentMixture
IOobject::groupName(species_[i], phaseName),
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
Ydefault
)
);
}
}
// Do not enforce constraint of sum of mass fractions to equal 1 here
// - not applicable to all models

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -62,6 +62,9 @@ protected:
//- Table of specie names
speciesTable species_;
//- List of specie active flags
List<bool> active_;
//- Species mass fractions
PtrList<volScalarField> Y_;
@ -98,6 +101,21 @@ public:
//- Return the table of species
inline const speciesTable& species() const;
//- Does the mixture include this specie?
inline bool contains(const word& specieName) const;
//- Return true for active species
inline bool active(label speciei) const;
//- Return the bool list of active species
inline const List<bool>& active() const;
//- Set speciei active
inline void setActive(label speciei);
//- Set speciei inactive
inline void setInactive(label speciei);
//- Return the mass-fraction fields
inline PtrList<volScalarField>& Y();
@ -115,9 +133,6 @@ public:
//- Return the const mass-fraction field for a specie given by name
inline const volScalarField& Y(const word& specieName) const;
//- Does the mixture include this specie?
inline bool contains(const word& specieName) const;
};

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -30,6 +30,39 @@ Foam::basicMultiComponentMixture::species() const
}
inline bool Foam::basicMultiComponentMixture::contains
(
const word& specieName
) const
{
return species_.contains(specieName);
}
inline bool Foam::basicMultiComponentMixture::active(label speciei) const
{
return active_[speciei];
}
inline const Foam::List<bool>& Foam::basicMultiComponentMixture::active() const
{
return active_;
}
inline void Foam::basicMultiComponentMixture::setActive(label speciei)
{
active_[speciei] = true;
}
inline void Foam::basicMultiComponentMixture::setInactive(label speciei)
{
active_[speciei] = false;
}
inline Foam::PtrList<Foam::volScalarField>&
Foam::basicMultiComponentMixture::Y()
{
@ -77,13 +110,4 @@ inline const Foam::volScalarField& Foam::basicMultiComponentMixture::Y
}
inline bool Foam::basicMultiComponentMixture::contains
(
const word& specieName
) const
{
return species_.contains(specieName);
}
// ************************************************************************* //

View File

@ -52,6 +52,10 @@ Foam::reactingMixture<ThermoType>::reactingMixture
PtrList<Reaction<ThermoType>>
(
autoPtr<chemistryReader<ThermoType>>::operator()().reactions()
),
speciesComposition_
(
autoPtr<chemistryReader<ThermoType>>::operator()().specieComposition()
)
{
autoPtr<chemistryReader<ThermoType>>::clear();

View File

@ -56,6 +56,12 @@ class reactingMixture
public multiComponentMixture<ThermoType>,
public PtrList<Reaction<ThermoType>>
{
// Private member data
//- Table of species composition
speciesCompositionTable speciesComposition_;
// Private Member Functions
//- Disallow default bitwise copy construct
@ -92,15 +98,21 @@ public:
return PtrList<Reaction<ThermoType>>::size();
}
Reaction<ThermoType>& operator [] (const label i)
Reaction<ThermoType>& operator[](const label i)
{
return PtrList<Reaction<ThermoType>>::operator[](i);
}
const Reaction<ThermoType>& operator [] (const label i) const
const Reaction<ThermoType>& operator[](const label i) const
{
return PtrList<Reaction<ThermoType>>::operator[](i);
}
//- Table of species composition
const speciesCompositionTable& specieComposition() const
{
return speciesComposition_;
}
};

View File

@ -0,0 +1,11 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Source tutorial run functions
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
cleanCase
rm -rf 0 chemFoam.out validation/OF_vs_CHEMKINII.eps validation/chemkinII
#------------------------------------------------------------------------------

View File

@ -0,0 +1,14 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Source tutorial run functions
. $WM_PROJECT_DIR/bin/tools/RunFunctions
# Set application name
application=`getApplication`
runApplication $application
(cd validation && ./Allrun $*)
#------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
!SENS
CONP
PRES 50.00 ! atm
TEMP 800.0 ! K
TIME 1.E-2 ! sec
DELT 1.E-6 ! sec
REAC IC8H18 0.08
REAC O2 1.0
REAC N2 3.76
END
! c8h18 + x o2 -> 8 co2 + 9 h2o
! -> 9 + 16 = 25 -> 12.5
! 1/12.5 = 0.08

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "chemkin";
object transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
".*"
{
transport
{
As 0;
Ts 0;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,75 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object chemistryProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
chemistryType
{
chemistrySolver ode;
chemistryThermo psi;
TDAC on;
}
chemistry on;
initialChemicalTimeStep 1e-7;
odeCoeffs
{
solver seulex;
absTol 1e-12;
relTol 1e-1;
}
reduction
{
active on;
// Switch logging of the reduction statistics and performance
log off;
// Tolerance depends on the reduction method, see details for each method
tolerance 1e-4;
// Available methods: DRG, DAC, DRGEP, PFA, EFA
method DAC;
// Search initiating set (SIS) of species, needed for most methods
initialSet
{
CO;
IC8H18;
HO2;
}
// For DAC, option to automatically change the SIS switch from HO2 to H2O
// and CO to CO2, + disable fuel
automaticSIS off;
// When automaticSIS, the method needs to know the fuel
fuelSpecies
{
IC8H18 1;
}
}
// Tabulation is not effective for single-cell ignition calculations
tabulation
{
method none;
}
// ************************************************************************* //

View File

@ -0,0 +1,34 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object initialConditions;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
constantProperty pressure;
fractionBasis mole;
fractions
{
IC8H18 0.08;
N2 3.76;
O2 1;
}
p 5.06625e+06;
T 800;
// ************************************************************************* //

View File

@ -0,0 +1,33 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object thermophysicalProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
thermoType
{
type hePsiThermo;
mixture reactingMixture;
transport sutherland;
thermo janaf;
energy sensibleEnthalpy;
equationOfState perfectGas;
specie specie;
}
CHEMKINFile "$FOAM_CASE/chemkin/chem.inp";
CHEMKINThermoFile "$FOAM_CASE/chemkin/therm.dat";
CHEMKINTransportFile "$FOAM_CASE/chemkin/transportProperties";
// ************************************************************************* //

View File

@ -0,0 +1,55 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application chemFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.01;
deltaT 1e-07;
maxDeltaT 1e-05;
adjustTimeStep on;
writeControl adjustableRunTime;
writeInterval 5e-4;
purgeWrite 0;
writeFormat ascii;
writeCompression uncompressed;
timeFormat general;
timePrecision 6;
runTimeModifiable yes;
DebugSwitches
{
SolverPerformance 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,32 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
ddtSchemes
{
default Euler;
}
gradSchemes
{}
divSchemes
{}
laplacianSchemes
{}
// ************************************************************************* //

View File

@ -0,0 +1,30 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
Yi
{
solver PBiCG;
preconditioner DILU;
tolerance 1e-12;
relTol 0;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,14 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Extract Chemkin II data into a friendlier format
echo "# Time [s] Temperature [K]" > chemkinII
grep '^ Time (sec)' ../chemkin/senk.out | awk '{print $4 " " $8 }' \
>> chemkinII
./createGraph
#------------------------------------------------------------------------------

View File

@ -0,0 +1,25 @@
#!/bin/sh
if ! which gnuplot > /dev/null 2>&1
then
echo "gnuplot not found - skipping graph creation" >&2
exit 1
fi
gnuplot<<EOF
set terminal postscript eps color enhanced "Helvetica,20"
set output "OF_vs_CHEMKINII.eps"
set xlabel "Time / [s]" font "Helvetica,24"
set ylabel "Temperature / [K]" font "Helvetica,24"
set grid
set key left top
set xrange [0:0.01]
set yrange [750:2750]
set ytic 250
plot \
"../chemFoam.out" u 1:2 t "OpenFOAM" with points lt 1 pt 6 ps 1.5,\
"chemkinII" with lines title "Chemkin II" lt -1
EOF
# ----------------------------------------------------------------- end-of-file

View File

@ -17,19 +17,19 @@ FoamFile
dimensions [0 0 0 1 0 0 0];
internalField uniform 293;
internalField uniform 2000;
boundaryField
{
fuel
{
type fixedValue;
value uniform 800;
value uniform 293;
}
air
{
type fixedValue;
value uniform 800;
value uniform 293;
}
outlet
{

View File

@ -11,7 +11,7 @@ FoamFile
format ascii;
class volScalarField;
location "0";
object O2;
object N2;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -17,19 +17,19 @@ FoamFile
dimensions [0 0 0 1 0 0 0];
internalField uniform 293;
internalField uniform 2000;
boundaryField
{
fuel
{
type fixedValue;
value uniform 800;
value uniform 293;
}
air
{
type fixedValue;
value uniform 800;
value uniform 293;
}
outlet
{

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object CH4;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0.0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 1.0;
}
air
{
type fixedValue;
value uniform 0.0;
}
outlet
{
type inletOutlet;
inletValue uniform 0.0;
value uniform 0.0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object CO2;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0;
}
air
{
type fixedValue;
value uniform 0;
}
outlet
{
type inletOutlet;
inletValue uniform 0;
value uniform 0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object H2O;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0;
}
air
{
type fixedValue;
value uniform 0;
}
outlet
{
type inletOutlet;
inletValue uniform 0;
value uniform 0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object N2;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 1;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0.0;
}
air
{
type fixedValue;
value uniform 0.77;
}
outlet
{
type inletOutlet;
inletValue uniform 1;
value uniform 1;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,47 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object O2;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0.0;
}
air
{
type fixedValue;
value uniform 0.23;
}
outlet
{
type inletOutlet;
inletValue uniform 0;
value uniform 0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,47 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object T;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 1 0 0 0];
internalField uniform 2000;
boundaryField
{
fuel
{
type fixedValue;
value uniform 293;
}
air
{
type fixedValue;
value uniform 293;
}
outlet
{
type inletOutlet;
inletValue uniform 293;
value uniform 293;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,46 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
location "0";
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0);
boundaryField
{
fuel
{
type fixedValue;
value uniform (0.1 0 0);
}
air
{
type fixedValue;
value uniform (-0.1 0 0);
}
outlet
{
type pressureInletOutletVelocity;
value $internalField;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,48 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object Ydefault;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0.0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0.0;
}
air
{
type fixedValue;
value uniform 0.0;
}
outlet
{
type inletOutlet;
inletValue uniform 0.0;
value uniform 0.0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,45 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object alphat;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -1 -1 0 0 0 0];
internalField uniform 0;
boundaryField
{
fuel
{
type fixedValue;
value uniform 0;
}
air
{
type fixedValue;
value uniform 0;
}
outlet
{
type zeroGradient;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,44 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -1 -2 0 0 0 0];
internalField uniform 1e5;
boundaryField
{
fuel
{
type zeroGradient;
}
air
{
type zeroGradient;
}
outlet
{
type totalPressure;
p0 $internalField;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,35 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object chemistryProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
chemistryType
{
chemistrySolver ode;
chemistryThermo psi;
}
chemistry on;
initialChemicalTimeStep 1e-7;
odeCoeffs
{
solver seulex;
absTol 1e-12;
relTol 1e-1;
}
// ************************************************************************* //

View File

@ -0,0 +1,27 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object combustionProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
combustionModel laminar<psiChemistryCombustion>;
active true;
laminarCoeffs
{
}
// ************************************************************************* //

View File

@ -0,0 +1,28 @@
elements
(
O
C
H
N
);
species
(
O2
H2O
CH4
CO2
N2
);
reactions
{
methaneReaction
{
type irreversibleArrheniusReaction;
reaction "CH4 + 2O2 = CO2 + 2H2O";
A 5.2e16;
beta 0;
Ta 14906;
}
}

View File

@ -0,0 +1,152 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 3.0.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object thermo.compressibleGas;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
O2
{
specie
{
nMoles 1;
molWeight 31.9988;
}
elements
{
O 2;
}
thermodynamics
{
Tlow 200;
Thigh 5000;
Tcommon 1000;
highCpCoeffs ( 3.69758 0.00061352 -1.25884e-07 1.77528e-11 -1.13644e-15 -1233.93 3.18917 );
lowCpCoeffs ( 3.21294 0.00112749 -5.75615e-07 1.31388e-09 -8.76855e-13 -1005.25 6.03474 );
}
transport
{
As 1.67212e-06;
Ts 170.672;
}
}
H2O
{
specie
{
nMoles 1;
molWeight 18.0153;
}
elements
{
O 1;
H 2;
}
thermodynamics
{
Tlow 200;
Thigh 5000;
Tcommon 1000;
highCpCoeffs ( 2.67215 0.00305629 -8.73026e-07 1.201e-10 -6.39162e-15 -29899.2 6.86282 );
lowCpCoeffs ( 3.38684 0.00347498 -6.3547e-06 6.96858e-09 -2.50659e-12 -30208.1 2.59023 );
}
transport
{
As 1.67212e-06;
Ts 170.672;
}
}
CH4
{
specie
{
nMoles 1;
molWeight 16.0428;
}
elements
{
C 1;
H 4;
}
thermodynamics
{
Tlow 200;
Thigh 6000;
Tcommon 1000;
highCpCoeffs ( 1.63543 0.0100844 -3.36924e-06 5.34973e-10 -3.15528e-14 -10005.6 9.9937 );
lowCpCoeffs ( 5.14988 -0.013671 4.91801e-05 -4.84744e-08 1.66694e-11 -10246.6 -4.64132 );
}
transport
{
As 1.67212e-06;
Ts 170.672;
}
}
CO2
{
specie
{
nMoles 1;
molWeight 44.01;
}
elements
{
C 1;
O 2;
}
thermodynamics
{
Tlow 200;
Thigh 5000;
Tcommon 1000;
highCpCoeffs ( 4.45362 0.00314017 -1.27841e-06 2.394e-10 -1.66903e-14 -48967 -0.955396 );
lowCpCoeffs ( 2.27572 0.00992207 -1.04091e-05 6.86669e-09 -2.11728e-12 -48373.1 10.1885 );
}
transport
{
As 1.67212e-06;
Ts 170.672;
}
}
N2
{
specie
{
nMoles 1;
molWeight 28.0134;
}
elements
{
N 2;
}
thermodynamics
{
Tlow 200;
Thigh 5000;
Tcommon 1000;
highCpCoeffs ( 2.92664 0.00148798 -5.68476e-07 1.0097e-10 -6.75335e-15 -922.798 5.98053 );
lowCpCoeffs ( 3.29868 0.00140824 -3.96322e-06 5.64152e-09 -2.44486e-12 -1020.9 3.95037 );
}
transport
{
As 1.67212e-06;
Ts 170.672;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,36 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object thermophysicalProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
thermoType
{
type hePsiThermo;
mixture reactingMixture;
transport sutherland;
thermo janaf;
energy sensibleEnthalpy;
equationOfState perfectGas;
specie specie;
}
inertSpecie N2;
chemistryReader foamChemistryReader;
foamChemistryFile "$FOAM_CASE/constant/reactionsGRI";
foamChemistryThermoFile "$FOAM_CASE/constant/thermo.compressibleGasGRI";
// ************************************************************************* //

View File

@ -0,0 +1,21 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object turbulenceProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
simulationType laminar;
// ************************************************************************* //

View File

@ -0,0 +1,82 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
convertToMeters 1;
vertices
(
(0.0 -0.01 -0.01)
(0.02 -0.01 -0.01)
(0.02 0.01 -0.01)
(0.0 0.01 -0.01)
(0.0 -0.01 0.01)
(0.02 -0.01 0.01)
(0.02 0.01 0.01)
(0.0 0.01 0.01)
);
blocks
(
hex (0 1 2 3 4 5 6 7) (100 40 1) simpleGrading (1 1 1)
);
edges
(
);
boundary
(
fuel
{
type patch;
faces
(
(0 4 7 3)
);
}
air
{
type patch;
faces
(
(1 2 6 5)
);
}
outlet
{
type patch;
faces
(
(0 1 5 4)
(7 6 2 3)
);
}
frontAndBack
{
type empty;
faces
(
(4 5 6 7)
(0 3 2 1)
);
}
);
mergePatchPairs
(
);
// ************************************************************************* //

View File

@ -0,0 +1,53 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application reactingFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.5;
deltaT 1e-6;
writeControl adjustableRunTime;
writeInterval 0.05;
purgeWrite 0;
writeFormat ascii;
writePrecision 6;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
adjustTimeStep yes;
maxCo 0.4;
// ************************************************************************* //

View File

@ -0,0 +1,29 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
note "mesh decomposition control dictionary";
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
numberOfSubdomains 4;
method hierarchical;
hierarchicalCoeffs
{
n (2 2 1);
delta 0.001;
order xyz;
}
// ************************************************************************* //

View File

@ -0,0 +1,57 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
ddtSchemes
{
default Euler;
}
gradSchemes
{
default Gauss linear;
}
divSchemes
{
default none;
div(phi,U) Gauss limitedLinearV 1;
div(phi,Yi_h) Gauss limitedLinear 1;
div(phi,K) Gauss limitedLinear 1;
div(phid,p) Gauss limitedLinear 1;
div(phi,epsilon) Gauss limitedLinear 1;
div(phi,k) Gauss limitedLinear 1;
div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;
}
laplacianSchemes
{
default Gauss linear orthogonal;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default orthogonal;
}
// ************************************************************************* //

Some files were not shown because too many files have changed in this diff Show More