From 421a14488ea9c7488602ece1b1afd3cdcff7a683 Mon Sep 17 00:00:00 2001 From: mattijs <mattijs@hunt.opencfd.co.uk> Date: Tue, 6 Jan 2009 20:54:08 +0000 Subject: [PATCH] problem cell removal --- src/autoMesh/Make/files | 1 + .../autoHexMeshDriver/autoRefineDriver.C | 10 +- .../meshRefinement/meshRefinement.H | 29 +- .../meshRefinement/meshRefinementBaffles.C | 664 +----------- .../meshRefinementProblemCells.C | 952 ++++++++++++++++++ .../refinementSurfaces/refinementSurfaces.C | 44 +- .../refinementSurfaces/refinementSurfaces.H | 9 + 7 files changed, 1053 insertions(+), 656 deletions(-) create mode 100644 src/autoMesh/autoHexMesh/meshRefinement/meshRefinementProblemCells.C diff --git a/src/autoMesh/Make/files b/src/autoMesh/Make/files index 96141445bea..fecec5db5db 100644 --- a/src/autoMesh/Make/files +++ b/src/autoMesh/Make/files @@ -15,6 +15,7 @@ $(autoHexMeshDriver)/pointData/pointData.C $(autoHexMesh)/meshRefinement/meshRefinementBaffles.C $(autoHexMesh)/meshRefinement/meshRefinement.C $(autoHexMesh)/meshRefinement/meshRefinementMerge.C +$(autoHexMesh)/meshRefinement/meshRefinementProblemCells.C $(autoHexMesh)/meshRefinement/meshRefinementRefine.C $(autoHexMesh)/refinementSurfaces/refinementSurfaces.C $(autoHexMesh)/shellSurfaces/shellSurfaces.C diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C index ed9fd058086..fc70f98ccc6 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C @@ -518,7 +518,9 @@ void Foam::autoRefineDriver::baffleAndSplitMesh // be like boundary face from now on so not coupled anymore. meshRefiner_.baffleAndSplitMesh ( - handleSnapProblems, + handleSnapProblems, // detect&remove potential snap problem + false, // perpendicular edge connected cells + scalarField(0), // per region perpendicular angle !handleSnapProblems, // merge free standing baffles? motionDict, const_cast<Time&>(mesh.time()), @@ -592,10 +594,14 @@ void Foam::autoRefineDriver::splitAndMergeBaffles const_cast<Time&>(mesh.time())++; } + const scalarField& perpAngle = meshRefiner_.surfaces().perpendicularAngle(); + meshRefiner_.baffleAndSplitMesh ( handleSnapProblems, - false, // merge free standing baffles? + handleSnapProblems, // remove perp edge connected cells + perpAngle, // perp angle + false, // merge free standing baffles? motionDict, const_cast<Time&>(mesh.time()), globalToPatch_, diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H index da533c4d136..5895f5ae3ad 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H @@ -36,6 +36,7 @@ SourceFiles meshRefinement.C meshRefinementBaffles.C meshRefinementMerge.C + meshRefinementProblemCells.C meshRefinementRefine.C \*---------------------------------------------------------------------------*/ @@ -51,6 +52,7 @@ SourceFiles #include "indirectPrimitivePatch.H" #include "pointFieldsFwd.H" #include "Tuple2.H" +#include "pointIndexHit.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -345,6 +347,8 @@ private: polyTopoChange& meshMod ) const; + // Problem cell handling + //- Helper function to mark face as being on 'boundary'. Used by // markFacesOnProblemCells void markBoundaryFace @@ -355,15 +359,32 @@ private: boolList& isBoundaryPoint ) const; + void findNearest + ( + const labelList& meshFaces, + List<pointIndexHit>& nearestInfo, + labelList& nearestSurface, + labelList& nearestRegion, + vectorField& nearestNormal + ) const; + + Map<label> findEdgeConnectedProblemCells + ( + const scalarField& perpendicularAngle, + const labelList& + ) const; + //- Returns list with for every internal face -1 or the patch - // they should be baffled into. + // they should be baffled into. If removeEdgeConnectedCells is set + // removes cells based on perpendicularAngle. labelList markFacesOnProblemCells ( + const bool removeEdgeConnectedCells, + const scalarField& perpendicularAngle, const labelList& globalToPatch ) const; - //- Returns list with for every internal face -1 or the patch - // they should be baffled into. + //- Initial test of marking faces using geometric information. labelList markFacesOnProblemCellsGeometric ( const dictionary& motionDict, @@ -589,6 +610,8 @@ public: void baffleAndSplitMesh ( const bool handleSnapProblems, + const bool removeEdgeConnectedCells, + const scalarField& perpendicularAngle, const bool mergeFreeStanding, const dictionary& motionDict, Time& runTime, diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C index 950cc7251b4..6c5315a12a0 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C @@ -44,10 +44,6 @@ License #include "OFstream.H" #include "regionSplit.H" #include "removeCells.H" -#include "motionSmoother.H" -#include "polyMeshGeometry.H" -#include "IOmanip.H" -#include "cellSet.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -230,7 +226,7 @@ void Foam::meshRefinement::getBafflePatches label vertI = 0; if (debug&OBJINTERSECTIONS) { - str.reset(new OFstream(mesh_.time().path()/"intersections.obj")); + str.reset(new OFstream(mesh_.time().timePath()/"intersections.obj")); Pout<< "getBafflePatches : Writing surface intersections to file " << str().name() << nl << endl; @@ -510,642 +506,6 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles } -void Foam::meshRefinement::markBoundaryFace -( - const label faceI, - boolList& isBoundaryFace, - boolList& isBoundaryEdge, - boolList& isBoundaryPoint -) const -{ - isBoundaryFace[faceI] = true; - - const labelList& fEdges = mesh_.faceEdges(faceI); - - forAll(fEdges, fp) - { - isBoundaryEdge[fEdges[fp]] = true; - } - - const face& f = mesh_.faces()[faceI]; - - forAll(f, fp) - { - isBoundaryPoint[f[fp]] = true; - } -} - - -// Returns list with for every internal face -1 or the patch they should -// be baffled into. Gets run after createBaffles so all the surface -// intersections have already been turned into baffles. Used to remove cells -// by baffling all their faces and have the splitMeshRegions chuck away non -// used regions. -Foam::labelList Foam::meshRefinement::markFacesOnProblemCells -( - const labelList& globalToPatch -) const -{ - const labelList& cellLevel = meshCutter_.cellLevel(); - const labelList& pointLevel = meshCutter_.pointLevel(); - const polyBoundaryMesh& patches = mesh_.boundaryMesh(); - - - // Per internal face (boundary faces not used) the patch that the - // baffle should get (or -1) - labelList facePatch(mesh_.nFaces(), -1); - - // Mark all points and edges on baffle patches (so not on any inlets, - // outlets etc.) - boolList isBoundaryPoint(mesh_.nPoints(), false); - boolList isBoundaryEdge(mesh_.nEdges(), false); - boolList isBoundaryFace(mesh_.nFaces(), false); - - // Fill boundary data. All elements on meshed patches get marked. - // Get the labels of added patches. - labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch)); - - forAll(adaptPatchIDs, i) - { - label patchI = adaptPatchIDs[i]; - - const polyPatch& pp = patches[patchI]; - - label faceI = pp.start(); - - forAll(pp, j) - { - markBoundaryFace - ( - faceI, - isBoundaryFace, - isBoundaryEdge, - isBoundaryPoint - ); - - faceI++; - } - } - - syncTools::syncPointList - ( - mesh_, - isBoundaryPoint, - orEqOp<bool>(), - false, // null value - false // no separation - ); - - syncTools::syncEdgeList - ( - mesh_, - isBoundaryEdge, - orEqOp<bool>(), - false, // null value - false // no separation - ); - - syncTools::syncFaceList - ( - mesh_, - isBoundaryFace, - orEqOp<bool>(), - false // no separation - ); - - - // For each cell count the number of anchor points that are on - // the boundary: - // 8 : check the number of (baffle) boundary faces. If 3 or more block - // off the cell since the cell would get squeezed down to a diamond - // (probably; if the 3 or more faces are unrefined (only use the - // anchor points)) - // 7 : store. Used to check later on whether there are points with - // 3 or more of these cells. (note that on a flat surface a boundary - // point will only have 4 cells connected to it) - - // Does cell have exactly 7 of its 8 anchor points on the boundary? - PackedList<1> hasSevenBoundaryAnchorPoints(mesh_.nCells(), 0u); - // If so what is the remaining non-boundary anchor point? - labelHashSet nonBoundaryAnchors(mesh_.nCells()/10000); - - // On-the-fly addressing storage. - DynamicList<label> dynFEdges; - DynamicList<label> dynCPoints; - - // Count of faces marked for baffling - label nBaffleFaces = 0; - - forAll(cellLevel, cellI) - { - const labelList& cPoints = mesh_.cellPoints(cellI, dynCPoints); - - // Get number of anchor points (pointLevel == cellLevel) - - label nBoundaryAnchors = 0; - label nNonAnchorBoundary = 0; - label nonBoundaryAnchor = -1; - - forAll(cPoints, i) - { - label pointI = cPoints[i]; - - if (pointLevel[pointI] <= cellLevel[cellI]) - { - // Anchor point - if (isBoundaryPoint[pointI]) - { - nBoundaryAnchors++; - } - else - { - // Anchor point which is not on the surface - nonBoundaryAnchor = pointI; - } - } - else if (isBoundaryPoint[pointI]) - { - nNonAnchorBoundary++; - } - } - - if (nBoundaryAnchors == 8) - { - const cell& cFaces = mesh_.cells()[cellI]; - - // Count boundary faces. - label nBfaces = 0; - - forAll(cFaces, cFaceI) - { - if (isBoundaryFace[cFaces[cFaceI]]) - { - nBfaces++; - } - } - - // If nBfaces > 1 make all non-boundary non-baffle faces baffles. - // We assume that this situation is where there is a single - // cell sticking out which would get flattened. - - // Eugene: delete cell no matter what. - //if (nBfaces > 1) - { - forAll(cFaces, cf) - { - label faceI = cFaces[cf]; - - if (facePatch[faceI] == -1 && mesh_.isInternalFace(faceI)) - { - facePatch[faceI] = getBafflePatch(facePatch, faceI); - nBaffleFaces++; - - // Mark face as a 'boundary' - markBoundaryFace - ( - faceI, - isBoundaryFace, - isBoundaryEdge, - isBoundaryPoint - ); - } - } - } - } - else if (nBoundaryAnchors == 7) - { - // Mark the cell. Store the (single!) non-boundary anchor point. - hasSevenBoundaryAnchorPoints.set(cellI, 1u); - nonBoundaryAnchors.insert(nonBoundaryAnchor); - } - } - - - // Loop over all points. If a point is connected to 4 or more cells - // with 7 anchor points on the boundary set those cell's non-boundary faces - // to baffles - - DynamicList<label> dynPCells; - - forAllConstIter(labelHashSet, nonBoundaryAnchors, iter) - { - label pointI = iter.key(); - - const labelList& pCells = mesh_.pointCells(pointI, dynPCells); - - // Count number of 'hasSevenBoundaryAnchorPoints' cells. - label n = 0; - - forAll(pCells, i) - { - if (hasSevenBoundaryAnchorPoints.get(pCells[i]) == 1u) - { - n++; - } - } - - if (n > 3) - { - // Point in danger of being what? Remove all 7-cells. - forAll(pCells, i) - { - label cellI = pCells[i]; - - if (hasSevenBoundaryAnchorPoints.get(cellI) == 1u) - { - const cell& cFaces = mesh_.cells()[cellI]; - - forAll(cFaces, cf) - { - label faceI = cFaces[cf]; - - if - ( - facePatch[faceI] == -1 - && mesh_.isInternalFace(faceI) - ) - { - facePatch[faceI] = getBafflePatch(facePatch, faceI); - nBaffleFaces++; - - // Mark face as a 'boundary' - markBoundaryFace - ( - faceI, - isBoundaryFace, - isBoundaryEdge, - isBoundaryPoint - ); - } - } - } - } - } - } - - - // Sync all. (note that pointdata and facedata not used anymore but sync - // anyway) - - syncTools::syncPointList - ( - mesh_, - isBoundaryPoint, - orEqOp<bool>(), - false, // null value - false // no separation - ); - - syncTools::syncEdgeList - ( - mesh_, - isBoundaryEdge, - orEqOp<bool>(), - false, // null value - false // no separation - ); - - syncTools::syncFaceList - ( - mesh_, - isBoundaryFace, - orEqOp<bool>(), - false // no separation - ); - - - // Find faces with all edges on the boundary and make them baffles - for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) - { - if (facePatch[faceI] == -1) - { - const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges); - label nFaceBoundaryEdges = 0; - - forAll(fEdges, fe) - { - if (isBoundaryEdge[fEdges[fe]]) - { - nFaceBoundaryEdges++; - } - } - - if (nFaceBoundaryEdges == fEdges.size()) - { - facePatch[faceI] = getBafflePatch(facePatch, faceI); - nBaffleFaces++; - - // Do NOT update boundary data since this would grow blocked - // faces across gaps. - } - } - } - - forAll(patches, patchI) - { - const polyPatch& pp = patches[patchI]; - - if (pp.coupled()) - { - label faceI = pp.start(); - - forAll(pp, i) - { - if (facePatch[faceI] == -1) - { - const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges); - label nFaceBoundaryEdges = 0; - - forAll(fEdges, fe) - { - if (isBoundaryEdge[fEdges[fe]]) - { - nFaceBoundaryEdges++; - } - } - - if (nFaceBoundaryEdges == fEdges.size()) - { - facePatch[faceI] = getBafflePatch(facePatch, faceI); - nBaffleFaces++; - - // Do NOT update boundary data since this would grow - // blocked faces across gaps. - } - } - - faceI++; - } - } - } - - Info<< "markFacesOnProblemCells : marked " - << returnReduce(nBaffleFaces, sumOp<label>()) - << " additional internal faces to be converted into baffles." - << endl; - - return facePatch; -} -//XXXXXXXXXXXXXX -// Mark faces to be baffled to prevent snapping problems. Does -// test to find nearest surface and checks which faces would get squashed. -Foam::labelList Foam::meshRefinement::markFacesOnProblemCellsGeometric -( - const dictionary& motionDict, - const labelList& globalToPatch -) const -{ - // Get the labels of added patches. - labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch)); - - // Construct addressing engine. - autoPtr<indirectPrimitivePatch> ppPtr - ( - meshRefinement::makePatch - ( - mesh_, - adaptPatchIDs - ) - ); - const indirectPrimitivePatch& pp = ppPtr(); - const pointField& localPoints = pp.localPoints(); - const labelList& meshPoints = pp.meshPoints(); - - // Find nearest (non-baffle) surface - pointField newPoints(mesh_.points()); - { - List<pointIndexHit> hitInfo; - labelList hitSurface; - surfaces_.findNearest - ( - surfaces_.getUnnamedSurfaces(), - localPoints, - scalarField(localPoints.size(), sqr(GREAT)), // sqr of attraction - hitSurface, - hitInfo - ); - - forAll(hitInfo, i) - { - if (hitInfo[i].hit()) - { - //label pointI = meshPoints[i]; - //Pout<< " " << pointI << " moved from " - // << mesh_.points()[pointI] << " by " - // << mag(hitInfo[i].hitPoint()-mesh_.points()[pointI]) - // << endl; - newPoints[meshPoints[i]] = hitInfo[i].hitPoint(); - } - } - } - - // Per face (internal or coupled!) the patch that the - // baffle should get (or -1). - labelList facePatch(mesh_.nFaces(), -1); - // Count of baffled faces - label nBaffleFaces = 0; - - -// // Sync position? Or not since same face on both side so just sync -// // result of baffle. -// -// const scalar minArea(readScalar(motionDict.lookup("minArea"))); -// -// Pout<< "markFacesOnProblemCellsGeometric : Comparing to minArea:" -// << minArea << endl; -// -// pointField facePoints; -// for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++) -// { -// const face& f = mesh_.faces()[faceI]; -// -// bool usesPatchPoint = false; -// -// facePoints.setSize(f.size()); -// forAll(f, fp) -// { -// Map<label>::const_iterator iter = pp.meshPointMap().find(f[fp]); -// -// if (iter != pp.meshPointMap().end()) -// { -// facePoints[fp] = newPosition[iter()]; -// usesPatchPoint = true; -// } -// else -// { -// facePoints[fp] = mesh_.points()[f[fp]]; -// } -// } -// -// if (usesPatchPoint) -// { -// // Check area of face wrt original area -// face identFace(identity(f.size())); -// -// if (identFace.mag(facePoints) < minArea) -// { -// facePatch[faceI] = getBafflePatch(facePatch, faceI); -// nBaffleFaces++; -// } -// } -// } -// -// -// const polyBoundaryMesh& patches = mesh_.boundaryMesh(); -// forAll(patches, patchI) -// { -// const polyPatch& pp = patches[patchI]; -// -// if (pp.coupled()) -// { -// forAll(pp, i) -// { -// label faceI = pp.start()+i; -// -// const face& f = mesh_.faces()[faceI]; -// -// bool usesPatchPoint = false; -// -// facePoints.setSize(f.size()); -// forAll(f, fp) -// { -// Map<label>::const_iterator iter = -// pp.meshPointMap().find(f[fp]); -// -// if (iter != pp.meshPointMap().end()) -// { -// facePoints[fp] = newPosition[iter()]; -// usesPatchPoint = true; -// } -// else -// { -// facePoints[fp] = mesh_.points()[f[fp]]; -// } -// } -// -// if (usesPatchPoint) -// { -// // Check area of face wrt original area -// face identFace(identity(f.size())); -// -// if (identFace.mag(facePoints) < minArea) -// { -// facePatch[faceI] = getBafflePatch(facePatch, faceI); -// nBaffleFaces++; -// } -// } -// } -// } -// } - - { - pointField oldPoints(mesh_.points()); - mesh_.movePoints(newPoints); - faceSet wrongFaces(mesh_, "wrongFaces", 100); - { - //motionSmoother::checkMesh(false, mesh_, motionDict, wrongFaces); - - // Just check the errors from squashing - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - const labelList allFaces(identity(mesh_.nFaces())); - label nWrongFaces = 0; - - scalar minArea(readScalar(motionDict.lookup("minArea"))); - if (minArea > -SMALL) - { - polyMeshGeometry::checkFaceArea - ( - false, - minArea, - mesh_, - mesh_.faceAreas(), - allFaces, - &wrongFaces - ); - - label nNewWrongFaces = returnReduce - ( - wrongFaces.size(), - sumOp<label>() - ); - - Info<< " faces with area < " - << setw(5) << minArea - << " m^2 : " - << nNewWrongFaces-nWrongFaces << endl; - - nWrongFaces = nNewWrongFaces; - } - -// scalar minDet(readScalar(motionDict.lookup("minDeterminant"))); - scalar minDet = 0.01; - if (minDet > -1) - { - polyMeshGeometry::checkCellDeterminant - ( - false, - minDet, - mesh_, - mesh_.faceAreas(), - allFaces, - polyMeshGeometry::affectedCells(mesh_, allFaces), - &wrongFaces - ); - - label nNewWrongFaces = returnReduce - ( - wrongFaces.size(), - sumOp<label>() - ); - - Info<< " faces on cells with determinant < " - << setw(5) << minDet << " : " - << nNewWrongFaces-nWrongFaces << endl; - - nWrongFaces = nNewWrongFaces; - } - } - - - forAllConstIter(faceSet, wrongFaces, iter) - { - label patchI = mesh_.boundaryMesh().whichPatch(iter.key()); - - if (patchI == -1 || mesh_.boundaryMesh()[patchI].coupled()) - { - facePatch[iter.key()] = getBafflePatch(facePatch, iter.key()); - nBaffleFaces++; - - //Pout<< " " << iter.key() - // //<< " on patch " << mesh_.boundaryMesh()[patchI].name() - // << " is destined for patch " << facePatch[iter.key()] - // << endl; - } - } - // Restore points. - mesh_.movePoints(oldPoints); - } - - - Info<< "markFacesOnProblemCellsGeometric : marked " - << returnReduce(nBaffleFaces, sumOp<label>()) - << " additional internal and coupled faces" - << " to be converted into baffles." << endl; - - syncTools::syncFaceList - ( - mesh_, - facePatch, - maxEqOp<label>(), - false // no separation - ); - - return facePatch; -} -//XXXXXXXX - - // Return a list of coupled face pairs, i.e. faces that use the same vertices. // (this information is recalculated instead of maintained since would be too // hard across splitMeshRegions). @@ -1855,13 +1215,13 @@ void Foam::meshRefinement::findCellZoneTopo break; } - // Synchronise regionToCellZone. - // Note: - // - region numbers are identical on all processors - // - keepRegion is identical ,, - // - cellZones are identical ,, - Pstream::listCombineGather(regionToCellZone, maxEqOp<label>()); - Pstream::listCombineScatter(regionToCellZone); + // Synchronise regionToCellZone. + // Note: + // - region numbers are identical on all processors + // - keepRegion is identical ,, + // - cellZones are identical ,, + Pstream::listCombineGather(regionToCellZone, maxEqOp<label>()); + Pstream::listCombineScatter(regionToCellZone); } @@ -1904,6 +1264,8 @@ void Foam::meshRefinement::findCellZoneTopo void Foam::meshRefinement::baffleAndSplitMesh ( const bool handleSnapProblems, + const bool removeEdgeConnectedCells, + const scalarField& perpendicularAngle, const bool mergeFreeStanding, const dictionary& motionDict, Time& runTime, @@ -1981,6 +1343,8 @@ void Foam::meshRefinement::baffleAndSplitMesh ( markFacesOnProblemCells ( + removeEdgeConnectedCells, + perpendicularAngle, globalToPatch ) //markFacesOnProblemCellsGeometric @@ -2024,6 +1388,8 @@ void Foam::meshRefinement::baffleAndSplitMesh ( markFacesOnProblemCells ( + removeEdgeConnectedCells, + perpendicularAngle, globalToPatch ) ); @@ -2099,7 +1465,7 @@ void Foam::meshRefinement::baffleAndSplitMesh { Pout<< "Writing subsetted mesh to time " << mesh_.time().timeName() << endl; - write(debug, runTime.path()/runTime.timeName()); + write(debug, runTime.timePath()); Pout<< "Dumped debug data in = " << runTime.cpuTimeIncrement() << " s\n" << nl << endl; } diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementProblemCells.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementProblemCells.C new file mode 100644 index 00000000000..8a027fa654b --- /dev/null +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementProblemCells.C @@ -0,0 +1,952 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*----------------------------------------------------------------------------*/ + +#include "meshRefinement.H" +#include "fvMesh.H" +#include "syncTools.H" +#include "Time.H" +#include "refinementSurfaces.H" +#include "pointSet.H" +#include "faceSet.H" +#include "indirectPrimitivePatch.H" +#include "OFstream.H" +#include "cellSet.H" +#include "searchableSurfaces.H" +#include "polyMeshGeometry.H" +#include "IOmanip.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::meshRefinement::markBoundaryFace +( + const label faceI, + boolList& isBoundaryFace, + boolList& isBoundaryEdge, + boolList& isBoundaryPoint +) const +{ + isBoundaryFace[faceI] = true; + + const labelList& fEdges = mesh_.faceEdges(faceI); + + forAll(fEdges, fp) + { + isBoundaryEdge[fEdges[fp]] = true; + } + + const face& f = mesh_.faces()[faceI]; + + forAll(f, fp) + { + isBoundaryPoint[f[fp]] = true; + } +} + + +void Foam::meshRefinement::findNearest +( + const labelList& meshFaces, + List<pointIndexHit>& nearestInfo, + labelList& nearestSurface, + labelList& nearestRegion, + vectorField& nearestNormal +) const +{ + pointField fc(meshFaces.size()); + forAll(meshFaces, i) + { + fc[i] = mesh_.faceCentres()[meshFaces[i]]; + } + + const labelList allSurfaces(identity(surfaces_.surfaces().size())); + + surfaces_.findNearest + ( + allSurfaces, + fc, + scalarField(fc.size(), sqr(GREAT)), // sqr of attraction + nearestSurface, + nearestInfo + ); + + // Do normal testing per surface. + nearestNormal.setSize(nearestInfo.size()); + nearestRegion.setSize(nearestInfo.size()); + + forAll(allSurfaces, surfI) + { + DynamicList<pointIndexHit> localHits; + + forAll(nearestSurface, i) + { + if (nearestSurface[i] == surfI) + { + localHits.append(nearestInfo[i]); + } + } + + label geomI = surfaces_.surfaces()[surfI]; + + pointField localNormals; + surfaces_.geometry()[geomI].getNormal(localHits, localNormals); + + labelList localRegion; + surfaces_.geometry()[geomI].getRegion(localHits, localRegion); + + label localI = 0; + forAll(nearestSurface, i) + { + if (nearestSurface[i] == surfI) + { + nearestNormal[i] = localNormals[localI]; + nearestRegion[i] = localRegion[localI]; + localI++; + } + } + } +} + + +Foam::Map<Foam::label> Foam::meshRefinement::findEdgeConnectedProblemCells +( + const scalarField& perpendicularAngle, + const labelList& globalToPatch +) const +{ + labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch)); + + // Construct addressing engine. + autoPtr<indirectPrimitivePatch> ppPtr + ( + meshRefinement::makePatch + ( + mesh_, + adaptPatchIDs + ) + ); + const indirectPrimitivePatch& pp = ppPtr(); + + + // 1. Collect faces to test + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + DynamicList<label> candidateFaces(pp.size()/20); + + const labelListList& edgeFaces = pp.edgeFaces(); + + const labelList& cellLevel = meshCutter_.cellLevel(); + + forAll(edgeFaces, edgeI) + { + const labelList& eFaces = edgeFaces[edgeI]; + + if (eFaces.size() == 2) + { + label face0 = pp.addressing()[eFaces[0]]; + label face1 = pp.addressing()[eFaces[1]]; + + label cell0 = mesh_.faceOwner()[face0]; + label cell1 = mesh_.faceOwner()[face1]; + + if (cellLevel[cell0] > cellLevel[cell1]) + { + // cell0 smaller. + const vector& n0 = pp.faceNormals()[eFaces[0]]; + const vector& n1 = pp.faceNormals()[eFaces[1]]; + + if (mag(n0 & n1) < 0.1) + { + candidateFaces.append(face0); + } + } + else if (cellLevel[cell1] > cellLevel[cell0]) + { + // cell1 smaller. + const vector& n0 = pp.faceNormals()[eFaces[0]]; + const vector& n1 = pp.faceNormals()[eFaces[1]]; + + if (mag(n0 & n1) < 0.1) + { + candidateFaces.append(face1); + } + } + } + } + candidateFaces.shrink(); + + Info<< "Testing " << returnReduce(candidateFaces.size(), sumOp<label>()) + << " faces on edge-connected cells of differing level." + << endl; + + if (debug) + { + faceSet fSet(mesh_, "edgeConnectedFaces", candidateFaces); + Pout<< "Writing " << fSet.size() + << " with problematic topology to faceSet " + << fSet.objectPath() << endl; + fSet.write(); + } + + + // 2. Find nearest surface on candidate faces + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + List<pointIndexHit> nearestInfo; + labelList nearestSurface; + labelList nearestRegion; + vectorField nearestNormal; + findNearest + ( + candidateFaces, + nearestInfo, + nearestSurface, + nearestRegion, + nearestNormal + ); + + + // 3. Test angle to surface + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + Map<label> candidateCells(candidateFaces.size()); + + faceSet perpFaces(mesh_, "perpendicularFaces", pp.size()/100); + + forAll(candidateFaces, i) + { + label faceI = candidateFaces[i]; + + vector n = mesh_.faceAreas()[faceI]; + n /= mag(n); + + label region = surfaces_.globalRegion + ( + nearestSurface[i], + nearestRegion[i] + ); + + scalar angle = + perpendicularAngle[region] + / 180.0 + * mathematicalConstant::pi; + + if (angle >= 0) + { + if (mag(n & nearestNormal[i]) < Foam::sin(angle)) + { + perpFaces.insert(faceI); + candidateCells.insert + ( + mesh_.faceOwner()[faceI], + globalToPatch[region] + ); + } + } + } + + if (debug) + { + Pout<< "Writing " << perpFaces.size() + << " faces that are perpendicular to the surface to set " + << perpFaces.objectPath() << endl; + perpFaces.write(); + } + return candidateCells; +} + + +// Returns list with for every internal face -1 or the patch they should +// be baffled into. Gets run after createBaffles so all the surface +// intersections have already been turned into baffles. Used to remove cells +// by baffling all their faces and have the splitMeshRegions chuck away non +// used regions. +Foam::labelList Foam::meshRefinement::markFacesOnProblemCells +( + const bool removeEdgeConnectedCells, + const scalarField& perpendicularAngle, + const labelList& globalToPatch +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const labelList& pointLevel = meshCutter_.pointLevel(); + const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + + + // Per internal face (boundary faces not used) the patch that the + // baffle should get (or -1) + labelList facePatch(mesh_.nFaces(), -1); + + // Mark all points and edges on baffle patches (so not on any inlets, + // outlets etc.) + boolList isBoundaryPoint(mesh_.nPoints(), false); + boolList isBoundaryEdge(mesh_.nEdges(), false); + boolList isBoundaryFace(mesh_.nFaces(), false); + + // Fill boundary data. All elements on meshed patches get marked. + // Get the labels of added patches. + labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch)); + + forAll(adaptPatchIDs, i) + { + label patchI = adaptPatchIDs[i]; + + const polyPatch& pp = patches[patchI]; + + label faceI = pp.start(); + + forAll(pp, j) + { + markBoundaryFace + ( + faceI, + isBoundaryFace, + isBoundaryEdge, + isBoundaryPoint + ); + + faceI++; + } + } + + // Count of faces marked for baffling + label nBaffleFaces = 0; + + if (removeEdgeConnectedCells && max(perpendicularAngle) >= 0) + { + Info<< "markFacesOnProblemCells :" + << " Checking for edge-connected cells of highly differing sizes." + << endl; + + // Pick up the cells that need to be removed and (a guess for) + // the patch they should be patched with. + Map<label> problemCells + ( + findEdgeConnectedProblemCells + ( + perpendicularAngle, + globalToPatch + ) + ); + + // Baffle all faces of cells that need to be removed + forAllConstIter(Map<label>, problemCells, iter) + { + const cell& cFaces = mesh_.cells()[iter.key()]; + + forAll(cFaces, i) + { + label faceI = cFaces[i]; + + if (facePatch[faceI] == -1 && mesh_.isInternalFace(faceI)) + { + facePatch[faceI] = getBafflePatch(facePatch, faceI); + nBaffleFaces++; + + // Mark face as a 'boundary' + markBoundaryFace + ( + faceI, + isBoundaryFace, + isBoundaryEdge, + isBoundaryPoint + ); + } + } + } + Info<< "markFacesOnProblemCells : Marked " + << returnReduce(nBaffleFaces, sumOp<label>()) + << " additional internal faces to be converted into baffles" + << " due to " + << returnReduce(problemCells.size(), sumOp<label>()) + << " cells edge-connected to lower level cells." << endl; + + if (debug) + { + cellSet problemCellSet(mesh_, "problemCells", problemCells.toc()); + Pout<< "Writing " << problemCellSet.size() + << " cells that are edge connected to coarser cell to set " + << problemCellSet.objectPath() << endl; + problemCellSet.write(); + } + } + + syncTools::syncPointList + ( + mesh_, + isBoundaryPoint, + orEqOp<bool>(), + false, // null value + false // no separation + ); + + syncTools::syncEdgeList + ( + mesh_, + isBoundaryEdge, + orEqOp<bool>(), + false, // null value + false // no separation + ); + + syncTools::syncFaceList + ( + mesh_, + isBoundaryFace, + orEqOp<bool>(), + false // no separation + ); + + + // For each cell count the number of anchor points that are on + // the boundary: + // 8 : check the number of (baffle) boundary faces. If 3 or more block + // off the cell since the cell would get squeezed down to a diamond + // (probably; if the 3 or more faces are unrefined (only use the + // anchor points)) + // 7 : store. Used to check later on whether there are points with + // 3 or more of these cells. (note that on a flat surface a boundary + // point will only have 4 cells connected to it) + + // Does cell have exactly 7 of its 8 anchor points on the boundary? + PackedList<1> hasSevenBoundaryAnchorPoints(mesh_.nCells(), 0u); + // If so what is the remaining non-boundary anchor point? + labelHashSet nonBoundaryAnchors(mesh_.nCells()/10000); + + // On-the-fly addressing storage. + DynamicList<label> dynFEdges; + DynamicList<label> dynCPoints; + + forAll(cellLevel, cellI) + { + const labelList& cPoints = mesh_.cellPoints(cellI, dynCPoints); + + // Get number of anchor points (pointLevel == cellLevel) + + label nBoundaryAnchors = 0; + label nNonAnchorBoundary = 0; + label nonBoundaryAnchor = -1; + + forAll(cPoints, i) + { + label pointI = cPoints[i]; + + if (pointLevel[pointI] <= cellLevel[cellI]) + { + // Anchor point + if (isBoundaryPoint[pointI]) + { + nBoundaryAnchors++; + } + else + { + // Anchor point which is not on the surface + nonBoundaryAnchor = pointI; + } + } + else if (isBoundaryPoint[pointI]) + { + nNonAnchorBoundary++; + } + } + + if (nBoundaryAnchors == 8) + { + const cell& cFaces = mesh_.cells()[cellI]; + + // Count boundary faces. + label nBfaces = 0; + + forAll(cFaces, cFaceI) + { + if (isBoundaryFace[cFaces[cFaceI]]) + { + nBfaces++; + } + } + + // If nBfaces > 1 make all non-boundary non-baffle faces baffles. + // We assume that this situation is where there is a single + // cell sticking out which would get flattened. + + // Eugene: delete cell no matter what. + //if (nBfaces > 1) + { + forAll(cFaces, cf) + { + label faceI = cFaces[cf]; + + if (facePatch[faceI] == -1 && mesh_.isInternalFace(faceI)) + { + facePatch[faceI] = getBafflePatch(facePatch, faceI); + nBaffleFaces++; + + // Mark face as a 'boundary' + markBoundaryFace + ( + faceI, + isBoundaryFace, + isBoundaryEdge, + isBoundaryPoint + ); + } + } + } + } + else if (nBoundaryAnchors == 7) + { + // Mark the cell. Store the (single!) non-boundary anchor point. + hasSevenBoundaryAnchorPoints.set(cellI, 1u); + nonBoundaryAnchors.insert(nonBoundaryAnchor); + } + } + + + // Loop over all points. If a point is connected to 4 or more cells + // with 7 anchor points on the boundary set those cell's non-boundary faces + // to baffles + + DynamicList<label> dynPCells; + + forAllConstIter(labelHashSet, nonBoundaryAnchors, iter) + { + label pointI = iter.key(); + + const labelList& pCells = mesh_.pointCells(pointI, dynPCells); + + // Count number of 'hasSevenBoundaryAnchorPoints' cells. + label n = 0; + + forAll(pCells, i) + { + if (hasSevenBoundaryAnchorPoints.get(pCells[i]) == 1u) + { + n++; + } + } + + if (n > 3) + { + // Point in danger of being what? Remove all 7-cells. + forAll(pCells, i) + { + label cellI = pCells[i]; + + if (hasSevenBoundaryAnchorPoints.get(cellI) == 1u) + { + const cell& cFaces = mesh_.cells()[cellI]; + + forAll(cFaces, cf) + { + label faceI = cFaces[cf]; + + if + ( + facePatch[faceI] == -1 + && mesh_.isInternalFace(faceI) + ) + { + facePatch[faceI] = getBafflePatch(facePatch, faceI); + nBaffleFaces++; + + // Mark face as a 'boundary' + markBoundaryFace + ( + faceI, + isBoundaryFace, + isBoundaryEdge, + isBoundaryPoint + ); + } + } + } + } + } + } + + + // Sync all. (note that pointdata and facedata not used anymore but sync + // anyway) + + syncTools::syncPointList + ( + mesh_, + isBoundaryPoint, + orEqOp<bool>(), + false, // null value + false // no separation + ); + + syncTools::syncEdgeList + ( + mesh_, + isBoundaryEdge, + orEqOp<bool>(), + false, // null value + false // no separation + ); + + syncTools::syncFaceList + ( + mesh_, + isBoundaryFace, + orEqOp<bool>(), + false // no separation + ); + + + // Find faces with all edges on the boundary and make them baffles + for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++) + { + if (facePatch[faceI] == -1) + { + const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges); + label nFaceBoundaryEdges = 0; + + forAll(fEdges, fe) + { + if (isBoundaryEdge[fEdges[fe]]) + { + nFaceBoundaryEdges++; + } + } + + if (nFaceBoundaryEdges == fEdges.size()) + { + facePatch[faceI] = getBafflePatch(facePatch, faceI); + nBaffleFaces++; + + // Do NOT update boundary data since this would grow blocked + // faces across gaps. + } + } + } + + forAll(patches, patchI) + { + const polyPatch& pp = patches[patchI]; + + if (pp.coupled()) + { + label faceI = pp.start(); + + forAll(pp, i) + { + if (facePatch[faceI] == -1) + { + const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges); + label nFaceBoundaryEdges = 0; + + forAll(fEdges, fe) + { + if (isBoundaryEdge[fEdges[fe]]) + { + nFaceBoundaryEdges++; + } + } + + if (nFaceBoundaryEdges == fEdges.size()) + { + facePatch[faceI] = getBafflePatch(facePatch, faceI); + nBaffleFaces++; + + // Do NOT update boundary data since this would grow + // blocked faces across gaps. + } + } + + faceI++; + } + } + } + + Info<< "markFacesOnProblemCells : marked " + << returnReduce(nBaffleFaces, sumOp<label>()) + << " additional internal faces to be converted into baffles." + << endl; + + return facePatch; +} +//XXXXXXXXXXXXXX +// Mark faces to be baffled to prevent snapping problems. Does +// test to find nearest surface and checks which faces would get squashed. +Foam::labelList Foam::meshRefinement::markFacesOnProblemCellsGeometric +( + const dictionary& motionDict, + const labelList& globalToPatch +) const +{ + // Get the labels of added patches. + labelList adaptPatchIDs(meshRefinement::addedPatches(globalToPatch)); + + // Construct addressing engine. + autoPtr<indirectPrimitivePatch> ppPtr + ( + meshRefinement::makePatch + ( + mesh_, + adaptPatchIDs + ) + ); + const indirectPrimitivePatch& pp = ppPtr(); + const pointField& localPoints = pp.localPoints(); + const labelList& meshPoints = pp.meshPoints(); + + // Find nearest (non-baffle) surface + pointField newPoints(mesh_.points()); + { + List<pointIndexHit> hitInfo; + labelList hitSurface; + surfaces_.findNearest + ( + surfaces_.getUnnamedSurfaces(), + localPoints, + scalarField(localPoints.size(), sqr(GREAT)), // sqr of attraction + hitSurface, + hitInfo + ); + + forAll(hitInfo, i) + { + if (hitInfo[i].hit()) + { + //label pointI = meshPoints[i]; + //Pout<< " " << pointI << " moved from " + // << mesh_.points()[pointI] << " by " + // << mag(hitInfo[i].hitPoint()-mesh_.points()[pointI]) + // << endl; + newPoints[meshPoints[i]] = hitInfo[i].hitPoint(); + } + } + } + + // Per face (internal or coupled!) the patch that the + // baffle should get (or -1). + labelList facePatch(mesh_.nFaces(), -1); + // Count of baffled faces + label nBaffleFaces = 0; + + +// // Sync position? Or not since same face on both side so just sync +// // result of baffle. +// +// const scalar minArea(readScalar(motionDict.lookup("minArea"))); +// +// Pout<< "markFacesOnProblemCellsGeometric : Comparing to minArea:" +// << minArea << endl; +// +// pointField facePoints; +// for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++) +// { +// const face& f = mesh_.faces()[faceI]; +// +// bool usesPatchPoint = false; +// +// facePoints.setSize(f.size()); +// forAll(f, fp) +// { +// Map<label>::const_iterator iter = pp.meshPointMap().find(f[fp]); +// +// if (iter != pp.meshPointMap().end()) +// { +// facePoints[fp] = newPosition[iter()]; +// usesPatchPoint = true; +// } +// else +// { +// facePoints[fp] = mesh_.points()[f[fp]]; +// } +// } +// +// if (usesPatchPoint) +// { +// // Check area of face wrt original area +// face identFace(identity(f.size())); +// +// if (identFace.mag(facePoints) < minArea) +// { +// facePatch[faceI] = getBafflePatch(facePatch, faceI); +// nBaffleFaces++; +// } +// } +// } +// +// +// const polyBoundaryMesh& patches = mesh_.boundaryMesh(); +// forAll(patches, patchI) +// { +// const polyPatch& pp = patches[patchI]; +// +// if (pp.coupled()) +// { +// forAll(pp, i) +// { +// label faceI = pp.start()+i; +// +// const face& f = mesh_.faces()[faceI]; +// +// bool usesPatchPoint = false; +// +// facePoints.setSize(f.size()); +// forAll(f, fp) +// { +// Map<label>::const_iterator iter = +// pp.meshPointMap().find(f[fp]); +// +// if (iter != pp.meshPointMap().end()) +// { +// facePoints[fp] = newPosition[iter()]; +// usesPatchPoint = true; +// } +// else +// { +// facePoints[fp] = mesh_.points()[f[fp]]; +// } +// } +// +// if (usesPatchPoint) +// { +// // Check area of face wrt original area +// face identFace(identity(f.size())); +// +// if (identFace.mag(facePoints) < minArea) +// { +// facePatch[faceI] = getBafflePatch(facePatch, faceI); +// nBaffleFaces++; +// } +// } +// } +// } +// } + + { + pointField oldPoints(mesh_.points()); + mesh_.movePoints(newPoints); + faceSet wrongFaces(mesh_, "wrongFaces", 100); + { + //motionSmoother::checkMesh(false, mesh_, motionDict, wrongFaces); + + // Just check the errors from squashing + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + const labelList allFaces(identity(mesh_.nFaces())); + label nWrongFaces = 0; + + scalar minArea(readScalar(motionDict.lookup("minArea"))); + if (minArea > -SMALL) + { + polyMeshGeometry::checkFaceArea + ( + false, + minArea, + mesh_, + mesh_.faceAreas(), + allFaces, + &wrongFaces + ); + + label nNewWrongFaces = returnReduce + ( + wrongFaces.size(), + sumOp<label>() + ); + + Info<< " faces with area < " + << setw(5) << minArea + << " m^2 : " + << nNewWrongFaces-nWrongFaces << endl; + + nWrongFaces = nNewWrongFaces; + } + +// scalar minDet(readScalar(motionDict.lookup("minDeterminant"))); + scalar minDet = 0.01; + if (minDet > -1) + { + polyMeshGeometry::checkCellDeterminant + ( + false, + minDet, + mesh_, + mesh_.faceAreas(), + allFaces, + polyMeshGeometry::affectedCells(mesh_, allFaces), + &wrongFaces + ); + + label nNewWrongFaces = returnReduce + ( + wrongFaces.size(), + sumOp<label>() + ); + + Info<< " faces on cells with determinant < " + << setw(5) << minDet << " : " + << nNewWrongFaces-nWrongFaces << endl; + + nWrongFaces = nNewWrongFaces; + } + } + + + forAllConstIter(faceSet, wrongFaces, iter) + { + label patchI = mesh_.boundaryMesh().whichPatch(iter.key()); + + if (patchI == -1 || mesh_.boundaryMesh()[patchI].coupled()) + { + facePatch[iter.key()] = getBafflePatch(facePatch, iter.key()); + nBaffleFaces++; + + //Pout<< " " << iter.key() + // //<< " on patch " << mesh_.boundaryMesh()[patchI].name() + // << " is destined for patch " << facePatch[iter.key()] + // << endl; + } + } + // Restore points. + mesh_.movePoints(oldPoints); + } + + + Info<< "markFacesOnProblemCellsGeometric : marked " + << returnReduce(nBaffleFaces, sumOp<label>()) + << " additional internal and coupled faces" + << " to be converted into baffles." << endl; + + syncTools::syncFaceList + ( + mesh_, + facePatch, + maxEqOp<label>(), + false // no separation + ); + + return facePatch; +} +//XXXXXXXX + + +// ************************************************************************* // diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C index 2f23e9706cd..276aa2fd014 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C @@ -53,8 +53,10 @@ Foam::refinementSurfaces::refinementSurfaces { labelList globalMinLevel(surfaceDicts.size(), 0); labelList globalMaxLevel(surfaceDicts.size(), 0); + scalarField globalAngle(surfaceDicts.size(), -GREAT); List<Map<label> > regionMinLevel(surfaceDicts.size()); List<Map<label> > regionMaxLevel(surfaceDicts.size()); + List<Map<scalar> > regionAngle(surfaceDicts.size()); //wordList globalPatchType(surfaceDicts.size()); //List<HashTable<word> > regionPatchType(surfaceDicts.size()); @@ -80,6 +82,12 @@ Foam::refinementSurfaces::refinementSurfaces dict.lookup("zoneInside") >> zoneInside_[surfI]; } + // Global perpendicular angle + if (dict.found("perpendicularAngle")) + { + globalAngle[surfI] = readScalar(dict.lookup("perpendicularAngle")); + } + //// Global patch name per surface //if (dict.found("patchType")) //{ @@ -130,6 +138,15 @@ Foam::refinementSurfaces::refinementSurfaces << exit(FatalError); } regionMaxLevel[surfI].insert(regionI, max); + + if (regionDict.found("perpendicularAngle")) + { + regionAngle[surfI].insert + ( + regionI, + readScalar(regionDict.lookup("perpendicularAngle")) + ); + } } } } @@ -170,6 +187,8 @@ Foam::refinementSurfaces::refinementSurfaces minLevel_ = 0; maxLevel_.setSize(nRegions); maxLevel_ = 0; + perpendicularAngle_.setSize(nRegions); + perpendicularAngle_ = -GREAT; //patchName_.setSize(nRegions); //patchType_.setSize(nRegions); @@ -182,6 +201,7 @@ Foam::refinementSurfaces::refinementSurfaces { minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI]; maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI]; + perpendicularAngle_[regionOffset_[surfI] + i] = globalAngle[surfI]; } // Overwrite with region specific information @@ -191,6 +211,7 @@ Foam::refinementSurfaces::refinementSurfaces minLevel_[globalRegionI] = iter(); maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()]; + perpendicularAngle_[globalRegionI] = regionAngle[surfI][iter.key()]; // Check validity if @@ -240,8 +261,10 @@ Foam::refinementSurfaces::refinementSurfaces { labelList globalMinLevel(surfacesDict.size(), 0); labelList globalMaxLevel(surfacesDict.size(), 0); + scalarField globalAngle(surfacesDict.size(), -GREAT); List<Map<label> > regionMinLevel(surfacesDict.size()); List<Map<label> > regionMaxLevel(surfacesDict.size()); + List<Map<scalar> > regionAngle(surfacesDict.size()); label surfI = 0; forAllConstIter(dictionary, surfacesDict, iter) @@ -274,6 +297,12 @@ Foam::refinementSurfaces::refinementSurfaces dict.lookup("zoneInside") >> zoneInside_[surfI]; } + // Global perpendicular angle + if (dict.found("perpendicularAngle")) + { + globalAngle[surfI] = readScalar(dict.lookup("perpendicularAngle")); + } + if (dict.found("regions")) { const dictionary& regionsDict = dict.subDict("regions"); @@ -306,6 +335,15 @@ Foam::refinementSurfaces::refinementSurfaces regionMinLevel[surfI].insert(regionI, refLevel[0]); regionMaxLevel[surfI].insert(regionI, refLevel[1]); + + if (regionDict.found("perpendicularAngle")) + { + regionAngle[surfI].insert + ( + regionI, + readScalar(regionDict.lookup("perpendicularAngle")) + ); + } } } } @@ -326,6 +364,8 @@ Foam::refinementSurfaces::refinementSurfaces minLevel_ = 0; maxLevel_.setSize(nRegions); maxLevel_ = 0; + perpendicularAngle_.setSize(nRegions); + perpendicularAngle_ = -GREAT; forAll(globalMinLevel, surfI) @@ -337,6 +377,7 @@ Foam::refinementSurfaces::refinementSurfaces { minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI]; maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI]; + perpendicularAngle_[regionOffset_[surfI] + i] = globalAngle[surfI]; } // Overwrite with region specific information @@ -346,6 +387,7 @@ Foam::refinementSurfaces::refinementSurfaces minLevel_[globalRegionI] = iter(); maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()]; + perpendicularAngle_[globalRegionI] = regionAngle[surfI][iter.key()]; // Check validity if @@ -454,8 +496,6 @@ void Foam::refinementSurfaces::setMinLevelFields const shellSurfaces& shells ) { - //minLevelFields_.setSize(surfaces_.size()); - forAll(surfaces_, surfI) { const searchableSurface& geom = allGeometry_[surfaces_[surfI]]; diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H index a20df19f29f..c727303173c 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H @@ -90,6 +90,9 @@ class refinementSurfaces //- From global region number to refinement level labelList maxLevel_; + //- From global region number to perpendicular angle + scalarField perpendicularAngle_; + // Private Member Functions @@ -178,6 +181,12 @@ public: return maxLevel_; } + //- From global region number to perpendicular angle + const scalarField& perpendicularAngle() const + { + return perpendicularAngle_; + } + // Helper -- GitLab