ENH: snappyHexMesh: optionally remove 'small' regions. Fixes #1772.

This is for a very specific use case where the faceZones are
imprinted after meshing the normal geometry. This sometimes
splits off badly connected bits of the mesh. One way to remove
these is to use e.g. subsetMesh. This embeds the
same functionality inside snappyHexMesh.
This commit is contained in:
mattijs
2020-07-13 15:29:12 +01:00
parent 331e86cf17
commit 950e667259
6 changed files with 252 additions and 58 deletions

View File

@ -244,15 +244,6 @@ private:
labelList& minLevel
) const;
//- Remove cells. Put exposedFaces into exposedPatchIDs.
autoPtr<mapPolyMesh> doRemoveCells
(
const labelList& cellsToRemove,
const labelList& exposedFaces,
const labelList& exposedPatchIDs,
removeCells& cellRemover
);
//- Get cells which are inside any closed surface. Note that
// all closed surfaces
// will have already been oriented to have keepPoint outside.
@ -1336,6 +1327,16 @@ public:
const List<labelPair>& baffles
);
//- Get per-face information (faceZone, master/slave patch)
void getZoneFaces
(
const labelList& zoneIDs,
labelList& faceZoneID,
labelList& ownPatch,
labelList& neiPatch,
labelList& nBaffles
) const;
//- Create baffles for faces on faceZones. Return created baffles
// (= pairs of faces) and corresponding faceZone
autoPtr<mapPolyMesh> createZoneBaffles
@ -1458,6 +1459,15 @@ public:
const writer<scalar>& leakPathFormatter
);
//- Remove cells. Put exposedFaces into exposedPatchIDs.
autoPtr<mapPolyMesh> doRemoveCells
(
const labelList& cellsToRemove,
const labelList& exposedFaces,
const labelList& exposedPatchIDs,
removeCells& cellRemover
);
//- Split faces into two
void doSplitFaces
(

View File

@ -715,35 +715,31 @@ Foam::List<Foam::labelPair> Foam::meshRefinement::subsetBaffles
}
Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles
void Foam::meshRefinement::getZoneFaces
(
const labelList& zoneIDs,
List<labelPair>& baffles,
labelList& originatingFaceZone
)
labelList& faceZoneID,
labelList& ownPatch,
labelList& neiPatch,
labelList& nBaffles
) const
{
autoPtr<mapPolyMesh> map;
if (zoneIDs.size() > 0)
{
const faceZoneMesh& faceZones = mesh_.faceZones();
// Split internal faces on interface surfaces
Info<< "Converting zoned faces into baffles ..." << endl;
// Per (internal) face the patch it should go into
labelList ownPatch(mesh_.nFaces(), -1);
labelList neiPatch(mesh_.nFaces(), -1);
labelList faceZoneID(mesh_.nFaces(), -1);
labelList nBaffles(zoneIDs.size(), Zero);
// Per (internal) face the patch related to the faceZone
ownPatch.setSize(mesh_.nFaces());
ownPatch= -1;
neiPatch.setSize(mesh_.nFaces());
neiPatch = -1;
faceZoneID.setSize(mesh_.nFaces());
faceZoneID = -1;
nBaffles.setSize(zoneIDs.size());
nBaffles = Zero;
forAll(zoneIDs, j)
{
label zoneI = zoneIDs[j];
const faceZone& fz = faceZones[zoneI];
const word& masterName = faceZoneToMasterPatch_[fz.name()];
label masterPatchI = mesh_.boundaryMesh().findPatchID(masterName);
const word& slaveName = faceZoneToSlavePatch_[fz.name()];
@ -777,6 +773,31 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles
}
}
}
}
Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles
(
const labelList& zoneIDs,
List<labelPair>& baffles,
labelList& originatingFaceZone
)
{
autoPtr<mapPolyMesh> map;
if (zoneIDs.size() > 0)
{
const faceZoneMesh& faceZones = mesh_.faceZones();
// Split internal faces on interface surfaces
Info<< "Converting zoned faces into baffles ..." << endl;
// Get faceZone and patch(es) per face (or -1 if face not on faceZone)
labelList faceZoneID;
labelList ownPatch;
labelList neiPatch;
labelList nBaffles;
getZoneFaces(zoneIDs, faceZoneID, ownPatch, neiPatch, nBaffles);
label nLocalBaffles = sum(nBaffles);

View File

@ -94,6 +94,7 @@ Foam::refinementParameters::refinementParameters
),
nErodeCellZone_(dict.getOrDefault<label>("nCellZoneErodeIter", 0)),
nFilterIter_(dict.getOrDefault<label>("nFilterIter", 2)),
minCellFraction_(dict.getOrDefault<scalar>("minCellFraction", 0)),
dryRun_(dryRun)
{
point locationInMesh;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2014 OpenFOAM Foundation
Copyright (C) 2015-2019 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -113,6 +113,8 @@ class refinementParameters
const label nFilterIter_;
const scalar minCellFraction_;
const bool dryRun_;
@ -235,6 +237,13 @@ public:
return nFilterIter_;
}
//- When are disconnected regions small. Fraction of overall size
// of a zone or background. Default 0.
scalar minCellFraction() const
{
return minCellFraction_;
}
// Other

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2015-2019 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -47,6 +47,8 @@ License
#include "fvMeshSubset.H"
#include "interpolationTable.H"
#include "snappyVoxelMeshDriver.H"
#include "regionSplit.H"
#include "removeCells.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -2869,6 +2871,142 @@ void Foam::snappyRefineDriver::mergePatchFaces
}
void Foam::snappyRefineDriver::deleteSmallRegions
(
const refinementParameters& refineParams
)
{
const fvMesh& mesh = meshRefiner_.mesh();
const cellZoneMesh& czm = mesh.cellZones();
//const labelList zoneIDs
//(
// meshRefiner_.getZones
// (
// List<surfaceZonesInfo::faceZoneType> fzTypes
// ({
// surfaceZonesInfo::BAFFLE,
// surfaceZonesInfo::BOUNDARY,
// });
// )
//);
const labelList zoneIDs(identity(mesh.faceZones().size()));
// Get faceZone and patch(es) per face (or -1 if face not on faceZone)
labelList faceZoneID;
labelList ownPatch;
labelList neiPatch;
labelList nB; // local count of faces per faceZone
meshRefiner_.getZoneFaces(zoneIDs, faceZoneID, ownPatch, neiPatch, nB);
// Mark all faces on outside of zones. Note: assumes that faceZones
// are consistent with the outside of cellZones ...
boolList isBlockedFace(mesh.nFaces(), false);
meshRefiner_.selectSeparatedCoupledFaces(isBlockedFace);
forAll(ownPatch, facei)
{
if (ownPatch[facei] != -1)
{
isBlockedFace[facei] = true;
}
}
// Map from cell to zone. Not that background cells are not -1 but
// cellZones.size()
labelList cellToZone(mesh.nCells(), czm.size());
for (const auto& cz : czm)
{
UIndirectList<label>(cellToZone, cz) = cz.index();
}
// Walk to split into regions
const regionSplit cellRegion(mesh, isBlockedFace);
// Count number of cells per zone and per region
labelList nCellsPerRegion(cellRegion.nRegions(), 0);
labelList regionToZone(cellRegion.nRegions(), -2);
labelList nCellsPerZone(czm.size()+1, 0);
forAll(cellRegion, celli)
{
const label regioni = cellRegion[celli];
const label zonei = cellToZone[celli];
// Zone for this region
regionToZone[regioni] = zonei;
nCellsPerRegion[regioni]++;
nCellsPerZone[zonei]++;
}
Pstream::listCombineGather(nCellsPerRegion, plusEqOp<label>());
Pstream::listCombineGather(regionToZone, maxEqOp<label>());
Pstream::listCombineGather(nCellsPerZone, plusEqOp<label>());
// Mark small regions
forAll(nCellsPerRegion, regioni)
{
const label zonei = regionToZone[regioni];
if
(
nCellsPerRegion[regioni]
< refineParams.minCellFraction()*nCellsPerZone[zonei]
)
{
Info<< "Deleting region " << regioni
<< " (size " << nCellsPerRegion[regioni]
<< ") of zone size " << nCellsPerZone[zonei]
<< endl;
// Mark region to be deleted. 0 size (= global) should never
// occur.
nCellsPerRegion[regioni] = 0;
}
}
DynamicList<label> cellsToRemove(mesh.nCells()/128);
forAll(cellRegion, celli)
{
if (nCellsPerRegion[cellRegion[celli]] == 0)
{
cellsToRemove.append(celli);
}
}
const label nTotCellsToRemove = returnReduce
(
cellsToRemove.size(),
sumOp<label>()
);
if (nTotCellsToRemove > 0)
{
Info<< "Deleting " << nTotCellsToRemove
<< " cells in small regions" << endl;
removeCells cellRemover(mesh);
cellsToRemove.shrink();
const labelList exposedFaces
(
cellRemover.getExposedFaces(cellsToRemove)
);
const labelList exposedPatch
(
UIndirectList<label>(ownPatch, exposedFaces)
);
(void)meshRefiner_.doRemoveCells
(
cellsToRemove,
exposedFaces,
exposedPatch,
cellRemover
);
}
}
void Foam::snappyRefineDriver::doRefine
(
const dictionary& refineDict,
@ -3099,6 +3237,17 @@ void Foam::snappyRefineDriver::doRefine
}
if (refineParams.minCellFraction() > 0)
{
// Some small disconnected bits of mesh might remain since at
// this point faceZones have not been converted into e.g. baffles.
// We don't know whether e.g. the baffles are reset to be cyclicAMI
// thus reconnecting. For now check if there are any particularly
// small regions.
deleteSmallRegions(refineParams);
}
if (!dryRun_ && Pstream::parRun())
{
Info<< nl

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2014 OpenFOAM Foundation
Copyright (C) 2015-2018 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -232,6 +232,10 @@ class snappyRefineDriver
const dictionary& motionDict
);
//- Optionally delete some small regions
void deleteSmallRegions(const refinementParameters&);
//- No copy construct
snappyRefineDriver(const snappyRefineDriver&) = delete;