diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C index 67a9c3a9444a3803f8c43dd270b2b7330219b32a..7b4d8577c4e7ace8293bf50a703c234bcc3193f2 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C @@ -1075,6 +1075,26 @@ int main(int argc, char *argv[]) << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + // Optionally read limit shells + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + const dictionary limitDict(refineDict.subOrEmptyDict("limitRegions")); + + if (!limitDict.empty()) + { + Info<< "Reading limit shells." << endl; + } + + shellSurfaces limitShells(allGeometry, limitDict); + + if (!limitDict.empty()) + { + Info<< "Read refinement shells in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + } + + + // Read feature meshes // ~~~~~~~~~~~~~~~~~~~ @@ -1105,7 +1125,8 @@ int main(int argc, char *argv[]) overwrite, // overwrite mesh files? surfaces, // for surface intersection refinement features, // for feature edges/point based refinement - shells // for volume (inside/outside) refinement + shells, // for volume (inside/outside) refinement + limitShells // limit of volume refinement ); Info<< "Calculated surface intersections in = " << mesh.time().cpuTimeIncrement() << " s" << nl << endl; diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict index 9b759b5ca4f6628dd9e11117d62697a0b12e0aef..ea073cd9f070647735f623262a850d4be8f4d220 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict @@ -95,10 +95,10 @@ castellatedMeshControls // actually be a lot less. maxGlobalCells 2000000; - // The surface refinement loop might spend lots of iterations refining just a - // few cells. This setting will cause refinement to stop if <= minimumRefine - // are selected for refinement. Note: it will at least do one iteration - // (unless the number of cells to refine is 0) + // The surface refinement loop might spend lots of iterations refining just + // a few cells. This setting will cause refinement to stop if + // <= minimumRefine cells are selected for refinement. Note: it will + // at least do one iteration (unless the number of cells to refine is 0) minRefinementCells 0; // Allow a certain level of imbalance during refining @@ -249,6 +249,13 @@ castellatedMeshControls //} } + + // Limit refinement in geometric region + limitRegions + { + } + + // Mesh selection // ~~~~~~~~~~~~~~ diff --git a/src/OpenFOAM/algorithms/indexedOctree/volumeType.H b/src/OpenFOAM/algorithms/indexedOctree/volumeType.H index 7bdfc043e6024e5b3a2417dbd4d8960b4927515a..3d845c414bef3fda5df79c57cb64d471f2dd3218 100644 --- a/src/OpenFOAM/algorithms/indexedOctree/volumeType.H +++ b/src/OpenFOAM/algorithms/indexedOctree/volumeType.H @@ -2,8 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation - \\/ M anipulation | + \\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation + \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -95,6 +95,12 @@ public: t_(t) {} + //- Construct from integer + explicit volumeType(const int t) + : + t_(static_cast<volumeType::type>(t)) + {} + // Member Functions diff --git a/src/mesh/autoMesh/Make/files b/src/mesh/autoMesh/Make/files index 081d70afbd52185b77011cfa13f68f8f07fea44e..29001bafb78ee672699f01948483be8bf7772d89 100644 --- a/src/mesh/autoMesh/Make/files +++ b/src/mesh/autoMesh/Make/files @@ -15,6 +15,7 @@ $(autoHexMesh)/meshRefinement/meshRefinement.C $(autoHexMesh)/meshRefinement/meshRefinementMerge.C $(autoHexMesh)/meshRefinement/meshRefinementProblemCells.C $(autoHexMesh)/meshRefinement/meshRefinementRefine.C +$(autoHexMesh)/meshRefinement/meshRefinementGapRefine.C $(autoHexMesh)/meshRefinement/patchFaceOrientation.C $(autoHexMesh)/refinementFeatures/refinementFeatures.C diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C index be908b76bbc9588fb48a586579613ac1539a62bd..e7e2217f27d3e9bb737c6bee289fef31e6f848b8 100644 --- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C +++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C @@ -105,7 +105,9 @@ Foam::label Foam::autoRefineDriver::featureEdgeRefine false, // internalRefinement false, // surfaceRefinement false, // curvatureRefinement + false, // smallFeatureRefinement false, // gapRefinement + false, // bigGapRefinement refineParams.maxGlobalCells(), refineParams.maxLocalCells() ) @@ -179,6 +181,127 @@ Foam::label Foam::autoRefineDriver::featureEdgeRefine } +Foam::label Foam::autoRefineDriver::smallFeatureRefine +( + const refinementParameters& refineParams, + const label maxIter +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + + label iter = 0; + + // See if any surface has an extendedGapLevel + labelList surfaceMaxLevel(meshRefiner_.surfaces().maxGapLevel()); + labelList shellMaxLevel(meshRefiner_.shells().maxGapLevel()); + + if (max(surfaceMaxLevel) == 0 && max(shellMaxLevel) == 0) + { + return iter; + } + + for (; iter < maxIter; iter++) + { + Info<< nl + << "Small surface feature refinement iteration " << iter << nl + << "--------------------------------------------" << nl + << endl; + + + // Determine cells to refine + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelList candidateCells + ( + meshRefiner_.refineCandidates + ( + refineParams.locationsInMesh(), + refineParams.curvature(), + refineParams.planarAngle(), + + false, // featureRefinement + false, // featureDistanceRefinement + false, // internalRefinement + false, // surfaceRefinement + false, // curvatureRefinement + true, // smallFeatureRefinement + false, // gapRefinement + false, // bigGapRefinement + refineParams.maxGlobalCells(), + refineParams.maxLocalCells() + ) + ); + + labelList cellsToRefine + ( + meshRefiner_.meshCutter().consistentRefinement + ( + candidateCells, + true + ) + ); + Info<< "Determined cells to refine in = " + << mesh.time().cpuTimeIncrement() << " s" << endl; + + + label nCellsToRefine = cellsToRefine.size(); + reduce(nCellsToRefine, sumOp<label>()); + + Info<< "Selected for refinement : " << nCellsToRefine + << " cells (out of " << mesh.globalData().nTotalCells() + << ')' << endl; + + // Stop when no cells to refine or have done minimum necessary + // iterations and not enough cells to refine. + if (nCellsToRefine == 0) + { + Info<< "Stopping refining since too few cells selected." + << nl << endl; + break; + } + + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + + if + ( + returnReduce + ( + (mesh.nCells() >= refineParams.maxLocalCells()), + orOp<bool>() + ) + ) + { + meshRefiner_.balanceAndRefine + ( + "small feature refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine, + refineParams.maxLoadUnbalance() + ); + } + else + { + meshRefiner_.refineAndBalance + ( + "small feature refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine, + refineParams.maxLoadUnbalance() + ); + } + } + return iter; +} + + Foam::label Foam::autoRefineDriver::surfaceOnlyRefine ( const refinementParameters& refineParams, @@ -218,7 +341,9 @@ Foam::label Foam::autoRefineDriver::surfaceOnlyRefine false, // internalRefinement true, // surfaceRefinement true, // curvatureRefinement + false, // smallFeatureRefinement false, // gapRefinement + false, // bigGapRefinement refineParams.maxGlobalCells(), refineParams.maxLocalCells() ) @@ -352,7 +477,9 @@ Foam::label Foam::autoRefineDriver::gapOnlyRefine false, // internalRefinement false, // surfaceRefinement false, // curvatureRefinement + false, // smallFeatureRefinement true, // gapRefinement + false, // bigGapRefinement refineParams.maxGlobalCells(), refineParams.maxLocalCells() ) @@ -527,6 +654,146 @@ Foam::label Foam::autoRefineDriver::gapOnlyRefine } +Foam::label Foam::autoRefineDriver::bigGapOnlyRefine +( + const refinementParameters& refineParams, + const label maxIter +) +{ + const fvMesh& mesh = meshRefiner_.mesh(); + + label iter = 0; + + // See if any surface has an extendedGapLevel + labelList surfaceMaxLevel(meshRefiner_.surfaces().maxGapLevel()); + labelList shellMaxLevel(meshRefiner_.shells().maxGapLevel()); + + label overallMaxLevel(max(max(surfaceMaxLevel), max(shellMaxLevel))); + + if (overallMaxLevel == 0) + { + return iter; + } + + + for (; iter < maxIter; iter++) + { + Info<< nl + << "Big gap refinement iteration " << iter << nl + << "------------------------------" << nl + << endl; + + + // Determine cells to refine + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelList candidateCells + ( + meshRefiner_.refineCandidates + ( + refineParams.locationsInMesh(), + refineParams.curvature(), + refineParams.planarAngle(), + + false, // featureRefinement + false, // featureDistanceRefinement + false, // internalRefinement + false, // surfaceRefinement + false, // curvatureRefinement + false, // smallFeatureRefinement + false, // gapRefinement + true, // bigGapRefinement + refineParams.maxGlobalCells(), + refineParams.maxLocalCells() + ) + ); + + + if (debug&meshRefinement::MESH) + { + Pout<< "Dumping " << candidateCells.size() + << " cells to cellSet candidateCellsFromBigGap." << endl; + cellSet c(mesh, "candidateCellsFromBigGap", candidateCells); + c.instance() = meshRefiner_.timeName(); + c.write(); + } + + labelList cellsToRefine + ( + meshRefiner_.meshCutter().consistentRefinement + ( + candidateCells, + true + ) + ); + Info<< "Determined cells to refine in = " + << mesh.time().cpuTimeIncrement() << " s" << endl; + + + label nCellsToRefine = cellsToRefine.size(); + reduce(nCellsToRefine, sumOp<label>()); + + Info<< "Selected for refinement : " << nCellsToRefine + << " cells (out of " << mesh.globalData().nTotalCells() + << ')' << endl; + + // Stop when no cells to refine or have done minimum necessary + // iterations and not enough cells to refine. + if + ( + nCellsToRefine == 0 + || ( + iter >= overallMaxLevel + && nCellsToRefine <= refineParams.minRefineCells() + ) + ) + { + Info<< "Stopping refining since too few cells selected." + << nl << endl; + break; + } + + + if (debug) + { + const_cast<Time&>(mesh.time())++; + } + + + if + ( + returnReduce + ( + (mesh.nCells() >= refineParams.maxLocalCells()), + orOp<bool>() + ) + ) + { + meshRefiner_.balanceAndRefine + ( + "big gap refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine, + refineParams.maxLoadUnbalance() + ); + } + else + { + meshRefiner_.refineAndBalance + ( + "big gap refinement iteration " + name(iter), + decomposer_, + distributor_, + cellsToRefine, + refineParams.maxLoadUnbalance() + ); + } + } + return iter; +} + + Foam::label Foam::autoRefineDriver::danglingCellRefine ( const refinementParameters& refineParams, @@ -1108,7 +1375,9 @@ Foam::label Foam::autoRefineDriver::shellRefine true, // internalRefinement false, // surfaceRefinement false, // curvatureRefinement + false, // smallFeatureRefinement false, // gapRefinement + false, // bigGapRefinement refineParams.maxGlobalCells(), refineParams.maxLocalCells() ) @@ -1630,6 +1899,13 @@ void Foam::autoRefineDriver::doRefine 0 // min cells to refine ); + // Refine cells that contain a gap + smallFeatureRefine + ( + refineParams, + 100 // maxIter + ); + // Refine based on surface surfaceOnlyRefine ( @@ -1650,6 +1926,13 @@ void Foam::autoRefineDriver::doRefine 1 // nBufferLayers ); + // Refine consistently across narrow gaps (a form of shell refinement) + bigGapOnlyRefine + ( + refineParams, + 100 // maxIter + ); + // Internal mesh refinement shellRefine ( diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H index 11ed1d9454d0b5c7d6db927e0fa25c0d9fdb1ef4..e952af9fd60e00aa5aaaa26b08ce694b6ce2c4af 100644 --- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H +++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H @@ -84,6 +84,13 @@ class autoRefineDriver const label minRefine ); + //- Refine all cells containing small surface features + label smallFeatureRefine + ( + const refinementParameters& refineParams, + const label maxIter + ); + //- Refine all cells interacting with the surface label surfaceOnlyRefine ( @@ -98,6 +105,13 @@ class autoRefineDriver const label maxIter ); + //- Refine all cells in large gaps + label bigGapOnlyRefine + ( + const refinementParameters& refineParams, + const label maxIter + ); + //- Refine cells with almost all sides refined label danglingCellRefine ( diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C index e4bfa8840c994ca689be4dcfb46ece5ae3e445fd..93818eb8d66013d54885341c5c18712431194694 100644 --- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C +++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C @@ -215,6 +215,55 @@ void Foam::meshRefinement::calcNeighbourData } +void Foam::meshRefinement::calcCellCellRays +( + const pointField& neiCc, + const labelList& neiLevel, + const labelList& testFaces, + pointField& start, + pointField& end, + labelList& minLevel +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + + start.setSize(testFaces.size()); + end.setSize(testFaces.size()); + minLevel.setSize(testFaces.size()); + + forAll(testFaces, i) + { + label faceI = testFaces[i]; + label own = mesh_.faceOwner()[faceI]; + + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + + start[i] = cellCentres[own]; + end[i] = cellCentres[nei]; + minLevel[i] = min(cellLevel[own], cellLevel[nei]); + } + else + { + label bFaceI = faceI - mesh_.nInternalFaces(); + + start[i] = cellCentres[own]; + end[i] = neiCc[bFaceI]; + minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]); + } + } + + // Extend segments a bit + { + const vectorField smallVec(ROOTSMALL*(end-start)); + start -= smallVec; + end += smallVec; + } +} + + // Find intersections of edges (given by their two endpoints) with surfaces. // Returns first intersection if there are more than one. void Foam::meshRefinement::updateIntersections(const labelList& changedFaces) @@ -1187,7 +1236,8 @@ Foam::meshRefinement::meshRefinement const bool overwrite, const refinementSurfaces& surfaces, const refinementFeatures& features, - const shellSurfaces& shells + const shellSurfaces& shells, + const shellSurfaces& limitShells ) : mesh_(mesh), @@ -1197,6 +1247,7 @@ Foam::meshRefinement::meshRefinement surfaces_(surfaces), features_(features), shells_(shells), + limitShells_(limitShells), meshCutter_ ( mesh, diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H index 31ef9f2e1a286d2bbc2cc9fa7c35a15bef20ebef..b2cbbd983f22d4d8de36ffdd8edc7ea6314bd278 100644 --- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H +++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H @@ -34,6 +34,7 @@ Description SourceFiles meshRefinement.C meshRefinementBaffles.C + meshRefinementGapRefine.C meshRefinementMerge.C meshRefinementProblemCells.C meshRefinementRefine.C @@ -53,6 +54,7 @@ SourceFiles #include "pointIndexHit.H" #include "wordPairHashTable.H" #include "surfaceZonesInfo.H" +#include "volumeType.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -176,6 +178,9 @@ private: //- All shell-refinement interaction const shellSurfaces& shells_; + //- All limit-refinement interaction + const shellSurfaces& limitShells_; + //- Refinement engine hexRef8 meshCutter_; @@ -226,10 +231,18 @@ private: ); //- Calculate coupled boundary end vector and refinement level - void calcNeighbourData + void calcNeighbourData(labelList& neiLevel, pointField& neiCc) const; + + //- Calculate rays from cell-centre to cell-centre and corresponding + // min cell refinement level + void calcCellCellRays ( - labelList& neiLevel, - pointField& neiCc + const pointField& neiCc, + const labelList& neiLevel, + const labelList& testFaces, + pointField& start, + pointField& end, + labelList& minLevel ) const; //- Remove cells. Put exposedFaces into exposedPatchIDs. @@ -241,12 +254,12 @@ private: removeCells& cellRemover ); - // Get cells which are inside any closed surface. Note that - // all closed surfaces - // will have already been oriented to have keepPoint outside. + //- Get cells which are inside any closed surface. Note that + // all closed surfaces + // will have already been oriented to have keepPoint outside. labelList getInsideCells(const word&) const; - // Do all to remove inside cells + //- Do all to remove inside cells autoPtr<mapPolyMesh> removeInsideCells ( const string& msg, @@ -302,6 +315,14 @@ private: label& nRefine ) const; + //- Unmark cells for refinement based on limit-shells. Return number + // of limited cells. + label unmarkInternalRefinement + ( + labelList& refineCell, + label& nRefine + ) const; + //- Collect faces that are intersected and whose neighbours aren't // yet marked for refinement. labelList getRefineCandidateFaces @@ -319,6 +340,83 @@ private: label& nRefine ) const; + //- Mark cells intersected by the surface if they are inside + // close gaps + label markSurfaceGapRefinement + ( + const scalar planarCos, + const label nAllowRefine, + const labelList& neiLevel, + const pointField& neiCc, + + labelList& refineCell, + label& nRefine + ) const; + + //- Generate single ray for cell to detect gap + bool generateRay + ( + const bool useSurfaceNormal, + + const point& nearPoint, + const vector& nearNormal, + const FixedList<label, 3>& gapInfo, + const volumeType& mode, + + const point& cc, + const label cLevel, + + point& start, + point& end, + point& start2, + point& end2 + ) const; + + //- Select candidate cells (cells inside a shell with gapLevel + // specified) + void selectGapCandidates + ( + const labelList& refineCell, + const label nRefine, + + labelList& cellMap, + List<FixedList<label, 3> >& shellGapInfo, + List<volumeType>& shellGapMode + ) const; + + //- Merge gap information coming from shell and from surface + // (surface wins) + void mergeGapInfo + ( + const FixedList<label, 3>& shellGapInfo, + const volumeType shellGapMode, + const FixedList<label, 3>& surfGapInfo, + const volumeType surfGapMode, + FixedList<label, 3>& gapInfo, + volumeType& gapMode + ) const; + + //- Mark cells for non-surface intersection based gap refinement + label markInternalGapRefinement + ( + const scalar planarCos, + const label nAllowRefine, + labelList& refineCell, + label& nRefine + ) const; + + //- Refine cells containing small gaps + label markSmallFeatureRefinement + ( + const scalar planarCos, + const label nAllowRefine, + const labelList& neiLevel, + const pointField& neiCc, + + labelList& refineCell, + label& nRefine + ) const; + //- Helper: count number of normals1 that are in normals2 label countMatches ( @@ -387,6 +485,7 @@ private: void getIntersections ( const labelList& surfacesToTest, + const labelList& neiLevel, const pointField& neiCc, const labelList& testFaces, @@ -567,7 +666,7 @@ private: const labelList& cellToZone, const labelList& neiCellZone, const labelList& faceToZone, - const boolList& meshFlipMap, + const PackedBoolList& meshFlipMap, polyTopoChange& meshMod ) const; @@ -631,7 +730,7 @@ private: const labelList& nMasterFaces, const labelList& faceToZone, const Map<label>& zoneToOrientation, - boolList& meshFlipMap + PackedBoolList& meshFlipMap ) const; @@ -657,6 +756,7 @@ public: const bool overwrite, const refinementSurfaces&, const refinementFeatures&, + const shellSurfaces&, const shellSurfaces& ); @@ -855,7 +955,9 @@ public: const bool internalRefinement, const bool surfaceRefinement, const bool curvatureRefinement, + const bool smallFeatureRefinement, const bool gapRefinement, + const bool bigGapRefinement, const label maxGlobalCells, const label maxLocalCells ) const; diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C index 6f500c117a10304be1cf1330ea45baec56674473..302882a3fb1d0e745125f61eb7404c74462b9bbd 100644 --- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C @@ -175,6 +175,7 @@ Foam::label Foam::meshRefinement::createBaffle void Foam::meshRefinement::getIntersections ( const labelList& surfacesToTest, + const labelList& neiLevel, const pointField& neiCc, const labelList& testFaces, @@ -198,8 +199,6 @@ void Foam::meshRefinement::getIntersections << str().name() << nl << endl; } - const pointField& cellCentres = mesh_.cellCentres(); - globalRegion1.setSize(mesh_.nFaces()); globalRegion1 = -1; @@ -213,29 +212,17 @@ void Foam::meshRefinement::getIntersections pointField start(testFaces.size()); pointField end(testFaces.size()); - forAll(testFaces, i) { - label faceI = testFaces[i]; - - label own = mesh_.faceOwner()[faceI]; - - if (mesh_.isInternalFace(faceI)) - { - start[i] = cellCentres[own]; - end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; - } - else - { - start[i] = cellCentres[own]; - end[i] = neiCc[faceI-mesh_.nInternalFaces()]; - } - } - - // Extend segments a bit - { - const vectorField smallVec(ROOTSMALL*(end-start)); - start -= smallVec; - end += smallVec; + labelList minLevel; + calcCellCellRays + ( + neiCc, + neiLevel, + testFaces, + start, + end, + minLevel + ); } @@ -319,6 +306,7 @@ void Foam::meshRefinement::getBafflePatches getIntersections ( surfaceZonesInfo::getUnnamedSurfaces(surfaces_.surfZones()), + neiLevel, neiCc, testFaces, globalRegion1, @@ -2608,7 +2596,7 @@ void Foam::meshRefinement::consistentOrientation const labelList& nMasterFacesPerEdge, const labelList& faceToZone, const Map<label>& zoneToOrientation, - boolList& meshFlipMap + PackedBoolList& meshFlipMap ) const { const polyBoundaryMesh& bm = mesh_.boundaryMesh(); @@ -2858,7 +2846,7 @@ void Foam::meshRefinement::zonify const labelList& cellToZone, const labelList& neiCellZone, const labelList& faceToZone, - const boolList& meshFlipMap, + const PackedBoolList& meshFlipMap, polyTopoChange& meshMod ) const { @@ -3902,6 +3890,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify getIntersections ( identity(surfaces_.surfaces().size()), // surfacesToTest, + neiLevel, neiCc, intersectedFaces(), // testFaces globalRegion1, @@ -4297,7 +4286,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify } - // 2. Combine faceZoneNames allocated on different processors + // 2.Combine faceZoneNames allocated on different processors Pstream::mapCombineGather(zonesToFaceZone, eqOp<word>()); Pstream::mapCombineScatter(zonesToFaceZone); @@ -4438,7 +4427,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify // - do a consistent orientation // - check number of faces with consistent orientation // - if <0 flip the whole patch - boolList meshFlipMap(mesh_.nFaces(), false); + PackedBoolList meshFlipMap(mesh_.nFaces(), false); { // Collect all data on zone faces without cellZones on either side. const indirectPrimitivePatch patch diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C new file mode 100644 index 0000000000000000000000000000000000000000..62a285928c128659b52964cd70621f37b96d3e2c --- /dev/null +++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C @@ -0,0 +1,1546 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2015 OpenFOAM Foundation + \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM 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. + + OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "meshRefinement.H" +#include "Time.H" +#include "refinementSurfaces.H" +#include "refinementFeatures.H" +#include "shellSurfaces.H" +#include "OBJstream.H" +#include "triSurfaceMesh.H" +#include "treeDataCell.H" +#include "searchableSurfaces.H" +#include "DynamicField.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::label Foam::meshRefinement::markSurfaceGapRefinement +( + const scalar planarCos, + + const label nAllowRefine, + const labelList& neiLevel, + const pointField& neiCc, + + labelList& refineCell, + label& nRefine +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + + // Get the gap level for the shells + const labelList maxLevel(shells_.maxGapLevel()); + + label oldNRefine = nRefine; + + if (max(maxLevel) > 0) + { + // Use cached surfaceIndex_ to detect if any intersection. If so + // re-intersect to determine level wanted. + + // Collect candidate faces + // ~~~~~~~~~~~~~~~~~~~~~~~ + + labelList testFaces(getRefineCandidateFaces(refineCell)); + + // Collect segments + // ~~~~~~~~~~~~~~~~ + + pointField start(testFaces.size()); + pointField end(testFaces.size()); + labelList minLevel(testFaces.size()); + + calcCellCellRays + ( + neiCc, + neiLevel, + testFaces, + start, + end, + minLevel + ); + + + // Collect cells to test for inside/outside in shell + labelList cellToCompact(mesh_.nCells(), -1); + labelList bFaceToCompact(mesh_.nFaces()-mesh_.nInternalFaces(), -1); + List<FixedList<label, 3> > shellGapInfo; + List<volumeType> shellGapMode; + { + DynamicField<point> compactToCc(mesh_.nCells()/10); + DynamicList<label> compactToLevel(compactToCc.capacity()); + forAll(testFaces, i) + { + label faceI = testFaces[i]; + label own = mesh_.faceOwner()[faceI]; + if (cellToCompact[own] == -1) + { + cellToCompact[own] = compactToCc.size(); + compactToCc.append(cellCentres[own]); + compactToLevel.append(cellLevel[own]); + } + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + if (cellToCompact[nei] == -1) + { + cellToCompact[nei] = compactToCc.size(); + compactToCc.append(cellCentres[nei]); + compactToLevel.append(cellLevel[nei]); + } + } + else + { + label bFaceI = faceI - mesh_.nInternalFaces(); + if (bFaceToCompact[bFaceI] == -1) + { + bFaceToCompact[bFaceI] = compactToCc.size(); + compactToCc.append(neiCc[bFaceI]); + compactToLevel.append(neiLevel[bFaceI]); + } + } + } + + shells_.findHigherGapLevel + ( + compactToCc, + compactToLevel, + shellGapInfo, + shellGapMode + ); + } + + + //OBJstream str(mesh_.time().timePath()/"markSurfaceRefinement.obj"); + //Info<< "Dumping rays to " << str.name( ) << endl; + + const List<FixedList<label, 3> >& extendedGapLevel = + surfaces_.extendedGapLevel(); + const List<volumeType>& extendedGapMode = + surfaces_.extendedGapMode(); + + labelList surface1; + List<pointIndexHit> hit1; + labelList region1; + vectorField normal1; + + { + labelList surface2; + List<pointIndexHit> hit2; + labelList region2; + vectorField normal2; + + surfaces_.findNearestIntersection + ( + identity(surfaces_.surfaces().size()), + start, + end, + + surface1, + hit1, + region1, + normal1, + + surface2, + hit2, + region2, + normal2 + ); + } + + + start.setSize(2*surface1.size()); + end.setSize(2*surface1.size()); + labelList map(2*surface1.size()); + pointField start2(2*surface1.size()); + pointField end2(2*surface1.size()); + labelList cellMap(2*surface1.size()); + + label compactI = 0; + + forAll(surface1, i) + { + label surfI = surface1[i]; + + if (surfI != -1) + { + label globalRegionI = surfaces_.globalRegion(surfI, region1[i]); + + label faceI = testFaces[i]; + const point& surfPt = hit1[i].hitPoint(); + + label own = mesh_.faceOwner()[faceI]; + if (cellToCompact[own] != -1) + { + // Combine info from shell and surface + label compactI = cellToCompact[own]; + FixedList<label, 3> gapInfo; + volumeType gapMode; + mergeGapInfo + ( + shellGapInfo[compactI], + shellGapMode[compactI], + extendedGapLevel[globalRegionI], + extendedGapMode[globalRegionI], + gapInfo, + gapMode + ); + + const point& cc = cellCentres[own]; + bool okRay = generateRay + ( + false, + surfPt, + normal1[i], + gapInfo, + gapMode, + surfPt+((cc-surfPt)&normal1[i])*normal1[i], + cellLevel[own], + + start[compactI], + end[compactI], + start2[compactI], + end2[compactI] + ); + cellMap[compactI] = own; + + if (okRay) + { + map[compactI++] = i; + } + } + if (mesh_.isInternalFace(faceI)) + { + label nei = mesh_.faceNeighbour()[faceI]; + if (cellToCompact[nei] != -1) + { + // Combine info from shell and surface + label compactI = cellToCompact[nei]; + FixedList<label, 3> gapInfo; + volumeType gapMode; + mergeGapInfo + ( + shellGapInfo[compactI], + shellGapMode[compactI], + extendedGapLevel[globalRegionI], + extendedGapMode[globalRegionI], + gapInfo, + gapMode + ); + + const point& cc = cellCentres[nei]; + bool okRay = generateRay + ( + false, + surfPt, + normal1[i], + gapInfo, + gapMode, + surfPt+((cc-surfPt)&normal1[i])*normal1[i], + cellLevel[nei], + + start[compactI], + end[compactI], + start2[compactI], + end2[compactI] + ); + cellMap[compactI] = nei; + + if (okRay) + { + map[compactI++] = i; + } + } + } + else + { + label bFaceI = faceI - mesh_.nInternalFaces(); + + if (bFaceToCompact[bFaceI] != -1) + { + // Combine info from shell and surface + label compactI = bFaceToCompact[bFaceI]; + FixedList<label, 3> gapInfo; + volumeType gapMode; + mergeGapInfo + ( + shellGapInfo[compactI], + shellGapMode[compactI], + extendedGapLevel[globalRegionI], + extendedGapMode[globalRegionI], + gapInfo, + gapMode + ); + + const point& cc = neiCc[bFaceI]; + bool okRay = generateRay + ( + false, + surfPt, + normal1[i], + gapInfo, + gapMode, + surfPt+((cc-surfPt)&normal1[i])*normal1[i], + neiLevel[bFaceI], + + start[compactI], + end[compactI], + start2[compactI], + end2[compactI] + ); + cellMap[compactI] = -1; + + if (okRay) + { + map[compactI++] = i; + } + } + } + } + } + + //Info<< "Retesting " << returnReduce(compactI, sumOp<label>()) + // << " out of " << returnReduce(start.size(), sumOp<label>()) + // << endl; + + start.setSize(compactI); + end.setSize(compactI); + start2.setSize(compactI); + end2.setSize(compactI); + map.setSize(compactI); + cellMap.setSize(compactI); + + testFaces = UIndirectList<label>(testFaces, map)(); + minLevel = UIndirectList<label>(minLevel, map)(); + surface1.clear(); + hit1.clear(); + region1.clear(); + normal1 = UIndirectList<vector>(normal1, map)(); + + // Do intersections in first direction + labelList surfaceHit; + vectorField surfaceNormal; + surfaces_.findNearestIntersection + ( + start, + end, + surfaceHit, + surfaceNormal + ); + { + // Do intersections in second direction and merge + labelList surfaceHit2; + vectorField surfaceNormal2; + surfaces_.findNearestIntersection + ( + start2, + end2, + surfaceHit2, + surfaceNormal2 + ); + forAll(surfaceHit, i) + { + if (surfaceHit[i] == -1 && surfaceHit2[i] != -1) + { + surfaceHit[i] = surfaceHit2[i]; + surfaceNormal[i] = surfaceNormal2[i]; + } + } + } + + + forAll(surfaceHit, i) + { + label surfI = surfaceHit[i]; + + if (surfI != -1) + { + // Found intersection with surface. Check opposite normal. + + label cellI = cellMap[i]; + + if (cellI != -1 && mag(normal1[i]&surfaceNormal[i]) > planarCos) + { + if + ( + !markForRefine + ( + surfI, + nAllowRefine, + refineCell[cellI], + nRefine + ) + ) + { + break; + } + } + } + } + + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } + } + + return returnReduce(nRefine-oldNRefine, sumOp<label>()); +} + + +//Foam::labelList Foam::meshRefinement::extractHits +//( +// const List<pointIndexHit>& info +//) +//{ +// labelList compactMap(info.size()); +// label compactI = 0; +// forAll(info, i) +// { +// if (info[i].hit()) +// { +// compactMap[compactI++] = i; +// } +// } +// compactMap.setSize(compactI); +// return compactMap; +//} +// +// +//void Foam::meshRefinement::mergeHits +//( +// const pointField& samples, +// const List<pointIndexHit>& extraInfo, +// List<pointIndexHit>& info +//) +//{ +// if (extraInfo.size() != info.size()) +// { +// FatalErrorIn +// ( +// "meshRefinement::mergeHits(const List<pointIndexHit>&" +// ", List<pointIndexHit>& info)" +// ) << "Sizes differ " << extraInfo.size() << ' ' << info.size() +// << exit(FatalError); +// } +// +// // Merge oppositeInfo2 into oppositeInfo +// forAll(extraInfo, i) +// { +// if (!info[i].hit()) +// { +// if (extraInfo[i].hit()) +// { +// info[i] = extraInfo[i]; +// } +// } +// else if (extraInfo[i].hit()) +// { +// const point& nearPt = samples[i]; //nearInfo[i].hitPoint(); +// +// scalar d = magSqr(info[i].hitPoint()-nearPt); +// scalar d2 = magSqr(extraInfo[i].hitPoint()-nearPt); +// +// if (d2 < d) +// { +// info[i] = extraInfo[i]; +// } +// } +// } +//} +// +// +//Foam::tmp<Foam::pointField> Foam::meshRefinement::extractPoints +//( +// const List<pointIndexHit>& info +//) +//{ +// tmp<pointField> tfld(new pointField(info.size())); +// pointField& fld = tfld(); +// +// forAll(info, i) +// { +// fld[i] = info[i].rawPoint(); +// } +// return tfld; +//} +// +// +//Foam::meshRefinement::findNearestOppositeOp::findNearestOppositeOp +//( +// const indexedOctree<treeDataTriSurface>& tree, +// const point& oppositePoint, +// const vector& oppositeNormal, +// const scalar minCos +//) +//: +// tree_(tree), +// oppositePoint_(oppositePoint), +// oppositeNormal_(oppositeNormal), +// minCos_(minCos) +//{} +// +// +//void Foam::meshRefinement::findNearestOppositeOp::operator() +//( +// const labelUList& indices, +// const point& sample, +// scalar& nearestDistSqr, +// label& minIndex, +// point& nearestPoint +//) const +//{ +// const treeDataTriSurface& shape = tree_.shapes(); +// const triSurface& patch = shape.patch(); +// const pointField& points = patch.points(); +// +// forAll(indices, i) +// { +// const label index = indices[i]; +// const labelledTri& f = patch[index]; +// +// pointHit nearHit = f.nearestPoint(sample, points); +// scalar distSqr = sqr(nearHit.distance()); +// +// if (distSqr < nearestDistSqr) +// { +// // Nearer. Check if +// // - a bit way from other hit +// // - in correct search cone +// vector d(nearHit.rawPoint()-oppositePoint_); +// scalar normalDist(d&oppositeNormal_); +// +// if (normalDist > Foam::sqr(SMALL) && normalDist/mag(d) > minCos_) +// { +// nearestDistSqr = distSqr; +// minIndex = index; +// nearestPoint = nearHit.rawPoint(); +// } +// } +// } +//} +// +// +//void Foam::meshRefinement::searchCone +//( +// const label surfI, +// labelList& nearMap, // cells +// scalarField& nearGap, // gap size +// List<pointIndexHit>& nearInfo, // nearest point on surface +// List<pointIndexHit>& oppositeInfo // detected point on gap (or miss) +//) const +//{ +// const labelList& cellLevel = meshCutter_.cellLevel(); +// const pointField& cellCentres = mesh_.cellCentres(); +// const scalar edge0Len = meshCutter_.level0EdgeLength(); +// +// const labelList& surfaceIndices = surfaces_.surfaces(); +// const List<FixedList<label, 3> >& extendedGapLevel = +// surfaces_.extendedGapLevel(); +// const List<volumeType>& extendedGapMode = surfaces_.extendedGapMode(); +// +// +// label geomI = surfaceIndices[surfI]; +// const searchableSurface& geom = surfaces_.geometry()[geomI]; +// +// const triSurfaceMesh& s = refCast<const triSurfaceMesh>(geom); +// const indexedOctree<treeDataTriSurface>& tree = s.tree(); +// +// +// const scalar searchCos(Foam::cos(degToRad(30))); +// +// // Normals for ray shooting and inside/outside detection +// vectorField nearNormal; +// geom.getNormal(nearInfo, nearNormal); +// // Regions +// labelList nearRegion; +// geom.getRegion(nearInfo, nearRegion); +// +// +// // Now loop over all near points and search in the half cone +// labelList map(nearInfo.size()); +// label compactI = 0; +// +// oppositeInfo.setSize(nearInfo.size()); +// +// forAll(nearInfo, i) +// { +// label globalRegionI = +// surfaces_.globalRegion(surfI, nearRegion[i]); +// +// // Get updated gap information now we have the region +// label nGapCells = extendedGapLevel[globalRegionI][0]; +// label minLevel = extendedGapLevel[globalRegionI][1]; +// label maxLevel = extendedGapLevel[globalRegionI][2]; +// volumeType mode = extendedGapMode[globalRegionI]; +// +// label cellI = nearMap[i]; +// label cLevel = cellLevel[cellI]; +// +// if (cLevel >= minLevel && cLevel < maxLevel) +// { +// scalar cellSize = edge0Len/pow(2, cLevel); +// +// // Update gap size +// nearGap[i] = nGapCells*cellSize; +// +// const point& nearPt = nearInfo[i].hitPoint(); +// vector v(cellCentres[cellI]-nearPt); +// scalar magV = mag(v); +// +// // Like with ray shooting we want to +// // - find triangles up to nearGap away on the wanted side of the +// // surface +// // - find triangles up to 0.5*cellSize away on the unwanted side +// // of the surface. This is for cells straddling the surface +// // where +// // the cell centre might be on the wrong side of the surface +// +// // Tbd: check that cell centre is inbetween the gap hits +// // (only if the cell is far enough away) +// +// scalar posNormalSize = 0.0; +// scalar negNormalSize = 0.0; +// +// if (mode == volumeType::OUTSIDE) +// { +// posNormalSize = nearGap[i]; +// if (magV < 0.5*cellSize) +// { +// negNormalSize = 0.5*cellSize; +// } +// } +// else if (mode == volumeType::INSIDE) +// { +// if (magV < 0.5*cellSize) +// { +// posNormalSize = 0.5*cellSize; +// } +// negNormalSize = nearGap[i]; +// } +// else +// { +// posNormalSize = nearGap[i]; +// negNormalSize = nearGap[i]; +// } +// +// // Test with positive normal +// oppositeInfo[compactI] = tree.findNearest +// ( +// nearPt, +// sqr(posNormalSize), +// findNearestOppositeOp +// ( +// tree, +// nearPt, +// nearNormal[i], +// searchCos +// ) +// ); +// +// if (oppositeInfo[compactI].hit()) +// { +// map[compactI++] = i; +// } +// else +// { +// // Test with negative normal +// oppositeInfo[compactI] = tree.findNearest +// ( +// nearPt, +// sqr(negNormalSize), +// findNearestOppositeOp +// ( +// tree, +// nearPt, +// -nearNormal[i], +// searchCos +// ) +// ); +// +// if (oppositeInfo[compactI].hit()) +// { +// map[compactI++] = i; +// } +// } +// } +// } +// +// Info<< "Selected " << returnReduce(compactI, sumOp<label>()) +// << " hits on the correct side out of " +// << returnReduce(map.size(), sumOp<label>()) << endl; +// map.setSize(compactI); +// oppositeInfo.setSize(compactI); +// +// nearMap = UIndirectList<label>(nearMap, map)(); +// nearGap = UIndirectList<scalar>(nearGap, map)(); +// nearInfo = UIndirectList<pointIndexHit>(nearInfo, map)(); +// nearNormal = UIndirectList<vector>(nearNormal, map)(); +// +// // Exclude hits which aren't opposite enough. E.g. you might find +// // a point on a perpendicular wall - but this does not consistute a gap. +// vectorField oppositeNormal; +// geom.getNormal(oppositeInfo, oppositeNormal); +// +// compactI = 0; +// forAll(oppositeInfo, i) +// { +// if ((nearNormal[i] & oppositeNormal[i]) < -0.707) +// { +// map[compactI++] = i; +// } +// } +// +// Info<< "Selected " << returnReduce(compactI, sumOp<label>()) +// << " hits opposite the nearest out of " +// << returnReduce(map.size(), sumOp<label>()) << endl; +// map.setSize(compactI); +// +// nearMap = UIndirectList<label>(nearMap, map)(); +// nearGap = UIndirectList<scalar>(nearGap, map)(); +// nearInfo = UIndirectList<pointIndexHit>(nearInfo, map)(); +// oppositeInfo = UIndirectList<pointIndexHit>(oppositeInfo, map)(); +//} + + +bool Foam::meshRefinement::generateRay +( + const bool useSurfaceNormal, + + const point& nearPoint, + const vector& nearNormal, + const FixedList<label, 3>& gapInfo, + const volumeType& mode, + + const point& cc, + const label cLevel, + + point& start, + point& end, + point& start2, + point& end2 +) const +{ + // We want to handle the following cases: + // - surface: small gap (marked with 'surface'). gap might be + // on inside or outside of surface. + // - A: cell well inside the gap. + // - B: cell well outside the gap. + // - C: cell straddling the gap. cell centre might be inside + // or outside + // + // +---+ + // | B | + // +---+ + // + // +------+ + // | | + // | C | + // --------|------|----surface + // +------+ + // + // +---+ + // | A | + // +---+ + // + // + // --------------------surface + // + // So: + // - find nearest point on surface + // - in situation A,B decide if on wanted side of surface + // - detect if locally a gap (and the cell inside the gap) by + // shooting a ray from the point on the surface in the direction + // of + // - A,B: the cell centre + // - C: the surface normal and/or negative surface normal + // and see we hit anything + // + // Variations of this scheme: + // - always shoot in the direction of the surface normal. This needs + // then an additional check to make sure the cell centre is + // somewhere inside the gap + // - instead of ray shooting use a 'constrained' nearest search + // by e.g. looking inside a search cone (implemented in searchCone). + // The problem with this constrained nearest is that it still uses + // the absolute nearest point on each triangle and only afterwards + // checks if it is inside the search cone. + + + // Decide which near points are good: + // - with updated minLevel and maxLevel and nearGap make sure + // the cell is still a candidate + // NOTE: inside the gap the nearest point on the surface will + // be HALF the gap size - otherwise we would have found + // a point on the opposite side + // - if the mode is both sides + // - or if the hit is inside the current cell (situation 'C', + // magV < 0.5cellSize) + // - or otherwise if on the correct side + + bool okRay = false; + + if (cLevel >= gapInfo[1] && cLevel < gapInfo[2]) + { + scalar cellSize = meshCutter_.level0EdgeLength()/pow(2, cLevel); + + // Calculate gap size + scalar nearGap = gapInfo[0]*cellSize; + + // Distance to nearest + vector v(cc-nearPoint); + scalar magV = mag(v); + + if (useSurfaceNormal || magV < 0.5*cellSize) + { + const vector& n = nearNormal; + + // Situation 'C' above: cell too close. Use surface + // normal to shoot rays + + if (mode == volumeType::OUTSIDE) + { + start = nearPoint+1e-6*n; + end = nearPoint+nearGap*n; + // Small second vector just to make sure to + // refine cell + start2 = nearPoint-1e-6*n; + end2 = nearPoint-0.5*cellSize*n; + } + else if (mode == volumeType::INSIDE) + { + start = nearPoint-1e-6*n; + end = nearPoint-nearGap*n; + // Small second vector just to make sure to + // refine cell + start2 = nearPoint+1e-6*n; + end2 = nearPoint+0.5*cellSize*n; + } + else if (mode == volumeType::MIXED) + { + start = nearPoint+1e-6*n; + end = nearPoint+nearGap*n; + + start2 = nearPoint-1e-6*n; + end2 = nearPoint-nearGap*n; + } + + okRay = true; + } + else + { + // Situation 'A' or 'B' above: cell well away. Test if + // cell on correct side of surface and shoot ray through + // cell centre. Note: no need to shoot ray in other + // direction since we're trying to detect cell inside + // the gap. + + scalar s = (v&nearNormal); + + if + ( + (mode == volumeType::MIXED) + || (mode == volumeType::OUTSIDE && s > SMALL) + || (mode == volumeType::INSIDE && s < -SMALL) + ) + { + // Use vector through cell centre + vector n(v/(magV+ROOTVSMALL)); + + start = nearPoint+1e-6*n; + end = nearPoint+nearGap*n; + // Dummy second vector + start2 = start; + end2 = start2; + + okRay = true; + } + } + } + + return okRay; +} + + +//void Foam::meshRefinement::shootRays +//( +// const label surfI, +// labelList& nearMap, +// scalarField& nearGap, +// List<pointIndexHit>& nearInfo, +// List<pointIndexHit>& oppositeInfo +//) const +//{ +// const labelList& cellLevel = meshCutter_.cellLevel(); +// const scalar edge0Len = meshCutter_.level0EdgeLength(); +// +// const labelList& surfaceIndices = surfaces_.surfaces(); +// const List<FixedList<label, 3> >& extendedGapLevel = +// surfaces_.extendedGapLevel(); +// const List<volumeType>& extendedGapMode = surfaces_.extendedGapMode(); +// +// +// label geomI = surfaceIndices[surfI]; +// const searchableSurface& geom = surfaces_.geometry()[geomI]; +// +// +// // Normals for ray shooting and inside/outside detection +// vectorField nearNormal; +// geom.getNormal(nearInfo, nearNormal); +// // Regions +// labelList nearRegion; +// geom.getRegion(nearInfo, nearRegion); +// +// labelList map(nearInfo.size()); +// +// pointField start(nearInfo.size()); +// pointField end(nearInfo.size()); +// pointField start2(nearInfo.size()); +// pointField end2(nearInfo.size()); +// +// label compactI = 0; +// forAll(nearInfo, i) +// { +// label globalRegionI = +// surfaces_.globalRegion(surfI, nearRegion[i]); +// +// label cellI = nearMap[i]; +// label cLevel = cellLevel[cellI]; +// scalar cellSize = edge0Len/pow(2, cLevel); +// +// // Update gap size +// nearGap[i] = extendedGapLevel[globalRegionI][0]*cellSize; +// +// // Construct one or two rays to test for oppositeness +// bool okRay = generateRay +// ( +// false, +// nearInfo[i].hitPoint(), +// nearNormal[i], +// extendedGapLevel[globalRegionI], +// extendedGapMode[globalRegionI], +// +// cellCentres[cellI], +// cellLevel[cellI], +// +// start[compactI], +// end[compactI], +// start2[compactI], +// end2[compactI] +// ); +// if (okRay) +// { +// map[compactI++] = i; +// } +// } +// +// Info<< "Selected " << returnReduce(compactI, sumOp<label>()) +// << " hits on the correct side out of " +// << returnReduce(map.size(), sumOp<label>()) << endl; +// map.setSize(compactI); +// start.setSize(compactI); +// end.setSize(compactI); +// start2.setSize(compactI); +// end2.setSize(compactI); +// +// nearMap = UIndirectList<label>(nearMap, map)(); +// nearGap = UIndirectList<scalar>(nearGap, map)(); +// nearInfo = UIndirectList<pointIndexHit>(nearInfo, map)(); +// +// geom.findLineAny(start, end, oppositeInfo); +// +// List<pointIndexHit> oppositeInfo2; +// geom.findLineAny(start2, end2, oppositeInfo2); +// mergeHits(extractPoints(nearInfo), oppositeInfo2, oppositeInfo); +//} + + +void Foam::meshRefinement::selectGapCandidates +( + const labelList& refineCell, + const label nRefine, + + labelList& cellMap, + List<FixedList<label, 3> >& shellGapInfo, + List<volumeType>& shellGapMode +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + + // Collect cells to test + cellMap.setSize(cellLevel.size()-nRefine); + label compactI = 0; + + forAll(cellLevel, cellI) + { + if (refineCell[cellI] == -1) + { + cellMap[compactI++] = cellI; + } + } + Info<< "Selected " << returnReduce(compactI, sumOp<label>()) + << " unmarked cells out of " + << mesh_.globalData().nTotalCells() << endl; + cellMap.setSize(compactI); + + // Do test to see whether cells are inside/outside shell with + // applicable specification (minLevel <= celllevel < maxLevel) + shells_.findHigherGapLevel + ( + pointField(cellCentres, cellMap), + UIndirectList<label>(cellLevel, cellMap)(), + shellGapInfo, + shellGapMode + ); + + // Compact out hits + + labelList map(shellGapInfo.size()); + compactI = 0; + forAll(shellGapInfo, i) + { + if (shellGapInfo[i][2] > 0) + { + map[compactI++] = i; + } + } + + Info<< "Selected " << returnReduce(compactI, sumOp<label>()) + << " cells inside gap shells out of " + << mesh_.globalData().nTotalCells() << endl; + + map.setSize(compactI); + cellMap = UIndirectList<label>(cellMap, map)(); + shellGapInfo = UIndirectList<FixedList<label, 3> >(shellGapInfo, map)(); + shellGapMode = UIndirectList<volumeType>(shellGapMode, map)(); +} + + +void Foam::meshRefinement::mergeGapInfo +( + const FixedList<label, 3>& shellGapInfo, + const volumeType shellGapMode, + const FixedList<label, 3>& surfGapInfo, + const volumeType surfGapMode, + FixedList<label, 3>& gapInfo, + volumeType& gapMode +) const +{ + if (surfGapInfo[0] == 0) + { + gapInfo = shellGapInfo; + gapMode = shellGapMode; + } + else if (shellGapInfo[0] == 0) + { + gapInfo = surfGapInfo; + gapMode = surfGapMode; + } + else + { + // Both specify a level. Does surface level win? Or does information + // need to be merged? + + //gapInfo[0] = max(surfGapInfo[0], shellGapInfo[0]); + //gapInfo[1] = min(surfGapInfo[1], shellGapInfo[1]); + //gapInfo[2] = max(surfGapInfo[2], shellGapInfo[2]); + gapInfo = surfGapInfo; + gapMode = surfGapMode; + } +} + + +Foam::label Foam::meshRefinement::markInternalGapRefinement +( + const scalar planarCos, + const label nAllowRefine, + + labelList& refineCell, + label& nRefine +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + const scalar edge0Len = meshCutter_.level0EdgeLength(); + + const List<FixedList<label, 3> >& extendedGapLevel = + surfaces_.extendedGapLevel(); + const List<volumeType>& extendedGapMode = surfaces_.extendedGapMode(); + + // Get the gap level for the shells + const labelList maxLevel(shells_.maxGapLevel()); + + label oldNRefine = nRefine; + + if (max(maxLevel) > 0) + { + // Collect cells to test + labelList cellMap; + List<FixedList<label, 3> > shellGapInfo; + List<volumeType> shellGapMode; + selectGapCandidates + ( + refineCell, + nRefine, + + cellMap, + shellGapInfo, + shellGapMode + ); + + + // Find nearest point and normal on the surfaces + List<pointIndexHit> nearInfo; + vectorField nearNormal; + labelList nearSurface; + labelList nearRegion; + { + // Now we have both the cell-level and the gap size information. Use + // this to calculate the gap size + scalarField gapSize(cellMap.size()); + forAll(cellMap, i) + { + label cellI = cellMap[i]; + scalar cellSize = edge0Len/pow(2, cellLevel[cellI]); + gapSize[i] = shellGapInfo[i][0]*cellSize; + } + + surfaces_.findNearestRegion + ( + identity(surfaces_.surfaces().size()), + pointField(cellCentres, cellMap), + sqr(gapSize), + nearSurface, + nearInfo, + nearRegion, + nearNormal + ); + } + + + + labelList map(nearInfo.size()); + pointField start(nearInfo.size()); + pointField end(nearInfo.size()); + pointField start2(nearInfo.size()); + pointField end2(nearInfo.size()); + + label compactI = 0; + + forAll(nearInfo, i) + { + if (nearInfo[i].hit()) + { + label globalRegionI = surfaces_.globalRegion + ( + nearSurface[i], + nearRegion[i] + ); + + // Combine info from shell and surface + FixedList<label, 3> gapInfo; + volumeType gapMode; + mergeGapInfo + ( + shellGapInfo[i], + shellGapMode[i], + extendedGapLevel[globalRegionI], + extendedGapMode[globalRegionI], + gapInfo, + gapMode + ); + + + // Construct one or two rays to test for oppositeness + bool okRay = generateRay + ( + false, + nearInfo[i].hitPoint(), + nearNormal[i], + gapInfo, + gapMode, + + cellCentres[cellMap[i]], + cellLevel[cellMap[i]], + + start[compactI], + end[compactI], + start2[compactI], + end2[compactI] + ); + if (okRay) + { + map[compactI++] = i; + } + } + } + + Info<< "Selected " << returnReduce(compactI, sumOp<label>()) + << " cells for testing out of " + << mesh_.globalData().nTotalCells() << endl; + map.setSize(compactI); + start.setSize(compactI); + end.setSize(compactI); + start2.setSize(compactI); + end2.setSize(compactI); + + cellMap = UIndirectList<label>(cellMap, map)(); + nearNormal = UIndirectList<vector>(nearNormal, map)(); + shellGapInfo.clear(); + shellGapMode.clear(); + nearInfo.clear(); + nearSurface.clear(); + nearRegion.clear(); + + + // Do intersections in first direction + labelList surfaceHit; + vectorField surfaceNormal; + surfaces_.findNearestIntersection + ( + start, + end, + surfaceHit, + surfaceNormal + ); + { + // Do intersections in second direction and merge + labelList surfaceHit2; + vectorField surfaceNormal2; + surfaces_.findNearestIntersection + ( + start2, + end2, + surfaceHit2, + surfaceNormal2 + ); + forAll(surfaceHit, i) + { + if (surfaceHit[i] == -1 && surfaceHit2[i] != -1) + { + surfaceHit[i] = surfaceHit2[i]; + surfaceNormal[i] = surfaceNormal2[i]; + } + } + } + + + forAll(surfaceHit, i) + { + label surfI = surfaceHit[i]; + + if (surfI != -1 && mag(nearNormal[i]&surfaceNormal[i]) > planarCos) + { + // Found intersection with surface. Check opposite normal. + + label cellI = cellMap[i]; + + if + ( + !markForRefine + ( + surfI, + nAllowRefine, + refineCell[cellI], + nRefine + ) + ) + { + break; + } + } + } + + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } + } + + return returnReduce(nRefine-oldNRefine, sumOp<label>()); +} + + +Foam::label Foam::meshRefinement::markSmallFeatureRefinement +( + const scalar planarCos, + const label nAllowRefine, + const labelList& neiLevel, + const pointField& neiCc, + + labelList& refineCell, + label& nRefine +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + + const labelList& surfaceIndices = surfaces_.surfaces(); + const List<FixedList<label, 3> >& extendedGapLevel = + surfaces_.extendedGapLevel(); + const List<volumeType>& extendedGapMode = surfaces_.extendedGapMode(); + + label oldNRefine = nRefine; + + // Check that we're using any gap refinement + labelList shellMaxLevel(shells_.maxGapLevel()); + + if (max(shellMaxLevel) == 0) + { + return 0; + } + + //- Force calculation of tetBasePt + (void)mesh_.tetBasePtIs(); + (void)mesh_.cellTree(); + + + forAll(surfaceIndices, surfI) + { + label geomI = surfaceIndices[surfI]; + const searchableSurface& geom = surfaces_.geometry()[geomI]; + + + // Get the element index in a roundabout way. Problem is e.g. + // distributed surface where local indices differ from global + // ones (needed for getRegion call) + + pointField ctrs; + labelList region; + vectorField normal; + { + // Representative local coordinates and bounding sphere + scalarField radiusSqr; + geom.boundingSpheres(ctrs, radiusSqr); + + List<pointIndexHit> info; + geom.findNearest(ctrs, radiusSqr, info); + + forAll(info, i) + { + if (!info[i].hit()) + { + FatalErrorIn("meshRefinement::markSmallFeatureRefinement") + << "fc:" << ctrs[i] + << " radius:" << radiusSqr[i] + << exit(FatalError); + } + } + + geom.getRegion(info, region); + geom.getNormal(info, normal); + } + + // Do test to see whether triangles are inside/outside shell with + // applicable specification (minLevel <= celllevel < maxLevel) + List<FixedList<label, 3> > shellGapInfo; + List<volumeType> shellGapMode; + shells_.findHigherGapLevel + ( + ctrs, + labelList(ctrs.size(), 0), + shellGapInfo, + shellGapMode + ); + + + labelList map(ctrs.size()); + labelList cellMap(ctrs.size()); + label compactI = 0; + + pointField start(ctrs.size()); + pointField end(ctrs.size()); + pointField start2(ctrs.size()); + pointField end2(ctrs.size()); + + forAll(ctrs, i) + { + if (shellGapInfo[i][2] > 0) + { + label globalRegionI = surfaces_.globalRegion(surfI, region[i]); + + // Combine info from shell and surface + FixedList<label, 3> gapInfo; + volumeType gapMode; + mergeGapInfo + ( + shellGapInfo[i], + shellGapMode[i], + extendedGapLevel[globalRegionI], + extendedGapMode[globalRegionI], + gapInfo, + gapMode + ); + + //- Option 1: use octree nearest searching inside polyMesh + //label cellI = mesh_.findCell(pt); + + //- Option 2: use octree 'inside' searching inside polyMesh. Is + // much faster. + label cellI = -1; + const indexedOctree<treeDataCell>& tree = mesh_.cellTree(); + if (tree.nodes().size() && tree.bb().contains(ctrs[i])) + { + cellI = tree.findInside(ctrs[i]); + } + + if (cellI != -1 && refineCell[cellI] == -1) + { + // Construct one or two rays to test for oppositeness + // Note that we always want to use the surface normal + // and not the vector from cell centre to surface point + + bool okRay = generateRay + ( + true, // always use surface normal + ctrs[i], + normal[i], + gapInfo, + gapMode, + + cellCentres[cellI], + cellLevel[cellI], + + start[compactI], + end[compactI], + start2[compactI], + end2[compactI] + ); + if (okRay) + { + cellMap[compactI] = cellI; + map[compactI++] = i; + } + } + } + } + + Info<< "Selected " << returnReduce(compactI, sumOp<label>()) + << " cells containing triangle centres out of " + << mesh_.globalData().nTotalCells() << endl; + map.setSize(compactI); + cellMap.setSize(compactI); + start.setSize(compactI); + end.setSize(compactI); + start2.setSize(compactI); + end2.setSize(compactI); + + ctrs.clear(); + region.clear(); + shellGapInfo.clear(); + shellGapMode.clear(); + normal = UIndirectList<vector>(normal, map)(); + + + // Do intersections in first direction. + // Note passing in of -1 for cell level such that it does not + // discard surfaces with level 0. (since can be overridden with + // gap level) + labelList surfaceHit; + vectorField surfaceNormal; + surfaces_.findNearestIntersection + ( + start, + end, + surfaceHit, + surfaceNormal + ); + { + // Do intersections in second direction and merge + labelList surfaceHit2; + vectorField surfaceNormal2; + surfaces_.findNearestIntersection + ( + start2, + end2, + surfaceHit2, + surfaceNormal2 + ); + forAll(surfaceHit, i) + { + if (surfaceHit[i] == -1 && surfaceHit2[i] != -1) + { + surfaceHit[i] = surfaceHit2[i]; + surfaceNormal[i] = surfaceNormal2[i]; + } + } + } + + + label nGaps = 0; + + forAll(surfaceHit, i) + { + label surfI = surfaceHit[i]; + + if (surfI != -1 && mag(normal[i]&surfaceNormal[i]) > planarCos) + { + nGaps++; + + if + ( + !markForRefine + ( + surfI, + nAllowRefine, + refineCell[cellMap[i]], + nRefine + ) + ) + { + break; + } + } + } + + Info<< "For surface " << geom.name() << " found " + << returnReduce(nGaps, sumOp<label>()) + << " cells in small gaps" << endl; + + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } + } + + return returnReduce(nRefine-oldNRefine, sumOp<label>()); +} + + +// ************************************************************************* // diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C index b27c4fae3f80a1b06c78b56993663662bb6acee8..8429a3c1175334cae79260499d718e9277757dba 100644 --- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C @@ -742,7 +742,7 @@ Foam::label Foam::meshRefinement::markInternalDistanceToFeatureRefinement } } - // Do test to see whether cells is inside/outside shell with higher level + // Do test to see whether cells are inside/outside shell with higher level labelList maxLevel; features_.findHigherLevel(testCc, testLevels, maxLevel); @@ -820,7 +820,7 @@ Foam::label Foam::meshRefinement::markInternalRefinement } } - // Do test to see whether cells is inside/outside shell with higher level + // Do test to see whether cells are inside/outside shell with higher level labelList maxLevel; shells_.findHigherLevel(testCc, testLevels, maxLevel); @@ -869,6 +869,56 @@ Foam::label Foam::meshRefinement::markInternalRefinement } +Foam::label Foam::meshRefinement::unmarkInternalRefinement +( + labelList& refineCell, + label& nRefine +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const pointField& cellCentres = mesh_.cellCentres(); + + label oldNRefine = nRefine; + + // Collect cells to test + pointField testCc(nRefine); + labelList testLevels(nRefine); + label testI = 0; + + forAll(cellLevel, cellI) + { + if (refineCell[cellI] >= 0) + { + testCc[testI] = cellCentres[cellI]; + testLevels[testI] = cellLevel[cellI]; + testI++; + } + } + + // Do test to see whether cells are inside/outside shell with higher level + labelList levelShell; + limitShells_.findLevel(testCc, testLevels, levelShell); + + // Mark for refinement. Note that we didn't store the original cellID so + // now just reloop in same order. + testI = 0; + forAll(cellLevel, cellI) + { + if (refineCell[cellI] >= 0) + { + if (levelShell[testI] != -1) + { + refineCell[cellI] = -1; + nRefine--; + } + testI++; + } + } + + return returnReduce(oldNRefine-nRefine, sumOp<label>()); +} + + // Collect faces that are intersected and whose neighbours aren't yet marked // for refinement. Foam::labelList Foam::meshRefinement::getRefineCandidateFaces @@ -922,7 +972,6 @@ Foam::label Foam::meshRefinement::markSurfaceRefinement ) const { const labelList& cellLevel = meshCutter_.cellLevel(); - const pointField& cellCentres = mesh_.cellCentres(); label oldNRefine = nRefine; @@ -941,36 +990,15 @@ Foam::label Foam::meshRefinement::markSurfaceRefinement pointField end(testFaces.size()); labelList minLevel(testFaces.size()); - forAll(testFaces, i) - { - label faceI = testFaces[i]; - - label own = mesh_.faceOwner()[faceI]; - - if (mesh_.isInternalFace(faceI)) - { - label nei = mesh_.faceNeighbour()[faceI]; - - start[i] = cellCentres[own]; - end[i] = cellCentres[nei]; - minLevel[i] = min(cellLevel[own], cellLevel[nei]); - } - else - { - label bFaceI = faceI - mesh_.nInternalFaces(); - - start[i] = cellCentres[own]; - end[i] = neiCc[bFaceI]; - minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]); - } - } - - // Extend segments a bit - { - const vectorField smallVec(ROOTSMALL*(end-start)); - start -= smallVec; - end += smallVec; - } + calcCellCellRays + ( + neiCc, + neiLevel, + testFaces, + start, + end, + minLevel + ); // Do test for higher intersections @@ -1130,6 +1158,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement pointField end(testFaces.size()); labelList minLevel(testFaces.size()); + // Note: uses isMasterFace otherwise could be call to calcCellCellRays forAll(testFaces, i) { label faceI = testFaces[i]; @@ -1719,7 +1748,6 @@ Foam::label Foam::meshRefinement::markProximityRefinement ) const { const labelList& cellLevel = meshCutter_.cellLevel(); - const pointField& cellCentres = mesh_.cellCentres(); label oldNRefine = nRefine; @@ -1739,36 +1767,15 @@ Foam::label Foam::meshRefinement::markProximityRefinement pointField end(testFaces.size()); labelList minLevel(testFaces.size()); - forAll(testFaces, i) - { - label faceI = testFaces[i]; - - label own = mesh_.faceOwner()[faceI]; - - if (mesh_.isInternalFace(faceI)) - { - label nei = mesh_.faceNeighbour()[faceI]; - - start[i] = cellCentres[own]; - end[i] = cellCentres[nei]; - minLevel[i] = min(cellLevel[own], cellLevel[nei]); - } - else - { - label bFaceI = faceI - mesh_.nInternalFaces(); - - start[i] = cellCentres[own]; - end[i] = neiCc[bFaceI]; - minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]); - } - } - - // Extend segments a bit - { - const vectorField smallVec(ROOTSMALL*(end-start)); - start -= smallVec; - end += smallVec; - } + calcCellCellRays + ( + neiCc, + neiLevel, + testFaces, + start, + end, + minLevel + ); // Test for all intersections (with surfaces of higher gap level than @@ -2045,7 +2052,9 @@ Foam::labelList Foam::meshRefinement::refineCandidates const bool internalRefinement, const bool surfaceRefinement, const bool curvatureRefinement, + const bool smallFeatureRefinement, const bool gapRefinement, + const bool bigGapRefinement, const label maxGlobalCells, const label maxLocalCells ) const @@ -2096,6 +2105,8 @@ Foam::labelList Foam::meshRefinement::refineCandidates calcNeighbourData(neiLevel, neiCc); + const scalar planarCos = Foam::cos(degToRad(planarAngle)); + // Cells pierced by feature lines // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2163,6 +2174,30 @@ Foam::labelList Foam::meshRefinement::refineCandidates ); Info<< "Marked for refinement due to surface intersection " << ": " << nSurf << " cells." << endl; + + // Refine intersected-cells only inside gaps. See + // markInternalGapRefinement to refine all cells inside gaps. + if + ( + planarCos >= -1 + && planarCos <= 1 + && max(shells_.maxGapLevel()) > 0 + ) + { + label nGapSurf = markSurfaceGapRefinement + ( + planarCos, + nAllowRefine, + neiLevel, + neiCc, + + refineCell, + nRefine + ); + Info<< "Marked for refinement due to surface intersection" + << " (at gaps)" + << ": " << nGapSurf << " cells." << endl; + } } // Refinement based on curvature of surface @@ -2190,7 +2225,33 @@ Foam::labelList Foam::meshRefinement::refineCandidates } - const scalar planarCos = Foam::cos(degToRad(planarAngle)); + // Refinement based on features smaller than cell size + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + if + ( + smallFeatureRefinement + && (planarCos >= -1 && planarCos <= 1) + && max(shells_.maxGapLevel()) > 0 + ) + { + label nGap = markSmallFeatureRefinement + ( + planarCos, + nAllowRefine, + neiLevel, + neiCc, + + refineCell, + nRefine + ); + Info<< "Marked for refinement due to close opposite surfaces " + << ": " << nGap << " cells." << endl; + } + + + // Refinement based on gap (only neighbouring cells) + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ( @@ -2217,6 +2278,44 @@ Foam::labelList Foam::meshRefinement::refineCandidates } + // Refinement based on gaps larger than cell size + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + if + ( + bigGapRefinement + && (planarCos >= -1 && planarCos <= 1) + && max(shells_.maxGapLevel()) > 0 + ) + { + // Refine based on gap information provided by shell and nearest + // surface + label nGap = markInternalGapRefinement + ( + planarCos, + nAllowRefine, + refineCell, + nRefine + ); + Info<< "Marked for refinement due to opposite surfaces" + << " " + << ": " << nGap << " cells." << endl; + } + + + // Limit refinement + // ~~~~~~~~~~~~~~~~ + + { + label nUnmarked = unmarkInternalRefinement(refineCell, nRefine); + if (nUnmarked > 0) + { + Info<< "Unmarked for refinement due to limit shells" + << " : " << nUnmarked << " cells." << endl; + } + } + + // Pack cells-to-refine // ~~~~~~~~~~~~~~~~~~~~ diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C index 7d47a612c9dc35a655594fdfe6a449b7fb490264..6f36ce59041f6d1dcecee87e8cd2b4bc3cbd3751 100644 --- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C @@ -157,11 +157,22 @@ Foam::refinementSurfaces::refinementSurfaces labelList globalMinLevel(surfI, 0); labelList globalMaxLevel(surfI, 0); labelList globalLevelIncr(surfI, 0); + + FixedList<label, 3> nullGapLevel; + nullGapLevel[0] = 0; + nullGapLevel[1] = 0; + nullGapLevel[2] = 0; + + List<FixedList<label, 3> > globalGapLevel(surfI); + List<volumeType> globalGapMode(surfI); + scalarField globalAngle(surfI, -GREAT); PtrList<dictionary> globalPatchInfo(surfI); List<Map<label> > regionMinLevel(surfI); List<Map<label> > regionMaxLevel(surfI); List<Map<label> > regionLevelIncr(surfI); + List<Map<FixedList<label, 3> > > regionGapLevel(surfI); + List<Map<volumeType> > regionGapMode(surfI); List<Map<scalar> > regionAngle(surfI); List<Map<autoPtr<dictionary> > > regionPatchInfo(surfI); @@ -212,6 +223,44 @@ Foam::refinementSurfaces::refinementSurfaces << exit(FatalIOError); } + + // Optional gapLevel specification + + globalGapLevel[surfI] = dict.lookupOrDefault + ( + "gapLevel", + nullGapLevel + ); + globalGapMode[surfI] = volumeType::names + [ + dict.lookupOrDefault<word> + ( + "gapMode", + volumeType::names[volumeType::MIXED] + ) + ]; + if + ( + globalGapMode[surfI] == volumeType::UNKNOWN + || globalGapLevel[surfI][0] < 0 + || globalGapLevel[surfI][1] < 0 + || globalGapLevel[surfI][2] < 0 + || globalGapLevel[surfI][1] > globalGapLevel[surfI][2] + ) + { + FatalIOErrorIn + ( + "refinementSurfaces::refinementSurfaces" + "(const searchableSurfaces&, const dictionary>&", + dict + ) << "Illegal gapLevel specification for surface " + << names_[surfI] + << " : gapLevel:" << globalGapLevel[surfI] + << " gapMode:" << volumeType::names[globalGapMode[surfI]] + << exit(FatalIOError); + } + + const searchableSurface& surface = allGeometry_[surfaces_[surfI]]; // Surface zones @@ -275,6 +324,54 @@ Foam::refinementSurfaces::refinementSurfaces << exit(FatalIOError); } + + + // Optional gapLevel specification + + FixedList<label, 3> gapSpec + ( + regionDict.lookupOrDefault + ( + "gapLevel", + nullGapLevel + ) + ); + regionGapLevel[surfI].insert(regionI, gapSpec); + volumeType gapModeSpec + ( + volumeType::names + [ + regionDict.lookupOrDefault<word> + ( + "gapMode", + volumeType::names[volumeType::MIXED] + ) + ] + ); + regionGapMode[surfI].insert(regionI, gapModeSpec); + if + ( + gapModeSpec == volumeType::UNKNOWN + || gapSpec[0] < 0 + || gapSpec[1] < 0 + || gapSpec[2] < 0 + || gapSpec[1] > gapSpec[2] + ) + { + FatalIOErrorIn + ( + "refinementSurfaces::refinementSurfaces" + "(const searchableSurfaces&," + " const dictionary>&", + dict + ) << "Illegal gapLevel specification for surface " + << names_[surfI] + << " : gapLevel:" << gapSpec + << " gapMode:" << volumeType::names[gapModeSpec] + << exit(FatalIOError); + } + + if (regionDict.found("perpendicularAngle")) { regionAngle[surfI].insert @@ -331,6 +428,10 @@ Foam::refinementSurfaces::refinementSurfaces maxLevel_ = 0; gapLevel_.setSize(nRegions); gapLevel_ = -1; + extendedGapLevel_.setSize(nRegions); + extendedGapLevel_ = nullGapLevel; + extendedGapMode_.setSize(nRegions); + extendedGapMode_ = volumeType::UNKNOWN; perpendicularAngle_.setSize(nRegions); perpendicularAngle_ = -GREAT; patchInfo_.setSize(nRegions); @@ -349,7 +450,8 @@ Foam::refinementSurfaces::refinementSurfaces gapLevel_[globalRegionI] = maxLevel_[globalRegionI] + globalLevelIncr[surfI]; - + extendedGapLevel_[globalRegionI] = globalGapLevel[surfI]; + extendedGapMode_[globalRegionI] = globalGapMode[surfI]; perpendicularAngle_[globalRegionI] = globalAngle[surfI]; if (globalPatchInfo.set(surfI)) { @@ -371,6 +473,10 @@ Foam::refinementSurfaces::refinementSurfaces gapLevel_[globalRegionI] = maxLevel_[globalRegionI] + regionLevelIncr[surfI][iter.key()]; + extendedGapLevel_[globalRegionI] = + regionGapLevel[surfI][iter.key()]; + extendedGapMode_[globalRegionI] = + regionGapMode[surfI][iter.key()]; } forAllConstIter(Map<scalar>, regionAngle[surfI], iter) { @@ -482,12 +588,28 @@ Foam::refinementSurfaces::refinementSurfaces // } +Foam::labelList Foam::refinementSurfaces::maxGapLevel() const +{ + labelList surfaceMax(surfaces_.size(), 0); + + forAll(surfaces_, surfI) + { + const wordList& regionNames = allGeometry_[surfaces_[surfI]].regions(); + + forAll(regionNames, regionI) + { + label globalI = globalRegion(surfI, regionI); + const FixedList<label, 3>& gapInfo = extendedGapLevel_[globalI]; + surfaceMax[surfI] = max(surfaceMax[surfI], gapInfo[2]); + } + } + return surfaceMax; +} + + // Precalculate the refinement level for every element of the searchable // surface. -void Foam::refinementSurfaces::setMinLevelFields -( - const shellSurfaces& shells -) +void Foam::refinementSurfaces::setMinLevelFields(const shellSurfaces& shells) { forAll(surfaces_, surfI) { @@ -1208,6 +1330,49 @@ void Foam::refinementSurfaces::findNearestIntersection } +void Foam::refinementSurfaces::findNearestIntersection +( + const pointField& start, + const pointField& end, + + labelList& surface1, + vectorField& normal1 +) const +{ + // Initialize arguments + surface1.setSize(start.size()); + surface1 = -1; + normal1.setSize(start.size()); + normal1 = vector::zero; + + // Current end of segment to test. + pointField nearest(end); + // Work array + List<pointIndexHit> nearestInfo(start.size()); + labelList region; + vectorField normal; + + forAll(surfaces_, surfI) + { + const searchableSurface& geom = allGeometry_[surfaces_[surfI]]; + + // See if any intersection between start and current nearest + geom.findLine(start, nearest, nearestInfo); + geom.getNormal(nearestInfo, normal); + + forAll(nearestInfo, pointI) + { + if (nearestInfo[pointI].hit()) + { + surface1[pointI] = surfI; + normal1[pointI] = normal[pointI]; + nearest[pointI] = nearestInfo[pointI].hitPoint(); + } + } + } +} + + void Foam::refinementSurfaces::findAnyIntersection ( const pointField& start, diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H index fadb9aaa2694e6b1d1b3dfa8c02e138a1c642307..72f20c17773bdd7d1637c0d9975acf14dd10b524 100644 --- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H @@ -42,6 +42,7 @@ SourceFiles #include "vectorList.H" #include "pointIndexHit.H" #include "surfaceZonesInfo.H" +#include "volumeType.H" #include "pointList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -85,6 +86,12 @@ class refinementSurfaces //- From global region number to small-gap level labelList gapLevel_; + //- From global region number to small-gap level specification + List<FixedList<label, 3> > extendedGapLevel_; + + //- From global region number to side of surface to detect + List<volumeType> extendedGapMode_; + //- From global region number to perpendicular angle scalarField perpendicularAngle_; @@ -188,6 +195,23 @@ public: return gapLevel_; } + //- From global region number to specification of gap and its + // refinement: 3 labels specifying + // - minimum wanted number of cells in the gap + // - minimum cell level when to start trying to detect gaps + // - maximum cell level to refine to (so do not detect gaps if + // cell >= maximum level) + const List<FixedList<label, 3> >& extendedGapLevel() const + { + return extendedGapLevel_; + } + + //- From global region number to side of surface to detect + const List<volumeType>& extendedGapMode() const + { + return extendedGapMode_; + } + //- From global region number to perpendicular angle const scalarField& perpendicularAngle() const { @@ -226,6 +250,9 @@ public: return minLevel_.size(); } + //- Per surface the maximum extendedGapLevel over all its regions + labelList maxGapLevel() const; + //- Calculate minLevelFields void setMinLevelFields ( @@ -314,6 +341,15 @@ public: vectorField& normal2 ) const; + //- Find nearest (to start only) intersection of edge + void findNearestIntersection + ( + const pointField& start, + const pointField& end, + labelList& surfaces, + vectorField& normal + ) const; + //- Used for debugging only: find intersection of edge. void findAnyIntersection ( diff --git a/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C b/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C index cd398025534b2394e07b2790afd40f725aa65b83..128d2892ec25a9bc85e2f53519f4d35878d68fd1 100644 --- a/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C +++ b/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -124,7 +124,7 @@ void Foam::shellSurfaces::setAndCheckLevels } else { - if (!allGeometry_[shells_[shellI]].hasVolumeType()) + if (!shell.hasVolumeType()) { FatalErrorIn ( @@ -152,6 +152,46 @@ void Foam::shellSurfaces::setAndCheckLevels } +void Foam::shellSurfaces::checkGapLevels +( + const dictionary& shellDict, + const label shellI, + const List<FixedList<label, 3> >& levels +) +{ + const searchableSurface& shell = allGeometry_[shells_[shellI]]; + + forAll(levels, regionI) + { + const FixedList<label, 3>& info = levels[regionI]; + + if (info[2] > 0) + { + if (modes_[shellI] == DISTANCE) + { + FatalIOErrorIn + ( + "shellSurfaces::shellSurfaces(..)", + shellDict + ) << "'gapLevel' specification cannot be used with mode " + << refineModeNames_[DISTANCE] + << " for shell " << shell.name() + << exit(FatalIOError); + } + } + } + + // Hardcode for region 0 + if (levels[0][0] > 0) + { + Info<< "Refinement level up to " << levels[0][2] + << " for all cells in gaps for shell " + << shell.name() << endl; + } +} + + + // Specifically orient triSurfaces using a calculated point outside. // Done since quite often triSurfaces not of consistent orientation which // is (currently) necessary for sideness calculation @@ -288,18 +328,18 @@ void Foam::shellSurfaces::findHigherLevel ); // Update maxLevel - forAll(nearInfo, candidateI) + forAll(nearInfo, i) { - if (nearInfo[candidateI].hit()) + if (nearInfo[i].hit()) { // Check which level it actually is in. label minDistI = findLower ( distances, - mag(nearInfo[candidateI].hitPoint()-candidates[candidateI]) + mag(nearInfo[i].hitPoint()-candidates[i]) ); - label pointI = candidateMap[candidateI]; + label pointI = candidateMap[i]; // pt is inbetween shell[minDistI] and shell[minDistI+1] maxLevel[pointI] = levels[minDistI+1]; @@ -356,6 +396,197 @@ void Foam::shellSurfaces::findHigherLevel } +void Foam::shellSurfaces::findHigherGapLevel +( + const pointField& pt, + const labelList& ptLevel, + const label shellI, + labelList& gapShell, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode +) const +{ + //TBD: hardcoded for region 0 information + const FixedList<label, 3>& info = extendedGapLevel_[shellI][0]; + volumeType mode = extendedGapMode_[shellI][0]; + + if (info[2] == 0) + { + return; + } + + + // Collect all those points that have a current maxLevel less than the + // shell. + + labelList candidateMap(pt.size()); + label candidateI = 0; + + forAll(ptLevel, pointI) + { + if (ptLevel[pointI] >= info[1] && ptLevel[pointI] < info[2]) + { + candidateMap[candidateI++] = pointI; + } + } + candidateMap.setSize(candidateI); + + // Do the expensive nearest test only for the candidate points. + List<volumeType> volType; + allGeometry_[shells_[shellI]].getVolumeType + ( + pointField(pt, candidateMap), + volType + ); + + forAll(volType, i) + { + label pointI = candidateMap[i]; + + bool isInside = (volType[i] == volumeType::INSIDE); + + if + ( + ( + (modes_[shellI] == INSIDE && isInside) + || (modes_[shellI] == OUTSIDE && !isInside) + ) + && info[2] > gapInfo[pointI][2] + ) + { + gapShell[pointI] = shellI; + gapInfo[pointI] = info; + gapMode[pointI] = mode; + } + } +} + + +void Foam::shellSurfaces::findLevel +( + const pointField& pt, + const label shellI, + labelList& minLevel, + labelList& shell +) const +{ + const labelList& levels = levels_[shellI]; + + if (modes_[shellI] == DISTANCE) + { + // Distance mode. + + const scalarField& distances = distances_[shellI]; + + // Collect all those points that have a current level equal/greater + // (any of) the shell. Also collect the furthest distance allowable + // to any shell with a higher level. + + pointField candidates(pt.size()); + labelList candidateMap(pt.size()); + scalarField candidateDistSqr(pt.size()); + label candidateI = 0; + + forAll(shell, pointI) + { + if (shell[pointI] == -1) + { + forAllReverse(levels, levelI) + { + if (levels[levelI] <= minLevel[pointI]) + { + candidates[candidateI] = pt[pointI]; + candidateMap[candidateI] = pointI; + candidateDistSqr[candidateI] = sqr(distances[levelI]); + candidateI++; + break; + } + } + } + } + candidates.setSize(candidateI); + candidateMap.setSize(candidateI); + candidateDistSqr.setSize(candidateI); + + // Do the expensive nearest test only for the candidate points. + List<pointIndexHit> nearInfo; + allGeometry_[shells_[shellI]].findNearest + ( + candidates, + candidateDistSqr, + nearInfo + ); + + // Update maxLevel + forAll(nearInfo, i) + { + if (nearInfo[i].hit()) + { + // Check which level it actually is in. + label minDistI = findLower + ( + distances, + mag(nearInfo[i].hitPoint()-candidates[i]) + ); + + label pointI = candidateMap[i]; + + // pt is inbetween shell[minDistI] and shell[minDistI+1] + shell[pointI] = shellI; + minLevel[pointI] = levels[minDistI+1]; + } + } + } + else + { + // Inside/outside mode + + // Collect all those points that have a current maxLevel less than the + // shell. + + pointField candidates(pt.size()); + labelList candidateMap(pt.size()); + label candidateI = 0; + + forAll(shell, pointI) + { + if (shell[pointI] == -1 && levels[0] <= minLevel[pointI]) + { + candidates[candidateI] = pt[pointI]; + candidateMap[candidateI] = pointI; + candidateI++; + } + } + candidates.setSize(candidateI); + candidateMap.setSize(candidateI); + + // Do the expensive nearest test only for the candidate points. + List<volumeType> volType; + allGeometry_[shells_[shellI]].getVolumeType(candidates, volType); + + forAll(volType, i) + { + if + ( + ( + modes_[shellI] == INSIDE + && volType[i] == volumeType::INSIDE + ) + || ( + modes_[shellI] == OUTSIDE + && volType[i] == volumeType::OUTSIDE + ) + ) + { + label pointI = candidateMap[i]; + shell[pointI] = shellI; + minLevel[pointI] = levels[0]; + } + } + } +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::shellSurfaces::shellSurfaces @@ -387,6 +618,15 @@ Foam::shellSurfaces::shellSurfaces distances_.setSize(shellI); levels_.setSize(shellI); + extendedGapLevel_.setSize(shellI); + extendedGapMode_.setSize(shellI); + + FixedList<label, 3> nullGapLevel; + nullGapLevel[0] = 0; + nullGapLevel[1] = 0; + nullGapLevel[2] = 0; + + HashSet<word> unmatchedKeys(shellsDict.toc()); shellI = 0; @@ -407,6 +647,85 @@ Foam::shellSurfaces::shellSurfaces // Read pairs of distance+level setAndCheckLevels(shellI, dict.lookup("levels")); + + + // Gap specification + // ~~~~~~~~~~~~~~~~~ + + + // Shell-wide gap level specification + const searchableSurface& surface = allGeometry_[geomI]; + const wordList& regionNames = surface.regions(); + + FixedList<label, 3> gapSpec + ( + dict.lookupOrDefault + ( + "gapLevel", + nullGapLevel + ) + ); + extendedGapLevel_[shellI].setSize(regionNames.size()); + extendedGapLevel_[shellI] = gapSpec; + + volumeType gapModeSpec + ( + volumeType::names + [ + dict.lookupOrDefault<word> + ( + "gapMode", + volumeType::names[volumeType::MIXED] + ) + ] + ); + extendedGapMode_[shellI].setSize(regionNames.size()); + extendedGapMode_[shellI] = gapModeSpec; + + + // Override on a per-region basis? + + if (dict.found("regions")) + { + const dictionary& regionsDict = dict.subDict("regions"); + forAll(regionNames, regionI) + { + if (regionsDict.found(regionNames[regionI])) + { + // Get the dictionary for region + const dictionary& regionDict = regionsDict.subDict + ( + regionNames[regionI] + ); + FixedList<label, 3> gapSpec + ( + regionDict.lookupOrDefault + ( + "gapLevel", + nullGapLevel + ) + ); + extendedGapLevel_[shellI][regionI] = gapSpec; + + volumeType gapModeSpec + ( + volumeType::names + [ + regionDict.lookupOrDefault<word> + ( + "gapMode", + volumeType::names[volumeType::MIXED] + ) + ] + ); + extendedGapMode_[shellI][regionI] = gapModeSpec; + } + } + } + + + checkGapLevels(dict, shellI, extendedGapLevel_[shellI]); + shellI++; } } @@ -444,6 +763,22 @@ Foam::label Foam::shellSurfaces::maxLevel() const } +Foam::labelList Foam::shellSurfaces::maxGapLevel() const +{ + labelList surfaceMax(extendedGapLevel_.size(), 0); + + forAll(extendedGapLevel_, shellI) + { + const List<FixedList<label, 3> >& levels = extendedGapLevel_[shellI]; + forAll(levels, i) + { + surfaceMax[shellI] = max(surfaceMax[shellI], levels[i][2]); + } + } + return surfaceMax; +} + + void Foam::shellSurfaces::findHigherLevel ( const pointField& pt, @@ -461,4 +796,66 @@ void Foam::shellSurfaces::findHigherLevel } +void Foam::shellSurfaces::findHigherGapLevel +( + const pointField& pt, + const labelList& ptLevel, + labelList& gapShell, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode +) const +{ + gapShell.setSize(pt.size()); + gapShell = -1; + + FixedList<label, 3> nullGapLevel; + nullGapLevel[0] = 0; + nullGapLevel[1] = 0; + nullGapLevel[2] = 0; + + gapInfo.setSize(pt.size()); + gapInfo = nullGapLevel; + + gapMode.setSize(pt.size()); + gapMode = volumeType::MIXED; + + forAll(shells_, shellI) + { + findHigherGapLevel(pt, ptLevel, shellI, gapShell, gapInfo, gapMode); + } +} + + +void Foam::shellSurfaces::findHigherGapLevel +( + const pointField& pt, + const labelList& ptLevel, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode +) const +{ + labelList gapShell; + findHigherGapLevel(pt, ptLevel, gapShell, gapInfo, gapMode); +} + + +void Foam::shellSurfaces::findLevel +( + const pointField& pt, + const labelList& ptLevel, + labelList& shell +) const +{ + shell.setSize(pt.size()); + shell = -1; + + labelList minLevel(ptLevel); + + forAll(shells_, shellI) + { + findLevel(pt, shellI, minLevel, shell); + } +} + + // ************************************************************************* // diff --git a/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H b/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H index 9b0e4c9e050be2dc3c43e9f84da3489ebb2f283e..13817de16f0b10d124f0ee90d54d904d0d5c33ba 100644 --- a/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H +++ b/src/mesh/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H @@ -2,8 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation - \\/ M anipulation | + \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation + \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -85,6 +85,15 @@ private: labelListList levels_; + // Gap level refinement + + //- Per shell, per region the small-gap level specification + List<List<FixedList<label, 3> > > extendedGapLevel_; + + //- Per shell, per region the small-gap level specification + List<List<volumeType> > extendedGapMode_; + + // Private data //- refineMode names @@ -93,15 +102,24 @@ private: // Private Member Functions - //- Helper function for initialisation. + //- Helper function for initialisation of levels void setAndCheckLevels ( const label shellI, const List<Tuple2<scalar, label> >& ); + //- Helper function for checking of gap information + void checkGapLevels + ( + const dictionary&, + const label shellI, + const List<FixedList<label, 3> >& levels + ); + void orient(); + //- Find first shell with a level higher than maxLevel void findHigherLevel ( const pointField& pt, @@ -109,6 +127,27 @@ private: labelList& maxLevel ) const; + //- Update highest min gap level + void findHigherGapLevel + ( + const pointField& pt, + const labelList& ptLevel, + const label shellI, + labelList& gapShell, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode + ) const; + + //- Find first shell with a level lower or equal to minLevel. Update + // minLevel and shell. + void findLevel + ( + const pointField& pt, + const label shellI, + labelList& minLevel, + labelList& shell + ) const; + public: // Constructors @@ -125,16 +164,11 @@ public: // Access - //const List<scalarField>& distances() const - //{ - // return distances_; - //} - // - ////- Per shell per distance the refinement level - //const labelListList& levels() const - //{ - // return levels_; - //} + //- Indices of surfaces that are shells + const labelList& shells() const + { + return shells_; + } // Query @@ -142,6 +176,9 @@ public: //- Highest shell level label maxLevel() const; + //- Highest shell gap level + labelList maxGapLevel() const; + //- Find shell level higher than ptLevel void findHigherLevel ( @@ -150,6 +187,33 @@ public: labelList& maxLevel ) const; + //- Find a shell whose minimum gap level is >= ptLevel + void findHigherGapLevel + ( + const pointField& pt, + const labelList& ptLevel, + labelList& gapShell, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode + ) const; + + //- Find a shell whose minimum gap level is >= ptLevel. gapInfo + // is (0 0 0) if no shell found + void findHigherGapLevel + ( + const pointField& pt, + const labelList& ptLevel, + List<FixedList<label, 3> >& gapInfo, + List<volumeType>& gapMode + ) const; + + //- Find first shell (or -1) with level equal or lower than ptLevel. + void findLevel + ( + const pointField& pt, + const labelList& ptLevel, + labelList& shell + ) const; }; diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files index 0c1b794f7c6d45d76d37d2448d8cc5b8e6725278..bd0abc24a9be4c307f0476f391e3ef3183699781 100644 --- a/src/meshTools/Make/files +++ b/src/meshTools/Make/files @@ -63,6 +63,7 @@ indexedOctree/treeDataTriSurface.C searchableSurface = searchableSurface $(searchableSurface)/searchableBox.C +$(searchableSurface)/searchableRotatedBox.C $(searchableSurface)/searchableCylinder.C $(searchableSurface)/searchableDisk.C $(searchableSurface)/searchablePlane.C @@ -75,6 +76,7 @@ $(searchableSurface)/searchableSurfacesQueries.C $(searchableSurface)/searchableSurfaceWithGaps.C $(searchableSurface)/triSurfaceMesh.C $(searchableSurface)/closedTriSurfaceMesh.C +$(searchableSurface)/subTriSurfaceMesh.C topoSets = sets/topoSets $(topoSets)/cellSet.C diff --git a/src/parallel/decompose/decompositionMethods/hierarchGeomDecomp/hierarchGeomDecomp.C b/src/parallel/decompose/decompositionMethods/hierarchGeomDecomp/hierarchGeomDecomp.C index 9928f39f4738c01dec1f2042c995c108fbf20c19..0d19394afdc2bcd98ea6b4242671f634a3cdfcbb 100644 --- a/src/parallel/decompose/decompositionMethods/hierarchGeomDecomp/hierarchGeomDecomp.C +++ b/src/parallel/decompose/decompositionMethods/hierarchGeomDecomp/hierarchGeomDecomp.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -408,7 +408,14 @@ void Foam::hierarchGeomDecomp::sortComponent { // No need for binary searching of bin size localSize = label(current.size()/n_[compI]); - rightCoord = sortedCoord[leftIndex+localSize]; + if (leftIndex+localSize < sortedCoord.size()) + { + rightCoord = sortedCoord[leftIndex+localSize]; + } + else + { + rightCoord = maxCoord; + } } else {