Finished writing first version of donorBasedLayeredOverlap fringe
Note: did not attempt to compile yet, let alone test it
This commit is contained in:
parent
31019383d2
commit
6a5117ed51
2 changed files with 565 additions and 131 deletions
|
@ -27,6 +27,7 @@ License
|
||||||
#include "faceCellsFringe.H"
|
#include "faceCellsFringe.H"
|
||||||
#include "oversetRegion.H"
|
#include "oversetRegion.H"
|
||||||
#include "addToRunTimeSelectionTable.H"
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
#include "syncTools.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
@ -41,11 +42,22 @@ namespace Foam
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::debug::tolerancesSwitch
|
||||||
|
Foam::donorBasedLayeredOverlapFringe::distTol_
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapDistanceTolerance"
|
||||||
|
0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::donorBasedLayeredOverlapFringe::calcAddressing() const
|
void Foam::donorBasedLayeredOverlapFringe::calcAddressing() const
|
||||||
{
|
{
|
||||||
if (acceptorsPtr_)
|
// Make sure that either acceptorsPtr is unnalocated or if it is allocated,
|
||||||
|
// that it is empty
|
||||||
|
if (acceptorsPtr_ && !acceptorsPtr_->empty())
|
||||||
{
|
{
|
||||||
FatalErrorIn
|
FatalErrorIn
|
||||||
(
|
(
|
||||||
|
@ -54,52 +66,438 @@ void Foam::donorBasedLayeredOverlapFringe::calcAddressing() const
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get reference to region cell zone
|
// Get list of all overset regions
|
||||||
const cellZone& rcz = region().zone();
|
const PtrList<oversetRegion>& allRegions =
|
||||||
|
this->region().overset().regions();
|
||||||
|
|
||||||
// Make a hash set to collect acceptor points
|
// Loop through all connected regions and check whether the fringe overlap
|
||||||
// Note: 2 patches connecting at the corner may create a duplicate,
|
// has been found for all of them
|
||||||
// which is filtered on insertion
|
bool allFringesReady = true;
|
||||||
labelHashSet acceptorSet;
|
forAll (connectedRegionIDs_, crI)
|
||||||
|
|
||||||
// Find patches and mark cells
|
|
||||||
forAll (patchNames_, nameI)
|
|
||||||
{
|
{
|
||||||
const polyPatchID curFringePatch
|
// Get ID of this region
|
||||||
(
|
const label& regionID = connectedRegionIDs_[crI];
|
||||||
patchNames_[nameI],
|
|
||||||
mesh().boundaryMesh()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!curFringePatch.active())
|
// Get the overset region
|
||||||
|
const oversetRegion& region = allRegions[regionID];
|
||||||
|
|
||||||
|
// Get the fringe algorithm from the region
|
||||||
|
const oversetFringe& fringe = region.fringe();
|
||||||
|
|
||||||
|
// If this is not faceCells fringe, issue a Warning. This fringe
|
||||||
|
// selection algorithm is intended to work only with faceCells fringe on
|
||||||
|
// the other side. VV, 9/Apr/2019
|
||||||
|
if (!isA<faceCellsFringe>(fringe))
|
||||||
{
|
{
|
||||||
FatalErrorIn
|
WarningIn
|
||||||
(
|
(
|
||||||
"void donorBasedLayeredOverlapFringe::calcAddressing() const"
|
"void Foam::donorBasedLayeredOverlapFringe::"
|
||||||
) << "Fringe patch " << patchNames_[nameI]
|
"updateIteration(donorAcceptorList&) const"
|
||||||
<< " cannot be found"
|
) << "donorBasedLayeredOverlap fringe is designed to work"
|
||||||
<< abort(FatalError);
|
<< " with faceCells fringe as a connected region fringe."
|
||||||
|
<< nl
|
||||||
|
<< "Connected overset region " << region.name()
|
||||||
|
<< " has " << fringe.type() " fringe type. "
|
||||||
|
<< nl
|
||||||
|
<< "Proceed with care!"
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unallocLabelList& curFaceCells =
|
// Update flag collecting whether all connected regions found the
|
||||||
mesh().boundaryMesh()[curFringePatch.index()].donorBasedLayeredOverlap();
|
// overlap
|
||||||
|
allFringesReady &= fringe.foundSuitableOverlap();
|
||||||
forAll (curFaceCells, fcI)
|
|
||||||
{
|
|
||||||
// Check if cell is in region zone
|
|
||||||
if (rcz.whichCell(curFaceCells[fcI]) > -1)
|
|
||||||
{
|
|
||||||
// Found acceptor
|
|
||||||
acceptorSet.insert(curFaceCells[fcI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect acceptors
|
// Sets containing all acceptors and all holes for all connected regions
|
||||||
acceptorsPtr_ = new labelList(acceptorSet.sortedToc());
|
labelHashSet allAcceptors(0.02*mesh.nCells());
|
||||||
|
labelHashSet allFringeHoles(0.02*mesh.nCells());
|
||||||
|
|
||||||
// Holes are empty for this fringe
|
if (allFringesReady)
|
||||||
fringeHolesPtr_ = new labelList();
|
{
|
||||||
|
// Loop through connected regions
|
||||||
|
forAll (connectedRegionIDs_, crI)
|
||||||
|
{
|
||||||
|
// Get ID of this region
|
||||||
|
const label& regionID = connectedRegionIDs_[crI];
|
||||||
|
|
||||||
|
// Get fringe of the connected region
|
||||||
|
const oversetFringe& fringe = allRegions[regionID].fringe();
|
||||||
|
|
||||||
|
// The fringe should be finalized, which means we may take a const
|
||||||
|
// reference to its final donor acceptors
|
||||||
|
const donorAcceptorList& crDonorAcceptorPairs =
|
||||||
|
fringe.finalDonorAcceptors();
|
||||||
|
|
||||||
|
// Hash set containing donors
|
||||||
|
labelHashSet donors(6*crDonorAcceptorPairs.size());
|
||||||
|
|
||||||
|
// Initialize centre of the donors of this connected region in order
|
||||||
|
// to search in a given direction
|
||||||
|
vector centrePoint(vector::zero);
|
||||||
|
|
||||||
|
// Loop through all donor/acceptors
|
||||||
|
forAll (crDonorAcceptorPairs, daI)
|
||||||
|
{
|
||||||
|
// Get this donor/acceptor pair
|
||||||
|
const donorAcceptor& daPair = crDonorAcceptorPairs[daI];
|
||||||
|
|
||||||
|
// Check whether all donors have been found
|
||||||
|
if (!daPair.donorFound())
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"updateIteration(donorAcceptorList&) const"
|
||||||
|
) << "Donor not found for donor/acceptor pair " << daI
|
||||||
|
<< nl
|
||||||
|
<< "Donor/acceptor data: " << daPair
|
||||||
|
<< nl
|
||||||
|
<< "In connected region: " << allRegions[regionID].name()
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark donors on my processor from this connected region. Note
|
||||||
|
// that the check has been made in constructor to make sure that
|
||||||
|
// this region is the only donor region for the connected region
|
||||||
|
if (daPair.donorProcNo() == Pstream::myProcNo())
|
||||||
|
{
|
||||||
|
// Get donor index
|
||||||
|
const label& dI = daPair.donorCell();
|
||||||
|
|
||||||
|
// Insert donor into the hash set
|
||||||
|
if (donors.insert(dI))
|
||||||
|
{
|
||||||
|
// Donor has been inserted (not previously found in the
|
||||||
|
// hash set), add donor point to centre point (the
|
||||||
|
// centre point will be calculated later on as
|
||||||
|
// arithmetic mean)
|
||||||
|
centrePoint += daPair.donorPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through extended donor cells
|
||||||
|
donorAcceptor::DynamicLabelList& extDonors =
|
||||||
|
daPair.extendedDonorCells();
|
||||||
|
donorAcceptor::DynamicPointList& extDonorPoints =
|
||||||
|
daPair.extendedDonorPoints();
|
||||||
|
|
||||||
|
forAll (extDonors, i)
|
||||||
|
{
|
||||||
|
// Get donor index
|
||||||
|
const label& edI = extDonors[i];
|
||||||
|
|
||||||
|
// Inser extended donor into the hash set
|
||||||
|
if (donors.insert(edI))
|
||||||
|
{
|
||||||
|
// Donor has been inserted (not previously found in
|
||||||
|
// the hash set), add extended donor point as well
|
||||||
|
centrePoint += extDonorPoints[i];
|
||||||
|
}
|
||||||
|
} // End for all extended donors
|
||||||
|
} // End if this donor is on my processor
|
||||||
|
} // End for all (master) donor cells
|
||||||
|
|
||||||
|
// Use the centre point as specified by the user if it was specified
|
||||||
|
// (if the regionCentrePoints_ list is not empty). This avoids
|
||||||
|
// parallel communication as well.
|
||||||
|
if (!regionCentrePoints_.empty())
|
||||||
|
{
|
||||||
|
// Use specified centre point, discarding the data we calculated
|
||||||
|
// above
|
||||||
|
centrePoint = regionCentrePoints_[crI];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// User did not specify centre points and the centre point holds
|
||||||
|
// the sum of all the points. Reduce the data
|
||||||
|
reduce(centrePoint, sumOp<vector>());
|
||||||
|
nUniqueDonors = returnReduce(donors.size(), sumOp<label>());
|
||||||
|
|
||||||
|
// Calculate the final centre point by finding the arithmetic mean
|
||||||
|
centrePoint /= nUniqueDonors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have a collection of all donors for this connected region
|
||||||
|
// and the centre point to move to. Let's collect the acceptors
|
||||||
|
labelHashSet acceptors(donors.size()); // Reasonable size estimate
|
||||||
|
|
||||||
|
// Get necessary mesh data (from polyMesh/primitiveMesh)
|
||||||
|
const polyMesh& mesh = this->mesh();
|
||||||
|
const vectorField& cc = mesh.cellCentres();
|
||||||
|
const vectorField& fc = mesh.faceCentres();
|
||||||
|
const cellList& meshCells = mesh.cells();
|
||||||
|
const unallocLabelList& owner = mesh.faceOwner();
|
||||||
|
const unallocLabelList& neighbour = mesh.faceNeighbour();
|
||||||
|
|
||||||
|
// Mark cells that are eligible to be acceptors (not donors)
|
||||||
|
boolList eligibleCells(mesh.nCells(), true);
|
||||||
|
forAllConstIter (labelHashSet, donors, iter)
|
||||||
|
{
|
||||||
|
eligibleCells[iter.key()] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop nLayers away from initial donors
|
||||||
|
for (label i = 0; i < nLayers_; ++i)
|
||||||
|
{
|
||||||
|
// Face markup for propagation
|
||||||
|
boolList propagateFace(mesh.nFaces(), false);
|
||||||
|
|
||||||
|
// Loop through all donors and mark faces that are pointing
|
||||||
|
// towards the centre point and have an eligible neighbour
|
||||||
|
forAllConstIter (labelHashSet, donors, iter)
|
||||||
|
{
|
||||||
|
// Get the cell index and the cell
|
||||||
|
const label& cellI = iter.key();
|
||||||
|
const label& cell = meshCells[cellI];
|
||||||
|
|
||||||
|
// Get cell centre of this donor and calculate distance to
|
||||||
|
// centre point
|
||||||
|
const vector& donorCentre = cc[cellI];
|
||||||
|
const scalar donorCentreToRegionCentreDist =
|
||||||
|
mag(donorCentre - centrePoint);
|
||||||
|
|
||||||
|
// Loop through all faces of the cell
|
||||||
|
forAll (cFaces, i)
|
||||||
|
{
|
||||||
|
// Get face index (global)
|
||||||
|
const label& faceI = cFaces[i];
|
||||||
|
|
||||||
|
// Get face centre and calculate distance to centre
|
||||||
|
// point
|
||||||
|
const vector& faceCentre = fc[faceI];
|
||||||
|
const scalar faceCentreToRegionCentreDist =
|
||||||
|
mag(faceCentre - centrePoint);
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
faceCentreToRegionCentreDist
|
||||||
|
- donorCentreToRegionCentreDist
|
||||||
|
< distTol_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Face is closer to the centre point than cell: we
|
||||||
|
// are moving in the right direction. Mark the face
|
||||||
|
propagateFace[faceI] = true;
|
||||||
|
}
|
||||||
|
} // End for all faces of the cell
|
||||||
|
} // End for all donor cells
|
||||||
|
|
||||||
|
// Sync the face list across processor boundaries
|
||||||
|
syncTools::syncFaceList
|
||||||
|
(
|
||||||
|
mesh,
|
||||||
|
propagateFace,
|
||||||
|
orOp<bool>(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loop through all faces and append acceptors
|
||||||
|
for (label faceI = 0; faceI < mesh.nInternalFaces(); ++faceI)
|
||||||
|
{
|
||||||
|
if (propagateFace[faceI])
|
||||||
|
{
|
||||||
|
// Face is marked, select owner or neighbour
|
||||||
|
const label& own = owner[faceI];
|
||||||
|
const label& nei = neighbour[faceI];
|
||||||
|
|
||||||
|
// Either owner or neighbour may be eligible, not both
|
||||||
|
if (eligibleCells[own])
|
||||||
|
{
|
||||||
|
// Owner cell is not a donor, insert it
|
||||||
|
acceptors.insert(own);
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[own] = false;
|
||||||
|
}
|
||||||
|
else if (eligibleCells[nei])
|
||||||
|
{
|
||||||
|
// Neighbour cell is not a donor, insert it
|
||||||
|
acceptors.insert(nei);
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[nei] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through boundary faces
|
||||||
|
for
|
||||||
|
(
|
||||||
|
label faceI = mesh.nInternalFaces();
|
||||||
|
faceI < mesh.nFaces();
|
||||||
|
++faceI
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (propagateFace[faceI])
|
||||||
|
{
|
||||||
|
// Face is marked, select owner if this is the right
|
||||||
|
// side. Neighbour handled on the other side
|
||||||
|
const label& own = owner[faceI];
|
||||||
|
|
||||||
|
if (eligibleCells[own])
|
||||||
|
{
|
||||||
|
// Face cell is not a donor, insert it
|
||||||
|
acceptors.insert(own);
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[own] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special treatment for last iteration
|
||||||
|
if (i == nLayers_ - 1)
|
||||||
|
{
|
||||||
|
// This is not the last iteration, transfer acceptors into
|
||||||
|
// donors
|
||||||
|
donors.transfer(acceptors);
|
||||||
|
|
||||||
|
// Resize acceptors list
|
||||||
|
acceptors.resize(donors.size());
|
||||||
|
}
|
||||||
|
} // End for specified number of layers
|
||||||
|
|
||||||
|
// At this point, we have the final set of acceptors and we marked
|
||||||
|
// all cells that are ineligible (either donor or acceptor). The
|
||||||
|
// remaining thing to do is to mark the interior holes
|
||||||
|
|
||||||
|
// Create a hash set containing fringe holes, initialized with
|
||||||
|
// acceptors in order to avoid having special conditions in the loop
|
||||||
|
// below for the first pass
|
||||||
|
labelHashSet fringeHoles(10*acceptors.size());
|
||||||
|
|
||||||
|
// Collect holes until there are no holes to collect
|
||||||
|
label nAddedHoles;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Reset number of newly added holes
|
||||||
|
nAddedHoles = 0;
|
||||||
|
|
||||||
|
// Face markup for propagation
|
||||||
|
boolList propagateFace(mesh.nFaces(), false);
|
||||||
|
|
||||||
|
// Loop through all acceptors and mark faces that are pointing
|
||||||
|
// towards the centre point and have eligible neighbour (not an
|
||||||
|
// acceptor or donor)
|
||||||
|
forAllConstIter (labelHashSet, fringeHoles, iter)
|
||||||
|
{
|
||||||
|
// Get the cell index and the cell
|
||||||
|
const label& cellI = iter.key();
|
||||||
|
const label& cell = meshCells[cellI];
|
||||||
|
|
||||||
|
// Note: there's no need to check for the distance here
|
||||||
|
// because there's always at least one "buffer" layer
|
||||||
|
// towards the outer side that consists of donors, which are
|
||||||
|
// marked as ineligible at the beginning
|
||||||
|
|
||||||
|
// Loop through all faces of the cell and mark all of them
|
||||||
|
// for propagation
|
||||||
|
forAll (cFaces, i)
|
||||||
|
{
|
||||||
|
propagateFace[cFaces[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync the face list across processor boundaries
|
||||||
|
syncTools::syncFaceList
|
||||||
|
(
|
||||||
|
mesh,
|
||||||
|
propagateFace,
|
||||||
|
orOp<bool>(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loop through all faces and append interior holes
|
||||||
|
for (label faceI = 0; faceI < mesh.nInternalFaces(); ++faceI)
|
||||||
|
{
|
||||||
|
if (propagateFace[faceI])
|
||||||
|
{
|
||||||
|
// Face is marked, select owner or neighbour
|
||||||
|
const label& own = owner[faceI];
|
||||||
|
const label& nei = neighbour[faceI];
|
||||||
|
|
||||||
|
// Either owner or neighbour may be eligible, not both
|
||||||
|
if (eligibleCells[own])
|
||||||
|
{
|
||||||
|
// Owner cell is not a hole (or an acceptor in the
|
||||||
|
// first iteration), insert it
|
||||||
|
if (fringeHoles.insert(own))
|
||||||
|
{
|
||||||
|
// Count number of added holes in this iteration
|
||||||
|
++nAddedHoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[own] = false;
|
||||||
|
}
|
||||||
|
else if (eligibleCells[nei])
|
||||||
|
{
|
||||||
|
// Neighbour cell is not a hole (or an acceptor in
|
||||||
|
// the first iteration), insert it
|
||||||
|
if (fringeHoles.insert(nei))
|
||||||
|
{
|
||||||
|
// Count number of added holes in this iteration
|
||||||
|
++nAddedHoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[nei] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through boundary faces
|
||||||
|
for
|
||||||
|
(
|
||||||
|
label faceI = mesh.nInternalFaces();
|
||||||
|
faceI < mesh.nFaces();
|
||||||
|
++faceI
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (propagateFace[faceI])
|
||||||
|
{
|
||||||
|
// Face is marked, select owner if this is the right
|
||||||
|
// side. Neighbour handled on the other side
|
||||||
|
const label& own = owner[faceI];
|
||||||
|
|
||||||
|
if (eligibleCells[own])
|
||||||
|
{
|
||||||
|
// Face cell is not a hole (or an acceptor in the
|
||||||
|
// first iteration), inser it
|
||||||
|
if (fringeHoles.insert(own))
|
||||||
|
{
|
||||||
|
++nAddedHoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as ineligible
|
||||||
|
eligibleCells[own] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We moved one layer "inside" the fringe. Keep going until
|
||||||
|
// there are no more holes to add
|
||||||
|
|
||||||
|
} while (nAddedHoles != 0);
|
||||||
|
|
||||||
|
// Finally, we have collected all the fringe holes and acceptors
|
||||||
|
// from this connected region. Append them to the global sets
|
||||||
|
allAcceptors += acceptors;
|
||||||
|
allFringeHoles += fringeHoles;
|
||||||
|
|
||||||
|
} // End for all connected regions
|
||||||
|
|
||||||
|
// Set acceptors and holes from the data for all regions
|
||||||
|
acceptorsPtr_ = new labelList(allAcceptors.sortedToc());
|
||||||
|
fringeHolesPtr_ = new labelList(allFringeHoles.sortedToc());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Connected fringes are not ready, allocate empty lists for acceptors
|
||||||
|
// and holes, which will be deleted when asked for again from the
|
||||||
|
// iterative procedure (see candidateAcceptors() and fringeHoles())
|
||||||
|
acceptorsPtr_ = new labelList(0);
|
||||||
|
holesPtr_ = new labelList(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,6 +530,25 @@ Foam::donorBasedLayeredOverlapFringe::donorBasedLayeredOverlapFringe
|
||||||
acceptorsPtr_(nullptr),
|
acceptorsPtr_(nullptr),
|
||||||
finalDonorAcceptorsPtr_(nullptr)
|
finalDonorAcceptorsPtr_(nullptr)
|
||||||
{
|
{
|
||||||
|
// Sanity check number of layers: must be greater than 0
|
||||||
|
if (nLayers_ < 1)
|
||||||
|
{
|
||||||
|
FatalIOErrorIn
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"donorBasedLayeredOverlapFringe\n"
|
||||||
|
"(\n"
|
||||||
|
" const fvMesh& mesh,\n"
|
||||||
|
" const oversetRegion& region,\n"
|
||||||
|
" const dictionary& dict\n"
|
||||||
|
")",
|
||||||
|
dict
|
||||||
|
) << "Invalid number of layers specified, nLayers = " nLayers_
|
||||||
|
<< nl
|
||||||
|
<< "The number should be greater than 0."
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
// Read names of connected regions
|
// Read names of connected regions
|
||||||
const wordList connectedRegionNames(dict.lookup("connectedRegions"));
|
const wordList connectedRegionNames(dict.lookup("connectedRegions"));
|
||||||
|
|
||||||
|
@ -150,10 +567,10 @@ Foam::donorBasedLayeredOverlapFringe::donorBasedLayeredOverlapFringe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through all regions and check whether the overlap has been found
|
// Loop through all regions and check whether the overlap has been found
|
||||||
forAll (connectedRegion_, crI)
|
forAll (connectedRegionNames, crI)
|
||||||
{
|
{
|
||||||
// Get name of this connected region
|
// Get name of this connected region
|
||||||
const word& crName = connectedRegion_[crI];
|
const word& crName = connectedRegionNames[crI];
|
||||||
|
|
||||||
// Find this region in the list of all regions
|
// Find this region in the list of all regions
|
||||||
const label regionID = findIndex(allRegions, crName);
|
const label regionID = findIndex(allRegions, crName);
|
||||||
|
@ -176,13 +593,51 @@ Foam::donorBasedLayeredOverlapFringe::donorBasedLayeredOverlapFringe
|
||||||
|
|
||||||
// Collect the region index in the list
|
// Collect the region index in the list
|
||||||
connectedRegionIDs_[crI] = regionID;
|
connectedRegionIDs_[crI] = regionID;
|
||||||
|
|
||||||
|
// Sanity check: if the specified connected donor region has more than 1
|
||||||
|
// donor regions, this fringe algorithm is attempted to be used for
|
||||||
|
// something that's not intended. Issue an error
|
||||||
|
if (allRegions[regionID].donorRegions().size() != 1)
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"donorBasedLayeredOverlapFringe\n"
|
||||||
|
"(\n"
|
||||||
|
" const fvMesh& mesh,\n"
|
||||||
|
" const oversetRegion& region,\n"
|
||||||
|
" const dictionary& dict\n"
|
||||||
|
")"
|
||||||
|
) << "Region " << crName << " specified as connected region, but"
|
||||||
|
<< " that region has "
|
||||||
|
<< allRegions[regionID].donorRegions().size() << " donor regions."
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check whether the donor region of connected region is actually
|
||||||
|
// this region
|
||||||
|
if (regionID != this->region().index())
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"donorBasedLayeredOverlapFringe\n"
|
||||||
|
"(\n"
|
||||||
|
" const fvMesh& mesh,\n"
|
||||||
|
" const oversetRegion& region,\n"
|
||||||
|
" const dictionary& dict\n"
|
||||||
|
")"
|
||||||
|
) << "The donor region of region " << crName
|
||||||
|
<< " should be only region " << this->region().name()
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check: number of (optionally) specified centre points must be
|
// Sanity check: number of (optionally) specified centre points must be
|
||||||
// equal to the number of connected regions
|
// equal to the number of connected regions
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
regionCentrePoints_.size()
|
!regionCentrePoints_.empty()
|
||||||
&& (regionCentrePoints_.size() != connectedRegionIDs_.size())
|
&& (regionCentrePoints_.size() != connectedRegionIDs_.size())
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -207,6 +662,33 @@ Foam::donorBasedLayeredOverlapFringe::donorBasedLayeredOverlapFringe
|
||||||
<< " make sure to specify centre points for all connected regions."
|
<< " make sure to specify centre points for all connected regions."
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity check: if the user has specified centre points, dynamic mesh
|
||||||
|
// simulations may be problematic. Issue a warning
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!regionCentrePoints_.empty()
|
||||||
|
&& isA<dynamicFvMesh>(this->mesh())
|
||||||
|
)
|
||||||
|
{
|
||||||
|
WarningIn
|
||||||
|
(
|
||||||
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"donorBasedLayeredOverlapFringe\n"
|
||||||
|
"(\n"
|
||||||
|
" const fvMesh& mesh,\n"
|
||||||
|
" const oversetRegion& region,\n"
|
||||||
|
" const dictionary& dict\n"
|
||||||
|
")"
|
||||||
|
) << "You have specified regionCentrePoints for a dynamic mesh"
|
||||||
|
<< " simulation."
|
||||||
|
<< nl
|
||||||
|
<< "Make sure that the centre points always remain in/near the"
|
||||||
|
<< " centre of donors in connected regions!"
|
||||||
|
<< nl
|
||||||
|
<< "Proceed with care!"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,98 +714,23 @@ bool Foam::donorBasedLayeredOverlapFringe::updateIteration
|
||||||
{
|
{
|
||||||
FatalErrorIn
|
FatalErrorIn
|
||||||
(
|
(
|
||||||
"donorBasedLayeredOverlapFringe::updateIteration(donorAcceptorList&"
|
"donorBasedLayeredOverlapFringe::"
|
||||||
|
"updateIteration(donorAcceptorList&) const"
|
||||||
) << "finalDonorAcceptorPtr_ already allocated. Something went "
|
) << "finalDonorAcceptorPtr_ already allocated. Something went "
|
||||||
<< "wrong with the iteration procedure (flag was not updated)."
|
<< "wrong with the iteration procedure (flag was not updated)."
|
||||||
<< nl << "This should not happen for donorBasedLayeredOverlapFringe."
|
<< nl << "This should not happen for donorBasedLayeredOverlapFringe."
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get list of all overset regions
|
// Allocate the list by reusing the argument list
|
||||||
const PtrList<oversetRegion>& allRegions =
|
finalDonorAcceptorsPtr_ = new donorAcceptorList
|
||||||
this->region().overset().regions();
|
(
|
||||||
|
donorAcceptorRegionData,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
// Loop through all connected regions and check whether the fringe overlap
|
// Set the flag to true and return
|
||||||
// has been found for all of them
|
updateSuitableOverlapFlag(true);
|
||||||
bool allFringesReady = true;
|
|
||||||
forAll (connectedRegionIDs_, crI)
|
|
||||||
{
|
|
||||||
// Get ID of this region
|
|
||||||
const label& regionID = connectedRegionIDs_[crI];
|
|
||||||
|
|
||||||
// Get the overset region
|
|
||||||
const oversetRegion& region = allRegions[regionID];
|
|
||||||
|
|
||||||
// Get the fringe algorithm from the region
|
|
||||||
const oversetFringe& fringe = region.fringe();
|
|
||||||
|
|
||||||
// If this is not faceCells fringe, issue a Warning. This fringe
|
|
||||||
// selection algorithm is intended to work only with faceCells fringe on
|
|
||||||
// the other side. VV, 9/Apr/2019
|
|
||||||
if (!isA<faceCellsFringe>(fringe))
|
|
||||||
{
|
|
||||||
WarningIn
|
|
||||||
(
|
|
||||||
"void Foam::donorBasedLayeredOverlapFringe::"
|
|
||||||
"calcAddressing() const"
|
|
||||||
) << "donorBasedLayeredOverlap fringe is designed to work"
|
|
||||||
<< " with faceCells fringe as a connected region fringe."
|
|
||||||
<< nl
|
|
||||||
<< "Connected overset region " << region.name()
|
|
||||||
<< " has " << fringe.type() " fringe type. "
|
|
||||||
<< nl
|
|
||||||
<< "Proceed with care!"
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update flag collecting whether all connected regions found the
|
|
||||||
// overlap
|
|
||||||
allFringesReady &= fringe.foundSuitableOverlap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allFringesReady)
|
|
||||||
{
|
|
||||||
// Loop through connected regions
|
|
||||||
forAll (connectedRegionIDs_, crI)
|
|
||||||
{
|
|
||||||
// Get ID of this region
|
|
||||||
const label& regionID = connectedRegionIDs_[crI];
|
|
||||||
|
|
||||||
// Get fringe of the connected region
|
|
||||||
const oversetFringe& fringe = allRegions[regionID].fringe();
|
|
||||||
|
|
||||||
// The fringe should be finalized, which means we may take a const
|
|
||||||
// reference to its final donor acceptors
|
|
||||||
const donorAcceptorList& crDonorAcceptorPairs =
|
|
||||||
fringe.finalDonorAcceptors();
|
|
||||||
|
|
||||||
// Sanity check the validity of donor
|
|
||||||
|
|
||||||
// Mark donors on my processor from this connected region
|
|
||||||
|
|
||||||
// Calculate the centre for this connected region if it isn't
|
|
||||||
// specified
|
|
||||||
|
|
||||||
// Mark all future acceptors by moving towards the centre using
|
|
||||||
// face-neighbour walk nLayers times
|
|
||||||
|
|
||||||
// Now that the acceptors are marked, mark all remaining holes
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the list by reusing the argument list
|
|
||||||
finalDonorAcceptorsPtr_ = new donorAcceptorList
|
|
||||||
(
|
|
||||||
donorAcceptorRegionData,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set the flag to true and return
|
|
||||||
updateSuitableOverlapFlag(true);
|
|
||||||
|
|
||||||
return foundSuitableOverlap();
|
|
||||||
} // else connected fringes are not ready yet, foundSuitableOverlap flag is
|
|
||||||
// alraedy false, so there's nothing to do
|
|
||||||
|
|
||||||
return foundSuitablaOverlap();
|
return foundSuitablaOverlap();
|
||||||
}
|
}
|
||||||
|
@ -335,6 +742,16 @@ const Foam::labelList& Foam::donorBasedLayeredOverlapFringe::fringeHoles() const
|
||||||
{
|
{
|
||||||
calcAddressing();
|
calcAddressing();
|
||||||
}
|
}
|
||||||
|
else if (fringeHolesPtr_->empty())
|
||||||
|
{
|
||||||
|
// Fringe holes pointer is empty, delete both acceptorPtr_ and
|
||||||
|
// fringeHolesPtr_ and calculate addressing. Since this fringe strategy
|
||||||
|
// depends on other fringes, we need to have a special control in the
|
||||||
|
// iterative algorithm that will start only when all the others are done
|
||||||
|
// See calcAddressing() for details
|
||||||
|
deleteDemandDrivenData(fringeHolesPtr_);
|
||||||
|
deleteDemandDrivenData(acceptorsPtr_);
|
||||||
|
}
|
||||||
|
|
||||||
return *fringeHolesPtr_;
|
return *fringeHolesPtr_;
|
||||||
}
|
}
|
||||||
|
@ -346,6 +763,16 @@ const Foam::labelList& Foam::donorBasedLayeredOverlapFringe::candidateAcceptors(
|
||||||
{
|
{
|
||||||
calcAddressing();
|
calcAddressing();
|
||||||
}
|
}
|
||||||
|
else if (acceptorsPtr_->empty())
|
||||||
|
{
|
||||||
|
// Acceptors pointer is empty, delete both acceptorPtr_ and
|
||||||
|
// fringeHolesPtr_ and calculate addressing. Since this fringe strategy
|
||||||
|
// depends on other fringes, we need to have a special control in the
|
||||||
|
// iterative algorithm that will start only when all the others are done
|
||||||
|
// See calcAddressing() for details
|
||||||
|
deleteDemandDrivenData(fringeHolesPtr_);
|
||||||
|
deleteDemandDrivenData(acceptorsPtr_);
|
||||||
|
}
|
||||||
|
|
||||||
return *acceptorsPtr_;
|
return *acceptorsPtr_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ Description
|
||||||
until the final donor/acceptor assembly has been performed for all regions
|
until the final donor/acceptor assembly has been performed for all regions
|
||||||
whose donor region is this region. Then, all donors are collected and the
|
whose donor region is this region. Then, all donors are collected and the
|
||||||
acceptors are cells neighbouring the donors nLayers towards the interior.
|
acceptors are cells neighbouring the donors nLayers towards the interior.
|
||||||
Interior is defined either by a user-specified point or as a centre of
|
Interior is defined either by user-specified points for each region or as a
|
||||||
volume of the donor cells.
|
centre of volume of the donor cells in particular region.
|
||||||
|
|
||||||
This fringe algorithm is intended to be used along with the faceCells fringe
|
This fringe algorithm is intended to be used along with the faceCells fringe
|
||||||
on the other side, where the cell sizes are not significantly different from
|
on the other side, where the cell sizes are not significantly different from
|
||||||
each other (e.g. 10:1 cell ratio will probably be problematic to correctly
|
each other (e.g. 10:1 cell ratio, where the finer cells are found on the
|
||||||
set-up).
|
background mesh will probably be problematic to correctly set-up).
|
||||||
|
|
||||||
Author
|
Author
|
||||||
Vuko Vukcevic, Wikki Ltd. All rights reserved.
|
Vuko Vukcevic, Wikki Ltd. All rights reserved.
|
||||||
|
@ -72,8 +72,8 @@ class donorBasedLayeredOverlapFringe
|
||||||
|
|
||||||
//- Optional list of points representing a rough estimate of the centre
|
//- Optional list of points representing a rough estimate of the centre
|
||||||
// for each underlying connected region. If these are not provided, the
|
// for each underlying connected region. If these are not provided, the
|
||||||
// centre is calculated as the centre of volume of all donors for a
|
// centre is calculated as the centre of all donors for a given
|
||||||
// given connected region
|
// connected region
|
||||||
pointList regionCentrePoints_;
|
pointList regionCentrePoints_;
|
||||||
|
|
||||||
//- How many layers to move away from connected region donors to define
|
//- How many layers to move away from connected region donors to define
|
||||||
|
@ -90,6 +90,13 @@ class donorBasedLayeredOverlapFringe
|
||||||
mutable donorAcceptorList* finalDonorAcceptorsPtr_;
|
mutable donorAcceptorList* finalDonorAcceptorsPtr_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private static data
|
||||||
|
|
||||||
|
//- Distance tolerance to determine propagation direction. Note:
|
||||||
|
// absolute value, default = 0. Might be useful is some strange cases
|
||||||
|
static const debug::tolerancesSwitch distTol_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- Disallow default bitwise copy construct
|
||||||
|
|
Reference in a new issue