/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright held by original author \\/ M anipulation | ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Description Checks for multiple patch faces on same cell and combines them. These result from e.g. refined neighbouring cells getting removed, leaving 4 exposed faces with same owner. Rules for merging: - only boundary faces (since multiple internal faces between two cells not allowed anyway) - faces have to have same owner - faces have to be connected via edge which are not features (so angle between them < feature angle) - outside of faces has to be single loop - outside of face should not be (or just slightly) concave (so angle between consecutive edges < concaveangle E.g. to allow all faces on same patch to be merged: combinePatchFaces .. cavity 180 -concaveAngle 90 \*---------------------------------------------------------------------------*/ #include "PstreamReduceOps.H" #include "argList.H" #include "objectRegistry.H" #include "Time.H" #include "directTopoChange.H" #include "polyModifyFace.H" #include "polyAddFace.H" #include "combineFaces.H" #include "removePoints.H" #include "polyMesh.H" #include "mapPolyMesh.H" #include "mathematicalConstants.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Sin of angle between two consecutive edges on a face. If sin(angle) larger // than this the face will be considered concave. const scalar defaultConcaveAngle = 30; // Same check as snapMesh void checkSnapMesh ( const Time& runTime, const polyMesh& mesh, labelHashSet& wrongFaces ) { IOdictionary snapDict ( IOobject ( "snapMeshDict", runTime.system(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE ) ); // Max nonorthogonality allowed scalar maxNonOrtho(readScalar(snapDict.lookup("maxNonOrtho"))); primitiveMesh::nonOrthThreshold_ = maxNonOrtho; // Max concaveness allowed. scalar maxConcave(readScalar(snapDict.lookup("maxConcave"))); primitiveMesh::faceAngleThreshold_ = maxConcave; // Min volume allowed (factor of minimum cellVolume) scalar relMinVol(readScalar(snapDict.lookup("minVol"))); const scalar minCellVol = min(mesh.cellVolumes()); const scalar minPyrVol = relMinVol*minCellVol; // Min area scalar minArea(readScalar(snapDict.lookup("minArea"))); if (maxNonOrtho < 180.0 - SMALL) { Pout<< "Checking non orthogonality" << endl; label nOldSize = wrongFaces.size(); mesh.checkFaceOrthogonality(false, &wrongFaces); Pout<< "Detected " << wrongFaces.size() - nOldSize << " faces with non-orthogonality > " << maxNonOrtho << " degrees" << endl; } if (minPyrVol > -GREAT) { Pout<< "Checking face pyramids" << endl; label nOldSize = wrongFaces.size(); mesh.checkFacePyramids(false, minPyrVol, &wrongFaces); Pout<< "Detected additional " << wrongFaces.size() - nOldSize << " faces with illegal face pyramids" << endl; } if (maxConcave < 180.0 - SMALL) { Pout<< "Checking face angles" << endl; label nOldSize = wrongFaces.size(); mesh.checkFaceAngles(false, &wrongFaces); Pout<< "Detected additional " << wrongFaces.size() - nOldSize << " faces with concavity > " << maxConcave << " degrees" << endl; } if (minArea > -SMALL) { Pout<< "Checking face areas" << endl; label nOldSize = wrongFaces.size(); const scalarField magFaceAreas = mag(mesh.faceAreas()); forAll(magFaceAreas, faceI) { if (magFaceAreas[faceI] < minArea) { wrongFaces.insert(faceI); } } Pout<< "Detected additional " << wrongFaces.size() - nOldSize << " faces with area < " << minArea << " m^2" << endl; } } // Merge faces on the same patch (usually from exposing refinement) // Can undo merges if these cause problems. label mergePatchFaces ( const scalar minCos, const scalar concaveSin, const bool snapMeshDict, const Time& runTime, polyMesh& mesh ) { // Patch face merging engine combineFaces faceCombiner(mesh); // Get all sets of faces that can be merged labelListList allFaceSets(faceCombiner.getMergeSets(minCos, concaveSin)); label nFaceSets = returnReduce(allFaceSets.size(), sumOp