diff --git a/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.C b/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.C index 082588d127..7838e12c3f 100644 --- a/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.C +++ b/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2020-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +29,7 @@ License #include "outletMappedUniformInletFvPatchField.H" #include "volFields.H" #include "surfaceFields.H" +#include "interpolateXY.H" // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -41,10 +42,15 @@ outletMappedUniformInletFvPatchField ) : fixedValueFvPatchField(p, iF), - outletPatchName_(), + uniformValuePtr_(nullptr), + outletNames_(), + offsets_(), + fractions_(), + timeDelays_(), + mapFields_(), + mapTimes_(), phiName_("phi"), - fraction_(1), - offset_(Zero) + curTimeIndex_(-1) {} @@ -58,11 +64,122 @@ outletMappedUniformInletFvPatchField ) : fixedValueFvPatchField(p, iF, dict), - outletPatchName_(dict.get("outletPatch")), + uniformValuePtr_ + ( + PatchFunction1::NewIfPresent + ( + p.patch(), + "uniformValue", + dict + ) + ), + outletNames_(), + offsets_(), + fractions_(), + timeDelays_(), + mapFields_(), + mapTimes_(), phiName_(dict.getOrDefault("phi", "phi")), - fraction_(dict.getOrDefault("fraction", 1)), - offset_(dict.getOrDefault("offset", Zero)) -{} + 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 (dict.found("value")) + { + fvPatchField::operator= + ( + Field("value", dict, p.size()) + ); + } + else + { + fvPatchField::operator=(this->patchInternalField()); + } +} template @@ -76,11 +193,26 @@ outletMappedUniformInletFvPatchField ) : fixedValueFvPatchField(ptf, p, iF, mapper), - outletPatchName_(ptf.outletPatchName_), + 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_), - fraction_(ptf.fraction_), - offset_(ptf.offset_) -{} + curTimeIndex_(-1) +{ + if (mapper.direct() && !mapper.hasUnmapped()) + { + // Use mapping instead of re-evaluation + this->map(ptf, mapper); + } + else + { + fvPatchField::operator=(this->patchInternalField()); + } +} template @@ -91,10 +223,15 @@ outletMappedUniformInletFvPatchField ) : fixedValueFvPatchField(ptf), - outletPatchName_(ptf.outletPatchName_), + 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_), - fraction_(ptf.fraction_), - offset_(ptf.offset_) + curTimeIndex_(-1) {} @@ -107,15 +244,54 @@ outletMappedUniformInletFvPatchField ) : fixedValueFvPatchField(ptf, iF), - outletPatchName_(ptf.outletPatchName_), + 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_), - fraction_(ptf.fraction_), - offset_(ptf.offset_) + 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() { @@ -124,53 +300,125 @@ void Foam::outletMappedUniformInletFvPatchField::updateCoeffs() return; } - const GeometricField& f - ( - dynamic_cast&> + if (curTimeIndex_ != this->db().time().timeIndex()) + { + const scalar t = this->db().time().timeOutputValue(); + + const GeometricField& f ( - this->internalField() - ) - ); + dynamic_cast&> + ( + this->internalField() + ) + ); - const fvPatch& p = this->patch(); - const label outletPatchID = - p.patch().boundaryMesh().findPatchID(outletPatchName_); + const fvPatch& p = this->patch(); - if (outletPatchID < 0) - { - FatalErrorInFunction - << "Unable to find outlet patch " << outletPatchName_ - << abort(FatalError); + 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 + ( + gSum(outlet.magSf()*outletFld)/gSum(outlet.magSf()) + ); + } + } + + + // 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(); } - const fvPatch& outletPatch = p.boundaryMesh()[outletPatchID]; - - const fvPatchField& outletPatchField = - f.boundaryField()[outletPatchID]; - - const auto& phi = - this->db().objectRegistry::template lookupObject - (phiName_); - - const scalarField& outletPatchPhi = phi.boundaryField()[outletPatchID]; - const scalar sumOutletPatchPhi = gSum(outletPatchPhi); - - if (sumOutletPatchPhi > SMALL) - { - Type averageOutletField = - gSum(outletPatchPhi*outletPatchField) - /sumOutletPatchPhi; - - this->operator==(averageOutletField*fraction_ + offset_); - } - else - { - Type averageOutletField = - gSum(outletPatch.magSf()*outletPatchField) - /gSum(outletPatch.magSf()); - - this->operator==(averageOutletField); - } fixedValueFvPatchField::updateCoeffs(); } @@ -180,10 +428,40 @@ template void Foam::outletMappedUniformInletFvPatchField::write(Ostream& os) const { fvPatchField::write(os); - os.writeEntry("outletPatch", outletPatchName_); + + 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_); - os.writeEntry("fraction", fraction_); - os.writeEntry("offset", offset_); + this->writeEntry("value", os); } diff --git a/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.H b/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.H index 0b586c771c..53b98b9149 100644 --- a/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.H +++ b/src/finiteVolume/fields/fvPatchFields/derived/outletMappedUniformInlet/outletMappedUniformInletFvPatchField.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2018 OpenFOAM Foundation - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2020-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,15 +32,17 @@ Group Description The \c outletMappedUniformInlet is an inlet boundary condition that - - averages the patch field of \ over a specified "outlet" patch + - averages patch fields of specified "outlet" patches and uniformly applies the averaged value over a specified inlet patch. - optionally, the averaged value can be scaled - and/or offset by a pair of specified values. + and/or offset by a specified value, + and/or mapped by a specified time delay. The governing equation of the boundary condition is: \f[ - \phi_{inlet} = f \phi_{outlet} + \phi_{offset} + \phi_{inlet} = + \sum_i \left( f_i \phi_{{outlet}_i} + \phi_{{offset}_i} \right) \f] where @@ -49,6 +51,7 @@ Description \phi_{outlet} | Averaged patch-field value at an outlet patch f | User-defined fraction value \phi_{offset} | User-defined offset value + i | Outlet-patch index \endvartable Usage @@ -56,32 +59,55 @@ Usage \verbatim { - // Mandatory entries (unmodifiable) - type outletMappedFilterInlet; - outletPatch ; + // Mandatory entries + type outletMappedUniformInlet; - // Optional entries (unmodifiable) - fraction 0.1; - offset 10; // (1 0 0); + outlets + { + + { + fraction >; + offset >; + timeDelay >; + } + + { + fraction >; + offset >; + timeDelay >; + } + ... + } + + // Optional entries + uniformValue >; phi phi; - // Optional (inherited) entries + // Inherited entries ... } \endverbatim where the entries mean: \table - Property | Description | Type | Reqd | Dflt + Property | Description | Type | Reqd | Deflt type | Type name: outletMappedUniformInlet | word | yes | - - outletPatch | Name of patch to be mapped | word | yes | - - fraction | Fraction value | scalar | no | 1 - offset | Offset value | Type | no | Zero + outlets | Dictionary name: outlets | dict | yes | - + fraction | Fraction value | Function1\ | no | 1 + offset | Offset value | Function1\ | no | Zero + timeDelay | Time delay | Function1\ | no | 0 + uniformValue | Base inlet patch field | PatchFunction1\ | no | Zero phi | Name of operand flux field | word | no | phi \endtable The inherited entries are elaborated in: - \link fixedValueFvPatchFields.H \endlink + - \link PatchFunction1.H \endlink + - \link Function1.H \endlink + +Note + - Any negative input of \c timeDelay entry + is forced to be zero without emitting any warnings. See also - Foam::fixedValueFvPatchField @@ -98,6 +124,7 @@ SourceFiles #define outletMappedUniformInletFvPatchField_H #include "fixedValueFvPatchFields.H" +#include "PatchFunction1.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -115,17 +142,32 @@ class outletMappedUniformInletFvPatchField { // Private Data - //- Name of the outlet patch to be mapped - word outletPatchName_; + //- Base inlet patch field + autoPtr> uniformValuePtr_; - //- Name of operand flux field + //- List of outlet-patch names + wordList outletNames_; + + //- List of outlet-patch field offsets + PtrList> offsets_; + + //- List of outlet-patch field fractions + PtrList> fractions_; + + //- List of outlet-patch field time delays + PtrList> timeDelays_; + + //- List of outlet-patch mapping fields + List> mapFields_; + + //- List of outlet-patch mapping times + List> mapTimes_; + + //- Name of operand flux field word phiName_; - //- Fraction value - scalar fraction_; - - //- Offset value - Type offset_; + //- Current time index + label curTimeIndex_; public: @@ -198,13 +240,20 @@ public: // Member Functions - // Access + // Mapping - //- Name of the outlet patch to be mapped - const word& outletPatchName() const - { - return outletPatchName_; - } + //- 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 fvPatchField&, + const labelList& + ); // Evaluation