/*---------------------------------------------------------------------------*\ ========= | \\ / 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; } // ************************************************************************* //