From 0bc59af9833f2c75f457b4e2ec49d020f13aaddc Mon Sep 17 00:00:00 2001 From: mattijs <mattijs> Date: Mon, 3 Feb 2020 09:27:19 +0000 Subject: [PATCH] ENH: snappyHexMesh: allow cellZone erosion. Fixes #1528. --- etc/caseDicts/annotated/snappyHexMeshDict | 4 + .../meshRefinement/meshRefinement.H | 11 + .../meshRefinement/meshRefinementBaffles.C | 378 +++++++++++++++++- 3 files changed, 391 insertions(+), 2 deletions(-) diff --git a/etc/caseDicts/annotated/snappyHexMeshDict b/etc/caseDicts/annotated/snappyHexMeshDict index 0dc00679460..a775ea3b65a 100644 --- a/etc/caseDicts/annotated/snappyHexMeshDict +++ b/etc/caseDicts/annotated/snappyHexMeshDict @@ -456,6 +456,10 @@ castellatedMeshControls // Erosion is specified as a number of erosion iterations. // Erosion has less chance of bleeding and changing the zone // for a complete region. + // A negative value implements 'growing' the cellZones which + // might help with small non-physical gaps inbetween cellZones. + // (currently only a single layer growth i.e. -1 is supported) + // Default value is 0. //nCellZoneErodeIter 2; } diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H index 7bbdcf96a31..bce5111d655 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H @@ -805,6 +805,17 @@ private: labelList& cellToZone ) const; + //- Variation of findCellZoneTopo: walks from cellZones but ignores + // face intersections (unnamedSurfaceRegion). WIP + void growCellZone + ( + const label nGrowCellZones, + const label backgroundZoneID, + labelList& unnamedSurfaceRegion, + labelList& namedSurfaceRegion, + labelList& cellToZone + ) const; + //- Make namedSurfaceRegion consistent with cellToZone // - clear out any blocked faces inbetween same cell zone. void makeConsistentFaceIndex diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C index fb15e770596..3b07b51c5e7 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C @@ -55,6 +55,9 @@ License #include "zeroGradientFvPatchFields.H" #include "volFields.H" +#include "FaceCellWave.H" +#include "wallPoints.H" + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::label Foam::meshRefinement::createBaffle @@ -2177,6 +2180,313 @@ void Foam::meshRefinement::erodeCellZone } +void Foam::meshRefinement::growCellZone +( + const label nGrowCellZones, + const label backgroundZoneID, + labelList& unnamedSurfaceRegion, + labelList& namedSurfaceRegion, // potentially zero size if no faceZones + labelList& cellToZone +) const +{ + if (nGrowCellZones != 1) + { + WarningInFunction + << "Growing currently only supported for single layer." + << " Exiting zone growing" << endl; + return; + } + + + // See meshRefinement::markProximityRefinementWave: + // - walk out nGrowCellZones iterations from outside of cellZone + // and wall into unassigned cells + // - detect any cells inbetween + // - multiple zones + // - zone and wall + // and + // - assign cells to the cellZone + // - unblock faces (along the path) inbetween + + + // Special tag for walls + const FixedList<label, 3> wallTag + ({ + labelMax, // Special value for wall face. Loses out to cellZone tag + labelMax, + labelMax + }); + + // Work arrays + pointField origins(1); + scalarField distSqrs(1); + List<FixedList<label, 3>> surfaces(1); + + + // Set up blockage. Marked with 0 distance (so always wins) + + //List<wallPoints> allFaceInfo(mesh_.nFaces()); + //for (label facei = 0; facei < mesh_.nInternalFaces(); facei++) + //{ + // if (unnamedSurfaceRegion[facei] != -1) + // { + // origins[0] = mesh_.faceCentres()[facei]; + // distSqrs[0] = 0.0; // Initial distance + // surfaces[0] = wallTag; + // allFaceInfo[facei] = wallPoints(origins, distSqrs, surfaces); + // } + //} + List<wallPoints> allCellInfo(mesh_.nCells()); + forAll(cellToZone, celli) + { + if (cellToZone[celli] >= 0) + { + const FixedList<label, 3> zoneTag + ({ + cellToZone[celli], // zone + 0, // 'region' + labelMax // 'sub-region' + }); + + origins[0] = mesh_.cellCentres()[celli]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = zoneTag; + allCellInfo[celli] = wallPoints(origins, distSqrs, surfaces); + } + } + + + DynamicList<wallPoints> faceDist(mesh_.nFaces()/128); + DynamicList<label> changedFaces(mesh_.nFaces()/128); + + for (label facei = 0; facei < mesh_.nInternalFaces(); facei++) + { + const label own = mesh_.faceOwner()[facei]; + const label nei = mesh_.faceNeighbour()[facei]; + if (cellToZone[own] >= 0 && cellToZone[nei] < 0) + { + // boundary between cellZone (own) and background/unvisited (nei) + + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = FixedList<label, 3> + ({ + cellToZone[own], // zone + 0, // 'region' + labelMax // 'sub-region' + }); + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + else if (cellToZone[own] < 0 && cellToZone[nei] >= 0) + { + // boundary between cellZone (nei) and background/unvisited (own) + + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = FixedList<label, 3> + ({ + cellToZone[nei], // zone + 0, // 'region' + labelMax // 'sub-region' + }); + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + else if (unnamedSurfaceRegion[facei] != -1) + { + // Seed (yet unpatched) wall faces + + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = wallTag; + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + } + + // Get coupled neighbour cellRegion + labelList neiCellZone; + syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone); + + const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + + // Calculate region to zone from cellRegions on either side of coupled + // face. + forAll(patches, patchi) + { + const polyPatch& pp = patches[patchi]; + + if (pp.coupled()) + { + // Like internal faces + forAll(pp, i) + { + label facei = pp.start()+i; + label own = mesh_.faceOwner()[facei]; + label bFacei = facei-mesh_.nInternalFaces(); + if (cellToZone[own] >= 0 && neiCellZone[bFacei] < 0) + { + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = Foam::sqr(GREAT); + surfaces[0] = FixedList<label, 3> + ({ + cellToZone[own], // zone + 0, // 'region' + labelMax // 'sub-region' + }); + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + else if (cellToZone[own] < 0 && cellToZone[own] >= 0) + { + // Handled on nbr processor + } + else if (unnamedSurfaceRegion[facei] != -1) + { + // Seed (yet unpatched) wall faces + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = wallTag; + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + } + } + else + { + // Seed wall faces + forAll(pp, i) + { + label facei = pp.start()+i; + label own = mesh_.faceOwner()[facei]; + if (cellToZone[own] < 0) + { + origins[0] = mesh_.faceCentres()[facei]; + distSqrs[0] = 0.0; // Initial distance + surfaces[0] = wallTag; + faceDist.append(wallPoints(origins, distSqrs, surfaces)); + changedFaces.append(facei); + } + } + } + } + + + List<wallPoints> allFaceInfo(mesh_.nFaces()); + FaceCellWave<wallPoints> wallDistCalc + ( + mesh_, + changedFaces, + faceDist, + allFaceInfo, + allCellInfo, + 0 // max iterations + ); + wallDistCalc.iterate(nGrowCellZones); + + + // Check for cells which are within nGrowCellZones of two cellZones or + // one cellZone and a wall + // TBD. Currently only one layer of growth handled. + + bitSet isChangedCell(mesh_.nCells()); + + forAll(allCellInfo, celli) + { + if (allCellInfo[celli].valid(wallDistCalc.data())) + { + const List<FixedList<label, 3>>& surfaces = + allCellInfo[celli].surface(); + + if (surfaces.size() > 1) + { + // Check if inbetween two cellZones or cellZone and wall + // Find 'nearest' other cellZone + scalar minDistSqr = Foam::sqr(GREAT); + label minZone = -1; + for (label i = 0; i < surfaces.size(); i++) + { + const label zonei = surfaces[i][0]; + const scalar d2 = allCellInfo[celli].distSqr()[i]; + if (zonei != cellToZone[celli] && d2 < minDistSqr) + { + minDistSqr = d2; + minZone = zonei; // zoneID + } + } + + if (minZone != -1) + { + if (minZone != cellToZone[celli] && minZone != wallTag[0]) + { + cellToZone[celli] = minZone; + isChangedCell.set(celli); + } + } + } + } + } + + + // Make sure to unset faces of changed cell + label nUnnamed = 0; + label nNamed = 0; + for (const label celli : isChangedCell) + { + const cell& cFaces = mesh_.cells()[celli]; + for (const label facei : cFaces) + { + const label own = mesh_.faceOwner()[facei]; + const label ownZone = cellToZone[own]; + + label nbrZone = -1; + if (mesh_.isInternalFace(facei)) + { + const label neiZone = cellToZone[mesh_.faceNeighbour()[facei]]; + nbrZone = (own != celli ? ownZone : neiZone); + } + else + { + nbrZone = neiCellZone[facei-mesh_.nInternalFaces()]; + } + + if (nbrZone == cellToZone[celli]) + { + if (unnamedSurfaceRegion[facei] != -1) + { + unnamedSurfaceRegion[facei] = -1; + nUnnamed++; + } + if + ( + namedSurfaceRegion.size() + && namedSurfaceRegion[facei] != -1 + ) + { + namedSurfaceRegion[facei] = -1; + nNamed++; + } + } + } + } + + if (debug) + { + Pout<< "growCellZone : grown cellZones by " + << returnReduce(isChangedCell.count(), sumOp<label>()) + << " cells (moved from background to nearest cellZone)" + << endl; + Pout<< "growCellZone : unmarked " + << returnReduce(nUnnamed, sumOp<label>()) + << " unzoned intersections; " + << returnReduce(nNamed, sumOp<label>()) + << " zoned intersections; " + << endl; + } +} + + void Foam::meshRefinement::makeConsistentFaceIndex ( const labelList& surfaceMap, @@ -2628,7 +2938,7 @@ void Foam::meshRefinement::zonify if (namedSurfaces.size()) { - if (nErodeCellZones <= 0) + if (nErodeCellZones == 0) { Info<< "Walking from known cellZones; crossing a faceZone " << "face changes cellZone" << nl << endl; @@ -2644,6 +2954,20 @@ void Foam::meshRefinement::zonify cellToZone ); } + else if (nErodeCellZones < 0) + { + Info<< "Growing cellZones by " << -nErodeCellZones + << " layers" << nl << endl; + + growCellZone + ( + -nErodeCellZones, + backgroundZoneID, + unnamedRegion1, + namedSurfaceRegion, + cellToZone + ); + } else { Info<< "Eroding cellZone cells to make these consistent with" @@ -2693,6 +3017,54 @@ void Foam::meshRefinement::zonify ); } } + else if (nErodeCellZones < 0 && gMax(cellToZone) >= 0) + { + // With multiple locationsInMesh and non-trivial cellZones we allow + // some growing of the cellZones to avoid any background cells + + Info<< "Growing cellZones by " << -nErodeCellZones + << " layers" << nl << endl; + + growCellZone + ( + -nErodeCellZones, + backgroundZoneID, + unnamedRegion1, + namedSurfaceRegion, // note: potentially zero sized + cellToZone + ); + + // Make sure namedSurfaceRegion is unset inbetween same cell zones. + if (!allowFreeStandingZoneFaces && namedSurfaceRegion.size()) + { + Info<< "Only keeping zone faces inbetween different cellZones." + << nl << endl; + + // Surfaces with faceZone but no cellZone + labelList standaloneNamedSurfaces + ( + surfaceZonesInfo::getStandaloneNamedSurfaces + ( + surfZones + ) + ); + + // Construct map from surface index to index in + // standaloneNamedSurfaces (or -1) + labelList surfaceMap(surfZones.size(), -1); + forAll(standaloneNamedSurfaces, i) + { + surfaceMap[standaloneNamedSurfaces[i]] = i; + } + + makeConsistentFaceIndex + ( + surfaceMap, + cellToZone, + namedSurfaceRegion + ); + } + } // Some stats @@ -2850,6 +3222,7 @@ void Foam::meshRefinement::handleSnapProblems if (debug&MESH) { + const_cast<Time&>(mesh_.time())++; Pout<< "Writing extra baffled mesh to time " << timeName() << endl; write @@ -3635,6 +4008,7 @@ void Foam::meshRefinement::baffleAndSplitMesh if (debug&MESH) { + const_cast<Time&>(mesh_.time())++; Pout<< "Writing baffled mesh to time " << timeName() << endl; write @@ -4538,7 +4912,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify // -2 : unset : not allowed! // -1 : not in any zone (zone 'none') // >=0: zoneID - // namedSurfaceRegion: + // namedSurfaceRegion: zero sized or: // -1 : face not intersecting a named surface // >=0 : index of named surface labelList cellToZone; -- GitLab