/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd.
\\/ 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 .
\*---------------------------------------------------------------------------*/
#include "diffusionMulticomponent.H"
#include "fvcGrad.H"
#include "reactingMixture.H"
#include "fvCFD.H"
#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * //
template
void Foam::combustionModels::
diffusionMulticomponent::init()
{
// Load default values
this->coeffs().readIfPresent("Ci", Ci_);
this->coeffs().readIfPresent("YoxStream", YoxStream_);
this->coeffs().readIfPresent("YfStream", YfStream_);
this->coeffs().readIfPresent("sigma", sigma_);
this->coeffs().readIfPresent("ftCorr", ftCorr_);
this->coeffs().readIfPresent("alpha", alpha_);
this->coeffs().readIfPresent("laminarIgn", laminarIgn_);
typedef typename Reaction::specieCoeffs specieCoeffs;
const speciesTable& species = this->thermo().composition().species();
scalarList specieStoichCoeffs(species.size());
const label nReactions = reactions_.size();
for (label k=0; k < nReactions; k++)
{
RijPtr_.set
(
k,
new volScalarField
(
IOobject
(
"Rijk" + Foam::name(k),
this->mesh_.time().timeName(),
this->mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
this->mesh_,
dimensionedScalar("Rij", dimMass/dimTime/dimVolume, 0.0),
zeroGradientFvPatchScalarField::typeName
)
);
RijPtr_[k].storePrevIter();
const List& lhs = reactions_[k].lhs();
const List& rhs = reactions_[k].rhs();
const label fuelIndex = species[fuelNames_[k]];
const label oxidantIndex = species[oxidantNames_[k]];
const scalar Wu = specieThermo_[fuelIndex].W();
const scalar Wox = specieThermo_[oxidantIndex].W();
forAll(lhs, i)
{
const label specieI = lhs[i].index;
specieStoichCoeffs[specieI] = -lhs[i].stoichCoeff;
qFuel_[k] +=
specieThermo_[specieI].hc()*lhs[i].stoichCoeff/Wu;
}
forAll(rhs, i)
{
const label specieI = rhs[i].index;
specieStoichCoeffs[specieI] = rhs[i].stoichCoeff;
qFuel_[k] -=
specieThermo_[specieI].hc()*rhs[i].stoichCoeff/Wu;
}
Info << "Fuel heat of combustion : " << qFuel_[k] << endl;
s_[k] =
(Wox*mag(specieStoichCoeffs[oxidantIndex]))
/ (Wu*mag(specieStoichCoeffs[fuelIndex]));
Info << "stoichiometric oxygen-fuel ratio : " << s_[k] << endl;
stoicRatio_[k] = s_[k]*YfStream_[k]/YoxStream_[k];
Info << "stoichiometric air-fuel ratio : " << stoicRatio_[k] << endl;
const scalar fStoich = 1.0/(1.0 + stoicRatio_[k]);
Info << "stoichiometric mixture fraction : " << fStoich << endl;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::combustionModels::diffusionMulticomponent::
diffusionMulticomponent
(
const word& modelType,
const fvMesh& mesh,
const word& combustionProperties,
const word& phaseName
)
:
CombThermoType(modelType, mesh, combustionProperties, phaseName),
reactions_
(
dynamic_cast&>(this->thermo())
),
specieThermo_
(
dynamic_cast&>
(this->thermo()).speciesData()
),
RijPtr_(reactions_.size()),
Ci_(reactions_.size(), 1.0),
fuelNames_(this->coeffs().lookup("fuels")),
oxidantNames_(this->coeffs().lookup("oxidants")),
qFuel_(reactions_.size()),
stoicRatio_(reactions_.size()),
s_(reactions_.size()),
YoxStream_(reactions_.size(), 0.23),
YfStream_(reactions_.size(), 1.0),
sigma_(reactions_.size(), 0.02),
oxidantRes_(this->coeffs().lookup("oxidantRes")),
ftCorr_(reactions_.size(), 0.0),
alpha_(1),
laminarIgn_(false)
{
init();
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template
Foam::tmp Foam::combustionModels::
diffusionMulticomponent::tc() const
{
return this->chemistryPtr_->tc();
}
template
void Foam::combustionModels::
diffusionMulticomponent::correct()
{
if (this->active())
{
typedef typename Reaction::specieCoeffs specieCoeffs;
const speciesTable& species = this->thermo().composition().species();
const label nReactions = reactions_.size();
PtrList RijlPtr(nReactions);
for (label k=0; k < nReactions; k++)
{
RijlPtr.set
(
k,
new volScalarField
(
IOobject
(
"Rijl" + Foam::name(k),
this->mesh_.time().timeName(),
this->mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
this->mesh_,
dimensionedScalar("Rijl", dimMass/dimTime/dimVolume, 0.0),
zeroGradientFvPatchScalarField::typeName
)
);
volScalarField& Rijl = RijlPtr[k];
// Obtain individual reaction rates for each reaction
const label fuelIndex = species[fuelNames_[k]];
if (laminarIgn_)
{
Rijl.ref() = -this->chemistryPtr_->calculateRR(k, fuelIndex);
}
// Look for the fuelStoic
const List& rhs = reactions_[k].rhs();
const List& lhs = reactions_[k].lhs();
// Set to zero RR's
forAll(lhs, l)
{
const label lIndex = lhs[l].index;
this->chemistryPtr_->RR(lIndex) =
dimensionedScalar("zero", dimMass/dimTime/dimVolume, 0.0);
}
forAll(rhs, l)
{
const label rIndex = rhs[l].index;
this->chemistryPtr_->RR(rIndex) =
dimensionedScalar("zero", dimMass/dimTime/dimVolume, 0.0);
}
}
for (label k=0; k < nReactions; k++)
{
const label fuelIndex = species[fuelNames_[k]];
const label oxidantIndex = species[oxidantNames_[k]];
const volScalarField& Yfuel =
this->thermo().composition().Y(fuelIndex);
const volScalarField& Yox =
this->thermo().composition().Y(oxidantIndex);
const volScalarField ft
(
"ft" + Foam::name(k),
(
s_[k]*Yfuel - (Yox - YoxStream_[k])
)
/(
s_[k]*YfStream_[k] + YoxStream_[k]
)
);
const scalar sigma = sigma_[k];
const scalar fStoich = 1.0/(1.0 + stoicRatio_[k]) + ftCorr_[k];
const volScalarField OAvailScaled
(
"OAvailScaled",
Yox/max(oxidantRes_[k], 1e-3)
);
const volScalarField preExp
(
"preExp" + Foam::name(k),
1.0 + sqr(OAvailScaled)
);
const volScalarField filter
(
(1.0/(sigma*sqrt(2.0*constant::mathematical::pi)))
* exp(-sqr(ft - fStoich)/(2*sqr(sigma)))
);
const volScalarField topHatFilter(pos(filter - 1e-3));
const volScalarField prob("prob" + Foam::name(k), preExp*filter);
const volScalarField RijkDiff
(
"RijkDiff",
Ci_[k]*this->turbulence().muEff()*prob*
(
mag(fvc::grad(Yfuel) & fvc::grad(Yox))
)
*pos(Yox)*pos(Yfuel)
);
volScalarField& Rijk = RijPtr_[k];
if (laminarIgn_)
{
Rijk =
min(RijkDiff, topHatFilter*RijlPtr[k]*pos(Yox)*pos(Yfuel));
}
else
{
Rijk = RijkDiff;
}
Rijk.relax(alpha_);
if (this->mesh_.time().outputTime() && debug)
{
Rijk.write();
ft.write();
}
// Look for the fuelStoic
const List& rhs = reactions_[k].rhs();
const List& lhs = reactions_[k].lhs();
scalar fuelStoic = 1.0;
forAll(lhs, l)
{
const label lIndex = lhs[l].index;
if (lIndex == fuelIndex)
{
fuelStoic = lhs[l].stoichCoeff;
break;
}
}
const scalar MwFuel = specieThermo_[fuelIndex].W();
// Update left hand side species
forAll(lhs, l)
{
const label lIndex = lhs[l].index;
const scalar stoichCoeff = lhs[l].stoichCoeff;
this->chemistryPtr_->RR(lIndex) +=
-Rijk*stoichCoeff*specieThermo_[lIndex].W()/fuelStoic/MwFuel;
}
// Update right hand side species
forAll(rhs, r)
{
const label rIndex = rhs[r].index;
const scalar stoichCoeff = rhs[r].stoichCoeff;
this->chemistryPtr_->RR(rIndex) +=
Rijk*stoichCoeff*specieThermo_[rIndex].W()/fuelStoic/MwFuel;
}
}
}
}
template
Foam::tmp
Foam::combustionModels::diffusionMulticomponent::R
(
volScalarField& Y
) const
{
tmp tSu(new fvScalarMatrix(Y, dimMass/dimTime));
fvScalarMatrix& Su = tSu.ref();
if (this->active())
{
const label specieI =
this->thermo().composition().species()[Y.member()];
Su += this->chemistryPtr_->RR(specieI);
}
return tSu;
}
template
Foam::tmp
Foam::combustionModels::diffusionMulticomponent::
Qdot() const
{
tmp tQdot
(
new volScalarField
(
IOobject
(
"Qdot",
this->mesh().time().timeName(),
this->mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
this->mesh(),
dimensionedScalar("dQ", dimEnergy/dimTime, 0.0),
zeroGradientFvPatchScalarField::typeName
)
);
if (this->active())
{
volScalarField& Qdot = tQdot.ref();
Qdot = this->chemistryPtr_->Qdot();
}
return tQdot;
}
template
bool Foam::combustionModels::
diffusionMulticomponent::read()
{
if (CombThermoType::read())
{
this->coeffs().readIfPresent("Ci", Ci_);
this->coeffs().readIfPresent("sigma", sigma_);
this->coeffs().readIfPresent("oxidantRes", oxidantRes_);
this->coeffs().readIfPresent("ftCorr", ftCorr_);
this->coeffs().readIfPresent("alpha", alpha_);
this->coeffs().readIfPresent("laminarIgn", laminarIgn_);
return true;
}
return false;
}
// ************************************************************************* //