/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application mergeOrSplitBaffles Group grpMeshManipulationUtilities Description Detects boundary faces that share points (baffles). Either merges them or duplicate the points. Usage \b mergeOrSplitBaffles [OPTION] Options: - \par -detectOnly Detect baffles and write to faceSet duplicateFaces. - \par -split Detect baffles and duplicate the points (used so the two sides can move independently) - \par -dict \ Specify a dictionary to read actions from. Note - can only handle pairwise boundary faces. So three faces using the same points is not handled (is illegal mesh anyway) - surfaces consisting of duplicate faces can be topologically split if the points on the interior of the surface cannot walk to all the cells that use them in one go. - Parallel operation (where duplicate face is perpendicular to a coupled boundary) is supported but not really tested. (Note that coupled faces themselves are not seen as duplicate faces) \*---------------------------------------------------------------------------*/ #include "argList.H" #include "Time.H" #include "syncTools.H" #include "faceSet.H" #include "pointSet.H" #include "meshTools.H" #include "polyTopoChange.H" #include "polyRemoveFace.H" #include "polyModifyFace.H" #include "indirectPrimitivePatch.H" #include "processorPolyPatch.H" #include "localPointRegion.H" #include "duplicatePoints.H" #include "ReadFields.H" #include "volFields.H" #include "surfaceFields.H" #include "processorMeshes.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // void insertDuplicateMerge ( const polyMesh& mesh, const labelList& boundaryFaces, const labelList& duplicates, polyTopoChange& meshMod ) { const faceList& faces = mesh.faces(); const labelList& faceOwner = mesh.faceOwner(); const faceZoneMesh& faceZones = mesh.faceZones(); forAll(duplicates, bFacei) { label otherFacei = duplicates[bFacei]; if (otherFacei != -1 && otherFacei > bFacei) { // Two duplicate faces. Merge. label face0 = boundaryFaces[bFacei]; label face1 = boundaryFaces[otherFacei]; label own0 = faceOwner[face0]; label own1 = faceOwner[face1]; if (own0 < own1) { // Use face0 as the new internal face. label zoneID = faceZones.whichZone(face0); bool zoneFlip = false; if (zoneID >= 0) { const faceZone& fZone = faceZones[zoneID]; zoneFlip = fZone.flipMap()[fZone.whichFace(face0)]; } meshMod.setAction(polyRemoveFace(face1)); meshMod.setAction ( polyModifyFace ( faces[face0], // modified face face0, // label of face being modified own0, // owner own1, // neighbour false, // face flip -1, // patch for face false, // remove from zone zoneID, // zone for face zoneFlip // face flip in zone ) ); } else { // Use face1 as the new internal face. label zoneID = faceZones.whichZone(face1); bool zoneFlip = false; if (zoneID >= 0) { const faceZone& fZone = faceZones[zoneID]; zoneFlip = fZone.flipMap()[fZone.whichFace(face1)]; } meshMod.setAction(polyRemoveFace(face0)); meshMod.setAction ( polyModifyFace ( faces[face1], // modified face face1, // label of face being modified own1, // owner own0, // neighbour false, // face flip -1, // patch for face false, // remove from zone zoneID, // zone for face zoneFlip // face flip in zone ) ); } } } } label patchSize(const polyMesh& mesh, const labelList& patchIDs) { const polyBoundaryMesh& patches = mesh.boundaryMesh(); label sz = 0; forAll(patchIDs, i) { const polyPatch& pp = patches[patchIDs[i]]; sz += pp.size(); } return sz; } labelList patchFaces(const polyMesh& mesh, const labelList& patchIDs) { const polyBoundaryMesh& patches = mesh.boundaryMesh(); labelList faceIDs(patchSize(mesh, patchIDs)); label sz = 0; forAll(patchIDs, i) { const polyPatch& pp = patches[patchIDs[i]]; forAll(pp, ppi) { faceIDs[sz++] = pp.start()+ppi; } } if (faceIDs.size() != sz) { FatalErrorInFunction << exit(FatalError); } return faceIDs; } labelList findBaffles(const polyMesh& mesh, const labelList& boundaryFaces) { // Get all duplicate face labels (in boundaryFaces indices!). labelList duplicates = localPointRegion::findDuplicateFaces ( mesh, boundaryFaces ); // Check that none are on processor patches const polyBoundaryMesh& patches = mesh.boundaryMesh(); forAll(duplicates, bFacei) { if (duplicates[bFacei] != -1) { label facei = boundaryFaces[bFacei]; label patchi = patches.whichPatch(facei); if (isA(patches[patchi])) { FatalErrorInFunction << "Duplicate face " << facei << " is on a processorPolyPatch." << "This is not allowed." << nl << "Face:" << facei << " is on patch:" << patches[patchi].name() << abort(FatalError); } } } // Write to faceSet for ease of post-processing. { faceSet duplicateSet ( mesh, "duplicateFaces", (mesh.nFaces() - mesh.nInternalFaces())/256 ); forAll(duplicates, bFacei) { label otherFacei = duplicates[bFacei]; if (otherFacei != -1 && otherFacei > bFacei) { duplicateSet.insert(boundaryFaces[bFacei]); duplicateSet.insert(boundaryFaces[otherFacei]); } } Info<< "Writing " << returnReduce(duplicateSet.size(), sumOp