ENH: Adding speciesSorption BC and patchCellsSource fvOption

speciesSorption is a zeroGradient BC which absorbs mass given by a first
order time derivative, absoprtion rate and an equilibrium value
calculated based on internal species values next to the wall.

patchCellsSource is a source fvOption which applies to the corresponding
species and apply the source calculated on the speciesSorption BC.

A new abstract virtual class was created to group BC's which
don't introduce a source to the matrix (i.e zeroGradient) but calculate
a mass sink/source which should be introduced into the matrix. This
is  done through the fvOption patchCellsSource.
This commit is contained in:
sergio
2021-09-20 15:29:41 +01:00
committed by Kutalmis Bercin
parent 33f381c052
commit a5bba64035
10 changed files with 1262 additions and 1 deletions

View File

@ -36,6 +36,7 @@ $(derivedSources)/tabulatedAccelerationSource/tabulatedAccelerationSource.C
$(derivedSources)/tabulatedAccelerationSource/tabulated6DoFAcceleration/tabulated6DoFAcceleration.C
$(derivedSources)/viscousDissipation/viscousDissipation.C
$(derivedSources)/buoyancyTurbSource/buoyancyTurbSource.C
$(derivedSources)/patchCellsSource/patchCellsSource.C
interRegion = sources/interRegion
$(interRegion)/interRegionHeatTransfer/interRegionHeatTransferModel/interRegionHeatTransferModel.C

View File

@ -8,6 +8,7 @@ EXE_INC = \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/solidThermo/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/reactionThermo/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude
@ -20,4 +21,5 @@ LIB_LIBS = \
-lsolidThermo \
-lturbulenceModels \
-lincompressibleTurbulenceModels \
-lcompressibleTurbulenceModels
-lcompressibleTurbulenceModels \
-lreactionThermophysicalModels

View File

@ -0,0 +1,195 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "patchCellsSource.H"
#include "fvMatrices.H"
#include "addToRunTimeSelectionTable.H"
#include "boundarySourcePatch.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
defineTypeNameAndDebug(patchCellsSource, 0);
addToRunTimeSelectionTable(option, patchCellsSource, dictionary);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fv::patchCellsSource::patchCellsSource
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
)
:
fv::option(sourceName, modelType, dict, mesh),
curTimeIndex_(-1),
UName_(coeffs_.getOrDefault<word>("U", "none")),
hName_(coeffs_.getOrDefault<word>("he", "none")),
speciesName_(coeffs_.getOrDefault<word>("species", "none"))
{
label nFields = 0;
if (UName_ != "none")
{
nFields++;
}
if (hName_ != "none")
{
nFields++;
}
if (speciesName_ != "none")
{
nFields++;
}
if (nFields > 1)
{
FatalErrorInFunction
<< "patchCellsSource : "
<< " cannot be used for more than one field."
<< exit(FatalError);
}
fieldNames_.resize(1);
if (speciesName_ != "none")
{
fieldNames_[0] = speciesName_;
}
if (UName_ != "none")
{
fieldNames_[0] = UName_;
}
if (hName_ != "none")
{
fieldNames_[0] = hName_;
}
fv::option::resetApplied();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::fv::patchCellsSource::addSup
(
const volScalarField& rho,
fvMatrix<scalar>& eqn,
const label fieldi
)
{
if (debug)
{
Info<< type() << ": applying source to " << eqn.psi().name() << endl;
}
if (curTimeIndex_ == mesh_.time().timeIndex())
{
return;
}
volScalarField* psiPtr;
// If source applied to he, we need to loop over T for BC's
if (hName_ != "none")
{
psiPtr = mesh_.getObjectPtr<volScalarField>("T");
}
else
{
auto* psi =
mesh_.getObjectPtr<volScalarField>(eqn.psi().name());
psiPtr = psi;
}
const volScalarField::Boundary& psib = psiPtr->boundaryField();
volScalarField mDot
(
IOobject
(
"mDot",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(eqn.dimensions()/dimVolume, Zero)
);
forAll(psib, patchi)
{
if (isA<boundarySourcePatch>(psib[patchi]))
{
const boundarySourcePatch& pp =
refCast<const boundarySourcePatch>(psib[patchi]);
const labelUList& fc = mesh_.boundary()[patchi].faceCells();
tmp<scalarField> tsb = pp.patchSource();
const scalarField& sb = tsb.cref();
forAll(fc, facei)
{
const label celli = fc[facei];
mDot[celli] += sb[facei];
}
}
}
eqn += mDot;
curTimeIndex_ = mesh_.time().timeIndex();
if (debug)
{
Info<< " Field source rate min/max : "
<< gMin(mDot) << " / " << gMax(mDot) << endl;
}
}
bool Foam::fv::patchCellsSource::read(const dictionary& dict)
{
if (!fv::option::read(dict))
{
return false;
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,162 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::fv::patchCellsSource
Group
grpFvOptionsSources
Description
Source defined by a boundary condition applied to cells next to patches.
This fvOption needs to be used with a \c boundarySourcePatch type of
boundary condition (e.g. \c speciesSorption and \c enthalpySorption.)
Usage
Minimal example by using \c constant/fvOptions:
\verbatim
<fvOptionName>
{
// Mandatory entries
type patchCellsSource;
// Optional entries
U <word>;
he <word>;
species <word>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: patchCellsSource | word | yes | -
U | Name of operand velocity field | word | no | none
he | Name of operand energy field | word | no | none
species | Name of operand species field | word | no | none
\endtable
The inherited entries are elaborated in:
- \link cellSetOption.H \endlink
SourceFiles
patchCellsSource.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_fv_patchCellsSource_H
#define Foam_fv_patchCellsSource_H
#include "fvMesh.H"
#include "volFields.H"
#include "cellSetOption.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
/*---------------------------------------------------------------------------*\
Class patchCellsSource Declaration
\*---------------------------------------------------------------------------*/
class patchCellsSource
:
public fv::option
{
// Private Data
//- Current time index (used for updating)
label curTimeIndex_;
//- Name of operand velocity field
word UName_;
//- Name of operand energy field
word hName_;
//- Name of operand species field
word speciesName_;
public:
//- Runtime type information
TypeName("patchCellsSource");
// Constructors
//- Construct from explicit source name and mesh
patchCellsSource
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
patchCellsSource(const patchCellsSource&) = delete;
//- No copy assignment
void operator=(const patchCellsSource&) = delete;
//- Destructor
virtual ~patchCellsSource() = default;
// Member Functions
//- Add explicit contribution to compressible enthalpy equation
virtual void addSup
(
const volScalarField& rho,
fvMatrix<scalar>& eqn,
const label fieldi
);
//- Read source dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -18,6 +18,8 @@ rhoReactionThermo/rhoReactionThermos.C
derivedFvPatchFields/fixedUnburntEnthalpy/fixedUnburntEnthalpyFvPatchScalarField.C
derivedFvPatchFields/gradientUnburntEnthalpy/gradientUnburntEnthalpyFvPatchScalarField.C
derivedFvPatchFields/mixedUnburntEnthalpy/mixedUnburntEnthalpyFvPatchScalarField.C
derivedFvPatchFields/speciesSorption/speciesSorptionFvPatchScalarField.C
derivedFvPatchFields/boundarySourcePatch/boundarySourcePatch.C
functionObjects/moleFractions/moleFractionsFunctionObjects.C

View File

@ -1,5 +1,6 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/transportModels/compressible/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
@ -9,6 +10,7 @@ EXE_INC = \
LIB_LIBS = \
-lfiniteVolume \
-lmeshTools \
-lcompressibleTransportModels \
-lfluidThermophysicalModels \
-lspecie \

View File

@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "boundarySourcePatch.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(boundarySourcePatch, 0);
}
// ************************************************************************* //

View File

@ -0,0 +1,78 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::boundarySourcePatch
Description
Pure virtual class for sources on cells next to patches.
SourceFiles
boundarySourcePatch.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_boundarySourcePatch_H
#define Foam_boundarySourcePatch_H
#include "scalarField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class boundarySourcePatch Declaration
\*---------------------------------------------------------------------------*/
class boundarySourcePatch
{
public:
//- Runtime type information
TypeName("boundarySourcePatch");
//- Destructor
virtual ~boundarySourcePatch() = default;
// Member Functions
//- Source applied on cells of the patch
virtual tmp<scalarField> patchSource() const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,459 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "speciesSorptionFvPatchScalarField.H"
#include "addToRunTimeSelectionTable.H"
#include "fvPatchFieldMapper.H"
#include "volFields.H"
#include "rhoReactionThermo.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::Enum
<
Foam::speciesSorptionFvPatchScalarField::equilibriumModelType
>
Foam::speciesSorptionFvPatchScalarField::equilibriumModelTypeNames
({
{ equilibriumModelType::LANGMUIR, "Langmuir" }
});
const Foam::Enum
<
Foam::speciesSorptionFvPatchScalarField::kineticModelType
>
Foam::speciesSorptionFvPatchScalarField::kinematicModelTypeNames
({
{ kineticModelType::PseudoFirstOrder, "PseudoFirstOrder" }
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::tmp<Foam::scalarField>
Foam::speciesSorptionFvPatchScalarField::calcMoleFractions() const
{
auto tMole = tmp<scalarField>::New(patch().size(), 0);
scalarField& Mole = tMole.ref();
if (db().foundObject<rhoReactionThermo>(basicThermo::dictName))
{
const auto& thermo = db().lookupObject<rhoReactionThermo>
(
basicThermo::dictName
);
const PtrList<volScalarField>& Y = thermo.composition().Y();
const volScalarField W(thermo.W());
const labelUList& faceCells = patch().faceCells();
const label speicesId =
thermo.composition().species()[this->internalField().name()];
const dimensionedScalar Wi
(
dimMass/dimMoles,
thermo.composition().W(speicesId)
);
const volScalarField X(W*Y[speicesId]/Wi);
forAll(faceCells, i)
{
const label cellId = faceCells[i];
Mole[i] = X[cellId];
}
}
else
{
FatalErrorInFunction
<< "Thermo type is not 'rhoReactionThermo'. " << nl
<< "This BC is designed to operate with a rho based thermo."
<< exit(FatalError);
}
return tMole;
}
Foam::volScalarField&
Foam::speciesSorptionFvPatchScalarField::field
(
const word& fieldName,
const dimensionSet& dim
) const
{
const fvMesh& mesh = this->internalField().mesh();
auto* ptr = mesh.getObjectPtr<volScalarField>(fieldName);
if (!ptr)
{
ptr = new volScalarField
(
IOobject
(
fieldName,
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh,
dimensionedScalar(dim, Zero)
);
ptr->store();
}
return *ptr;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::speciesSorptionFvPatchScalarField::speciesSorptionFvPatchScalarField
(
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF
)
:
zeroGradientFvPatchScalarField(p, iF),
equilibriumModel_(equilibriumModelType::LANGMUIR),
kinematicModel_(kineticModelType::PseudoFirstOrder),
thicknessPtr_(nullptr),
kabs_(1),
kl_(0),
max_(1),
rhoS_(0),
pName_("p"),
dfldp_(p.size(), 0),
mass_(p.size(), 0)
{}
Foam::speciesSorptionFvPatchScalarField::speciesSorptionFvPatchScalarField
(
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF,
const dictionary& dict
)
:
zeroGradientFvPatchScalarField(p, iF, dict),
equilibriumModel_(equilibriumModelTypeNames.get("equilibriumModel", dict)),
kinematicModel_(kinematicModelTypeNames.get("kinematicModel", dict)),
thicknessPtr_(PatchFunction1<scalar>::New(p.patch(), "thickness", dict)),
kabs_(dict.getCheck<scalar>("kabs", scalarMinMax::ge(0))),
kl_(dict.getCheck<scalar>("kl", scalarMinMax::ge(0))),
max_(dict.getCheck<scalar>("max", scalarMinMax::ge(0))),
rhoS_(dict.get<scalar>("rhoS")),
pName_(dict.getOrDefault<word>("p", "p")),
dfldp_
(
dict.found("dfldp")
? scalarField("dfldp", dict, p.size())
: scalarField(p.size(), 0)
),
mass_
(
dict.found("mass")
? scalarField("mass", dict, p.size())
: scalarField(p.size(), 0)
)
{
if (dict.found("value"))
{
fvPatchScalarField::operator=
(
scalarField("value", dict, p.size())
);
}
else
{
fvPatchField<scalar>::operator=(Zero);
}
}
Foam::speciesSorptionFvPatchScalarField::speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField& ptf,
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF,
const fvPatchFieldMapper& mapper
)
:
zeroGradientFvPatchScalarField(ptf, p, iF, mapper),
equilibriumModel_(ptf.equilibriumModel_),
kinematicModel_(ptf.kinematicModel_),
thicknessPtr_(ptf.thicknessPtr_.clone(patch().patch())),
kabs_(ptf.kabs_),
kl_(ptf.kl_),
max_(ptf.max_),
rhoS_(ptf.rhoS_),
pName_(ptf.pName_),
dfldp_(ptf.dfldp_, mapper),
mass_(ptf.mass_, mapper)
{}
Foam::speciesSorptionFvPatchScalarField::speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField& ptf
)
:
zeroGradientFvPatchScalarField(ptf),
equilibriumModel_(ptf.equilibriumModel_),
kinematicModel_(ptf.kinematicModel_),
thicknessPtr_(ptf.thicknessPtr_.clone(patch().patch())),
kabs_(ptf.kabs_),
kl_(ptf.kl_),
max_(ptf.max_),
rhoS_(ptf.rhoS_),
pName_(ptf.pName_),
dfldp_(ptf.dfldp_),
mass_(ptf.mass_)
{}
Foam::speciesSorptionFvPatchScalarField::speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField& ptf,
const DimensionedField<scalar, volMesh>& iF
)
:
zeroGradientFvPatchScalarField(ptf, iF),
equilibriumModel_(ptf.equilibriumModel_),
kinematicModel_(ptf.kinematicModel_),
thicknessPtr_(ptf.thicknessPtr_.clone(patch().patch())),
kabs_(ptf.kabs_),
kl_(ptf.kl_),
max_(ptf.max_),
rhoS_(ptf.rhoS_),
pName_(ptf.pName_),
dfldp_(ptf.dfldp_),
mass_(ptf.mass_)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::speciesSorptionFvPatchScalarField::autoMap
(
const fvPatchFieldMapper& m
)
{
zeroGradientFvPatchScalarField::autoMap(m);
dfldp_.autoMap(m);
mass_.autoMap(m);
if (thicknessPtr_)
{
thicknessPtr_->autoMap(m);
}
}
void Foam::speciesSorptionFvPatchScalarField::rmap
(
const fvPatchScalarField& ptf,
const labelList& addr
)
{
zeroGradientFvPatchScalarField::rmap(ptf, addr);
const auto& tiptf = refCast<const speciesSorptionFvPatchScalarField>(ptf);
dfldp_.rmap(tiptf.dfldp_, addr);
mass_.rmap(tiptf.mass_, addr);
if (thicknessPtr_)
{
thicknessPtr_->rmap(tiptf.thicknessPtr_(), addr);
}
}
Foam::tmp<Foam::scalarField> Foam::speciesSorptionFvPatchScalarField::
patchSource() const
{
const auto& thermo = db().lookupObject<rhoReactionThermo>
(
basicThermo::dictName
);
const label speicesId =
thermo.composition().species()[this->internalField().name()];
const scalar Wi(thermo.composition().W(speicesId));
const scalar t = db().time().timeOutputValue();
const scalarField h(thicknessPtr_->value(t));
const scalarField AbyV(this->patch().magSf());
// Solid mass [kg]
const scalarField mass(h*AbyV*rhoS_);
scalarField Vol(this->patch().size());
forAll(AbyV, facei)
{
const label faceCelli = this->patch().faceCells()[facei];
Vol[facei] = this->internalField().mesh().V()[faceCelli];
}
// The moles absorbed by the solid
// dfldp[mol/kg/sec]* mass[kg]* Wi[kg/mol] / Vol[m3]= [kg/sec/m3]
const scalarField dfldp(-dfldp_*mass*Wi*1e-3/Vol);
if (debug)
{
Info<< " Patch mass rate min/max [kg/m3/sec]: "
<< gMin(dfldp) << " - " << gMax(dfldp) << endl;
}
return tmp<scalarField>::New(dfldp);
}
Foam::tmp<Foam::scalarField> Foam::speciesSorptionFvPatchScalarField::
mass() const
{
return tmp<scalarField>::New(mass_);
}
void Foam::speciesSorptionFvPatchScalarField::updateCoeffs()
{
if (updated())
{
return;
}
// equilibrium in mol/kg
scalarField cEq(patch().size(), 0);
switch (equilibriumModel_)
{
case equilibriumModelType::LANGMUIR:
{
// mole fraction
tmp<scalarField> tco = calcMoleFractions();
const fvPatchField<scalar>& pp =
patch().lookupPatchField<volScalarField, scalar>(pName_);
cEq = max_*(kl_*tco()*pp/(1 + kl_*tco()*pp));
break;
}
default:
break;
}
// source [mol/kg/sec]
dfldp_ = Zero;
switch (kinematicModel_)
{
case kineticModelType::PseudoFirstOrder:
{
dfldp_ = kabs_*(cEq - mass_);
}
default:
break;
}
// mass [mol/kg]
const scalar dt = db().time().deltaTValue();
mass_ += dfldp_*dt;
mass_ = max(mass_, scalar(0));
scalarField& pMass =
field
(
"absorbedMass" + this->internalField().name(),
dimensionSet(dimMoles/dimMass)
).boundaryFieldRef()[patch().index()];
pMass = mass_;
if (debug)
{
Info<< " Absorption rate min/max [mol/kg/sec]: "
<< gMin(dfldp_) << " - " << gMax(dfldp_) << endl;
}
zeroGradientFvPatchScalarField::updateCoeffs();
}
void Foam::speciesSorptionFvPatchScalarField::write(Ostream& os) const
{
fvPatchScalarField::write(os);
os.writeEntry
(
"equilibriumModel", equilibriumModelTypeNames[equilibriumModel_]
);
os.writeEntry
(
"kinematicModel", kinematicModelTypeNames[kinematicModel_]
);
if (thicknessPtr_)
{
thicknessPtr_->writeData(os);
}
os.writeEntry("kabs", kabs_);
os.writeEntry("kl", kl_);
os.writeEntry("max", max_);
os.writeEntry("rhoS", rhoS_);
dfldp_.writeEntry("dfldp", os);
mass_.writeEntry("mass", os);
os.writeEntryIfDifferent<word>("p", "p", pName_);
writeEntry("value", os);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makePatchTypeField
(
fvPatchScalarField,
speciesSorptionFvPatchScalarField
);
}
// ************************************************************************* //

View File

@ -0,0 +1,322 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::speciesSorptionFvPatchScalarField
Group
grpGenericBoundaryConditions
Description
This boundary condition provides a first-order zero-gradient
condition for a given scalar field to model time-dependent
adsorption-desorption processes.
\f[
\frac{d c}{d t} = k_{ads} (c_{eq} - c_{abs})
\f]
where
\vartable
c_{eq} | Equilibrium concentration
c_{abs} | Absorbed at wall
k_{ads} | Adsorption rate constant [1/s]
\endvartable
\f[
c_{eq} = c_{max} \frac{k_l \, c_{int}}{1 + k_l \, c_{int}}
\f]
where
\vartable
c_{max} | Maximum concentration
k_l | Langmuir constant
c_{int} | Local cell value concentration
\endvartable
Usage
Example of the boundary condition specification:
\verbatim
<patchName>
{
// Mandatory entries
type speciesSorption;
equilibriumModel <word>;
kinematicModel <word>;
kabs <scalar>;
kl <scalar>;
max <scalar>;
thickness <PatchFunction1<scalar>>;
rhoS <scalar>;
// Optional entries
dfldp <scalarField>;
mass <scalarField>;
pName <word>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: speciesSorption | word | yes | -
equilibriumModel | Equilibrium model | word | yes | -
kinematicModel | Kinematic model | word | yes | -
kabs | Adsorption rate constant [1/s] | scalar | yes | -
kl | Langmuir constant [1/Pa] | scalar | yes | -
max | Maximum concentation at wall [mol/kg] | scalar | yes | -
thickness| Solid thickness along the patch <!--
--> | PatchFunction1\<scalar\> | yes | -
rhoS | Solid density | scalar | yes | -
dfldp | Source on cells next to patch | scalarField | no | Zero
mass | Absorbed mass per kg of absorbent [mol/kg] <!--
--> | scalarField | no | Zero
pName | Name of operand pressure field | word | no | p
\endtable
Options for the \c equilibriumModel entry:
\verbatim
Langmuir | Langmuir model
\endverbatim
Options for the \c kinematicModel entry:
\verbatim
PseudoFirstOrder | Pseudo first-order model
\endverbatim
The inherited entries are elaborated in:
- \link zeroGradientFvPatchFields.H \endlink
- \link PatchFunction1.H \endlink
SourceFiles
speciesSorptionFvPatchScalarField.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_speciesSorptionFvPatchScalarField_H
#define Foam_speciesSorptionFvPatchScalarField_H
#include "boundarySourcePatch.H"
#include "zeroGradientFvPatchFields.H"
#include "PatchFunction1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class speciesSorptionFvPatchScalarField Declaration
\*---------------------------------------------------------------------------*/
class speciesSorptionFvPatchScalarField
:
public zeroGradientFvPatchField<scalar>,
public boundarySourcePatch
{
public:
// Public Enumeration
//- Options for the equilibrum model
enum equilibriumModelType : char
{
LANGMUIR = 0
};
//- Options for the kinematic model
enum kineticModelType : char
{
PseudoFirstOrder = 0
};
//- Names for equilibriumModelType
static const Enum<equilibriumModelType> equilibriumModelTypeNames;
//- Names for kineticModelType
static const Enum<kineticModelType> kinematicModelTypeNames;
private:
// Private Data
//- Equilibrium model
enum equilibriumModelType equilibriumModel_;
//- Kinematic model
enum kineticModelType kinematicModel_;
//- Solid thickness along the patch
autoPtr<PatchFunction1<scalar>> thicknessPtr_;
//- Adsorption rate constant [1/sec]
scalar kabs_;
//- Langmuir adsorption constant [1/Pa]
scalar kl_;
//- Maximum density on patch [mol/kg]
scalar max_;
//- Solid density
scalar rhoS_;
//- Name of operand pressure field
word pName_;
//- Source on cells next to patch [mol/kg/sec]
scalarField dfldp_;
//- Absorbed mass per kg of absorbent [mol/kg]
scalarField mass_;
// Private Member Functions
//- Calculate the mole fraction fields
tmp<scalarField> calcMoleFractions() const;
//- Lookup (or create) field for output
volScalarField& field(const word&, const dimensionSet&) const;
public:
//- Runtime type information
TypeName("speciesSorption");
// Constructors
//- Construct from patch and internal field
speciesSorptionFvPatchScalarField
(
const fvPatch&,
const DimensionedField<scalar, volMesh>&
);
//- Construct from patch, internal field and dictionary
speciesSorptionFvPatchScalarField
(
const fvPatch&,
const DimensionedField<scalar, volMesh>&,
const dictionary&
);
//- Construct by mapping given
//- speciesSorptionFvPatchScalarField onto a new patch
speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField&,
const fvPatch&,
const DimensionedField<scalar, volMesh>&,
const fvPatchFieldMapper&
);
//- Construct as copy
speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField&
);
//- Construct and return a clone
virtual tmp<fvPatchScalarField> clone() const
{
return tmp<fvPatchScalarField>
(
new speciesSorptionFvPatchScalarField(*this)
);
}
//- Construct as copy setting internal field reference
speciesSorptionFvPatchScalarField
(
const speciesSorptionFvPatchScalarField&,
const DimensionedField<scalar, volMesh>&
);
//- Construct and return a clone setting internal field reference
virtual tmp<fvPatchScalarField> clone
(
const DimensionedField<scalar, volMesh>& iF
) const
{
return tmp<fvPatchScalarField>
(
new speciesSorptionFvPatchScalarField(*this, iF)
);
}
// Member Functions
// Mapping
//- Map (and resize as needed) from self given a mapping object
virtual void autoMap
(
const fvPatchFieldMapper&
);
//- Reverse map the given fvPatchField onto this fvPatchField
virtual void rmap
(
const fvPatchScalarField&,
const labelList&
);
// Evaluation
//- Source of cells next to the patch
virtual tmp<scalarField> patchSource() const;
//- Access to mass
tmp<scalarField> mass() const;
//- Update the coefficients associated with the patch field
virtual void updateCoeffs();
// I-O
//- Write
virtual void write(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //