diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C index c62a340a02e5a63d5408f6af790c313bdc93ce33..508bdcb2d8dd6ee2231602a4054b4919bf1114f6 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C @@ -1342,6 +1342,17 @@ int main(int argc, char *argv[]) const snapParameters snapParams(snapDict, dryRun); + Info<< "Setting refinement level of surface to be consistent" + << " with curvature." << endl; + surfaces.setCurvatureMinLevelFields + ( + refineParams.curvature(), + meshRefiner.meshCutter().level0EdgeLength() + ); + Info<< "Checked curvature refinement in = " + << mesh.time().cpuTimeIncrement() << " s" << nl << endl; + + // Add all the cellZones and faceZones // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/etc/caseDicts/annotated/snappyHexMeshDict b/etc/caseDicts/annotated/snappyHexMeshDict index e4d319f8f090260cfa13f2d3eafd6e0d3a46a0fe..b66214a74eebdc377a28a7b183893ae913bd30ab 100644 --- a/etc/caseDicts/annotated/snappyHexMeshDict +++ b/etc/caseDicts/annotated/snappyHexMeshDict @@ -230,6 +230,21 @@ castellatedMeshControls // outside locations. Default is only after all refinement has // been done. //leakLevel 10; + + // Additional refinement for regions of high curvature. Expressed + // (bit similar to gapLevel) as: + // - number of cells per radius of curvature. (usually 1 is + // good enough) + // - starting cell level? Not used at the moment. + // - maximum cell level. This can be smaller or larger than the + // max 'surface' level + // - minumum curvature radius to ignore (expressed as a cell level). + // This can be used to avoid detecting small sharp surface + // features. Set to -1 to ignore. + // (sometimes you want more refinement than sharp features since + // these can be done with feature edge snapping (so can leave + // level (0 0)) + //curvatureLevel (10 0 10 -1); } } diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H index fb0d7305d048e856699881498d454be29c97d139..2e985707b7b4364291c3fe435e8f36797ef5af9e 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H @@ -471,6 +471,19 @@ private: label& nRefine ) const; + //- Refine cells containing triangles with high refinement level + // (currently due to high curvature or being inside shell with + // high level) + label markSurfaceFieldRefinement + ( + 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 ( @@ -479,6 +492,18 @@ private: const scalar tol = 1e-6 ) const; + //- Detect if two intersection points are high curvature (w.r.t. + // lengthscale + bool highCurvature + ( + const scalar minCosAngle, + const scalar lengthScale, + const point& p0, + const vector& n0, + const point& p1, + const vector& n1 + ) const; + //- Mark cells for surface curvature based refinement. Marks if // local curvature > curvature or if on different regions // (markDifferingRegions) diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementGapRefine.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementGapRefine.C index 01af06203290b3070f2fbcbab8ca253f90d7c5bb..a4e26a976b8e17836cb1074b8d8ee6f699dac797 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementGapRefine.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementGapRefine.C @@ -1833,4 +1833,120 @@ Foam::label Foam::meshRefinement::markSmallFeatureRefinement } +////XXXXXXXX +Foam::label Foam::meshRefinement::markSurfaceFieldRefinement +( + const label nAllowRefine, + const labelList& neiLevel, + const pointField& neiCc, + + labelList& refineCell, + label& nRefine +) const +{ + const labelList& cellLevel = meshCutter_.cellLevel(); + const labelList& surfaceIndices = surfaces_.surfaces(); + + label oldNRefine = nRefine; + + //- Force calculation of tetBasePt + (void)mesh_.tetBasePtIs(); + (void)mesh_.cellTree(); + const indexedOctree<treeDataCell>& tree = 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; + labelList minLevelField; + { + // 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()) + { + FatalErrorInFunction + << "fc:" << ctrs[i] + << " radius:" << radiusSqr[i] + << exit(FatalError); + } + } + + geom.getRegion(info, region); + geom.getField(info, minLevelField); + } + + if (minLevelField.size() != geom.size()) + { + Pout<< "** no minLevelField" << endl; + continue; + } + + + label nOldRefine = 0; + + forAll(ctrs, i) + { + label cellI = -1; + if (tree.nodes().size() && tree.bb().contains(ctrs[i])) + { + cellI = tree.findInside(ctrs[i]); + } + + if + ( + cellI != -1 + && refineCell[cellI] == -1 + && minLevelField[i] > cellLevel[cellI] + ) + { + if + ( + !markForRefine + ( + surfI, + nAllowRefine, + refineCell[cellI], + nRefine + ) + ) + { + break; + } + } + } + + Info<< "For surface " << geom.name() << " found " + << returnReduce(nRefine-nOldRefine, sumOp<label>()) + << " cells containing cached refinement field" << endl; + + if + ( + returnReduce(nRefine, sumOp<label>()) + > returnReduce(nAllowRefine, sumOp<label>()) + ) + { + Info<< "Reached refinement limit." << endl; + } + } + + return returnReduce(nRefine-oldNRefine, sumOp<label>()); +} +////XXXXXXXXX + + // ************************************************************************* // diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C index 2344db2dd90782bd0f22e01369f11f90772ac04b..e1873dca63c2f069e4ef41a4f95aaac059559bb6 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C @@ -1109,6 +1109,71 @@ Foam::label Foam::meshRefinement::countMatches } +//XXXXXX +//bool Foam::meshRefinement::highCurvature +//( +// const scalar minCosAngle, +// const point& p0, +// const vector& n0, +// const point& p1, +// const vector& n1 +//) const +//{ +// return ((n0&n1) < minCosAngle); +//} +bool Foam::meshRefinement::highCurvature +( + const scalar minCosAngle, + const scalar lengthScale, + const point& p0, + const vector& n0, + const point& p1, + const vector& n1 +) const +{ + const scalar cosAngle = (n0&n1); + + if (cosAngle < minCosAngle) + { + // Sharp feature, independent of intersection points + return true; + } + else if (cosAngle > 1-1e-6) + { + // Co-planar + return false; + } + else + { + // Calculate radius of curvature + + vector axis(n0 ^ n1); + const plane pl0(p0, (n0 ^ axis)); + const scalar r1 = pl0.normalIntersect(p1, n1); + + //const point radiusPoint(p1+r1*n1); + //DebugVar(radiusPoint); + const plane pl1(p1, (n1 ^ axis)); + const scalar r0 = pl1.normalIntersect(p0, n0); + + //const point radiusPoint(p0+r0*n0); + //DebugVar(radiusPoint); + //- Take average radius. Bit ad hoc + const scalar radius = 0.5*(mag(r1)+mag(r0)); + + if (radius < lengthScale) + { + return true; + } + else + { + return false; + } + } +} +//XXXXX + + // Mark cells for surface curvature based refinement. Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement ( @@ -1187,9 +1252,12 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement // Test for all intersections (with surfaces of higher max level than // minLevel) and cache per cell the interesting inter labelListList cellSurfLevels(mesh_.nCells()); + List<pointList> cellSurfLocations(mesh_.nCells()); List<vectorList> cellSurfNormals(mesh_.nCells()); { + // Per segment the intersection point of the surfaces + List<pointList> surfaceLocation; // Per segment the normals of the surfaces List<vectorList> surfaceNormal; // Per segment the list of levels of the surfaces @@ -1205,6 +1273,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement labelList(surfaces_.maxLevel().size(), 0), // min level surfaces_.maxLevel(), + surfaceLocation, surfaceNormal, surfaceLevel ); @@ -1216,12 +1285,14 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement labelList visitOrder; forAll(surfaceNormal, pointI) { + pointList& pLocations = surfaceLocation[pointI]; vectorList& pNormals = surfaceNormal[pointI]; labelList& pLevel = surfaceLevel[pointI]; - sortedOrder(pNormals, visitOrder, normalLess(pNormals)); + sortedOrder(pNormals, visitOrder, normalLess(pLocations)); - pNormals = List<point>(pNormals, visitOrder); + pLocations = List<point>(pLocations, visitOrder); + pNormals = List<vector>(pNormals, visitOrder); pLevel = labelUIndList(pLevel, visitOrder); } @@ -1236,6 +1307,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement label faceI = testFaces[i]; label own = mesh_.faceOwner()[faceI]; + const pointList& fPoints = surfaceLocation[i]; const vectorList& fNormals = surfaceNormal[i]; const labelList& fLevels = surfaceLevel[i]; @@ -1244,6 +1316,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement if (fLevels[hitI] > cellLevel[own]) { cellSurfLevels[own].append(fLevels[hitI]); + cellSurfLocations[own].append(fPoints[hitI]); cellSurfNormals[own].append(fNormals[hitI]); } @@ -1253,6 +1326,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement if (fLevels[hitI] > cellLevel[nei]) { cellSurfLevels[nei].append(fLevels[hitI]); + cellSurfLocations[nei].append(fPoints[hitI]); cellSurfNormals[nei].append(fNormals[hitI]); } } @@ -1266,7 +1340,7 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement if (debug) { label nSet = 0; - label nNormals = 9; + label nNormals = 0; forAll(cellSurfNormals, cellI) { const vectorList& normals = cellSurfNormals[cellI]; @@ -1296,21 +1370,38 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement for ( label cellI = 0; - !reachedLimit && cellI < cellSurfNormals.size(); + !reachedLimit && cellI < cellSurfLocations.size(); cellI++ ) { + const pointList& points = cellSurfLocations[cellI]; const vectorList& normals = cellSurfNormals[cellI]; const labelList& levels = cellSurfLevels[cellI]; + // Current cell size + const scalar cellSize = + meshCutter_.level0EdgeLength()/pow(2.0, cellLevel[cellI]); + // n^2 comparison of all normals in a cell for (label i = 0; !reachedLimit && i < normals.size(); i++) { for (label j = i+1; !reachedLimit && j < normals.size(); j++) { - if ((normals[i] & normals[j]) < curvature) + //if ((normals[i] & normals[j]) < curvature) + if + ( + highCurvature + ( + curvature, + cellSize, + points[i], + normals[i], + points[j], + normals[j] + ) + ) { - label maxLevel = max(levels[i], levels[j]); + const label maxLevel = max(levels[i], levels[j]); if (cellLevel[cellI] < maxLevel) { @@ -1358,8 +1449,10 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement label own = mesh_.faceOwner()[faceI]; label nei = mesh_.faceNeighbour()[faceI]; + const pointList& ownPoints = cellSurfLocations[own]; const vectorList& ownNormals = cellSurfNormals[own]; const labelList& ownLevels = cellSurfLevels[own]; + const pointList& neiPoints = cellSurfLocations[nei]; const vectorList& neiNormals = cellSurfNormals[nei]; const labelList& neiLevels = cellSurfLevels[nei]; @@ -1379,13 +1472,30 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement if (!ownIsSubset && !neiIsSubset) { + // Current average cell size. Is min? max? average? + const scalar cellSize = + meshCutter_.level0EdgeLength() + / pow(2.0, min(cellLevel[own], cellLevel[nei])); + // n^2 comparison of between ownNormals and neiNormals for (label i = 0; !reachedLimit && i < ownNormals.size(); i++) { for (label j = 0; !reachedLimit && j < neiNormals.size(); j++) { // Have valid data on both sides. Check curvature. - if ((ownNormals[i] & neiNormals[j]) < curvature) + //if ((ownNormals[i] & neiNormals[j]) < curvature) + if + ( + highCurvature + ( + curvature, + cellSize, + ownPoints[i], + ownNormals[i], + neiPoints[j], + neiNormals[j] + ) + ) { // See which side to refine. if (cellLevel[own] < ownLevels[i]) @@ -1441,7 +1551,11 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement } - // Send over surface normal to neighbour cell. + // Send over surface point/normal to neighbour cell. +// labelListList neiSurfaceLevel; +// syncTools::swapBoundaryCellList(mesh_, cellSurfLevels, neiSurfaceLevel); + List<vectorList> neiSurfacePoints; + syncTools::swapBoundaryCellList(mesh_, cellSurfLocations, neiSurfacePoints); List<vectorList> neiSurfaceNormals; syncTools::swapBoundaryCellList(mesh_, cellSurfNormals, neiSurfaceNormals); @@ -1456,9 +1570,13 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement label own = mesh_.faceOwner()[faceI]; label bFaceI = faceI - mesh_.nInternalFaces(); + const pointList& ownPoints = cellSurfLocations[own]; const vectorList& ownNormals = cellSurfNormals[own]; const labelList& ownLevels = cellSurfLevels[own]; + + const pointList& neiPoints = neiSurfacePoints[bFaceI]; const vectorList& neiNormals = neiSurfaceNormals[bFaceI]; + //const labelList& neiLevels = neiSurfaceLevel[bFacei]; // Special case: owner normals set is a subset of the neighbour // normals. Do not do curvature refinement since other cell's normals @@ -1475,13 +1593,30 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement if (!ownIsSubset && !neiIsSubset) { + // Current average cell size. Is min? max? average? + const scalar cellSize = + meshCutter_.level0EdgeLength() + / pow(2.0, min(cellLevel[own], neiLevel[bFaceI])); + // n^2 comparison of between ownNormals and neiNormals for (label i = 0; !reachedLimit && i < ownNormals.size(); i++) { for (label j = 0; !reachedLimit && j < neiNormals.size(); j++) { // Have valid data on both sides. Check curvature. - if ((ownNormals[i] & neiNormals[j]) < curvature) + //if ((ownNormals[i] & neiNormals[j]) < curvature) + if + ( + highCurvature + ( + curvature, + cellSize, + ownPoints[i], + ownNormals[i], + neiPoints[j], + neiNormals[j] + ) + ) { if (cellLevel[own] < ownLevels[i]) { @@ -2205,25 +2340,46 @@ Foam::labelList Foam::meshRefinement::refineCandidates // Refinement based on features smaller than cell size // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - if - ( - smallFeatureRefinement - && (planarCos >= -1 && planarCos <= 1) - && max(shells_.maxGapLevel()) > 0 - ) + if (smallFeatureRefinement) { - label nGap = markSmallFeatureRefinement + label nGap = 0; + if ( - planarCos, - nAllowRefine, - neiLevel, - neiCc, + planarCos >= -1 + && planarCos <= 1 + && max(shells_.maxGapLevel()) > 0 + ) + { + nGap = markSmallFeatureRefinement + ( + planarCos, + nAllowRefine, + neiLevel, + neiCc, - refineCell, - nRefine - ); + refineCell, + nRefine + ); + } Info<< "Marked for refinement due to close opposite surfaces " << ": " << nGap << " cells." << endl; + + label nCurv = 0; + if (max(surfaces_.maxCurvatureLevel()) > 0) + { + nCurv = markSurfaceFieldRefinement + ( + nAllowRefine, + neiLevel, + neiCc, + + refineCell, + nRefine + ); + Info<< "Marked for refinement" + << " due to curvature " + << ": " << nCurv << " cells." << endl; + } } diff --git a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C index c98a71adab73c46403022d8aadad67a50d584678..1e0de1362dc96dbfac08ab53b26ea22afe5b7aec 100644 --- a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2020 OpenCFD Ltd. + Copyright (C) 2015-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,6 +38,8 @@ License // For dictionary::get wrapper #include "meshRefinement.H" +#include "OBJstream.H" + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::labelList Foam::refinementSurfaces::findHigherLevel @@ -194,15 +196,14 @@ Foam::refinementSurfaces::refinementSurfaces labelList globalMaxLevel(surfI, Zero); labelList globalLevelIncr(surfI, Zero); - FixedList<label, 3> nullGapLevel; - nullGapLevel[0] = 0; - nullGapLevel[1] = 0; - nullGapLevel[2] = 0; - + const FixedList<label, 3> nullGapLevel({0, 0, 0}); List<FixedList<label, 3>> globalGapLevel(surfI); List<volumeType> globalGapMode(surfI); boolList globalGapSelf(surfI); + const FixedList<label, 4> nullCurvLevel({0, 0, 0, -1}); + List<FixedList<label, 4>> globalCurvLevel(surfI); + scalarField globalAngle(surfI, -GREAT); PtrList<dictionary> globalPatchInfo(surfI); @@ -216,6 +217,7 @@ Foam::refinementSurfaces::refinementSurfaces List<Map<FixedList<label, 3>>> regionGapLevel(surfI); List<Map<volumeType>> regionGapMode(surfI); List<Map<bool>> regionGapSelf(surfI); + List<Map<FixedList<label, 4>>> regionCurvLevel(surfI); List<Map<scalar>> regionAngle(surfI); List<Map<autoPtr<dictionary>>> regionPatchInfo(surfI); List<Map<label>> regionBlockLevel(surfI); @@ -307,6 +309,19 @@ Foam::refinementSurfaces::refinementSurfaces globalGapSelf[surfI] = dict.getOrDefault<bool>("gapSelf", true); + globalCurvLevel[surfI] = nullCurvLevel; + if (dict.readIfPresent("curvatureLevel", globalCurvLevel[surfI])) + { + if (globalCurvLevel[surfI][0] <= 0) + { + FatalIOErrorInFunction(dict) + << "Illegal curvatureLevel specification for surface " + << names_[surfI] + << " : curvatureLevel:" << globalCurvLevel[surfI] + << exit(FatalIOError); + } + } + const searchableSurface& surface = allGeometry_[surfaces_[surfI]]; // Surface zones @@ -435,6 +450,20 @@ Foam::refinementSurfaces::refinementSurfaces ) ); + FixedList<label, 4> curvSpec(nullCurvLevel); + if (regionDict.readIfPresent("curvatureLevel", curvSpec)) + { + if (curvSpec[0] <= 0) + { + FatalIOErrorInFunction(dict) + << "Illegal curvatureLevel specification for surface " + << names_[surfI] + << " : curvatureLevel:" << curvSpec + << exit(FatalIOError); + } + } + regionCurvLevel[surfI].insert(regionI, curvSpec); + if (regionDict.found("perpendicularAngle")) { regionAngle[surfI].insert @@ -505,6 +534,8 @@ Foam::refinementSurfaces::refinementSurfaces extendedGapMode_ = volumeType::UNKNOWN; selfProximity_.setSize(nRegions); selfProximity_ = true; + extendedCurvatureLevel_.setSize(nRegions); + extendedCurvatureLevel_ = nullCurvLevel; perpendicularAngle_.setSize(nRegions); perpendicularAngle_ = -GREAT; patchInfo_.setSize(nRegions); @@ -531,6 +562,8 @@ Foam::refinementSurfaces::refinementSurfaces extendedGapLevel_[globalRegionI] = globalGapLevel[surfI]; extendedGapMode_[globalRegionI] = globalGapMode[surfI]; selfProximity_[globalRegionI] = globalGapSelf[surfI]; + extendedCurvatureLevel_[globalRegionI] = + globalCurvLevel[surfI]; perpendicularAngle_[globalRegionI] = globalAngle[surfI]; if (globalPatchInfo.set(surfI)) { @@ -560,6 +593,8 @@ Foam::refinementSurfaces::refinementSurfaces regionGapMode[surfI][iter.key()]; selfProximity_[globalRegionI] = regionGapSelf[surfI][iter.key()]; + extendedCurvatureLevel_[globalRegionI] = + regionCurvLevel[surfI][iter.key()]; } forAllConstIters(regionAngle[surfI], iter) { @@ -713,6 +748,26 @@ Foam::labelList Foam::refinementSurfaces::maxGapLevel() const } +Foam::labelList Foam::refinementSurfaces::maxCurvatureLevel() const +{ + labelList surfaceMax(surfaces_.size(), Zero); + + forAll(surfaces_, surfI) + { + const wordList& regionNames = allGeometry_[surfaces_[surfI]].regions(); + + forAll(regionNames, regionI) + { + label globalI = globalRegion(surfI, regionI); + const FixedList<label, 4>& gapInfo = + extendedCurvatureLevel_[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) @@ -763,13 +818,15 @@ void Foam::refinementSurfaces::setMinLevelFields(const shellSurfaces& shells) // In case of triangulated surfaces only cache value if triangle // centre and vertices are in same shell - if (isA<triSurface>(geom)) + const auto* tsPtr = isA<const triSurface>(geom); + + if (tsPtr) { label nUncached = 0; // Check if points differing from ctr level - const triSurface& ts = refCast<const triSurface>(geom); + const triSurface& ts = *tsPtr; const pointField& points = ts.points(); // Determine minimum expected level to avoid having to @@ -845,6 +902,312 @@ void Foam::refinementSurfaces::setMinLevelFields(const shellSurfaces& shells) } +// Precalculate the refinement level for every element of the searchable +// surface. +void Foam::refinementSurfaces::setCurvatureMinLevelFields +( + const scalar cosAngle, + const scalar level0EdgeLength +) +{ + const labelList maxCurvLevel(maxCurvatureLevel()); + + + forAll(surfaces_, surfI) + { + // Check if there is a specification of the extended curvature + if (maxCurvLevel[surfI] <= 0) + { + continue; + } + + const searchableSurface& geom = allGeometry_[surfaces_[surfI]]; + + const auto* tsPtr = isA<const triSurface>(geom); + + // Cache the refinement level (max of surface level and shell level) + // on a per-element basis. Only makes sense if there are lots of + // elements. Possibly should have 'enough' elements to have fine + // enough resolution but for now just make sure we don't catch e.g. + // searchableBox (size=6) + if (tsPtr) + { + // Representative local coordinates and bounding sphere + pointField ctrs; + scalarField radiusSqr; + geom.boundingSpheres(ctrs, radiusSqr); + + labelList minLevelField(ctrs.size(), Zero); + //labelList surfMin(ctrs.size(), Zero); + labelList surfMax(ctrs.size(), Zero); + labelList nCurvCells(ctrs.size(), Zero); + labelList curvIgnore(ctrs.size(), -1); + { + // 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) + List<pointIndexHit> info; + geom.findNearest(ctrs, radiusSqr, info); + + // Get per element the region + labelList region; + geom.getRegion(info, region); + + // See if a cached level field available (from e.g. shells) + labelList cachedField; + geom.getField(info, cachedField); + + // From the region get the surface-wise refinement level + forAll(minLevelField, i) + { + if (info[i].hit()) //Note: should not be necessary + { + const label globali = globalRegion(surfI, region[i]); + curvIgnore[i] = extendedCurvatureLevel_[globali][3]; + nCurvCells[i] = extendedCurvatureLevel_[globali][0]; + //surfMin[i] = extendedCurvatureLevel_[globali][1]; + surfMax[i] = extendedCurvatureLevel_[globali][2]; + + minLevelField[i] = minLevel(surfI, region[i]); + if (cachedField.size() > i) + { + minLevelField[i] = + max(minLevelField[i], cachedField[i]); + } + } + } + } + + // Calculate per-triangle curvature. This is the max of the + // measured point-based curvature + some constraints. + scalarField cellCurv(ctrs.size(), Zero); + { + // Walk surface and detect sharp features. Returns maximum + // curvature (per surface point. Note: returns per point, not + // per localpoint) + const auto& ts = *tsPtr; + auto tcurv(triSurfaceTools::curvatures(ts)); + auto& curv = tcurv.ref(); + + // Reset curvature on sharp edges (and neighbours since + // curvature uses extended stencil) + { + const auto& edgeFaces = ts.edgeFaces(); + const auto& edges = ts.edges(); + const auto& points = ts.points(); + const auto& mp = ts.meshPoints(); + + bitSet isOnSharpEdge(points.size()); + forAll(edgeFaces, edgei) + { + const auto& eFaces = edgeFaces[edgei]; + const edge meshE(mp, edges[edgei]); + + if (eFaces.size() == 2) + { + const auto& f0 = ts[eFaces[0]]; + const auto& f1 = ts[eFaces[1]]; + + const vector n0 = f0.unitNormal(points); + + const int dir0 = f0.edgeDirection(meshE); + const int dir1 = f1.edgeDirection(meshE); + vector n1 = f1.unitNormal(points); + if (dir0 == dir1) + { + // Flip since use edge in same direction + // (should not be the case for 'proper' + // surfaces) + n1 = -n1; + } + + if ((n0&n1) < cosAngle) + { + isOnSharpEdge.set(meshE[0]); + isOnSharpEdge.set(meshE[1]); + } + } + } + + // Extend by one layer + { + bitSet oldOnSharpEdge(isOnSharpEdge); + isOnSharpEdge = false; + for (const auto& f : ts) + { + for (const label pointi : f) + { + if (oldOnSharpEdge[pointi]) + { + // Mark all points on triangle + isOnSharpEdge.set(f); + break; + } + } + } + } + + + // Unmark curvature + autoPtr<OBJstream> str; + //if (debug) + //{ + // str.reset + // ( + // new OBJstream + // ( + // "sharpEdgePoints_" + // + geom.name() + // + ".obj" + // ) + // ); + // Info<< "Writing sharp edge points to " + // << str().name() << endl; + //} + + for (const label pointi : isOnSharpEdge) + { + // Reset measured point-based curvature + curv[pointi] = 0.0; + if (str) + { + str().write(points[pointi]); + } + } + } + + // Reset curvature on -almost- sharp edges. + // This resets the point-based curvature if the edge + // is considered to be a sharp edge based on its actual + // curvature. This is only used if the 'ignore' level is + // given. + { + // Pass 1: accumulate constraints on the points - get + // the minimum of curvature constraints on the + // connected triangles. Looks at user-specified + // min curvature - does not use actual measured + // curvature + scalarField pointMinCurv(ts.nPoints(), VGREAT); + + forAll(ts, i) + { + // Is ignore level given for surface + const label level = curvIgnore[i]; + if (level >= 0) + { + // Convert to (inv) size + const scalar length = level0EdgeLength/(2<<level); + const scalar invLength = 1.0/length; + for (const label pointi : ts[i]) + { + if + ( + invLength < pointMinCurv[pointi] + && curv[pointi] > SMALL + ) + { + //Pout<< "** at location:" + // << ts.points()[pointi] + // << " measured curv:" << curv[pointi] + // << " radius:" << 1.0/curv[pointi] + // << " ignore level:" << level + // << " ignore radius:" << length + // << " resetting minCurv to " + // << invLength + // << endl; + } + + pointMinCurv[pointi] = + min(pointMinCurv[pointi], invLength); + } + } + } + + // Clip curvature (should do nothing for most points unless + // ignore-level is triggered) + forAll(pointMinCurv, pointi) + { + if (pointMinCurv[pointi] < curv[pointi]) + { + //Pout<< "** at location:" << ts.points()[pointi] + // << " measured curv:" << curv[pointi] + // << " radius:" << 1.0/curv[pointi] + // << " cellLimit:" << pointMinCurv[pointi] + // << endl; + + // Set up to ignore point + //curv[pointi] = pointMinCurv[pointi]; + curv[pointi] = 0.0; + } + } + } + + + forAll(ts, i) + { + const auto& f = ts[i]; + // Take max curvature (= min radius of curvature) + cellCurv[i] = max(curv[f[0]], max(curv[f[1]], curv[f[2]])); + } + } + + + //if(debug) + //{ + // const scalar maxCurv = gMax(cellCurv); + // if (maxCurv > SMALL) + // { + // const scalar r = scalar(1.0)/maxCurv; + // + // Pout<< "For geometry " << geom.name() + // << " have curvature max " << maxCurv + // << " which equates to radius:" << r + // << " which equates to refinement level " + // << log2(level0EdgeLength/r) + // << endl; + // } + //} + + forAll(cellCurv, i) + { + if (cellCurv[i] > SMALL && nCurvCells[i] > 0) + { + //- ?If locally have a cached field override the + // surface-based level ignore any curvature? + //if (minLevelField[i] > surfMin[i]) + //{ + // // Ignore curvature + //} + //else + //if (surfMin[i] == surfMax[i]) + //{ + // // Ignore curvature. Bypass calculation below. + //} + //else + { + // Re-work the curvature into a radius and into a + // number of cells + const scalar r = scalar(1.0)/cellCurv[i]; + const scalar level = + log2(nCurvCells[i]*level0EdgeLength/r); + const label l = round(level); + + if (l > minLevelField[i] && l <= surfMax[i]) + { + minLevelField[i] = l; + } + } + } + } + + + // Store minLevelField on surface + const_cast<searchableSurface&>(geom).setField(minLevelField); + } + } +} + + // Find intersections of edge. Return -1 or first surface with higher minLevel // number. void Foam::refinementSurfaces::findHigherIntersection diff --git a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H index 16d8582c09111c92a00c539a55ab3623527dcb57..2c4ff38380ff71dde8ad1ab0db1d52d287e607bd 100644 --- a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H @@ -110,6 +110,9 @@ class refinementSurfaces // (in gap refinement) boolList selfProximity_; + //- From global region number to curvature specification + List<FixedList<label, 4>> extendedCurvatureLevel_; + //- From global region number to perpendicular angle scalarField perpendicularAngle_; @@ -263,6 +266,19 @@ public: return selfProximity_; } + //- From global region number to specification of curvature + // refinement: 4 labels specifying + // - minimum wanted number of cells in the curvature radius + // - ?minimum cell level when to start trying to detect gaps + // - maximum cell level to refine to (so do not detect curvature if + // celllevel >= maximum level) + // - minimum radius to ignore (expressed as refinement level). + // This can be used to ignore feature-edges. Set to -1 to ignore. + const List<FixedList<label, 4>>& extendedCurvatureLevel() const + { + return extendedCurvatureLevel_; + } + //- From global region number to perpendicular angle const scalarField& perpendicularAngle() const { @@ -307,12 +323,23 @@ public: //- Per surface the maximum extendedGapLevel over all its regions labelList maxGapLevel() const; - //- Calculate minLevelFields + //- Per surface the maximum curvatureLevel over all its regions + labelList maxCurvatureLevel() const; + + //- Calculate minLevelFields according to both surface- and + // shell-based levels void setMinLevelFields ( const shellSurfaces& shells ); + //- Update minLevelFields according to (triSurface-only) curvature + void setCurvatureMinLevelFields + ( + const scalar cosAngle, + const scalar level0EdgeLength + ); + ////- Helper: count number of triangles per region //static labelList countRegions(const triSurface&); diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C index 5b336ed18fc9b9caa8d94e8370a44a8c7c9fc5c4..7fc5cccc86950aeeb39e905c0587eea09abf8530 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C @@ -230,10 +230,16 @@ Foam::label Foam::snappyRefineDriver::smallFeatureRefine label iter = 0; // See if any surface has an extendedGapLevel - labelList surfaceMaxLevel(meshRefiner_.surfaces().maxGapLevel()); - labelList shellMaxLevel(meshRefiner_.shells().maxGapLevel()); + const labelList surfaceMaxLevel(meshRefiner_.surfaces().maxGapLevel()); + const labelList shellMaxLevel(meshRefiner_.shells().maxGapLevel()); + const labelList curvMaxLevel(meshRefiner_.surfaces().maxCurvatureLevel()); - if (max(surfaceMaxLevel) == 0 && max(shellMaxLevel) == 0) + if + ( + max(surfaceMaxLevel) == 0 + && max(shellMaxLevel) == 0 + && max(curvMaxLevel) == 0 + ) { return iter; } @@ -3382,6 +3388,7 @@ void Foam::snappyRefineDriver::doRefine ( max(meshRefiner_.surfaces().maxGapLevel()) > 0 || max(meshRefiner_.shells().maxGapLevel()) > 0 + || max(meshRefiner_.surfaces().maxCurvatureLevel()) > 0 ) { // In case we use automatic gap level refinement do some pre-refinement diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/Allclean b/tutorials/mesh/snappyHexMesh/block_with_curvature/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..21a3ef143cef22ef26bb903f23d8ae89c6b63f23 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/Allclean @@ -0,0 +1,12 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase0 + +# Remove surface and features +rm -rf constant/triSurface +rm -rf constant/extendedFeatureEdgeMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/Allrun b/tutorials/mesh/snappyHexMesh/block_with_curvature/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..02e4d82318f03445668c51f3412c5829027a5049 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/Allrun @@ -0,0 +1,18 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +mkdir -p constant/triSurface + +cp -f \ + resources/geometry/curvature-box.stl.gz \ + constant/triSurface + +runApplication surfaceFeatureExtract + +runApplication blockMesh + +runApplication snappyHexMesh -overwrite + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/README.txt b/tutorials/mesh/snappyHexMesh/block_with_curvature/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a02065b59b69b1129f2b544bb381ef4419f792d --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/README.txt @@ -0,0 +1,6 @@ +testcase to demonstrate surface-curvature-based refinement. +- starts from a single cell +- has uniform surface refinement 0 +- but has curvature detection to refine up to 10 +- also uses limitRegions to not refine half the domain (in x direction) +- note that there is still refinement bleeding due to the 2:1 limitation diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/resources/geometry/curvature-box.stl.gz b/tutorials/mesh/snappyHexMesh/block_with_curvature/resources/geometry/curvature-box.stl.gz new file mode 100644 index 0000000000000000000000000000000000000000..925f4bdeafd4ef95ce447890ba3ed2917e111ba1 Binary files /dev/null and b/tutorials/mesh/snappyHexMesh/block_with_curvature/resources/geometry/curvature-box.stl.gz differ diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/blockMeshDict b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..388d4d4238147e15835219ae1dd59d55b904006c --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/blockMeshDict @@ -0,0 +1,58 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + ( 0 -0.2 0) + ( 0.5 -0.2 0) + ( 0.5 0.3 0) + ( 0 0.3 0) + ( 0 -0.2 0.5) + ( 0.5 -0.2 0.5) + ( 0.5 0.3 0.5) + ( 0 0.3 0.5) +); + +blocks +( +// hex (0 1 2 3 4 5 6 7) (15 10 10) simpleGrading (1 1 1) + hex (0 1 2 3 4 5 6 7) (1 1 1) simpleGrading (1 1 1) +); + +edges +(); + +boundary +( + allBoundary + { + type patch; + faces + ( + (3 7 6 2) + (1 5 4 0) //back + (2 6 5 1) //outlet + (0 4 7 3) //inlet + (0 3 2 1) //lowerWall + (4 5 6 7) //upperWall + ); + } +); + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/controlDict b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..48f8127e1420007edf96534086ed3fed8803b3b4 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/controlDict @@ -0,0 +1,55 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//DebugSwitches +//{ +// fvGeometryScheme 1; +// highAspectRatio 1; +// basic 1; +//} + +application simpleFoam; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 15000; + +deltaT 1; + +writeControl timeStep; + +writeInterval 5000; + +purgeWrite 2; + +writeFormat binary; + +writePrecision 15; + +writeCompression off; + +timeFormat general; + +timePrecision 8; + +runTimeModifiable false; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSchemes b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..bd9bab5f29374ddbe4972f1d34faf17a87da000d --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSchemes @@ -0,0 +1,53 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{ +} + +gradSchemes +{ +} + +divSchemes +{ +} + +laplacianSchemes +{ +} + +interpolationSchemes +{ +} + +snGradSchemes +{ +} + +wallDist +{ +} + +geometry +{ + type highAspectRatio; + minAspect 10; + maxAspect 100; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSolution b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..3316c1cc7442e77827d4046b830134e5ca339662 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/fvSolution @@ -0,0 +1,22 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/meshQualityDict b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/meshQualityDict new file mode 100644 index 0000000000000000000000000000000000000000..e06a30787985a7a65430be05e2fb0fb45018ac5c --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/meshQualityDict @@ -0,0 +1,78 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object meshQualityDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- Maximum non-orthogonality allowed. Set to 180 to disable. +maxNonOrtho 65; + +//- Max skewness allowed. Set to <0 to disable. +maxBoundarySkewness 20; +maxInternalSkewness 4; + +//- Max concaveness allowed. Is angle (in degrees) below which concavity +// is allowed. 0 is straight face, <0 would be convex face. +// Set to 180 to disable. +maxConcave 80; + +//- Minimum pyramid volume. Is absolute volume of cell pyramid. +// Set to a sensible fraction of the smallest cell volume expected. +// Set to very negative number (e.g. -1E30) to disable. +minVol 1e-13; + +//- Minimum quality of the tet formed by the face-centre +// and variable base point minimum decomposition triangles and +// the cell centre. Set to very negative number (e.g. -1E30) to +// disable. +// <0 = inside out tet, +// 0 = flat tet +// 1 = regular tet +minTetQuality 1e-15; + +//- Minimum face area. Set to <0 to disable. +minArea -1; + +//- Minimum face twist. Set to <-1 to disable. dot product of face normal +// (itself the average of the triangle normals) +// and face centre triangles normal +minTwist 0.02; + +//- Minimum normalised cell determinant. This is the determinant of all +// the areas of internal faces. It is a measure of how much of the +// outside area of the cell is to other cells. The idea is that if all +// outside faces of the cell are 'floating' (zeroGradient) the +// 'fixedness' of the cell is determined by the area of the internal faces. +// 1 = hex, <= 0 = folded or flattened illegal cell +minDeterminant 0.001; + +//- Relative position of face in relation to cell centres (0.5 for orthogonal +// mesh) (0 -> 0.5) +minFaceWeight 0.05; + +//- Volume ratio of neighbouring cells (0 -> 1) +minVolRatio 0.01; + +//- Per triangle normal compared to that of preceding triangle. Must be >0 +// for Fluent compatibility +minTriangleTwist -1; + + +//- If >0 : preserve cells with all points on the surface if the +// resulting volume after snapping (by approximation) is larger than +// minVolCollapseRatio times old volume (i.e. not collapsed to flat cell). +// If <0 : delete always. +//minVolCollapseRatio 0.1; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..b1f8b166e05023eea6b82a51c0745f5ca6215522 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict @@ -0,0 +1,587 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object snappyHexMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Which of the steps to run +castellatedMesh true; +snap false; +addLayers false; + + +// Optional: single region surfaces get patch names according to +// surface only. Multi-region surfaces get patch name +// surface "_ "region. Default is true +// singleRegionName false; + +// Optional: avoid patch-face merging. Allows mesh to be used for +// refinement/unrefinement +// mergePatchFaces false; // default true + +// Optional: preserve all generated patches. Default is to remove +// zero-sized patches. +// keepPatches true; + + +// Geometry. Definition of all surfaces. All surfaces are of class +// searchableSurface. +// Surfaces are used +// - to specify refinement for any mesh cell intersecting it +// - to specify refinement for any mesh cell inside/outside/near +// - to 'snap' the mesh boundary to the surface +geometry +{ + box_limit + { + type box; + min (-1000 -1000 -1000); + max (0.125 1000 1000); + } + cylinder_all + { + //- Radius 0.1m + type triSurfaceMesh; + file curvature-box.stl; + } +}; + + +// Settings for the castellatedMesh generation. +castellatedMeshControls +{ + + // Refinement parameters + // ~~~~~~~~~~~~~~~~~~~~~ + + // If local number of cells is >= maxLocalCells on any processor + // switches from from refinement followed by balancing + // (current method) to (weighted) balancing before refinement. + maxLocalCells 1000000; + + // Overall cell limit (approximately). Refinement will stop immediately + // upon reaching this number so a refinement level might not complete. + // Note that this is the number of cells before removing the part which + // is not 'visible' from the keepPoint. The final number of cells might + // actually be a lot less. + maxGlobalCells 20000000; + + // The surface refinement loop might spend lots of iterations refining just + // a few cells. This setting will cause refinement to stop if + // <= minRefinementCells cells are selected for refinement. Note: it will + // at least do one iteration unless + // a: the number of cells to refine is 0 + // b: minRefinementCells = -1. This is a special value indicating + // no refinement. + minRefinementCells 0; + + // Allow a certain level of imbalance during refining + // (since balancing is quite expensive) + // Expressed as fraction of perfect balance (= overall number of cells / + // nProcs). 0=balance always. + maxLoadUnbalance 0.10; + + // Number of buffer layers between different levels. + // 1 means normal 2:1 refinement restriction, larger means slower + // refinement. + nCellsBetweenLevels 4; + + + // Explicit feature edge refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies a level for any cell intersected by explicitly provided + // edges. + // This is a featureEdgeMesh, read from constant/triSurface for now. + // Specify 'levels' in the same way as the 'distance' mode in the + // refinementRegions (see below). The old specification + // level 2; + // is equivalent to + // levels ((0 2)); + + features + ( + ); + + + // Surface based refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies two levels for every surface. The first is the minimum level, + // every cell intersecting a surface gets refined up to the minimum level. + // The second level is the maximum level. Cells that 'see' multiple + // intersections where the intersections make an + // angle > resolveFeatureAngle get refined up to the maximum level. + + refinementSurfaces + { + cylinder_all + { + // Surface-wise min and max refinement level. max level is only used + // for sharp angles (see 'resolveFeatureAngle') + level (0 0); + + // Additional refinement for regions of high curvature. Expressed + // (bit similar to gapLevel) as: + // - number of cells per radius of curvature. (usually 1 is + // good enough) + // - starting cell level? Not used at the moment. + // - maximum cell level. This can be smaller or larger than the + // max 'surface' level + // - minumum curvature radius to ignore (expressed as a cell level). + // This can be used to avoid detecting small sharp surface + // features. Set to -1 to ignore. + // + // Sometimes you want more refinement than sharp features since + // these can be done with feature edge snapping (so can leave + // 'level (0 0)') + curvatureLevel (10 0 10 -1); + + // To trigger small feature refinement + //gapLevel (1 0 1); + } + } + + // Feature angle: + // - used if min and max refinement level of a surface differ + // - used if feature snapping (see snapControls below) is used + resolveFeatureAngle 45; + + + // Region-wise refinement + // ~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies refinement level for cells in relation to a surface. One of + // three modes + // - distance. 'levels' specifies per distance to the surface the + // wanted refinement level. The distances need to be specified in + // increasing order. + // - inside. 'levels' is only one entry and only the level is used. All + // cells inside the surface get refined up to the level. The surface + // needs to be closed for this to be possible. + // - outside. Same but cells outside. + + refinementRegions + { + } + + + + // Optionally limit refinement in geometric region. This limits all + // refinement (from features, refinementSurfaces, refinementRegions) + // in a given geometric region. The syntax is exactly the same as for the + // refinementRegions; the cell level now specifies the upper limit + // for any cell. (a special setting is cell level -1 which will remove + // any cells inside the region). Note that it does not override the + // refinement constraints given by the nCellsBetweenLevels setting. + limitRegions + { + box_limit + { + mode inside; + + // Don't refine at all inside 'box_limit' + levels ((10000 0)); + } + } + + + // Mesh selection + // ~~~~~~~~~~~~~~ + + // After refinement patches get added for all refinementSurfaces and + // all cells intersecting the surfaces get put into these patches. The + // section reachable from the location(s)InMesh is kept. + // NOTE: This point should never be on a face, always inside a cell, even + // after refinement. + // + // There are two different ways of specifying the regions to keep: + // 1. a single locationInMesh. This is the unzoned part of the mesh. + // All the 'zoned' surfaces are marked as such + // in the refinementSurfaces with the faceZone and cellZone keywords. + // It is illegal to have the locationInMesh inside a surface for which + // a cellZone is specified. + // + // or + // + // 2. multiple locationsInMesh, with per location the name of the cellZone. + // This uses walking to determine zones and automatically creates + // faceZones on the outside of cellZones. The special name 'none' is + // used to indicate the unzoned/background part of the mesh. + + + // Ad 1. Specify a single location and how to treat faces inbetween + // cellZones + locationInMesh (0.101 0.101 0.101); + + // Whether any faceZones (as specified in the refinementSurfaces) + // are only on the boundary of corresponding cellZones. + // Not used if there are no faceZones. The behaviour has changed + // with respect to previous versions: + // true : all intersections with surface are put in faceZone + // (same behaviour as before) + // false : depending on the type of surface intersected: + // - if intersecting surface has faceZone only (so no cellZone) + // leave in faceZone (so behave as if set to true) (= changed + // behaviour) + // - if intersecting surface has faceZone and cellZone + // remove if inbetween same cellZone or if on boundary + // (same behaviour as before) + allowFreeStandingZoneFaces true; + + + + // 2. Specify multiple locations with optional cellZones for the + // regions (use cellZone "none" to specify the unzoned cells) + // FaceZones are automatically constructed from the + // names of the cellZones: <cellZoneA> _to_ <cellZoneB> + // where the cellZoneA is the lowest numbered cellZone (non-cellZone + // cells are in a special region called "none" which is always + // last). + + + + + // Optional locations that should not be reachable from + // location(s)InMesh +// locationsOutsideMesh ((100 100 100)); + + // Optional: do not remove cells likely to give snapping problems + // handleSnapProblems false; + + // Optional: switch off topological test for cells to-be-squashed + // and use geometric test instead + //useTopologicalSnapDetection false; + + // Optional: do not refine surface cells with opposite faces of + // differing refinement levels + //interfaceRefine false; + + // Optional: use an erosion instead of region assignment to allocate + // left-over cells to the background region (i.e. make cellZones + // consistent with the intersections of the surface). + // Erosion is specified as a number of erosion iterations. + // Erosion has less chance of bleeding and changing the zone + // for a complete region. + //nCellZoneErodeIter 2; +} + +// Settings for the snapping. +snapControls +{ + // Number of patch smoothing iterations before finding correspondence + // to surface + nSmoothPatch 3; + + // Optional: number of smoothing iterations for internal points on + // refinement interfaces. This will reduce non-orthogonality on + // refinement interfaces. + //nSmoothInternal $nSmoothPatch; + + // Maximum relative distance for points to be attracted by surface. + // True distance is this factor times local maximum edge length. + tolerance 1.0; + + // Number of mesh displacement relaxation iterations. + nSolveIter 30; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // (wip) disable snapping to opposite near surfaces (revert to 22x + // behaviour) + // detectNearSurfacesSnap false; + + + // Feature snapping + + // Number of feature edge snapping iterations. + // Leave out altogether to disable. + nFeatureSnapIter 10; + + // Detect (geometric only) features by sampling the surface + // (default=false). + implicitFeatureSnap false; + + // Use castellatedMeshControls::features (default = true) + explicitFeatureSnap true; + + // Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap false; + + + //- When to run face splitting (never at first iteration, always + // at last iteration). Is interval. Default -1 (disabled) + //nFaceSplitInterval 5; + + + // (wip) Optional for explicit feature snapping: + //- Detect baffle edges. Default is true. + //detectBaffles false; + //- On any faces where points are on multiple regions (see + // multiRegionFeatureSnap) have the other points follow these points + // instead of having their own independent movement, i.e. have snapping + // to multi-region edges/points take priority. This might aid snapping + // to sharp edges that are also region edges. The default is false. + //releasePoints true; + //- Walk along feature edges, adding missing ones. Default is true. + //stringFeatures false; + //- If diagonal attraction also attract other face points. Default is + // false + //avoidDiagonal true; + //- When splitting what concave faces to leave intact. Default is 45 + // degrees. + //concaveAngle 30; + //- When splitting the minimum area ratio of faces. If face split + // causes ratio of area less than this do not split. Default is 0.3 + //minAreaRatio 0.3; + //- Attract points only to the surface they originate from. Default + // false. This can improve snapping of intersecting surfaces. + strictRegionSnap true; +} + +// Settings for the layer addition. +addLayersControls +{ + // Are the thickness parameters below relative to the undistorted + // size of the refined cell outside layer (true) or absolute sizes (false). + relativeSizes true; + + // Layer thickness specification. This can be specified in one of following + // ways: + // - expansionRatio and finalLayerThickness (cell nearest internal mesh) + // - expansionRatio and firstLayerThickness (cell on surface) + // - overall thickness and firstLayerThickness + // - overall thickness and finalLayerThickness + // - overall thickness and expansionRatio + // + // Note: the mode thus selected is global, i.e. one cannot override the + // mode on a per-patch basis (only the values can be overridden) + + // Expansion factor for layer mesh + expansionRatio 1.5; + + // Wanted thickness of the layer furthest away from the wall. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + finalLayerThickness 0.3; + + // Wanted thickness of the layer next to the wall. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + //firstLayerThickness 0.3; + + // Wanted overall thickness of layers. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + //thickness 0.5 + + + // Minimum overall thickness of total layers. If for any reason layer + // cannot be above minThickness do not add layer. + // If relativeSizes this is relative to undistorted size of cell + // outside layer.. + minThickness 0.1; + + + // Per final patch or faceZone (so not geometry!) the layer information + // Note: This behaviour changed after 21x. Any non-mentioned patches + // now slide unless: + // - nSurfaceLayers is explicitly mentioned to be 0. + // - angle to nearest surface < slipFeatureAngle (see below) + layers + { + "internalFace.*" {nSurfaceLayers 20; } + aerofoil + { + nSurfaceLayers 20; + } + } + + // If points get not extruded do nGrow layers of connected faces that are + // also not grown. This helps convergence of the layer addition process + // close to features. + // Note: changed(corrected) w.r.t 1.7.x! (didn't do anything in 1.7.x) + nGrow -1; + + // Advanced settings + + + // Static analysis of starting mesh + + // When not to extrude surface. 0 is flat surface, 90 is when two faces + // are perpendicular. Note: was not working correctly < 1806 + featureAngle 180; + + // When to merge patch faces. Default is featureAngle. Useful when + // featureAngle is large. + //mergePatchFacesAngle 45; + + // Stop layer growth on highly warped cells + maxFaceThicknessRatio 1000;//0.5; + + + // Patch displacement + + // Number of smoothing iterations of surface normals + nSmoothSurfaceNormals 1; + + // Smooth layer thickness over surface patches + nSmoothThickness 10; + + + + // Choice of mesh shrinking algorithm + + // Optional mesh shrinking algorithm (default is displacementMedialAxis) + // The displacementMotionSolver is a wrapper around the displacement + // motion solvers. It needs specification of the solver to use and + // its control dictionary. + //meshShrinker displacementMotionSolver; + //solver displacementLaplacian; + //displacementLaplacianCoeffs + //{ + // diffusivity quadratic inverseDistance + // ( + // sphere.stl_firstSolid + // maxY + // ); + //} + // Note that e.g. displacementLaplacian needs entries in + // fvSchemes, fvSolution. Also specify a minIter > 1 when solving + // cellDisplacement since otherwise solution might not be sufficiently + // accurate on points. + + + // Medial axis analysis (for use with default displacementMedialAxis) + + // Angle used to pick up medial axis points + // Note: changed(corrected) w.r.t 1.7.x! 90 degrees corresponds to 130 + // in 1.7.x. + minMedialAxisAngle 90; + + // Reduce layer growth where ratio thickness to medial + // distance is large + maxThicknessToMedialRatio 0.3; + + // Number of smoothing iterations of interior mesh movement direction + nSmoothNormals 3; + + // Optional: limit the number of steps walking away from the surface. + // Default is unlimited. + //nMedialAxisIter 10; + + // Optional: smooth displacement after medial axis determination. + // default is 0. + //nSmoothDisplacement 90; + + // (wip)Optional: do not extrude any point where + // (false) : all surrounding faces are not fully extruded + // (true) : all surrounding points are not extruded + // Default is false. + //detectExtrusionIsland true; + + // Optional: do not extrude around sharp edges if both faces are not + // fully extruded i.e. if one of the faces on either side would + // become a wedge. + // Default is 0.5*featureAngle. Set to -180 always attempt extrusion + //layerTerminationAngle 25; + + // Optional: disable shrinking of edges that have one (or two) points + // on an extruded patch. + // Default is false to enable single/two cell thick channels to still + // have layers. In <=1806 this was true by default. On larger gaps it + // should have no effect. + //disableWallEdges true; + + // Optional: at non-patched sides allow mesh to slip if extrusion + // direction makes angle larger than slipFeatureAngle. Default is + // 0.5*featureAngle. + slipFeatureAngle 10; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + + // Mesh shrinking + + // Create buffer region for new layer terminations, i.e. gradually + // step down number of layers. Set to <0 to terminate layer in one go. + nBufferCellsNoExtrude 0; + + // Overall max number of layer addition iterations. The mesher will + // exit if it reaches this number of iterations; possibly with an + // illegal mesh. + nLayerIter 50; + + // Max number of iterations after which relaxed meshQuality controls + // get used. Up to nRelaxedIter it uses the settings in + // meshQualityControls, + // after nRelaxedIter it uses the values in + // meshQualityControls::relaxed. + nRelaxedIter 0; + + // Additional reporting: if there are just a few faces where there + // are mesh errors (after adding the layers) print their face centres. + // This helps in tracking down problematic mesh areas. + //additionalReporting true; +} + +// Generic mesh quality settings. At any undoable phase these determine +// where to undo. +meshQualityControls +{ + // Specify mesh quality constraints in separate dictionary so can + // be reused (e.g. checkMesh -meshQuality) + #include "meshQualityDict" + + minDeterminant 1e-8; + + // Optional : some meshing phases allow usage of relaxed rules. + // See e.g. addLayersControls::nRelaxedIter. + relaxed + { + // Maximum non-orthogonality allowed. Set to 180 to disable. + maxNonOrtho 75; + minTetQuality -1e30; + minTwist -1; + } + + + // Advanced + + // Number of error distribution iterations + nSmoothScale 4; + // amount to scale back displacement at error points + errorReduction 0.75; +} + + +// Debug flags +//debugFlags +//( +// mesh // write intermediate meshes +//); + + +//// Format for writing lines. E.g. leak path. Default is vtk format. +//setFormat ensight; + +// Merge tolerance. Is fraction of overall bounding box of initial mesh. +// Note: the write tolerance needs to be higher than this. +mergeTolerance 1e-6; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict.orig b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict.orig new file mode 100644 index 0000000000000000000000000000000000000000..727fc6b77d31a27ccb596c2ab4f1470fafc5dc1f --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/snappyHexMeshDict.orig @@ -0,0 +1,622 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object snappyHexMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Which of the steps to run +castellatedMesh true; +snap false; +addLayers false; + + +// Optional: single region surfaces get patch names according to +// surface only. Multi-region surfaces get patch name +// surface "_ "region. Default is true +// singleRegionName false; + +// Optional: avoid patch-face merging. Allows mesh to be used for +// refinement/unrefinement +// mergePatchFaces false; // default true + +// Optional: preserve all generated patches. Default is to remove +// zero-sized patches. +// keepPatches true; + + +// Geometry. Definition of all surfaces. All surfaces are of class +// searchableSurface. +// Surfaces are used +// - to specify refinement for any mesh cell intersecting it +// - to specify refinement for any mesh cell inside/outside/near +// - to 'snap' the mesh boundary to the surface +geometry +{ + all + { + type box; + min (-1000 -1000 -1000); + max (1000 1000 1000); + } + cylinder_all + { + //- Radius 0.1m + type triSurfaceMesh; + file curvature-box.stl; + } +}; + + +// Settings for the castellatedMesh generation. +castellatedMeshControls +{ + + // Refinement parameters + // ~~~~~~~~~~~~~~~~~~~~~ + + // If local number of cells is >= maxLocalCells on any processor + // switches from from refinement followed by balancing + // (current method) to (weighted) balancing before refinement. + maxLocalCells 1000000; + + // Overall cell limit (approximately). Refinement will stop immediately + // upon reaching this number so a refinement level might not complete. + // Note that this is the number of cells before removing the part which + // is not 'visible' from the keepPoint. The final number of cells might + // actually be a lot less. + maxGlobalCells 20000000; + + // The surface refinement loop might spend lots of iterations refining just + // a few cells. This setting will cause refinement to stop if + // <= minRefinementCells cells are selected for refinement. Note: it will + // at least do one iteration unless + // a: the number of cells to refine is 0 + // b: minRefinementCells = -1. This is a special value indicating + // no refinement. + minRefinementCells 0; + + // Allow a certain level of imbalance during refining + // (since balancing is quite expensive) + // Expressed as fraction of perfect balance (= overall number of cells / + // nProcs). 0=balance always. + maxLoadUnbalance 0.10; + + // Number of buffer layers between different levels. + // 1 means normal 2:1 refinement restriction, larger means slower + // refinement. + nCellsBetweenLevels 4; + + + // Explicit feature edge refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies a level for any cell intersected by explicitly provided + // edges. + // This is a featureEdgeMesh, read from constant/triSurface for now. + // Specify 'levels' in the same way as the 'distance' mode in the + // refinementRegions (see below). The old specification + // level 2; + // is equivalent to + // levels ((0 2)); + + features + ( + ); + + + // Surface based refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies two levels for every surface. The first is the minimum level, + // every cell intersecting a surface gets refined up to the minimum level. + // The second level is the maximum level. Cells that 'see' multiple + // intersections where the intersections make an + // angle > resolveFeatureAngle get refined up to the maximum level. + + refinementSurfaces + { + cylinder_all + { + // Surface-wise min and max refinement level. max level is only used + // for sharp angles (see 'resolveFeatureAngle') + level (0 0); + + // Additional refinement for regions of high curvature. Expressed + // (bit similar to gapLevel) as: + // - number of cells per radius of curvature. (usually 1 is + // good enough) + // - starting cell level? Not used at the moment. + // - maximum cell level. This can be smaller or larger than the + // max 'surface' level + // - minumum curvature radius to ignore (expressed as a cell level). + // This can be used to avoid detecting small sharp surface + // features. Set to -1 to ignore. + // + // Sometimes you want more refinement than sharp features since + // these can be done with feature edge snapping (so can leave + // 'level (0 0)') + curvatureLevel (10 0 10 -1); + + // To trigger small feature refinement + //gapLevel (1 0 1); + } + } + +//- looking at triangle mesh itself? E.g. cables with 3 triangles do not need +//refinement. +//- what about 90 degree angles. Do NOT refine. +//Refine always. With chamfer: currently not +// detected. So curvature refinement is just extension of resolveFeatureAngle +// mechanism. +//- disconnected surfaces. Currently not needed. Can also only be on single patch. +//- triangle clouds. Currently not needed. +//- limited to volume as well (like gapLevel). Not currently. Happy with either +// - global (like resolveFeatureAngle) +// - per patch (like resolveFeatureAngle) + + // Feature angle: + // - used if min and max refinement level of a surface differ + // - used if feature snapping (see snapControls below) is used + resolveFeatureAngle 45; + + + // Region-wise refinement + // ~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies refinement level for cells in relation to a surface. One of + // three modes + // - distance. 'levels' specifies per distance to the surface the + // wanted refinement level. The distances need to be specified in + // increasing order. + // - inside. 'levels' is only one entry and only the level is used. All + // cells inside the surface get refined up to the level. The surface + // needs to be closed for this to be possible. + // - outside. Same but cells outside. + + refinementRegions + { + all + { + mode inside; + + // Dummy base level + levels ((10000 0)); + + // If cells + // - have level 0..9 + // - and are in a gap < 3 cell sizes across + // - with the gap on the inside ('inside'), outside ('outside') + // or both ('mixed') of the surface + // refine them + //gapLevel (4 0 10); + //gapMode outside; + } + } + + + + // Optionally limit refinement in geometric region. This limits all + // refinement (from features, refinementSurfaces, refinementRegions) + // in a given geometric region. The syntax is exactly the same as for the + // refinementRegions; the cell level now specifies the upper limit + // for any cell. (a special setting is cell level -1 which will remove + // any cells inside the region). Note that it does not override the + // refinement constraints given by the nCellsBetweenLevels setting. + limitRegions + { + } + + + // Mesh selection + // ~~~~~~~~~~~~~~ + + // After refinement patches get added for all refinementSurfaces and + // all cells intersecting the surfaces get put into these patches. The + // section reachable from the location(s)InMesh is kept. + // NOTE: This point should never be on a face, always inside a cell, even + // after refinement. + // + // There are two different ways of specifying the regions to keep: + // 1. a single locationInMesh. This is the unzoned part of the mesh. + // All the 'zoned' surfaces are marked as such + // in the refinementSurfaces with the faceZone and cellZone keywords. + // It is illegal to have the locationInMesh inside a surface for which + // a cellZone is specified. + // + // or + // + // 2. multiple locationsInMesh, with per location the name of the cellZone. + // This uses walking to determine zones and automatically creates + // faceZones on the outside of cellZones. The special name 'none' is + // used to indicate the unzoned/background part of the mesh. + + + // Ad 1. Specify a single location and how to treat faces inbetween + // cellZones + locationInMesh (0.101 0.101 0.101); + + // Whether any faceZones (as specified in the refinementSurfaces) + // are only on the boundary of corresponding cellZones. + // Not used if there are no faceZones. The behaviour has changed + // with respect to previous versions: + // true : all intersections with surface are put in faceZone + // (same behaviour as before) + // false : depending on the type of surface intersected: + // - if intersecting surface has faceZone only (so no cellZone) + // leave in faceZone (so behave as if set to true) (= changed + // behaviour) + // - if intersecting surface has faceZone and cellZone + // remove if inbetween same cellZone or if on boundary + // (same behaviour as before) + allowFreeStandingZoneFaces true; + + + + // 2. Specify multiple locations with optional cellZones for the + // regions (use cellZone "none" to specify the unzoned cells) + // FaceZones are automatically constructed from the + // names of the cellZones: <cellZoneA> _to_ <cellZoneB> + // where the cellZoneA is the lowest numbered cellZone (non-cellZone + // cells are in a special region called "none" which is always + // last). + + + + + // Optional locations that should not be reachable from + // location(s)InMesh +// locationsOutsideMesh ((100 100 100)); + + // Optional: do not remove cells likely to give snapping problems + // handleSnapProblems false; + + // Optional: switch off topological test for cells to-be-squashed + // and use geometric test instead + //useTopologicalSnapDetection false; + + // Optional: do not refine surface cells with opposite faces of + // differing refinement levels + //interfaceRefine false; + + // Optional: use an erosion instead of region assignment to allocate + // left-over cells to the background region (i.e. make cellZones + // consistent with the intersections of the surface). + // Erosion is specified as a number of erosion iterations. + // Erosion has less chance of bleeding and changing the zone + // for a complete region. + //nCellZoneErodeIter 2; +} + +// Settings for the snapping. +snapControls +{ + // Number of patch smoothing iterations before finding correspondence + // to surface + nSmoothPatch 3; + + // Optional: number of smoothing iterations for internal points on + // refinement interfaces. This will reduce non-orthogonality on + // refinement interfaces. + //nSmoothInternal $nSmoothPatch; + + // Maximum relative distance for points to be attracted by surface. + // True distance is this factor times local maximum edge length. + tolerance 1.0; + + // Number of mesh displacement relaxation iterations. + nSolveIter 30; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // (wip) disable snapping to opposite near surfaces (revert to 22x + // behaviour) + // detectNearSurfacesSnap false; + + + // Feature snapping + + // Number of feature edge snapping iterations. + // Leave out altogether to disable. + nFeatureSnapIter 10; + + // Detect (geometric only) features by sampling the surface + // (default=false). + implicitFeatureSnap false; + + // Use castellatedMeshControls::features (default = true) + explicitFeatureSnap true; + + // Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap false; + + + //- When to run face splitting (never at first iteration, always + // at last iteration). Is interval. Default -1 (disabled) + //nFaceSplitInterval 5; + + + // (wip) Optional for explicit feature snapping: + //- Detect baffle edges. Default is true. + //detectBaffles false; + //- On any faces where points are on multiple regions (see + // multiRegionFeatureSnap) have the other points follow these points + // instead of having their own independent movement, i.e. have snapping + // to multi-region edges/points take priority. This might aid snapping + // to sharp edges that are also region edges. The default is false. + //releasePoints true; + //- Walk along feature edges, adding missing ones. Default is true. + //stringFeatures false; + //- If diagonal attraction also attract other face points. Default is + // false + //avoidDiagonal true; + //- When splitting what concave faces to leave intact. Default is 45 + // degrees. + //concaveAngle 30; + //- When splitting the minimum area ratio of faces. If face split + // causes ratio of area less than this do not split. Default is 0.3 + //minAreaRatio 0.3; + //- Attract points only to the surface they originate from. Default + // false. This can improve snapping of intersecting surfaces. + strictRegionSnap true; +} + +// Settings for the layer addition. +addLayersControls +{ + // Are the thickness parameters below relative to the undistorted + // size of the refined cell outside layer (true) or absolute sizes (false). + relativeSizes true; + + // Layer thickness specification. This can be specified in one of following + // ways: + // - expansionRatio and finalLayerThickness (cell nearest internal mesh) + // - expansionRatio and firstLayerThickness (cell on surface) + // - overall thickness and firstLayerThickness + // - overall thickness and finalLayerThickness + // - overall thickness and expansionRatio + // + // Note: the mode thus selected is global, i.e. one cannot override the + // mode on a per-patch basis (only the values can be overridden) + + // Expansion factor for layer mesh + expansionRatio 1.5; + + // Wanted thickness of the layer furthest away from the wall. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + finalLayerThickness 0.3; + + // Wanted thickness of the layer next to the wall. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + //firstLayerThickness 0.3; + + // Wanted overall thickness of layers. + // If relativeSizes this is relative to undistorted size of cell + // outside layer. + //thickness 0.5 + + + // Minimum overall thickness of total layers. If for any reason layer + // cannot be above minThickness do not add layer. + // If relativeSizes this is relative to undistorted size of cell + // outside layer.. + minThickness 0.1; + + + // Per final patch or faceZone (so not geometry!) the layer information + // Note: This behaviour changed after 21x. Any non-mentioned patches + // now slide unless: + // - nSurfaceLayers is explicitly mentioned to be 0. + // - angle to nearest surface < slipFeatureAngle (see below) + layers + { + "internalFace.*" {nSurfaceLayers 20; } + aerofoil + { + nSurfaceLayers 20; + } + } + + // If points get not extruded do nGrow layers of connected faces that are + // also not grown. This helps convergence of the layer addition process + // close to features. + // Note: changed(corrected) w.r.t 1.7.x! (didn't do anything in 1.7.x) + nGrow -1; + + // Advanced settings + + + // Static analysis of starting mesh + + // When not to extrude surface. 0 is flat surface, 90 is when two faces + // are perpendicular. Note: was not working correctly < 1806 + featureAngle 180; + + // When to merge patch faces. Default is featureAngle. Useful when + // featureAngle is large. + //mergePatchFacesAngle 45; + + // Stop layer growth on highly warped cells + maxFaceThicknessRatio 1000;//0.5; + + + // Patch displacement + + // Number of smoothing iterations of surface normals + nSmoothSurfaceNormals 1; + + // Smooth layer thickness over surface patches + nSmoothThickness 10; + + + + // Choice of mesh shrinking algorithm + + // Optional mesh shrinking algorithm (default is displacementMedialAxis) + // The displacementMotionSolver is a wrapper around the displacement + // motion solvers. It needs specification of the solver to use and + // its control dictionary. + //meshShrinker displacementMotionSolver; + //solver displacementLaplacian; + //displacementLaplacianCoeffs + //{ + // diffusivity quadratic inverseDistance + // ( + // sphere.stl_firstSolid + // maxY + // ); + //} + // Note that e.g. displacementLaplacian needs entries in + // fvSchemes, fvSolution. Also specify a minIter > 1 when solving + // cellDisplacement since otherwise solution might not be sufficiently + // accurate on points. + + + // Medial axis analysis (for use with default displacementMedialAxis) + + // Angle used to pick up medial axis points + // Note: changed(corrected) w.r.t 1.7.x! 90 degrees corresponds to 130 + // in 1.7.x. + minMedialAxisAngle 90; + + // Reduce layer growth where ratio thickness to medial + // distance is large + maxThicknessToMedialRatio 0.3; + + // Number of smoothing iterations of interior mesh movement direction + nSmoothNormals 3; + + // Optional: limit the number of steps walking away from the surface. + // Default is unlimited. + //nMedialAxisIter 10; + + // Optional: smooth displacement after medial axis determination. + // default is 0. + //nSmoothDisplacement 90; + + // (wip)Optional: do not extrude any point where + // (false) : all surrounding faces are not fully extruded + // (true) : all surrounding points are not extruded + // Default is false. + //detectExtrusionIsland true; + + // Optional: do not extrude around sharp edges if both faces are not + // fully extruded i.e. if one of the faces on either side would + // become a wedge. + // Default is 0.5*featureAngle. Set to -180 always attempt extrusion + //layerTerminationAngle 25; + + // Optional: disable shrinking of edges that have one (or two) points + // on an extruded patch. + // Default is false to enable single/two cell thick channels to still + // have layers. In <=1806 this was true by default. On larger gaps it + // should have no effect. + //disableWallEdges true; + + // Optional: at non-patched sides allow mesh to slip if extrusion + // direction makes angle larger than slipFeatureAngle. Default is + // 0.5*featureAngle. + slipFeatureAngle 10; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + + // Mesh shrinking + + // Create buffer region for new layer terminations, i.e. gradually + // step down number of layers. Set to <0 to terminate layer in one go. + nBufferCellsNoExtrude 0; + + // Overall max number of layer addition iterations. The mesher will + // exit if it reaches this number of iterations; possibly with an + // illegal mesh. + nLayerIter 50; + + // Max number of iterations after which relaxed meshQuality controls + // get used. Up to nRelaxedIter it uses the settings in + // meshQualityControls, + // after nRelaxedIter it uses the values in + // meshQualityControls::relaxed. + nRelaxedIter 0; + + // Additional reporting: if there are just a few faces where there + // are mesh errors (after adding the layers) print their face centres. + // This helps in tracking down problematic mesh areas. + //additionalReporting true; +} + +// Generic mesh quality settings. At any undoable phase these determine +// where to undo. +meshQualityControls +{ + // Specify mesh quality constraints in separate dictionary so can + // be reused (e.g. checkMesh -meshQuality) + #include "meshQualityDict" + + minDeterminant 1e-8; + + // Optional : some meshing phases allow usage of relaxed rules. + // See e.g. addLayersControls::nRelaxedIter. + relaxed + { + // Maximum non-orthogonality allowed. Set to 180 to disable. + maxNonOrtho 75; + minTetQuality -1e30; + minTwist -1; + } + + + // Advanced + + // Number of error distribution iterations + nSmoothScale 4; + // amount to scale back displacement at error points + errorReduction 0.75; +} + +// Advanced + +// Debug flags +debugFlags +( +// mesh // write intermediate meshes +// intersections // write current mesh intersections as .obj files +// featureSeeds // write information about explicit feature edge +// // refinement +// attraction // write attraction as .obj files +// layerInfo // write information about layers +); +// +//// Write flags +//writeFlags +//( +// scalarLevels // write volScalarField with cellLevel for postprocessing +// layerSets // write cellSets, faceSets of faces in layer +// layerFields // write volScalarField for layer coverage +//); + + +//// Format for writing lines. E.g. leak path. Default is vtk format. +//setFormat ensight; + +// Merge tolerance. Is fraction of overall bounding box of initial mesh. +// Note: the write tolerance needs to be higher than this. +mergeTolerance 1e-6; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/block_with_curvature/system/surfaceFeatureExtractDict b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..2504325d35bc27574ea57e69a1bd3cc338305663 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/block_with_curvature/system/surfaceFeatureExtractDict @@ -0,0 +1,60 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2112 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- temp dictionary with common settings +_surfaceExtract +{ + // Extract raw features (none | extractFromFile | extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 120; + + // Output surface curvature + curvature true; + + // Do not mark region edges + geometricTestOnly yes; + + // Generate additional intersection features (none | self | region) + intersectionMethod none; + + // Tolerance for surface intersections + // tolerance 1e-3; + +// Output options: + + // Write features to obj format for postprocessing + writeObj yes; + + // Write closeness/curvature/proximity fields as VTK for postprocessing + writeVTK yes; +} + + +curvature-box.stl +{ + $_surfaceExtract; +} + + +//- Remove temp from dictionary so it doesn't think it is a surface +#remove _surfaceExtract + +// ************************************************************************* //