Layered overlap fringe strategy. Author: Vuko Vukcevic. Merge: Hrvoje Jasak.

This commit is contained in:
Hrvoje Jasak 2019-01-30 14:38:37 +00:00
commit b3b16d1cc8
5 changed files with 659 additions and 4 deletions

View file

@ -5,6 +5,7 @@ oversetFringe/oversetFringe/newOversetFringe.C
oversetFringe/manualFringe/manualFringe.C oversetFringe/manualFringe/manualFringe.C
oversetFringe/faceCellsFringe/faceCellsFringe.C oversetFringe/faceCellsFringe/faceCellsFringe.C
oversetFringe/overlapFringe/overlapFringe/overlapFringe.C oversetFringe/overlapFringe/overlapFringe/overlapFringe.C
oversetFringe/overlapFringe/layeredOverlapFringe/layeredOverlapFringe.C
oversetFringe/overlapFringe/adaptiveOverlapFringe/adaptiveOverlapFringe.C oversetFringe/overlapFringe/adaptiveOverlapFringe/adaptiveOverlapFringe.C
oversetFringe/compositeFringe/compositeFringe.C oversetFringe/compositeFringe/compositeFringe.C

View file

@ -418,7 +418,6 @@ Foam::adaptiveOverlapFringe::adaptiveOverlapFringe
dict.lookupOrDefault<scalar>("orphanSuitability", 1) dict.lookupOrDefault<scalar>("orphanSuitability", 1)
), ),
suitablePairsSuit_(0) suitablePairsSuit_(0)
{} {}

View file

@ -0,0 +1,474 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.1
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "layeredOverlapFringe.H"
#include "oversetRegion.H"
#include "oversetMesh.H"
#include "polyPatchID.H"
#include "processorFvPatchFields.H"
#include "oversetFvPatchFields.H"
#include "typeInfo.H"
#include "cellSet.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(layeredOverlapFringe, 0);
addToRunTimeSelectionTable(oversetFringe, layeredOverlapFringe, dictionary);
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::layeredOverlapFringe::evaluateNonOversetBoundaries
(
volScalarField::GeometricBoundaryField& psib
)
{
// Code practically copy/pasted from GeometricBoundaryField::evaluateCoupled
// GeometricBoundaryField should be redesigned to accomodate for such needs
if
(
Pstream::defaultComms() == Pstream::blocking
|| Pstream::defaultComms() == Pstream::nonBlocking
)
{
forAll(psib, patchI)
{
// Get fvPatchField
fvPatchScalarField& psip = psib[patchI];
if (psip.coupled() && !isA<oversetFvPatchScalarField>(psip))
{
psip.initEvaluate(Pstream::defaultComms());
}
}
// Block for any outstanding requests
if (Pstream::defaultComms() == Pstream::nonBlocking)
{
IPstream::waitRequests();
OPstream::waitRequests();
}
forAll(psib, patchI)
{
// Get fvPatchField
fvPatchScalarField& psip = psib[patchI];
if (psip.coupled() && !isA<oversetFvPatchScalarField>(psip))
{
psip.evaluate(Pstream::defaultComms());
}
}
}
else if (Pstream::defaultComms() == Pstream::scheduled)
{
// Get the mesh by looking at first fvPatchField
const lduSchedule& patchSchedule =
psib[0].dimensionedInternalField().mesh().globalData().
patchSchedule();
forAll(patchSchedule, patchEvalI)
{
if (patchSchedule[patchEvalI].init)
{
// Get fvPatchField
fvPatchScalarField psip = psib[patchSchedule[patchEvalI].patch];
if (psip.coupled() && !isA<oversetFvPatchScalarField>(psip))
{
psip.initEvaluate(Pstream::scheduled);
}
}
else
{
// Get fvPatchField
fvPatchScalarField psip = psib[patchSchedule[patchEvalI].patch];
if (psip.coupled() && !isA<oversetFvPatchScalarField>(psip))
{
psip.evaluate(Pstream::scheduled);
}
}
}
}
else
{
FatalErrorIn("layeredOverlapFringe::evaluateNonOversetBoundaries()")
<< "Unsuported communications type "
<< Pstream::commsTypeNames[Pstream::defaultCommsType()]
<< exit(FatalError);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::layeredOverlapFringe::calcAddressing() const
{
if (fringeHolesPtr_ || acceptorsPtr_)
{
FatalErrorIn("void layeredOverlapFringe::calcAddressing() const")
<< "Fringe addressing already calculated"
<< abort(FatalError);
}
// Get initial holes and surrounding acceptors
// Algorithm:
// - Create indicator field for correct data exchange accross processor
// boundaries
// - Get holes from overset region (and optionally from specified set)
// and mark immediate neighbours of holes as acceptors
// Get necessary mesh data
const fvMesh& mesh = region().mesh();
const labelListList& cc = mesh.cellCells();
// Get cut holes from overset region
const labelList& cutHoles = region().cutHoles();
// Debug
if (oversetMesh::debug && cutHoles.empty())
{
Pout<< "Did not find any holes to initialise the overlap fringe "
<< "assembly. Proceeding to specified holes..."
<< endl;
}
// Initialise mask field for eligible acceptors (cells that are not
// holes)
boolList eligibleAcceptors(mesh.nCells(), true);
// Read user specified holes into allHoles list. Note: if the cell set
// is not found, the list will be empty
cellSet allHoles
(
mesh,
holesSetName_,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
);
// Extend allHoles with cutHoles
allHoles.insert(cutHoles);
// Note: Because we cannot assume anything about parallel decomposition and
// we use neighbourhood walk algorithm, there is no easy way to go across
// processor boundaries. We will create an indicator field marking all
// possible cut cells and all possible face cells of given patches. Then, we
// will use this indicator field to transfer the search to the other side.
// Create the indicator field
volScalarField processorIndicator
(
IOobject
(
"processorIndicator",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionedScalar("minusOne", dimless, -1.0)
);
scalarField& processorIndicatorIn = processorIndicator.internalField();
// Mark all holes
forAllConstIter (cellSet, allHoles, iter)
{
const label& holeCellI = iter.key();
// Mask eligible acceptors
eligibleAcceptors[holeCellI] = false;
// Mark cut hole cell in processor indicator field
processorIndicatorIn[holeCellI] = 1.0;
}
// Hash set for storing acceptors
labelHashSet candidateAcceptors(mesh.nCells());
// Extend nLayers away from initial set. Note postfix increment
while (layerIter_++ != nLayers_)
{
// Append candidate acceptors to holes for this iteration and reset
// candidate acceptors
allHoles += candidateAcceptors;
candidateAcceptors.clear();
// Loop through all holes and find acceptor candidates
forAllConstIter (cellSet, allHoles, iter)
{
const label& holeCellI = iter.key();
// Get neighbours of this hole cell
const labelList& hNbrs = cc[holeCellI];
// Loop through neighbours of this hole cell
forAll (hNbrs, nbrI)
{
// Check whether the neighbouring cell is eligible
const label& nbrCellI = hNbrs[nbrI];
if (eligibleAcceptors[nbrCellI])
{
// Append the cell and mask it to avoid duplicate entries
candidateAcceptors.insert(nbrCellI);
eligibleAcceptors[nbrCellI] = false;
}
}
}
// Get boundary field
volScalarField::GeometricBoundaryField& processorIndicatorBf =
processorIndicator.boundaryField();
// Perform update accross coupled boundaries, excluding overset patch
evaluateNonOversetBoundaries(processorIndicatorBf);
// Loop through boundary field
forAll (processorIndicatorBf, patchI)
{
// Get patch field
const fvPatchScalarField& chipf = processorIndicatorBf[patchI];
// Only perform acceptor search if this is a processor boundary
if (isA<processorFvPatchScalarField>(chipf))
{
// Get neighbour field
const scalarField nbrProcIndicator =
chipf.patchNeighbourField();
// Get face cells
const unallocLabelList& fc = chipf.patch().faceCells();
// Loop through neighbouring processor field
forAll (nbrProcIndicator, pfaceI)
{
if
(
nbrProcIndicator[pfaceI] > 0.0
&& eligibleAcceptors[fc[pfaceI]]
)
{
// The cell on the other side is a hole or acceptor from
// face cells of a given patch, while the cell on this
// side has not been marked yet neither as an acceptor
// or as a hole. Append the cell to candidate acceptors
// and mark it as ineligible in order to propage the
// fringe on this side
candidateAcceptors.insert(fc[pfaceI]);
eligibleAcceptors[fc[pfaceI]] = false;
}
}
}
}
}
// Issue an error if no acceptors have been found for initial guess
if (returnReduce(candidateAcceptors.size(), sumOp<label>()) == 0)
{
FatalErrorIn
(
"void adaptiveOverlapFringe::calcAddressing() const"
) << "Did not find any acceptors to begin with."
<< "Check definition of adaptiveOverlap in oversetMeshDict"
<< " for region: " << this->region().name() << nl
<< "More specifically, check definition of:" << nl
<< "1. holePatches (mandatory entry)" << nl
<< "2. holes (optional entry)" << nl
<< abort(FatalError);
}
// Now we have a nice layout of acceptors that are nLayers away from
// specified holes. Copy into members
acceptorsPtr_ = new labelList(candidateAcceptors.toc());
fringeHolesPtr_ = new labelList(allHoles.toc());
}
void Foam::layeredOverlapFringe::clearAddressing() const
{
deleteDemandDrivenData(fringeHolesPtr_);
deleteDemandDrivenData(acceptorsPtr_);
deleteDemandDrivenData(finalDonorAcceptorsPtr_);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from dictionary
Foam::layeredOverlapFringe::layeredOverlapFringe
(
const fvMesh& mesh,
const oversetRegion& region,
const dictionary& dict
)
:
oversetFringe(mesh, region, dict),
fringeHolesPtr_(NULL),
acceptorsPtr_(NULL),
finalDonorAcceptorsPtr_(NULL),
nLayers_(readLabel(dict.lookup("nLayers"))),
layerIter_(0),
holesSetName_(dict.lookupOrDefault<word>("holes", word()))
{
// Sanity check
if (nLayers_ < 1)
{
FatalIOErrorIn
(
"layeredOverlapFringe::layeredOverlapFringe\n"
"(\n"
" const fvMesh& mesh,\n"
" const oversetRegion& region,\n"
" const dictionary& dict,\n"
")\n",
dict
) << "Invalid number of layers specified. "
<< nl
<< "Please specify value above 1."
<< exit(FatalIOError);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::layeredOverlapFringe::~layeredOverlapFringe()
{
clearAddressing();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::layeredOverlapFringe::updateIteration
(
donorAcceptorList& donorAcceptorRegionData
) const
{
if (!fringeHolesPtr_ || !acceptorsPtr_)
{
FatalErrorIn("layeredOverlapFringe::updateIteration()")
<< "fringeHolesPtr_ or acceptorsPtr_ is not allocated. "
<< "Make sure you have called acceptors() or fringeHoles() to "
<< "calculate the initial set of donor/acceptors before "
<< "actually updating iteration."
<< abort(FatalError);
}
if (finalDonorAcceptorsPtr_)
{
FatalErrorIn("layeredOverlapFringe::updateIteration()")
<< "Called iteration update with finalDonorAcceptorsPtr_ "
<< "allocated. This means that the final overlap has been "
<< "achieved, prohibiting calls to updateIteration."
<< abort(FatalError);
}
// Allocate the list by reusing the argument list. Note: all the work has
// been done in calcAddressing actually since this is not an iterative
// process by definition
finalDonorAcceptorsPtr_ = new donorAcceptorList
(
donorAcceptorRegionData,
true
);
// Set the flag to true and return
updateSuitableOverlapFlag(true);
return foundSuitableOverlap();
}
const Foam::labelList& Foam::layeredOverlapFringe::fringeHoles() const
{
if (!fringeHolesPtr_)
{
calcAddressing();
}
return *fringeHolesPtr_;
}
const Foam::labelList& Foam::layeredOverlapFringe::candidateAcceptors() const
{
if (!acceptorsPtr_)
{
calcAddressing();
}
return *acceptorsPtr_;
}
Foam::donorAcceptorList& Foam::layeredOverlapFringe::finalDonorAcceptors() const
{
if (!finalDonorAcceptorsPtr_)
{
FatalErrorIn("layeredOverlapFringe::finalDonorAcceptors()")
<< "finalDonorAcceptorPtr_ not allocated. Make sure you have "
<< "called layeredOverlapFringe::updateIteration() before asking for "
<< "final set of donor/acceptor pairs."
<< abort(FatalError);
}
if (!foundSuitableOverlap())
{
FatalErrorIn("layeredOverlapFringe::finalDonorAcceptors()")
<< "Attemted to access finalDonorAcceptors but suitable overlap "
<< "has not been found. This is not allowed. "
<< abort(FatalError);
}
return *finalDonorAcceptorsPtr_;
}
void Foam::layeredOverlapFringe::update() const
{
Info<< "layeredOverlapFringe::update() const" << endl;
// Clear everything, including acceptors and fringe holes
clearAddressing();
// Reset counter to zero
layerIter_ = 0;
// Set flag to false and clear final donor/acceptors only
updateSuitableOverlapFlag(false);
}
// ************************************************************************* //

View file

@ -0,0 +1,180 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.1
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
Class
layeredOverlapFringe
Description
Layered overlap fringe algorithm. Uses neighbourhood walk nLayers deep to
run away from user specified holes (holePatches and optional manual cell set
containing holes) and identify acceptors.
Holds and manages following data:
- fringeHolesPtr_: holds fringe holes
- acceptorsPtr_: holds acceptors
- finalDonorAcceptorsPtr_: holds final set of donor/acceptors
- fringeIter_: iteration counter
No need to control the iterative process in updateIteration member function,
acceptors are found in calcAddressing as in e.g. faceCells fringe.
Member function updateIteration controls the iterative process:
Author
Vuko Vukcevic, Wikki Ltd. All rights reserved.
SourceFiles
layeredOverlapFringe.C
\*---------------------------------------------------------------------------*/
#ifndef layeredOverlapFringe_H
#define layeredOverlapFringe_H
#include "oversetFringe.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class layeredOverlapFringe Declaration
\*---------------------------------------------------------------------------*/
class layeredOverlapFringe
:
public oversetFringe
{
// Private data
//- Fringe hole cells
mutable labelList* fringeHolesPtr_;
//- Acceptor cells
mutable labelList* acceptorsPtr_;
//- Final donor/acceptor pairs for this region (fringe)
mutable donorAcceptorList* finalDonorAcceptorsPtr_;
//- Number of layers
const label nLayers_;
//- Iteration counter
mutable label layerIter_;
// Optional initialization data
//- Name of the cell set defining initial holes (empty by default).
// Useful when the resolution of the background mesh is much
// coarser than the front mesh and no hole is found
const word holesSetName_;
// Private Member Functions
// Copy control
//- Disallow default bitwise copy construct
layeredOverlapFringe(const layeredOverlapFringe&);
//- Disallow default bitwise assignment
void operator=(const layeredOverlapFringe&);
// Addressing calculation functions
//- Calculate hole-acceptor addressing
void calcAddressing() const;
//- Clear hole-acceptor addressing
void clearAddressing() const;
public:
//- Runtime type information
TypeName("layeredOverlap");
// Static Member Functions
//- Helper function used to evaluate coupled boundaries, excluding
// overset patch
static void evaluateNonOversetBoundaries
(
volScalarField::GeometricBoundaryField& psib
);
// Constructors
//- Construct from dictionary
layeredOverlapFringe
(
const fvMesh& mesh,
const oversetRegion& region,
const dictionary& dict
);
//- Destructor
virtual ~layeredOverlapFringe();
// Member Functions
//- Update iteration.
virtual bool updateIteration
(
donorAcceptorList& donorAcceptorRegionData
) const;
//- Return list of hole cells
// Fringe hole cells are collected in addition to geometric hole
// cells, which fall outside of all donor regions
virtual const labelList& fringeHoles() const;
//- Return list of acceptor cells
virtual const labelList& candidateAcceptors() const;
//- Return list of final donor acceptor pairs. Note: caller may
// invalidate finalDonorAcceptorsPtr_ for optimisation purposes
virtual donorAcceptorList& finalDonorAcceptors() const;
//- Update the fringe
virtual void update() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -419,19 +419,20 @@ Foam::overlapFringe::overlapFringe
// Sanity check // Sanity check
if (minGlobalFraction_ < SMALL || minGlobalFraction_ > 1.0) if (minGlobalFraction_ < SMALL || minGlobalFraction_ > 1.0)
{ {
FatalErrorIn FatalIOErrorIn
( (
"overlapFringe::overlapFringe\n" "overlapFringe::overlapFringe\n"
"(\n" "(\n"
" const fvMesh& mesh,\n" " const fvMesh& mesh,\n"
" const oversetRegion& region,\n" " const oversetRegion& region,\n"
" const dictionary& dict,\n" " const dictionary& dict,\n"
")\n" ")\n",
dict
) << "Invalid suitablePairFraction found while reading the overlap " ) << "Invalid suitablePairFraction found while reading the overlap "
<< "fringe dictionary." << "fringe dictionary."
<< nl << nl
<< "Please specify value between 0 and 1." << "Please specify value between 0 and 1."
<< endl; << exit(FatalIOError);
} }
} }