/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020-2025 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 .
\*---------------------------------------------------------------------------*/
#include "outletMappedUniformInletFvPatchField.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "interpolateXY.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::outletMappedUniformInletFvPatchField::
outletMappedUniformInletFvPatchField
(
const fvPatch& p,
const DimensionedField& iF
)
:
fixedValueFvPatchField(p, iF),
uniformValuePtr_(nullptr),
outletNames_(),
offsets_(),
fractions_(),
timeDelays_(),
mapFields_(),
mapTimes_(),
phiName_("phi"),
curTimeIndex_(-1)
{}
template
Foam::outletMappedUniformInletFvPatchField::
outletMappedUniformInletFvPatchField
(
const fvPatch& p,
const DimensionedField& iF,
const dictionary& dict
)
:
fixedValueFvPatchField(p, iF, dict),
uniformValuePtr_
(
PatchFunction1::NewIfPresent
(
p.patch(),
"uniformValue",
dict
)
),
outletNames_(),
offsets_(),
fractions_(),
timeDelays_(),
mapFields_(),
mapTimes_(),
phiName_(dict.getOrDefault("phi", "phi")),
curTimeIndex_(-1)
{
const dictionary& outletDict = dict.subDict("outlets");
if (outletDict.empty())
{
FatalIOErrorInFunction(outletDict)
<< "outlets dictionary is empty."
<< exit(FatalIOError);
}
outletNames_.setSize(outletDict.size());
offsets_.setSize(outletDict.size());
fractions_.setSize(outletDict.size());
timeDelays_.setSize(outletDict.size());
mapFields_.setSize(outletDict.size());
mapTimes_.setSize(outletDict.size());
label outleti = 0;
for (const entry& dEntry : outletDict)
{
const word& key = dEntry.keyword();
if (!dEntry.isDict())
{
FatalIOErrorInFunction(outletDict)
<< "Entry " << key << " is not a dictionary." << nl
<< exit(FatalIOError);
}
const dictionary& subDict = dEntry.dict();
outletNames_[outleti] = key;
offsets_.set
(
outleti,
Function1::NewIfPresent
(
"offset",
subDict,
word::null,
&this->db()
)
);
fractions_.set
(
outleti,
Function1::NewIfPresent
(
"fraction",
subDict,
word::null,
&this->db()
)
);
timeDelays_.set
(
outleti,
Function1::NewIfPresent
(
"timeDelay",
subDict,
word::null,
&this->db()
)
);
mapFields_[outleti] =
subDict.getOrDefault>
(
"mapField",
DynamicList()
);
mapTimes_[outleti] =
subDict.getOrDefault>
(
"mapTime",
DynamicList()
);
++outleti;
}
if (!this->readValueEntry(dict))
{
// Fallback: set to the internal field
this->extrapolateInternal();
}
}
template
Foam::outletMappedUniformInletFvPatchField::
outletMappedUniformInletFvPatchField
(
const outletMappedUniformInletFvPatchField& ptf,
const fvPatch& p,
const DimensionedField& iF,
const fvPatchFieldMapper& mapper
)
:
fixedValueFvPatchField(ptf, p, iF, mapper),
uniformValuePtr_(ptf.uniformValuePtr_.clone(p.patch())),
outletNames_(ptf.outletNames_),
offsets_(ptf.offsets_),
fractions_(ptf.fractions_),
timeDelays_(ptf.timeDelays_),
mapFields_(ptf.mapFields_),
mapTimes_(ptf.mapTimes_),
phiName_(ptf.phiName_),
curTimeIndex_(-1)
{
if (mapper.direct() && !mapper.hasUnmapped())
{
// Use mapping instead of re-evaluation
this->map(ptf, mapper);
}
else
{
// Fallback: set to the internal field
this->extrapolateInternal();
}
}
template
Foam::outletMappedUniformInletFvPatchField::
outletMappedUniformInletFvPatchField
(
const outletMappedUniformInletFvPatchField& ptf
)
:
fixedValueFvPatchField(ptf),
uniformValuePtr_(ptf.uniformValuePtr_.clone(this->patch().patch())),
outletNames_(ptf.outletNames_),
offsets_(ptf.offsets_),
fractions_(ptf.fractions_),
timeDelays_(ptf.timeDelays_),
mapFields_(ptf.mapFields_),
mapTimes_(ptf.mapTimes_),
phiName_(ptf.phiName_),
curTimeIndex_(-1)
{}
template
Foam::outletMappedUniformInletFvPatchField::
outletMappedUniformInletFvPatchField
(
const outletMappedUniformInletFvPatchField& ptf,
const DimensionedField& iF
)
:
fixedValueFvPatchField(ptf, iF),
uniformValuePtr_(ptf.uniformValuePtr_.clone(this->patch().patch())),
outletNames_(ptf.outletNames_),
offsets_(ptf.offsets_),
fractions_(ptf.fractions_),
timeDelays_(ptf.timeDelays_),
mapFields_(ptf.mapFields_),
mapTimes_(ptf.mapTimes_),
phiName_(ptf.phiName_),
curTimeIndex_(-1)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template
void Foam::outletMappedUniformInletFvPatchField::autoMap
(
const fvPatchFieldMapper& m
)
{
fixedValueFvPatchField::autoMap(m);
if (uniformValuePtr_)
{
uniformValuePtr_->autoMap(m);
}
}
template
void Foam::outletMappedUniformInletFvPatchField::rmap
(
const fvPatchField& ptf,
const labelList& addr
)
{
fixedValueFvPatchField::rmap(ptf, addr);
const auto& tiptf =
refCast(ptf);
if (uniformValuePtr_)
{
uniformValuePtr_->rmap(tiptf.uniformValuePtr_(), addr);
}
}
template
void Foam::outletMappedUniformInletFvPatchField::updateCoeffs()
{
if (this->updated())
{
return;
}
if (curTimeIndex_ != this->db().time().timeIndex())
{
const scalar t = this->db().time().timeOutputValue();
const GeometricField& f
(
dynamic_cast&>
(
this->internalField()
)
);
const fvPatch& p = this->patch();
forAll(outletNames_, i)
{
const word& outletName = outletNames_[i];
const label outletID =
p.patch().boundaryMesh().findPatchID(outletName);
if (outletID < 0)
{
FatalErrorInFunction
<< "Unable to find outlet patch " << outletName
<< abort(FatalError);
}
// Collect the map time for this outlet patch
DynamicList& mapTime = mapTimes_[i];
scalar timeDelay = 0;
if (timeDelays_.set(i))
{
timeDelay = max(timeDelays_[i].value(t), scalar(0));
}
mapTime.append(t + timeDelay);
// Collect the map field for this outlet patch and map time
const fvPatchField& outletFld = f.boundaryField()[outletID];
DynamicList& mapField = mapFields_[i];
const auto& phi =
this->db().objectRegistry::template
lookupObject(phiName_);
const scalarField& outletPhi = phi.boundaryField()[outletID];
const scalar sumOutletPhi = gSum(outletPhi);
if (sumOutletPhi > SMALL)
{
Type offset(Zero);
if (offsets_.set(i))
{
offset = offsets_[i].value(t);
}
scalar fraction = 1;
if (fractions_.set(i))
{
fraction = fractions_[i].value(t);
}
mapField.append
(
gSum(outletPhi*outletFld)/sumOutletPhi*fraction
+ offset
);
}
else
{
const fvPatch& outlet = p.boundaryMesh()[outletID];
mapField.append
(
gWeightedAverage(outlet.magSf(), outletFld)
);
}
}
// Map the stored fields onto inlet if the time condition is met
Type inletFld(Zero);
forAll(outletNames_, i)
{
DynamicList& mapTime = mapTimes_[i];
DynamicList& mapField = mapFields_[i];
if (!mapTime.empty())
{
if (t >= mapTime.first())
{
inletFld += interpolateXY(t, mapTime, mapField);
// Remove any stored fields and times if possible
int i = 0;
while (!mapTime.empty() && t >= mapTime[i])
{
mapTime.remove(i);
mapField.remove(i);
++i;
}
}
}
}
if (uniformValuePtr_)
{
this->operator==(inletFld + uniformValuePtr_->value(t));
}
else
{
this->operator==(inletFld);
}
curTimeIndex_ = this->db().time().timeIndex();
}
fixedValueFvPatchField::updateCoeffs();
}
template
void Foam::outletMappedUniformInletFvPatchField::write(Ostream& os) const
{
fvPatchField::write(os);
if (uniformValuePtr_)
{
uniformValuePtr_->writeData(os);
}
os.beginBlock("outlets");
forAll(outletNames_, i)
{
os.beginBlock(outletNames_[i]);
if (offsets_.set(i))
{
offsets_[i].writeData(os);
}
if (fractions_.set(i))
{
fractions_[i].writeData(os);
}
if (timeDelays_.set(i))
{
timeDelays_[i].writeData(os);
}
if (!mapFields_.empty())
{
mapFields_[i].writeEntry("mapField", os);
}
if (!mapTimes_.empty())
{
mapTimes_[i].writeEntry("mapTime", os);
}
os.endBlock();
}
os.endBlock();
os.writeEntryIfDifferent("phi", "phi", phiName_);
fvPatchField::writeValueEntry(os);
}
// ************************************************************************* //