mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-12-28 03:37:59 +00:00
ENH: mergeOrSplitBaffles: allow operation on selected patches. Fixes #314.
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,15 +28,31 @@ Group
|
||||
grpMeshManipulationUtilities
|
||||
|
||||
Description
|
||||
Detects faces that share points (baffles). Either merge them or
|
||||
Detects boundary faces that share points (baffles). Either merges them or
|
||||
duplicate the points.
|
||||
|
||||
Notes:
|
||||
Usage
|
||||
\b mergeOrSplitBaffles [OPTION]
|
||||
|
||||
Options:
|
||||
- \par -detect
|
||||
Detect baffles and write to faceSet duplicateFaces.
|
||||
|
||||
- \par -merge
|
||||
Detect baffles and convert to internal faces.
|
||||
|
||||
- \par -split
|
||||
Detect baffles and duplicate the points (used so the two sides
|
||||
can move independently)
|
||||
|
||||
- \par -dict \<dictionary\>
|
||||
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)
|
||||
|
||||
- there is no option to only split/merge some baffles.
|
||||
|
||||
- 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.
|
||||
@ -71,6 +87,7 @@ using namespace Foam;
|
||||
void insertDuplicateMerge
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const labelList& boundaryFaces,
|
||||
const labelList& duplicates,
|
||||
polyTopoChange& meshMod
|
||||
)
|
||||
@ -87,8 +104,8 @@ void insertDuplicateMerge
|
||||
{
|
||||
// Two duplicate faces. Merge.
|
||||
|
||||
label face0 = mesh.nInternalFaces() + bFacei;
|
||||
label face1 = mesh.nInternalFaces() + otherFacei;
|
||||
label face0 = boundaryFaces[bFacei];
|
||||
label face1 = boundaryFaces[otherFacei];
|
||||
|
||||
label own0 = faceOwner[face0];
|
||||
label own1 = faceOwner[face1];
|
||||
@ -156,6 +173,45 @@ void insertDuplicateMerge
|
||||
}
|
||||
|
||||
|
||||
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!).
|
||||
@ -173,7 +229,7 @@ labelList findBaffles(const polyMesh& mesh, const labelList& boundaryFaces)
|
||||
{
|
||||
if (duplicates[bFacei] != -1)
|
||||
{
|
||||
label facei = mesh.nInternalFaces() + bFacei;
|
||||
label facei = boundaryFaces[bFacei];
|
||||
label patchi = patches.whichPatch(facei);
|
||||
|
||||
if (isA<processorPolyPatch>(patches[patchi]))
|
||||
@ -205,12 +261,12 @@ labelList findBaffles(const polyMesh& mesh, const labelList& boundaryFaces)
|
||||
|
||||
if (otherFacei != -1 && otherFacei > bFacei)
|
||||
{
|
||||
duplicateSet.insert(mesh.nInternalFaces() + bFacei);
|
||||
duplicateSet.insert(mesh.nInternalFaces() + otherFacei);
|
||||
duplicateSet.insert(boundaryFaces[bFacei]);
|
||||
duplicateSet.insert(boundaryFaces[otherFacei]);
|
||||
}
|
||||
}
|
||||
|
||||
Pout<< "Writing " << duplicateSet.size()
|
||||
Info<< "Writing " << returnReduce(duplicateSet.size(), sumOp<label>())
|
||||
<< " duplicate faces to faceSet " << duplicateSet.objectPath()
|
||||
<< nl << endl;
|
||||
duplicateSet.write();
|
||||
@ -220,8 +276,6 @@ labelList findBaffles(const polyMesh& mesh, const labelList& boundaryFaces)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
@ -232,6 +286,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#include "addOverwriteOption.H"
|
||||
#include "addRegionOption.H"
|
||||
#include "addDictOption.H"
|
||||
argList::addBoolOption
|
||||
(
|
||||
"detectOnly",
|
||||
@ -249,25 +304,89 @@ int main(int argc, char *argv[])
|
||||
#include "createNamedMesh.H"
|
||||
|
||||
const word oldInstance = mesh.pointsInstance();
|
||||
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
||||
|
||||
const bool readDict = args.optionFound("dict");
|
||||
const bool split = args.optionFound("split");
|
||||
const bool overwrite = args.optionFound("overwrite");
|
||||
const bool detectOnly = args.optionFound("detectOnly");
|
||||
|
||||
// Collect all boundary faces
|
||||
labelList boundaryFaces(mesh.nFaces() - mesh.nInternalFaces());
|
||||
|
||||
forAll(boundaryFaces, i)
|
||||
if (readDict && (split || detectOnly))
|
||||
{
|
||||
boundaryFaces[i] = i+mesh.nInternalFaces();
|
||||
FatalErrorInFunction
|
||||
<< "Use of dictionary for settings not compatible with"
|
||||
<< " using command line arguments for \"split\""
|
||||
<< " or \"detectOnly\"" << exit(FatalError);
|
||||
}
|
||||
|
||||
|
||||
if (detectOnly)
|
||||
labelList detectPatchIDs;
|
||||
labelList splitPatchIDs;
|
||||
labelList mergePatchIDs;
|
||||
|
||||
if (readDict)
|
||||
{
|
||||
findBaffles(mesh, boundaryFaces);
|
||||
return 0;
|
||||
const word dictName;
|
||||
#include "setSystemMeshDictionaryIO.H"
|
||||
|
||||
Info<< "Reading " << dictName << "\n" << endl;
|
||||
IOdictionary dict(dictIO);
|
||||
|
||||
if (dict.found("detect"))
|
||||
{
|
||||
wordReList patchNames(dict.subDict("detect").lookup("patches"));
|
||||
detectPatchIDs = patches.patchSet(patchNames).sortedToc();
|
||||
Info<< "Detecting baffles on " << detectPatchIDs.size()
|
||||
<< " patches with "
|
||||
<< returnReduce(patchSize(mesh, detectPatchIDs), sumOp<label>())
|
||||
<< " faces" << endl;
|
||||
}
|
||||
if (dict.found("merge"))
|
||||
{
|
||||
wordReList patchNames(dict.subDict("merge").lookup("patches"));
|
||||
mergePatchIDs = patches.patchSet(patchNames).sortedToc();
|
||||
Info<< "Detecting baffles on " << mergePatchIDs.size()
|
||||
<< " patches with "
|
||||
<< returnReduce(patchSize(mesh, mergePatchIDs), sumOp<label>())
|
||||
<< " faces" << endl;
|
||||
}
|
||||
if (dict.found("split"))
|
||||
{
|
||||
wordReList patchNames(dict.subDict("split").lookup("patches"));
|
||||
splitPatchIDs = patches.patchSet(patchNames).sortedToc();
|
||||
Info<< "Detecting baffles on " << splitPatchIDs.size()
|
||||
<< " patches with "
|
||||
<< returnReduce(patchSize(mesh, splitPatchIDs), sumOp<label>())
|
||||
<< " faces" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (detectOnly)
|
||||
{
|
||||
detectPatchIDs = identity(patches.size());
|
||||
}
|
||||
else if (split)
|
||||
{
|
||||
splitPatchIDs = identity(patches.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
mergePatchIDs = identity(patches.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (detectPatchIDs.size())
|
||||
{
|
||||
findBaffles(mesh, patchFaces(mesh, detectPatchIDs));
|
||||
|
||||
if (detectOnly)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read objects in time directory
|
||||
@ -308,64 +427,118 @@ int main(int argc, char *argv[])
|
||||
ReadFields(mesh, objects, stFlds);
|
||||
|
||||
|
||||
// Mesh change engine
|
||||
polyTopoChange meshMod(mesh);
|
||||
|
||||
|
||||
if (split)
|
||||
if (mergePatchIDs.size())
|
||||
{
|
||||
Pout<< "Topologically splitting duplicate surfaces"
|
||||
<< ", i.e. duplicating points internal to duplicate surfaces."
|
||||
Info<< "Merging duplicate faces" << nl << endl;
|
||||
|
||||
// Mesh change engine
|
||||
polyTopoChange meshMod(mesh);
|
||||
|
||||
const labelList boundaryFaces(patchFaces(mesh, mergePatchIDs));
|
||||
|
||||
// Get all duplicate face pairs (in boundaryFaces indices!).
|
||||
labelList duplicates(findBaffles(mesh, boundaryFaces));
|
||||
|
||||
// Merge into internal faces.
|
||||
insertDuplicateMerge(mesh, boundaryFaces, duplicates, meshMod);
|
||||
|
||||
if (!overwrite)
|
||||
{
|
||||
runTime++;
|
||||
}
|
||||
|
||||
// Change the mesh. No inflation.
|
||||
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
|
||||
|
||||
// Update fields
|
||||
mesh.updateMesh(map);
|
||||
|
||||
// Move mesh (since morphing does not do this)
|
||||
if (map().hasMotionPoints())
|
||||
{
|
||||
mesh.movePoints(map().preMotionPoints());
|
||||
}
|
||||
|
||||
if (overwrite)
|
||||
{
|
||||
mesh.setInstance(oldInstance);
|
||||
}
|
||||
Info<< "Writing mesh to time " << runTime.timeName() << endl;
|
||||
mesh.write();
|
||||
}
|
||||
|
||||
|
||||
if (splitPatchIDs.size())
|
||||
{
|
||||
Info<< "Topologically splitting duplicate surfaces"
|
||||
<< ", i.e. duplicating points internal to duplicate surfaces"
|
||||
<< nl << endl;
|
||||
|
||||
// Determine points on split patches
|
||||
DynamicList<label> candidates;
|
||||
{
|
||||
label sz = 0;
|
||||
forAll(splitPatchIDs, i)
|
||||
{
|
||||
sz += patches[splitPatchIDs[i]].nPoints();
|
||||
}
|
||||
candidates.setCapacity(sz);
|
||||
|
||||
PackedBoolList isCandidate(mesh.nPoints());
|
||||
forAll(splitPatchIDs, i)
|
||||
{
|
||||
const labelList& mp = patches[splitPatchIDs[i]].meshPoints();
|
||||
forAll(mp, mpi)
|
||||
{
|
||||
label pointi = mp[mpi];
|
||||
if (isCandidate.set(pointi))
|
||||
{
|
||||
candidates.append(pointi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Analyse which points need to be duplicated
|
||||
localPointRegion regionSide(mesh);
|
||||
localPointRegion regionSide(mesh, candidates);
|
||||
|
||||
// Point duplication engine
|
||||
duplicatePoints pointDuplicator(mesh);
|
||||
|
||||
// Mesh change engine
|
||||
polyTopoChange meshMod(mesh);
|
||||
|
||||
// Insert topo changes
|
||||
pointDuplicator.setRefinement(regionSide, meshMod);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pout<< "Merging duplicate faces."
|
||||
<< nl << endl;
|
||||
|
||||
// Get all duplicate face labels (in boundaryFaces indices!).
|
||||
labelList duplicates(findBaffles(mesh, boundaryFaces));
|
||||
if (!overwrite)
|
||||
{
|
||||
runTime++;
|
||||
}
|
||||
|
||||
// Merge into internal faces.
|
||||
insertDuplicateMerge(mesh, duplicates, meshMod);
|
||||
}
|
||||
// Change the mesh. No inflation.
|
||||
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
|
||||
|
||||
if (!overwrite)
|
||||
{
|
||||
runTime++;
|
||||
}
|
||||
// Update fields
|
||||
mesh.updateMesh(map);
|
||||
|
||||
// Change the mesh. No inflation.
|
||||
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
|
||||
// Move mesh (since morphing does not do this)
|
||||
if (map().hasMotionPoints())
|
||||
{
|
||||
mesh.movePoints(map().preMotionPoints());
|
||||
}
|
||||
|
||||
// Update fields
|
||||
mesh.updateMesh(map);
|
||||
if (overwrite)
|
||||
{
|
||||
mesh.setInstance(oldInstance);
|
||||
}
|
||||
Info<< "Writing mesh to time " << runTime.timeName() << endl;
|
||||
mesh.write();
|
||||
|
||||
// Move mesh (since morphing does not do this)
|
||||
if (map().hasMotionPoints())
|
||||
{
|
||||
mesh.movePoints(map().preMotionPoints());
|
||||
}
|
||||
|
||||
if (overwrite)
|
||||
{
|
||||
mesh.setInstance(oldInstance);
|
||||
}
|
||||
Pout<< "Writing mesh to time " << runTime.timeName() << endl;
|
||||
mesh.write();
|
||||
|
||||
// Dump duplicated points (if any)
|
||||
if (split)
|
||||
{
|
||||
// Dump duplicated points (if any)
|
||||
const labelList& pointMap = map().pointMap();
|
||||
|
||||
labelList nDupPerPoint(map().nOldPoints(), 0);
|
||||
@ -385,7 +558,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
Pout<< "Writing " << dupPoints.size()
|
||||
Info<< "Writing " << returnReduce(dupPoints.size(), sumOp<label>())
|
||||
<< " duplicated points to pointSet "
|
||||
<< dupPoints.objectPath() << nl << endl;
|
||||
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: plus |
|
||||
| \\ / A nd | Web: www.OpenFOAM.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
object mergeOrSplitBafflesDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Detect baffles (boundary faces sharing points) on selected set of patches
|
||||
// and write to a faceSet.
|
||||
detect
|
||||
{
|
||||
patches (".*Wall");
|
||||
}
|
||||
|
||||
// Detect baffles (on selected patches) and merge these into internal faces.
|
||||
merge
|
||||
{
|
||||
patches ("mergePatch");
|
||||
}
|
||||
|
||||
// Detect baffles (on selected patches) and duplicate the points. This is
|
||||
// used if e.g. the two sides need to move separately. Note that since the
|
||||
// points are duplicated the two faces are no longer baffles.
|
||||
split
|
||||
{
|
||||
patches ("split.*Patches");
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user