/*---------------------------------------------------------------------------*\
========= |
\\ / 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