/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation \\/ 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 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application snappyHexMesh Description Automatic split hex mesher. Refines and snaps to surface. \*---------------------------------------------------------------------------*/ #include "argList.H" #include "Time.H" #include "fvMesh.H" #include "autoRefineDriver.H" #include "autoSnapDriver.H" #include "autoLayerDriver.H" #include "searchableSurfaces.H" #include "refinementSurfaces.H" #include "refinementFeatures.H" #include "shellSurfaces.H" #include "decompositionMethod.H" #include "noDecomp.H" #include "fvMeshDistribute.H" #include "wallPolyPatch.H" #include "refinementParameters.H" #include "snapParameters.H" #include "layerParameters.H" #include "vtkSetWriter.H" #include "faceSet.H" #include "motionSmoother.H" #include "polyTopoChange.H" #include "cellModeller.H" #include "uindirectPrimitivePatch.H" #include "surfZoneIdentifierList.H" #include "UnsortedMeshedSurface.H" #include "MeshedSurface.H" #include "globalIndex.H" #include "IOmanip.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Convert size (as fraction of defaultCellSize) to refinement level label sizeCoeffToRefinement ( const scalar level0Coeff, // ratio of hex cell size v.s. defaultCellSize const scalar sizeCoeff ) { return round(::log(level0Coeff/sizeCoeff)/::log(2)); } autoPtr createRefinementSurfaces ( const searchableSurfaces& allGeometry, const dictionary& surfacesDict, const dictionary& shapeControlDict, const label gapLevelIncrement, const scalar level0Coeff ) { autoPtr surfacePtr; // Count number of surfaces. label surfI = 0; forAll(allGeometry.names(), geomI) { const word& geomName = allGeometry.names()[geomI]; if (surfacesDict.found(geomName)) { surfI++; } } labelList surfaces(surfI); wordList names(surfI); wordList faceZoneNames(surfI); wordList cellZoneNames(surfI); List zoneInside ( surfI, refinementSurfaces::NONE ); pointField zoneInsidePoints(surfI); List faceType ( surfI, refinementSurfaces::INTERNAL ); labelList regionOffset(surfI); labelList globalMinLevel(surfI, 0); labelList globalMaxLevel(surfI, 0); labelList globalLevelIncr(surfI, 0); PtrList globalPatchInfo(surfI); List > regionMinLevel(surfI); List > regionMaxLevel(surfI); List > regionLevelIncr(surfI); List > regionAngle(surfI); List > > regionPatchInfo(surfI); surfI = 0; forAll(allGeometry.names(), geomI) { const word& geomName = allGeometry.names()[geomI]; // Definition of surfaces to conform to // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (surfacesDict.found(geomName)) { names[surfI] = geomName; surfaces[surfI] = geomI; const dictionary& shapeDict = shapeControlDict.subDict(geomName); // Find the index in shapeControlDict // Invert surfaceCellSize to get the refinementLevel const word scsFuncName = shapeDict.lookup("surfaceCellSizeFunction"); const dictionary& scsDict = shapeDict.subDict(scsFuncName + "Coeffs"); const scalar surfaceCellSize = readScalar(scsDict.lookup("surfaceCellSizeCoeff")); const label refLevel = sizeCoeffToRefinement ( level0Coeff, surfaceCellSize ); globalMinLevel[surfI] = refLevel; globalMaxLevel[surfI] = refLevel; globalLevelIncr[surfI] = gapLevelIncrement; const dictionary& dict = surfacesDict.subDict(geomName); // Global zone names per surface if (dict.readIfPresent("faceZone", faceZoneNames[surfI])) { // Read optional entry to determine inside of faceZone word method; bool hasSide = dict.readIfPresent("cellZoneInside", method); if (hasSide) { zoneInside[surfI] = refinementSurfaces::areaSelectionAlgoNames[method]; if (zoneInside[surfI] == refinementSurfaces::INSIDEPOINT) { dict.lookup("insidePoint") >> zoneInsidePoints[surfI]; } } else { // Check old syntax bool inside; if (dict.readIfPresent("zoneInside", inside)) { hasSide = true; zoneInside[surfI] = ( inside ? refinementSurfaces::INSIDE : refinementSurfaces::OUTSIDE ); } } // Read optional cellZone name if (dict.readIfPresent("cellZone", cellZoneNames[surfI])) { if ( ( zoneInside[surfI] == refinementSurfaces::INSIDE || zoneInside[surfI] == refinementSurfaces::OUTSIDE ) && !allGeometry[surfaces[surfI]].hasVolumeType() ) { IOWarningIn ( "createRefinementSurfaces(..)", dict ) << "Illegal entry zoneInside " << refinementSurfaces::areaSelectionAlgoNames [ zoneInside[surfI] ] << " for faceZone " << faceZoneNames[surfI] << " since surface " << names[surfI] << " is not closed." << endl; } } else if (hasSide) { IOWarningIn ( "createRefinementSurfaces(..)", dict ) << "Unused entry zoneInside for faceZone " << faceZoneNames[surfI] << " since no cellZone specified." << endl; } // How to handle faces on faceZone word faceTypeMethod; if (dict.readIfPresent("faceType", faceTypeMethod)) { faceType[surfI] = refinementSurfaces::faceZoneTypeNames[faceTypeMethod]; } } // Global perpendicular angle if (dict.found("patchInfo")) { globalPatchInfo.set ( surfI, dict.subDict("patchInfo").clone() ); } // Per region override of patchInfo if (dict.found("regions")) { const dictionary& regionsDict = dict.subDict("regions"); const wordList& regionNames = allGeometry[surfaces[surfI]].regions(); forAll(regionNames, regionI) { if (regionsDict.found(regionNames[regionI])) { // Get the dictionary for region const dictionary& regionDict = regionsDict.subDict ( regionNames[regionI] ); if (regionDict.found("patchInfo")) { regionPatchInfo[surfI].insert ( regionI, regionDict.subDict("patchInfo").clone() ); } } } } // Per region override of cellSize if (shapeDict.found("regions")) { const dictionary& shapeControlRegionsDict = shapeDict.subDict("regions"); const wordList& regionNames = allGeometry[surfaces[surfI]].regions(); forAll(regionNames, regionI) { if (shapeControlRegionsDict.found(regionNames[regionI])) { const dictionary& shapeControlRegionDict = shapeControlRegionsDict.subDict ( regionNames[regionI] ); const word scsFuncName = shapeControlRegionDict.lookup ( "surfaceCellSizeFunction" ); const dictionary& scsDict = shapeControlRegionDict.subDict ( scsFuncName + "Coeffs" ); const scalar surfaceCellSize = readScalar ( scsDict.lookup("surfaceCellSizeCoeff") ); const label refLevel = sizeCoeffToRefinement ( level0Coeff, surfaceCellSize ); regionMinLevel[surfI].insert(regionI, refLevel); regionMaxLevel[surfI].insert(regionI, refLevel); regionLevelIncr[surfI].insert(regionI, 0); } } } surfI++; } } // Calculate local to global region offset label nRegions = 0; forAll(surfaces, surfI) { regionOffset[surfI] = nRegions; nRegions += allGeometry[surfaces[surfI]].regions().size(); } // Rework surface specific information into information per global region labelList minLevel(nRegions, 0); labelList maxLevel(nRegions, 0); labelList gapLevel(nRegions, -1); PtrList patchInfo(nRegions); forAll(globalMinLevel, surfI) { label nRegions = allGeometry[surfaces[surfI]].regions().size(); // Initialise to global (i.e. per surface) for (label i = 0; i < nRegions; i++) { label globalRegionI = regionOffset[surfI] + i; minLevel[globalRegionI] = globalMinLevel[surfI]; maxLevel[globalRegionI] = globalMaxLevel[surfI]; gapLevel[globalRegionI] = maxLevel[globalRegionI] + globalLevelIncr[surfI]; if (globalPatchInfo.set(surfI)) { patchInfo.set ( globalRegionI, globalPatchInfo[surfI].clone() ); } } // Overwrite with region specific information forAllConstIter(Map