ENH: cyclicACMI: optional scaling with PatchFunction1.

Added 'scale' parameter to cyclicACMI. Scales the amount of 'coupledness' (= mask). Allows opening/closing without mesh motion.
This commit is contained in:
Mattijs Janssens 2020-12-11 10:35:06 +00:00 committed by Andrew Heather
parent 6ac8e06245
commit 31ecf0d732
20 changed files with 1499 additions and 162 deletions

View File

@ -43,6 +43,43 @@ namespace Foam
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
bool Foam::cyclicACMIFvPatch::updateAreas() const
{
// Give AMI chance to update itself
bool updated = cyclicACMIPolyPatch_.updateAreas();
if (!cyclicACMIPolyPatch_.owner())
{
return updated;
}
if (updated || !cyclicACMIPolyPatch_.upToDate(areaTime_))
{
if (debug)
{
Pout<< "cyclicACMIFvPatch::updateAreas() : updating fv areas for "
<< name() << " and " << this->nonOverlapPatch().name()
<< endl;
}
const fvPatch& nonOverlapPatch = this->nonOverlapPatch();
const cyclicACMIFvPatch& nbrACMI = neighbPatch();
const fvPatch& nbrNonOverlapPatch = nbrACMI.nonOverlapPatch();
resetPatchAreas(*this);
resetPatchAreas(nonOverlapPatch);
resetPatchAreas(nbrACMI);
resetPatchAreas(nbrNonOverlapPatch);
updated = true;
// Mark my data to be up to date with ACMI polyPatch level
cyclicACMIPolyPatch_.setUpToDate(areaTime_);
}
return updated;
}
void Foam::cyclicACMIFvPatch::resetPatchAreas(const fvPatch& fvp) const
{
const_cast<vectorField&>(fvp.Sf()) = fvp.patch().faceAreas();
@ -100,6 +137,35 @@ void Foam::cyclicACMIFvPatch::makeWeights(scalarField& w) const
}
// * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
Foam::cyclicACMIFvPatch::cyclicACMIFvPatch
(
const polyPatch& patch,
const fvBoundaryMesh& bm
)
:
coupledFvPatch(patch, bm),
cyclicACMILduInterface(),
cyclicACMIPolyPatch_(refCast<const cyclicACMIPolyPatch>(patch)),
areaTime_
(
IOobject
(
"areaTime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
)
{
areaTime_.eventNo() = -1;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::cyclicACMIFvPatch::coupled() const
@ -178,91 +244,103 @@ void Foam::cyclicACMIFvPatch::movePoints()
return;
}
// Set the patch face areas to be consistent with the changes made at the
// polyPatch level
const fvPatch& nonOverlapPatch = this->nonOverlapPatch();
const cyclicACMIFvPatch& nbrACMI = neighbPatch();
const fvPatch& nbrNonOverlapPatch = nbrACMI.nonOverlapPatch();
resetPatchAreas(*this);
resetPatchAreas(nonOverlapPatch);
resetPatchAreas(nbrACMI);
resetPatchAreas(nbrNonOverlapPatch);
// Scale the mesh flux
const labelListList& newSrcAddr = AMI().srcAddress();
const labelListList& newTgtAddr = AMI().tgtAddress();
const fvMesh& mesh = boundaryMesh().mesh();
surfaceScalarField& meshPhi = const_cast<fvMesh&>(mesh).setPhi();
surfaceScalarField::Boundary& meshPhiBf = meshPhi.boundaryFieldRef();
// Note: phip and phiNonOverlapp will be different sizes if new faces
// have been added
scalarField& phip = meshPhiBf[cyclicACMIPolyPatch_.index()];
scalarField& phiNonOverlapp =
meshPhiBf[nonOverlapPatch.patch().index()];
const auto& localFaces = cyclicACMIPolyPatch_.localFaces();
const auto& localPoints = cyclicACMIPolyPatch_.localPoints();
forAll(phip, facei)
if (!cyclicACMIPolyPatch_.upToDate(areaTime_))
{
if (newSrcAddr[facei].empty())
if (debug)
{
// AMI patch with no connection to other coupled faces
phip[facei] = 0.0;
Pout<< "cyclicACMIFvPatch::movePoints() : updating fv areas for "
<< name() << " and " << this->nonOverlapPatch().name()
<< endl;
}
else
// Set the patch face areas to be consistent with the changes made
// at the polyPatch level
const fvPatch& nonOverlapPatch = this->nonOverlapPatch();
const cyclicACMIFvPatch& nbrACMI = neighbPatch();
const fvPatch& nbrNonOverlapPatch = nbrACMI.nonOverlapPatch();
resetPatchAreas(*this);
resetPatchAreas(nonOverlapPatch);
resetPatchAreas(nbrACMI);
resetPatchAreas(nbrNonOverlapPatch);
// Scale the mesh flux
const labelListList& newSrcAddr = AMI().srcAddress();
const labelListList& newTgtAddr = AMI().tgtAddress();
const fvMesh& mesh = boundaryMesh().mesh();
surfaceScalarField& meshPhi = const_cast<fvMesh&>(mesh).setPhi();
surfaceScalarField::Boundary& meshPhiBf = meshPhi.boundaryFieldRef();
// Note: phip and phiNonOverlap will be different sizes if new faces
// have been added
scalarField& phip = meshPhiBf[cyclicACMIPolyPatch_.index()];
scalarField& phiNonOverlapp =
meshPhiBf[nonOverlapPatch.patch().index()];
const auto& points = mesh.points();
forAll(phip, facei)
{
// Scale the mesh flux according to the area fraction
const face& fAMI = localFaces[facei];
if (newSrcAddr[facei].empty())
{
// AMI patch with no connection to other coupled faces
phip[facei] = 0.0;
}
else
{
// Scale the mesh flux according to the area fraction
const face& fAMI = cyclicACMIPolyPatch_[facei];
// Note: using raw point locations to calculate the geometric
// area - faces areas are currently scaled (decoupled from
// mesh points)
const scalar geomArea = fAMI.mag(localPoints);
phip[facei] *= magSf()[facei]/geomArea;
// Note: using raw point locations to calculate the geometric
// area - faces areas are currently scaled (decoupled from
// mesh points)
const scalar geomArea = fAMI.mag(points);
phip[facei] *= magSf()[facei]/geomArea;
}
}
}
forAll(phiNonOverlapp, facei)
{
const scalar w = 1.0 - cyclicACMIPolyPatch_.srcMask()[facei];
phiNonOverlapp[facei] *= w;
}
scalarField& nbrPhip = meshPhiBf[nbrACMI.patch().index()];
scalarField& nbrPhiNonOverlapp =
meshPhiBf[nbrNonOverlapPatch.patch().index()];
const auto& nbrLocalFaces = nbrACMI.patch().localFaces();
const auto& nbrLocalPoints = nbrACMI.patch().localPoints();
forAll(nbrPhip, facei)
{
if (newTgtAddr[facei].empty())
forAll(phiNonOverlapp, facei)
{
nbrPhip[facei] = 0.0;
const scalar w = 1.0 - cyclicACMIPolyPatch_.srcMask()[facei];
phiNonOverlapp[facei] *= w;
}
else
const cyclicACMIPolyPatch& nbrPatch = nbrACMI.cyclicACMIPatch();
scalarField& nbrPhip = meshPhiBf[nbrPatch.index()];
scalarField& nbrPhiNonOverlapp =
meshPhiBf[nbrNonOverlapPatch.patch().index()];
forAll(nbrPhip, facei)
{
const face& fAMI = nbrLocalFaces[facei];
if (newTgtAddr[facei].empty())
{
nbrPhip[facei] = 0.0;
}
else
{
const face& fAMI = nbrPatch[facei];
// Note: using raw point locations to calculate the geometric
// area - faces areas are currently scaled (decoupled from
// mesh points)
const scalar geomArea = fAMI.mag(nbrLocalPoints);
nbrPhip[facei] *= nbrACMI.magSf()[facei]/geomArea;
// Note: using raw point locations to calculate the geometric
// area - faces areas are currently scaled (decoupled from
// mesh points)
const scalar geomArea = fAMI.mag(points);
nbrPhip[facei] *= nbrACMI.magSf()[facei]/geomArea;
}
}
}
forAll(nbrPhiNonOverlapp, facei)
{
const scalar w = 1.0 - cyclicACMIPolyPatch_.tgtMask()[facei];
nbrPhiNonOverlapp[facei] *= w;
forAll(nbrPhiNonOverlapp, facei)
{
const scalar w = 1.0 - cyclicACMIPolyPatch_.tgtMask()[facei];
nbrPhiNonOverlapp[facei] *= w;
}
// Mark my data to be up to date with ACMI polyPatch level
cyclicACMIPolyPatch_.setUpToDate(areaTime_);
}
}

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2013-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -60,11 +61,18 @@ class cyclicACMIFvPatch
const cyclicACMIPolyPatch& cyclicACMIPolyPatch_;
//- Flag to detect whether AMI is up to date with mesh points
mutable uniformDimensionedScalarField areaTime_;
protected:
// Protected Member functions
//- Update the AMI and patch areas. Return true if anything updated
virtual bool updateAreas() const;
//- Helper function to reset the FV patch areas from the primitive patch
void resetPatchAreas(const fvPatch& fvp) const;
@ -84,12 +92,7 @@ public:
// Constructors
//- Construct from polyPatch
cyclicACMIFvPatch(const polyPatch& patch, const fvBoundaryMesh& bm)
:
coupledFvPatch(patch, bm),
cyclicACMILduInterface(),
cyclicACMIPolyPatch_(refCast<const cyclicACMIPolyPatch>(patch))
{}
cyclicACMIFvPatch(const polyPatch& patch, const fvBoundaryMesh& bm);
// Member functions
@ -181,6 +184,9 @@ public:
const Field<Type>& fld
) const
{
// Make sure areas are up-to-date
updateAreas();
return
cyclicACMIPolyPatch_.cyclicAMIPolyPatch::interpolate
(

View File

@ -43,6 +43,117 @@ namespace Foam
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
bool Foam::cyclicACMIPolyPatch::updateAreas() const
{
const polyMesh& mesh = boundaryMesh().mesh();
bool updated = false;
if (!owner())
{
return updated;
}
// Check if underlying AMI up to date
if (!mesh.upToDatePoints(AMITime_))
{
// This should not happen normally since resetAMI is triggered
// by any point motion.
FatalErrorInFunction << "Problem : AMI is up to event:"
<< AMITime_.eventNo()
<< " mesh points are up to time " << mesh.pointsInstance()
<< " patch:" << this->name()
<< exit(FatalError);
}
// Check if scaling enabled (and necessary)
if
(
srcScalePtr_.valid()
&& (updated || prevTimeIndex_ != mesh.time().timeIndex())
)
{
if (debug)
{
Pout<< "cyclicACMIPolyPatch::updateAreas() :"
<< " patch:" << this->name()
<< " neighbPatch:" << this->neighbPatch().name()
<< " AMITime_:" << AMITime_.eventNo()
<< " uptodate:" << mesh.upToDatePoints(AMITime_)
<< " mesh.time().timeIndex():" << mesh.time().timeIndex()
<< " prevTimeIndex_:" << prevTimeIndex_
<< endl;
}
if (createAMIFaces_)
{
WarningInFunction
<< "Topology changes and scaling currently not supported."
<< " Patch " << this->name() << endl;
}
const scalar t = mesh.time().timeOutputValue();
// Note: ideally preserve src/tgtMask before clipping to tolerance ...
srcScaledMask_ =
min
(
scalar(1) - tolerance_,
max(tolerance_, srcScalePtr_->value(t)*srcMask_)
);
if (!tgtScalePtr_.valid())
{
tgtScalePtr_= srcScalePtr_.clone(neighbPatch());
}
tgtScaledMask_ =
min
(
scalar(1) - tolerance_,
max(tolerance_, tgtScalePtr_->value(t)*tgtMask_)
);
if (debug)
{
Pout<< "cyclicACMIPolyPatch::updateAreas : scaling masks"
<< " for " << name() << " mask " << gAverage(srcScaledMask_)
<< " and " << nonOverlapPatch().name()
<< " mask " << gAverage(srcScaledMask_) << endl;
}
// Calculate areas from the masks
cyclicACMIPolyPatch& cpp = const_cast<cyclicACMIPolyPatch&>(*this);
const cyclicACMIPolyPatch& nbrCpp = neighbPatch();
cpp.scalePatchFaceAreas(*this, srcScaledMask_, thisSf_, thisNoSf_);
cpp.scalePatchFaceAreas(nbrCpp, tgtScaledMask_, nbrSf_, nbrNoSf_);
prevTimeIndex_ = mesh.time().timeIndex();
AMITime_.setUpToDate();
updated = true;
}
return updated;
}
bool Foam::cyclicACMIPolyPatch::upToDate(const regIOobject& io) const
{
// Is io up to date with
// - underlying AMI
// - scaling
return io.upToDate(AMITime_);
}
void Foam::cyclicACMIPolyPatch::setUpToDate(regIOobject& io) const
{
io.setUpToDate();
}
void Foam::cyclicACMIPolyPatch::reportCoverage
(
const word& name,
@ -72,6 +183,85 @@ void Foam::cyclicACMIPolyPatch::reportCoverage
}
void Foam::cyclicACMIPolyPatch::scalePatchFaceAreas
(
const cyclicACMIPolyPatch& acmipp,
const scalarField& mask, // srcMask_
const vectorList& faceArea, // this->faceAreas();
const vectorList& noFaceArea // nonOverlapPatch.faceAreas()
)
{
// Primitive patch face areas have been cleared/reset based on the raw
// points - need to reset to avoid double-accounting of face areas
const scalar maxTol = scalar(1) - tolerance_;
const polyPatch& nonOverlapPatch = acmipp.nonOverlapPatch();
vectorField::subField noSf = nonOverlapPatch.faceAreas();
DebugPout
<< "rescaling non-overlap patch areas for: "
<< nonOverlapPatch.name() << endl;
if (mask.size() != noSf.size())
{
WarningInFunction
<< "Inconsistent sizes for patch: " << acmipp.name()
<< " - not manipulating patches" << nl
<< " - size: " << size() << nl
<< " - non-overlap patch size: " << noSf.size() << nl
<< " - mask size: " << mask.size() << nl
<< "This is OK for decomposition but"
<< " should be considered fatal at run-time" << endl;
return;
}
forAll(noSf, facei)
{
const scalar w = min(maxTol, max(tolerance_, mask[facei]));
noSf[facei] = noFaceArea[facei]*(scalar(1) - w);
}
if (!createAMIFaces_)
{
// Note: for topological update (createAMIFaces_ = true)
// AMI coupled patch face areas are updated as part of the topological
// updates, e.g. by the calls to cyclicAMIPolyPatch's setTopology and
// initMovePoints
DebugPout
<< "scaling coupled patch areas for: " << acmipp.name() << endl;
// Scale the coupled patch face areas
vectorField::subField Sf = acmipp.faceAreas();
forAll(Sf, facei)
{
Sf[facei] = faceArea[facei]*max(tolerance_, mask[facei]);
}
// Re-normalise the weights since the effect of overlap is already
// accounted for in the area
auto& weights = const_cast<scalarListList&>(acmipp.weights());
auto& weightsSum = const_cast<scalarField&>(acmipp.weightsSum());
forAll(weights, i)
{
scalarList& wghts = weights[i];
if (wghts.size())
{
scalar& sum = weightsSum[i];
forAll(wghts, j)
{
wghts[j] /= sum;
}
sum = 1.0;
}
}
}
}
void Foam::cyclicACMIPolyPatch::resetAMI() const
{
resetAMI(boundaryMesh().mesh().points());
@ -164,86 +354,37 @@ void Foam::cyclicACMIPolyPatch::scalePatchFaceAreas()
return;
}
scalePatchFaceAreas(*this);
scalePatchFaceAreas(this->neighbPatch());
}
const polyPatch& nonOverlapPatch = this->nonOverlapPatch();
const cyclicACMIPolyPatch& nbrPatch = this->neighbPatch();
const polyPatch& nbrNonOverlapPatch = nbrPatch.nonOverlapPatch();
void Foam::cyclicACMIPolyPatch::scalePatchFaceAreas
(
const cyclicACMIPolyPatch& acmipp
)
{
// Primitive patch face areas have been cleared/reset based on the raw
// points - need to reset to avoid double-accounting of face areas
const scalar maxTol = scalar(1) - tolerance_;
const scalarField& mask = acmipp.mask();
const polyPatch& nonOverlapPatch = acmipp.nonOverlapPatch();
vectorField::subField noSf = nonOverlapPatch.faceAreas();
DebugPout
<< "rescaling non-overlap patch areas for: " << nonOverlapPatch.name()
<< endl;
if (mask.size() != noSf.size())
if (srcScalePtr_.valid())
{
WarningInFunction
<< "Inconsistent sizes for patch: " << acmipp.name()
<< " - not manipulating patches" << nl
<< " - size: " << size() << nl
<< " - non-overlap patch size: " << noSf.size() << nl
<< " - mask size: " << mask.size() << nl
<< "This is OK for decomposition but should be considered fatal "
<< "at run-time" << endl;
return;
// Save overlap geometry for later scaling
thisSf_ = this->faceAreas();
thisNoSf_ = nonOverlapPatch.faceAreas();
nbrSf_ = nbrPatch.faceAreas();
nbrNoSf_ = nbrNonOverlapPatch.faceAreas();
}
forAll(noSf, facei)
{
const scalar w = min(maxTol, max(tolerance_, mask[facei]));
noSf[facei] *= scalar(1) - w;
}
// In-place scale the patch areas
scalePatchFaceAreas
(
*this,
srcMask_, // unscaled mask
this->faceAreas(),
nonOverlapPatch.faceAreas()
);
scalePatchFaceAreas
(
nbrPatch,
tgtMask_, // unscaled mask
nbrPatch.faceAreas(),
nbrNonOverlapPatch.faceAreas()
);
if (!createAMIFaces_)
{
// Note: for topological update (createAMIFaces_ = true)
// AMI coupled patch face areas are updated as part of the topological
// updates, e.g. by the calls to cyclicAMIPolyPatch's setTopology and
// initMovePoints
DebugPout
<< "scaling coupled patch areas for: " << acmipp.name() << endl;
// Scale the coupled patch face areas
vectorField::subField Sf = acmipp.faceAreas();
forAll(Sf, facei)
{
Sf[facei] *= max(tolerance_, mask[facei]);
}
// Re-normalise the weights since the effect of overlap is already
// accounted for in the area
auto& weights = const_cast<scalarListList&>(acmipp.weights());
auto& weightsSum = const_cast<scalarField&>(acmipp.weightsSum());
forAll(weights, i)
{
scalarList& wghts = weights[i];
if (wghts.size())
{
scalar& sum = weightsSum[i];
forAll(wghts, j)
{
wghts[j] /= sum;
}
sum = 1.0;
}
}
}
// Mark current AMI as up to date with points
boundaryMesh().mesh().setUpToDatePoints(AMITime_);
}
@ -328,13 +469,33 @@ void Foam::cyclicACMIPolyPatch::clearGeom()
const Foam::scalarField& Foam::cyclicACMIPolyPatch::srcMask() const
{
return srcMask_;
if (srcScalePtr_.valid())
{
// Make sure areas are up-to-date
updateAreas();
return srcScaledMask_;
}
else
{
return srcMask_;
}
}
const Foam::scalarField& Foam::cyclicACMIPolyPatch::tgtMask() const
{
return tgtMask_;
if (tgtScalePtr_.valid())
{
// Make sure areas are up-to-date
updateAreas();
return tgtScaledMask_;
}
else
{
return tgtMask_;
}
}
@ -366,7 +527,21 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
nonOverlapPatchName_(word::null),
nonOverlapPatchID_(-1),
srcMask_(),
tgtMask_()
tgtMask_(),
AMITime_
(
IOobject
(
"AMITime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
),
prevTimeIndex_(-1)
{
AMIPtr_->setRequireMatch(false);
@ -389,7 +564,27 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
nonOverlapPatchName_(dict.get<word>("nonOverlapPatch")),
nonOverlapPatchID_(-1),
srcMask_(),
tgtMask_()
tgtMask_(),
srcScalePtr_
(
dict.found("scale")
? PatchFunction1<scalar>::New(*this, "scale", dict)
: nullptr
),
AMITime_
(
IOobject
(
"AMITime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
),
prevTimeIndex_(-1)
{
AMIPtr_->setRequireMatch(false);
@ -416,7 +611,27 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
nonOverlapPatchName_(pp.nonOverlapPatchName_),
nonOverlapPatchID_(-1),
srcMask_(),
tgtMask_()
tgtMask_(),
srcScalePtr_
(
pp.srcScalePtr_.valid()
? pp.srcScalePtr_.clone(*this)
: nullptr
),
AMITime_
(
IOobject
(
"AMITime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
),
prevTimeIndex_(-1)
{
AMIPtr_->setRequireMatch(false);
@ -440,7 +655,27 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
nonOverlapPatchName_(nonOverlapPatchName),
nonOverlapPatchID_(-1),
srcMask_(),
tgtMask_()
tgtMask_(),
srcScalePtr_
(
pp.srcScalePtr_.valid()
? pp.srcScalePtr_.clone(*this)
: nullptr
),
AMITime_
(
IOobject
(
"AMITime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
),
prevTimeIndex_(-1)
{
AMIPtr_->setRequireMatch(false);
@ -470,7 +705,27 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
nonOverlapPatchName_(pp.nonOverlapPatchName_),
nonOverlapPatchID_(-1),
srcMask_(),
tgtMask_()
tgtMask_(),
srcScalePtr_
(
pp.srcScalePtr_.valid()
? pp.srcScalePtr_.clone(*this)
: nullptr
),
AMITime_
(
IOobject
(
"AMITime",
boundaryMesh().mesh().pointsInstance(),
boundaryMesh().mesh(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
dimensionedScalar("time", dimTime, -GREAT)
),
prevTimeIndex_(-1)
{
AMIPtr_->setRequireMatch(false);
}
@ -481,6 +736,17 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
const Foam::cyclicACMIPolyPatch& Foam::cyclicACMIPolyPatch::neighbPatch() const
{
const polyPatch& pp = this->boundaryMesh()[neighbPatchID()];
// Bit of checking now we know neighbour patch
if (!owner() && srcScalePtr_.valid())
{
WarningInFunction
<< "Ignoring \"scale\" setting in slave patch " << name()
<< endl;
srcScalePtr_.clear();
tgtScalePtr_.clear();
}
return refCast<const cyclicACMIPolyPatch>(pp);
}
@ -578,6 +844,11 @@ void Foam::cyclicACMIPolyPatch::write(Ostream& os) const
cyclicAMIPolyPatch::write(os);
os.writeEntry("nonOverlapPatch", nonOverlapPatchName_);
if (owner() && srcScalePtr_.valid())
{
srcScalePtr_->writeData(os);
}
}

View File

@ -28,7 +28,29 @@ Class
Foam::cyclicACMIPolyPatch
Description
Cyclic patch for Arbitrarily Coupled Mesh Interface (ACMI)
Cyclic patch for Arbitrarily Coupled Mesh Interface (ACMI).
Mixes cyclicAMI behaviour with non-coupled patch behaviour using
the overlap area fraction. The non-coupled patch is specified through
the nonOverlapPatch keyword.
Usage
Example of the patch specification:
type cyclicACMI;
neighbourPatch ACMI2_couple; // cyclicAMI neighbour patch
nonOverlapPatch ACMI1_blockage; // patch for uncoupled faces
// Optional time-dependent scaling (PatchFunction1)
scale table
(
(0.00 1.0)
(0.02 1.0)
(0.0201 0.0)
);
See also
cyclicAMIPolyPatch.C
SourceFiles
cyclicACMIPolyPatch.C
@ -42,6 +64,9 @@ SourceFiles
#include "AMIPatchToPatchInterpolation.H"
#include "polyBoundaryMesh.H"
#include "partialFaceAreaWeightAMI.H"
#include "PatchFunction1.H"
#include "uniformDimensionedFields.H"
#include "vectorList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -74,6 +99,34 @@ private:
mutable scalarField tgtMask_;
// Scaling of overlap (optional)
//- Weighting for source mask
mutable autoPtr<PatchFunction1<scalar>> srcScalePtr_;
//- Weighting for target mask
mutable autoPtr<PatchFunction1<scalar>> tgtScalePtr_;
//- Stored face areas
mutable vectorField thisSf_;
mutable vectorField thisNoSf_;
mutable vectorField nbrSf_;
mutable vectorField nbrNoSf_;
//- Scaled version of source mask
mutable scalarField srcScaledMask_;
//- Scaled version of target mask
mutable scalarField tgtScaledMask_;
//- Flag to detect whether AMI is up to date with mesh points
mutable uniformDimensionedScalarField AMITime_;
//- Flag to detect whether scaled masks are up to date with
// current time
mutable label prevTimeIndex_;
protected:
// Protected Member Functions
@ -96,7 +149,13 @@ protected:
virtual void scalePatchFaceAreas();
//- Scale patch face areas to maintain physical area
virtual void scalePatchFaceAreas(const cyclicACMIPolyPatch& acmipp);
virtual void scalePatchFaceAreas
(
const cyclicACMIPolyPatch& acmipp,
const scalarField& mask,
const vectorList& faceArea,
const vectorList& noFaceArea
);
//- Initialise the calculation of the patch geometry
virtual void initGeometry(PstreamBuffers&);
@ -297,6 +356,20 @@ public:
//- Write the polyPatch data as a dictionary
virtual void write(Ostream&) const;
// Handling optional scaling (time dependency)
//- Update the AMI and patch areas. Return true if anything
// updated
virtual bool updateAreas() const;
//- Return true if given object is up to date with *this
// (note : like regIOobject::upToDate but operates on object)
bool upToDate(const regIOobject&) const;
//- Set object up to date with *this
// (note : like regIOobject::setUpToDate but operates on object)
void setUpToDate(regIOobject&) const;
};

View File

@ -55,7 +55,7 @@ inline const Foam::scalarField& Foam::cyclicACMIPolyPatch::mask() const
{
if (owner())
{
return srcMask_;
return srcMask();
}
return neighbPatch().tgtMask();

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0);
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type pressureInletOutletVelocity;
value uniform (0 0 0);
}
outlet1
{
type inletOutlet;
inletValue uniform (0 0 0);
value uniform (0 0 0);
}
outlet2
{
type inletOutlet;
inletValue uniform (0 0 0);
value uniform (0 0 0);
}
wall
{
type noSlip;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,54 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object epsilon;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -3 0 0 0 0];
internalField uniform 200;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type turbulentMixingLengthDissipationRateInlet;
mixingLength 0.01; // 1cm - half channel height
value $internalField;
}
outlet1
{
type inletOutlet;
inletValue $internalField;
}
outlet2
{
type inletOutlet;
inletValue $internalField;
}
wall
{
type epsilonWallFunction;
value $internalField;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,54 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object k;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0.2;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type turbulentIntensityKineticEnergyInlet;
intensity 0.05; // 5% turbulent intensity
value $internalField;
}
outlet1
{
type inletOutlet;
inletValue $internalField;
}
outlet2
{
type inletOutlet;
inletValue $internalField;
}
wall
{
type kqRWallFunction;
value uniform 0;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,47 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object nuTilda;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -1 0 0 0 0];
internalField uniform 0;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type zeroGradient;
}
outlet1
{
type zeroGradient;
}
outlet2
{
type zeroGradient;
}
wall
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,53 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object nut;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -1 0 0 0 0];
internalField uniform 0;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type calculated;
value uniform 0;
}
outlet1
{
type calculated;
value uniform 0;
}
outlet2
{
type calculated;
value uniform 0;
}
wall
{
type nutkWallFunction;
value uniform 0;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,55 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type uniformTotalPressure;
p0 table
(
(0 40)
//(0 10)
//(1 40)
);
}
outlet1
{
type fixedValue;
value uniform 10;
}
outlet2
{
type fixedValue;
value uniform 10;
}
wall
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object s;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
//- Set patchGroups for constraint patches
#includeEtc "caseDicts/setConstraintTypes"
inlet
{
type fixedValue;
value $internalField;
}
outlet1
{
type inletOutlet;
inletValue $internalField;
}
outlet2
{
type inletOutlet;
inletValue $internalField;
}
wall
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -0,0 +1,2 @@
Copy of T-junction tutorial. Inlet on left, one outlet at bottom, one at top.
cyclicAMI with switching to direct flow to bottom or top

View File

@ -0,0 +1,22 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
transportModel Newtonian;
nu 1e-05;
// ************************************************************************* //

View File

@ -0,0 +1,30 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object turbulenceProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
simulationType RAS;
RAS
{
RASModel kEpsilon;
turbulence on;
printCoeffs on;
}
// ************************************************************************* //

View File

@ -0,0 +1,284 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// outlet1
// +-+
// | |
// | |
// | |
// | |
// +-----------+-+
// |inlet | |
// +-----------+-+
// | |
// | |
// | |
// | |
// +-+
// outlet2
scale 1;
vertices
(
(0.0 -0.01 0) //0
(0.19 -0.01 0)
(0.19 0.01 0) //2
(0.0 0.01 0)
(0.19 -0.02 0) //4
(0.23 -0.02 0)
(0.23 0.02 0) //6
(0.19 0.02 0)
(0.2 -0.21 0) //8
(0.22 -0.21 0)
(0.22 -0.02 0) //10
(0.2 -0.02 0)
(0.2 0.02 0) //12
(0.22 0.02 0)
(0.22 0.21 0) //14
(0.2 0.21 0)
// Z
(0.0 -0.01 0.01)
(0.19 -0.01 0.01)
(0.19 0.01 0.01)
(0.0 0.01 0.01)
(0.19 -0.02 0.01)
(0.23 -0.02 0.01)
(0.23 0.02 0.01)
(0.19 0.02 0.01)
(0.2 -0.21 0.01)
(0.22 -0.21 0.01)
(0.22 -0.02 0.01)
(0.2 -0.02 0.01)
(0.2 0.02 0.01)
(0.22 0.02 0.01)
(0.22 0.21 0.01)
(0.2 0.21 0.01)
);
blocks
(
// inlet block
hex (0 1 2 3 16 17 18 19) inlet (50 5 1) simpleGrading (1 1 1)
// central block
hex (4 5 6 7 20 21 22 23) central (12 12 1) simpleGrading (1 1 1)
// bottom block
hex (8 9 10 11 24 25 26 27) bottom (5 50 1) simpleGrading (1 1 1)
// top block
hex (12 13 14 15 28 29 30 31) top (5 50 1) simpleGrading (1 1 1)
);
edges
(
);
boundary
(
inlet
{
type patch;
faces
(
(0 16 19 3)
);
}
outlet1
{
type patch;
faces
(
(8 9 25 24)
);
}
outlet2
{
type patch;
faces
(
(14 15 31 30)
);
}
walls
{
type wall;
faces
(
// Inlet block
(2 3 19 18)
(0 1 17 16)
// Central block
(5 6 22 21)
// Bottom block
(8 24 27 11)
(9 10 26 25)
// Top block
(13 14 30 29)
(12 28 31 15)
);
}
// Inlet - Central block
// ~~~~~~~~~~~~~~~~~~~~~
inlet_central_couple
{
type cyclicACMI;
neighbourPatch central_inlet_couple;
nonOverlapPatch inlet_central_blockage;
faces
(
(1 2 18 17)
);
}
inlet_central_blockage
{
type wall;
faces
(
(1 2 18 17)
);
}
central_inlet_couple
{
type cyclicACMI;
neighbourPatch inlet_central_couple;
nonOverlapPatch central_inlet_blockage;
faces
(
(4 20 23 7)
);
}
central_inlet_blockage
{
type wall;
faces
(
(4 20 23 7)
);
}
// Central - Bottom block
// ~~~~~~~~~~~~~~~~~~~~~
bottom_central_couple
{
type cyclicACMI;
neighbourPatch central_bottom_couple;
nonOverlapPatch bottom_central_blockage;
faces
(
(10 11 27 26)
);
scale table
(
(0.00 1.0)
(0.20 1.0)
(0.30 0.0)
);
}
bottom_central_blockage
{
type wall;
faces
(
(10 11 27 26)
);
}
central_bottom_couple
{
type cyclicACMI;
neighbourPatch bottom_central_couple;
nonOverlapPatch central_bottom_blockage;
faces
(
(4 5 21 20)
);
}
central_bottom_blockage
{
type wall;
faces
(
(4 5 21 20)
);
}
// Central - Top block
// ~~~~~~~~~~~~~~~~~~~
top_central_couple
{
type cyclicACMI;
neighbourPatch central_top_couple;
nonOverlapPatch top_central_blockage;
faces
(
(12 13 29 28)
);
scale table
(
(0.00 0.0)
(0.20 0.0)
(0.30 1.0)
);
}
top_central_blockage
{
type wall;
faces
(
(12 13 29 28)
);
}
central_top_couple
{
type cyclicACMI;
neighbourPatch top_central_couple;
nonOverlapPatch central_top_blockage;
faces
(
(6 7 23 22)
);
}
central_top_blockage
{
type wall;
faces
(
(6 7 23 22)
);
}
);
// ************************************************************************* //

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application pimpleFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.4;
deltaT 0.001;
writeControl adjustableRunTime;
writeInterval 0.01;
purgeWrite 0;
writeFormat ascii;
writePrecision 6;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
adjustTimeStep yes;
maxCo 1.0;
// ************************************************************************* //

View File

@ -0,0 +1,21 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
numberOfSubdomains 3;
method scotch;
// ************************************************************************* //

View File

@ -0,0 +1,57 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
ddtSchemes
{
default Euler;
}
gradSchemes
{
default Gauss linear;
}
divSchemes
{
default none;
div(phi,U) Gauss limitedLinearV 1;
div(phi,k) Gauss limitedLinear 1;
div(phi,epsilon) Gauss limitedLinear 1;
div(phi,R) Gauss limitedLinear 1;
div(phi,s) Gauss limitedLinear 1;
div(R) Gauss linear;
div(phi,nuTilda) Gauss limitedLinear 1;
div((nuEff*dev2(T(grad(U))))) Gauss linear;
}
laplacianSchemes
{
default Gauss linear corrected;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default corrected;
}
// ************************************************************************* //

View File

@ -0,0 +1,74 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1906 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
p
{
solver GAMG;
tolerance 1e-06;
relTol 0.01;
smoother GaussSeidel;
}
"(pFinal|pcorrFinal)"
{
solver GAMG;
tolerance 1e-06;
relTol 0;
smoother GaussSeidel;
}
"(U|k|epsilon|s)"
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-05;
relTol 0.1;
}
"(U|k|epsilon|s)Final"
{
$U;
tolerance 1e-05;
relTol 0;
}
}
PIMPLE
{
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 0;
pRefCell 0;
pRefValue 0;
correctPhi false;
}
relaxationFactors
{
equations
{
"U.*" 1;
"k.*" 1;
"epsilon.*" 1;
"s.*" 1;
}
}
// ************************************************************************* //