From db859b968c09c5d6bc5e43e4ae0c4bdced698f48 Mon Sep 17 00:00:00 2001 From: Vuko Vukcevic Date: Mon, 20 May 2019 16:16:13 +0200 Subject: [PATCH] First version of cuttingPatchFringe algorithm Similar to donorBasedOverlapFringe but better in a sense that it relies on determining inside/outside region by creating an STL of the patch from donor region. Note: still has bugs --- src/overset/oversetMesh/Make/files | 1 + .../cuttingPatchFringe/cuttingPatchFringe.C | 772 ++++++++++++++++++ .../cuttingPatchFringe/cuttingPatchFringe.H | 163 ++++ 3 files changed, 936 insertions(+) create mode 100644 src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.C create mode 100644 src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.H diff --git a/src/overset/oversetMesh/Make/files b/src/overset/oversetMesh/Make/files index 2a7175cc0..d21982f92 100644 --- a/src/overset/oversetMesh/Make/files +++ b/src/overset/oversetMesh/Make/files @@ -5,6 +5,7 @@ oversetFringe/oversetFringe/newOversetFringe.C oversetFringe/manualFringe/manualFringe.C oversetFringe/faceCellsFringe/faceCellsFringe.C oversetFringe/donorBasedLayeredOverlapFringe/donorBasedLayeredOverlapFringe.C +oversetFringe/cuttingPatchFringe/cuttingPatchFringe.C oversetFringe/overlapFringe/overlapFringe/overlapFringe.C oversetFringe/overlapFringe/layeredOverlapFringe/layeredOverlapFringe.C oversetFringe/overlapFringe/adaptiveOverlapFringe/adaptiveOverlapFringe.C diff --git a/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.C b/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.C new file mode 100644 index 000000000..f3b49587e --- /dev/null +++ b/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.C @@ -0,0 +1,772 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 . + +\*---------------------------------------------------------------------------*/ + +#include "cuttingPatchFringe.H" +#include "oversetMesh.H" +#include "oversetRegion.H" +#include "faceCellsFringe.H" +#include "oversetRegion.H" +#include "polyPatchID.H" +#include "addToRunTimeSelectionTable.H" +#include "syncTools.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(cuttingPatchFringe, 0); + addToRunTimeSelectionTable + ( + oversetFringe, + cuttingPatchFringe, + dictionary + ); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::cuttingPatchFringe::init() const +{ + // Set size of the list containing IDs + connectedRegionIDs_.setSize(connectedRegionNames_.size()); + + // Get list of all overset regions + const PtrList& allRegions = + this->region().overset().regions(); + + // Create list of all region names for easy lookup + wordList allRegionNames(allRegions.size()); + forAll (allRegionNames, arI) + { + allRegionNames[arI] = allRegions[arI].name(); + } + + // Loop through all regions and check whether the overlap has been found + forAll (connectedRegionNames_, crI) + { + // Get name of this connected region + const word& crName = connectedRegionNames_[crI]; + + // Find this region in the list of all regions + const label regionID = findIndex(allRegionNames, crName); + + if (regionID == -1) + { + FatalErrorIn("void cuttingPatchFringe::init() const") + << "Region " << crName << " not found in list of regions." + << "List of overset regions: " << allRegionNames + << abort(FatalError); + } + + // Collect the region index in the list + 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 for. Issue an error + if (allRegions[regionID].donorRegions().size() != 1) + { + FatalErrorIn("void cuttingPatchFringe::init() const") + << "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 (allRegions[regionID].donorRegions()[0] != this->region().index()) + { + FatalErrorIn("void cuttingPatchFringe::init() const") + << "The donor region of region " << crName + << " should be only region " << this->region().name() + << abort(FatalError); + } + } +} + + +void Foam::cuttingPatchFringe::calcAddressing() const +{ + // Make sure that either acceptorsPtr is unnalocated or if it is allocated, + // that it is empty + if (acceptorsPtr_ && !acceptorsPtr_->empty()) + { + FatalErrorIn + ( + "void Foam::cuttingPatchFringe::calcAddressing() const" + ) << "Addressing already calculated" + << abort(FatalError); + } + + if (!isInitialized_) + { + // This is the first call, initialize the data and set flag to true + init(); + isInitialized_ = true; + } + + // Get list of all overset regions + const PtrList& allRegions = + this->region().overset().regions(); + + // Sets containing all acceptors and all holes for all connected regions + const polyMesh& mesh = this->mesh(); + labelHashSet allAcceptors(0.02*mesh.nCells()); + labelHashSet allFringeHoles(0.02*mesh.nCells()); + + if (debug) + { + Info<< "All dependent fringes are ready." + << " Starting face cells cut patch fringe assembly..." << endl; + } + + // 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(); + + // If this is not faceCells fringe, issue an Error. This fringe + // selection algorithm is intended to work only with faceCells fringe on + // the other side. VV, 9/Apr/2019 + if (!isA(fringe)) + { + FatalErrorIn + ( + "void Foam::cuttingPatchFringe::" + "updateIteration(donorAcceptorList&) const" + ) << "cuttingPatch fringe is designed to work" + << " with faceCells fringe as a connected region fringe." + << nl + << "Connected overset region " << allRegions[regionID].name() + << " has " << fringe.type() << " fringe type. " + << nl + << "Proceed with care!" + << abort(FatalError); + } + const faceCellsFringe& fcFringe = + refCast(fringe); + + // Get patch names from faceCells fringe + const wordList& fcPatchNames = fcFringe.patchNames(); + + // Find the patches + labelHashSet patchIDs; + + forAll (fcPatchNames, nameI) + { + // Get polyPatchID and check if valid + const polyPatchID fringePatch + ( + fcPatchNames[nameI], + mesh.boundaryMesh() + ); + + if (!fringePatch.active()) + { + FatalErrorIn + ( + "void cuttingPatchFringe::calcAddressing const" + ) << "Fringe patch " << fcPatchNames[nameI] + << " for region " << allRegions[regionID].name() + << " cannot be found." + << abort(FatalError); + } + + // Store patch ID in the set + patchIDs.insert(fringePatch.index()); + } + + // Note: same code as in oversetRegion::calcHoleTriMesh. Consider + // refactoring. VV, 20/May/2019 + + // Make and invert local triSurface + triFaceList triFaces; + pointField triPoints; + + // Memory management + { + triSurface ts = triSurfaceTools::triangulate + ( + mesh.boundaryMesh(), + patchIDs + ); + + // Clean mutiple points and zero-sized triangles + ts.cleanup(false); + + triFaces.setSize(ts.size()); + triPoints = ts.points(); + + forAll (ts, tsI) + { + triFaces[tsI] = ts[tsI].reverseFace(); + } + } + + if (Pstream::parRun()) + { + // Combine all faces and points into a single list + + List allTriFaces(Pstream::nProcs()); + List allTriPoints(Pstream::nProcs()); + + allTriFaces[Pstream::myProcNo()] = triFaces; + allTriPoints[Pstream::myProcNo()] = triPoints; + + Pstream::gatherList(allTriFaces); + Pstream::scatterList(allTriFaces); + + Pstream::gatherList(allTriPoints); + Pstream::scatterList(allTriPoints); + + // Re-pack points and faces + + label nTris = 0; + label nPoints = 0; + + forAll (allTriFaces, procI) + { + nTris += allTriFaces[procI].size(); + nPoints += allTriPoints[procI].size(); + } + + // Pack points + triPoints.setSize(nPoints); + + // Prepare point renumbering array + labelListList renumberPoints(Pstream::nProcs()); + + nPoints = 0; + + forAll (allTriPoints, procI) + { + const pointField& ptp = allTriPoints[procI]; + + renumberPoints[procI].setSize(ptp.size()); + + labelList& procRenumberPoints = renumberPoints[procI]; + + forAll (ptp, ptpI) + { + triPoints[nPoints] = ptp[ptpI]; + procRenumberPoints[ptpI] = nPoints; + + nPoints++; + } + } + + // Pack triangles and renumber into complete points on the fly + triFaces.setSize(nTris); + + nTris = 0; + + forAll (allTriFaces, procI) + { + const triFaceList& ptf = allTriFaces[procI]; + + const labelList& procRenumberPoints = renumberPoints[procI]; + + forAll (ptf, ptfI) + { + const triFace& procFace = ptf[ptfI]; + + triFace& renumberFace = triFaces[nTris]; + + forAll (renumberFace, rfI) + { + renumberFace[rfI] = + procRenumberPoints[procFace[rfI]]; + } + + nTris++; + } + } + } + + // Make a complete triSurface from local data + triSurface patchTriMesh(triFaces, triPoints); + + // Clean up duplicate points and zero sized triangles + patchTriMesh.cleanup(false); + + // Get this region + const oversetRegion& myRegion = this->region(); + + // Debug: write down the tri mesh + if (Pstream::master()) + { + patchTriMesh.write + ( + word + ( + "patchTriSurface_region" + myRegion.name() + + "_connectedRegion" + allRegions[regionID].name() + ".vtk" + ) + ); + } + + // Create the tri surface search object + triSurfaceSearch patchTriSearch(patchTriMesh); + + // Get cells in this region + const labelList& myRegionCells = myRegion.regionCells(); + + // Get cell centres for inside-outside search using search object + vectorField myCC(myRegionCells.size()); + + // Cell centres from polyMesh + const vectorField& cc = mesh.cellCentres(); + + forAll (myCC, i) + { + myCC[i] = cc[myRegionCells[i]]; + } + + // Inside mask: all cells within search object will be marked + boolList insideMask(mesh.nCells(), false); + + // Get inside cells for cells in my region only + boolList myRegionInsideMask = patchTriSearch.calcInside(myCC); + + // Note: insideMask has the size of all mesh cells and + // myRegionInsideMask has the size of cells in this region + forAll (myRegionInsideMask, i) + { + insideMask[myRegionCells[i]] = myRegionInsideMask[i]; + } + + // Get necessary mesh data (from polyMesh/primitiveMesh) + const cellList& meshCells = mesh.cells(); + const unallocLabelList& owner = mesh.faceOwner(); + const unallocLabelList& neighbour = mesh.faceNeighbour(); + + // Collect all inside cells either as hole cells or acceptor + // cells. For the first iteration, acceptor cells are the cells that + // have at least one neighbour cell that is not marked + labelHashSet acceptors(myRegionCells.size()/10); + + // Bool list for collecting faces with at least one unmarked + // cell (to determine the acceptors for the first iteration) + boolList hasUnmarkedCell(mesh.nFaces(), false); + + // Loop through all cells + forAll (insideMask, cellI) + { + if (!insideMask[cellI]) + { + // This cell is not inside (it is unmarked). Loop through + // its faces and set the flag + const cell& cFaces = meshCells[cellI]; + + forAll (cFaces, i) + { + // Set the mark for this global face and break out + hasUnmarkedCell[cFaces[i]] = true; + break; + } + } + } + + // Sync the face list across processor boundaries + syncTools::syncFaceList + ( + mesh, + hasUnmarkedCell, + orOp(), + false + ); + + // Mark-up for all hole faces + boolList holeFaceMask(mesh.nFaces(), false); + + // Loop again through all cells and collect marked ones into + // acceptors or holes, depending on whether they have unmarked cell + // as a neighbour (indicating an acceptor) + forAll (insideMask, cellI) + { + if (insideMask[cellI]) + { + // This cell is inside the covered region + const cell& cFaces = meshCells[cellI]; + + // Helper variable to determine whether this marked cell + // should be collected as a hole + bool isHole = true; + + forAll (cFaces, i) + { + // Get global face index + const label& faceI = cFaces[i]; + + // Check whether this neighbour is unmarked + if (hasUnmarkedCell[faceI]) + { + // This cell has unmarked neighbour, collect it into + // the acceptor list, set isHole to false and break + acceptors.insert(cellI); + isHole = false; + break; + } + } + + // If this is a hole, collect it and mark its faces + if (isHole) + { + holeCellMask[cellI] = true; + + // Loop through cell faces and mark them + const cell& cFaces = meshCells[cellI]; + + forAll (cFaces, i) + { + holeFaceMask[cFaces[i]] = true; + } + } + } // End if cell is inside + } // End for all cells + + // Hash set containing new acceptors (for successive iterations) + labelHashSet newAcceptors(acceptors.size()); + + // Now that we have the initial set of acceptors (and holes), 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 around hole + // cells. This way, we make sure that we go towards the correct, + // inside direction + forAllConstIter (labelHashSet, acceptors, iter) + { + // Get the cell index and the cell + const label& cellI = iter.key(); + const cell& cFaces = meshCells[cellI]; + + // Loop through all faces of the cell + forAll (cFaces, i) + { + // Get face index (global) + const label& faceI = cFaces[i]; + + if (holeFaceMask[faceI]) + { + // This is a hole face, we are moving in the right + // direction. Mark the face for propagation + 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(), + 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 hole, not both + if (holeCellMask[own]) + { + // Owner cell is a hole, insert it + newAcceptors.insert(own); + + // Update hole mask + holeCellMask[own] = false; + } + else if (holeCellMask[nei]) + { + // Neighbour cell is a hole, insert it + newAcceptors.insert(nei); + + // Update hole mask + holeCellMask[nei] = false; + } + + // Also update hole face mask for next iteration + holeFaceMask[faceI] = 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 (holeCellMask[own]) + { + // Face cell is a hole, insert it + newAcceptors.insert(own); + + // Update hole mask + holeCellMask[own] = false; + } + + // Also update hole face mask for next iteration + holeFaceMask[faceI] = false; + } + } + + // Transfer newAcceptors into acceptors for next iteration or + // for final assembly. Resize newAcceptors accordingly + acceptors.transfer(newAcceptors); + newAcceptors.resize(acceptors.size()); + + } // End for specified number of layers + + // At this point, we have the final set of acceptors and we marked + // all cells that should be holes. Collect holes into hash set (could be + // optimized by using dynamic lists) + labelHashSet fringeHoles(myRegionCells.size()/10); + + forAll (holeCellMask, cellI) + { + if (holeCellMask[cellI]) + { + fringeHoles.insert(cellI); + } + } + + // Finally, we have fringe holes and acceptors and we need to add them + // to the list containing all acceptors and holes (for all connected + // regions) + allAcceptors += acceptors; + allFringeHoles += fringeHoles; + } + + // Set acceptors and holes from the data for all regions + acceptorsPtr_ = new labelList(allAcceptors.sortedToc()); + fringeHolesPtr_ = new labelList(allFringeHoles.sortedToc()); + + if (debug) + { + Info<< "In cuttingPatchFringe::calcAddressing() const" << nl + << "Found " << acceptorsPtr_->size() << " acceptors." << nl + << "Found " << fringeHolesPtr_->size() << " fringe holes." << endl; + } +} + + +void Foam::cuttingPatchFringe::clearAddressing() const +{ + deleteDemandDrivenData(fringeHolesPtr_); + deleteDemandDrivenData(acceptorsPtr_); + deleteDemandDrivenData(finalDonorAcceptorsPtr_); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +// Construct from dictionary +Foam::cuttingPatchFringe::cuttingPatchFringe +( + const fvMesh& mesh, + const oversetRegion& region, + const dictionary& dict +) +: + oversetFringe(mesh, region, dict), + connectedRegionNames_(dict.lookup("connectedRegions")), + connectedRegionIDs_(), + nLayers_(readLabel(dict.lookup("nLayers"))), + fringeHolesPtr_(nullptr), + acceptorsPtr_(nullptr), + finalDonorAcceptorsPtr_(nullptr), + isInitialized_(false) +{ + // Sanity check number of layers: must be greater than 0 + if (nLayers_ < 1) + { + FatalIOErrorIn + ( + "cuttingPatchFringe::" + "cuttingPatchFringe\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); + } + + // Preferably, the number of layers should be at least 2 + if (nLayers_ == 1) + { + WarningIn + ( + "cuttingPatchFringe::" + "cuttingPatchFringe\n" + "(\n" + " const fvMesh& mesh,\n" + " const oversetRegion& region,\n" + " const dictionary& dict\n" + ")" + ) << "You have specified nLayers = " << nLayers_ + << nl + << "We strongly advise to use at least 2 layers to avoid" + << " possibility of having acceptors that cannot find decent" + << " donors on the other side." + << abort(FatalError); + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cuttingPatchFringe::~cuttingPatchFringe() +{ + clearAddressing(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::cuttingPatchFringe::updateIteration +( + donorAcceptorList& donorAcceptorRegionData +) const +{ + // If the donorAcceptor list has been allocated, something went wrong with + // the iteration procedure (not-updated flag): this function has been called + // more than once, which should not happen for cuttingPatchFringe + if (finalDonorAcceptorsPtr_) + { + FatalErrorIn + ( + "cuttingPatchFringe::" + "updateIteration(donorAcceptorList&) const" + ) << "finalDonorAcceptorPtr_ already allocated. Something went " + << "wrong with the iteration procedure (flag was not updated)." + << nl + << "This should not happen for cuttingPatchFringe." + << abort(FatalError); + } + + // Allocate the list by reusing the argument list + finalDonorAcceptorsPtr_ = new donorAcceptorList + ( + donorAcceptorRegionData, + true + ); + + // Set the flag to true and return + updateSuitableOverlapFlag(true); + + return foundSuitableOverlap(); +} + + +const Foam::labelList& Foam::cuttingPatchFringe::fringeHoles() const +{ + if (!fringeHolesPtr_) + { + calcAddressing(); + } + + return *fringeHolesPtr_; +} + + +const Foam::labelList& Foam::cuttingPatchFringe::candidateAcceptors() const +{ + if (!acceptorsPtr_) + { + calcAddressing(); + } + + return *acceptorsPtr_; +} + + +Foam::donorAcceptorList& +Foam::cuttingPatchFringe::finalDonorAcceptors() const +{ + if (!finalDonorAcceptorsPtr_) + { + FatalErrorIn("cuttingPatchFringe::finalDonorAcceptors()") + << "finalDonorAcceptorPtr_ not allocated. Make sure you have" + << " called cuttingPatchFringe::updateIteration() before" + << " asking for final set of donor/acceptor pairs." + << abort(FatalError); + } + + if (!foundSuitableOverlap()) + { + FatalErrorIn("cuttingPatchFringe::finalDonorAcceptors()") + << "Attemted to access finalDonorAcceptors but suitable overlap " + << "has not been found. This is not allowed. " + << abort(FatalError); + } + + return *finalDonorAcceptorsPtr_; +} + + +void Foam::cuttingPatchFringe::update() const +{ + Info<< "cuttingPatchFringe::update() const" << endl; + + // Clear out + clearAddressing(); + + // Set flag to false and clear final donor/acceptors only + deleteDemandDrivenData(finalDonorAcceptorsPtr_); + updateSuitableOverlapFlag(false); +} + + +// ************************************************************************* // diff --git a/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.H b/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.H new file mode 100644 index 000000000..cc885c303 --- /dev/null +++ b/src/overset/oversetMesh/oversetFringe/cuttingPatchFringe/cuttingPatchFringe.H @@ -0,0 +1,163 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 . + +Class + cuttingPatchFringe + +Description + Fringe algorithm based on collecting all the cells cut by its donor region + patch (assuming faceCells algorithm is used). Inside cells are marked and + moved nLayers towards the interior to define the acceptors as robustly as + possible. + +Author + Vuko Vukcevic, Wikki Ltd. All rights reserved. + +SourceFiles + cuttingPatchFringe.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cuttingPatchFringe_H +#define cuttingPatchFringe_H + +#include "oversetFringe.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class cuttingPatchFringe Declaration +\*---------------------------------------------------------------------------*/ + +class cuttingPatchFringe +: + public oversetFringe +{ + // Private data + + //- Names of connected regions. Looked up on construction + wordList connectedRegionNames_; + + //- Regions IDs from which the donors will be collected as a starting + // point. Note: initialized in init private member function because we + // cannot initialize it in constructor. This is because certain overset + // regions (and their fringes) may not be initialized at this point. + mutable labelList connectedRegionIDs_; + + //- How many layers to move away from connected region donors to define + // acceptor (and holes) + label nLayers_; + + //- Fringe hole cells + mutable labelList* fringeHolesPtr_; + + //- Acceptor cells + mutable labelList* acceptorsPtr_; + + //- Final donor/acceptor pairs for this region (fringe) + mutable donorAcceptorList* finalDonorAcceptorsPtr_; + + //- Initialization helper + mutable bool isInitialized_; + + + // Private Member Functions + + //- Initialization + void init() const; + + //- Calculate hole and acceptor addressing + void calcAddressing() const; + + //- Clear addressing + void clearAddressing() const; + + +public: + + //- Runtime type information + TypeName("cuttingPatch"); + + + // Constructors + + //- Construct from dictionary + cuttingPatchFringe + ( + const fvMesh& mesh, + const oversetRegion& region, + const dictionary& dict + ); + + //- Disallow default bitwise copy construct + cuttingPatchFringe + ( + const cuttingPatchFringe& + ) = delete; + + //- Disallow default bitwise assignment + void operator=(const cuttingPatchFringe&) = delete; + + + // Destructor + + virtual ~cuttingPatchFringe(); + + + // Member Functions + + //- Update iteration. Note: invalidates parameter + virtual bool updateIteration + ( + donorAcceptorList& donorAcceptorRegionData + ) const; + + //- Return list of deactivated (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 + +// ************************************************************************* //