1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
28 Detects faces that share points (baffles). Either merge them or
32 - can only handle pairwise boundary faces. So three faces using
33 the same points is not handled (is illegal mesh anyway)
35 - there is no option to only split/merge some baffles.
37 - surfaces consisting of duplicate faces can be topologically split
38 if the points on the interior of the surface cannot walk to all the
39 cells that use them in one go.
41 - Parallel operation (where duplicate face is perpendicular to a coupled
42 boundary) is supported but not really tested.
43 (Note that coupled faces themselves are not seen as duplicate faces)
45 \*---------------------------------------------------------------------------*/
49 #include "syncTools.H"
52 #include "meshTools.H"
53 #include "polyTopoChange.H"
54 #include "polyRemoveFace.H"
55 #include "polyModifyFace.H"
56 #include "indirectPrimitivePatch.H"
57 #include "processorPolyPatch.H"
58 #include "localPointRegion.H"
59 #include "duplicatePoints.H"
60 #include "ReadFields.H"
61 #include "volFields.H"
62 #include "surfaceFields.H"
66 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
68 void insertDuplicateMerge
71 const labelList& duplicates,
72 polyTopoChange& meshMod
75 const faceList& faces = mesh.faces();
76 const labelList& faceOwner = mesh.faceOwner();
77 const faceZoneMesh& faceZones = mesh.faceZones();
79 forAll(duplicates, bFaceI)
81 label otherFaceI = duplicates[bFaceI];
83 if (otherFaceI != -1 && otherFaceI > bFaceI)
85 // Two duplicate faces. Merge.
87 label face0 = mesh.nInternalFaces() + bFaceI;
88 label face1 = mesh.nInternalFaces() + otherFaceI;
90 label own0 = faceOwner[face0];
91 label own1 = faceOwner[face1];
95 // Use face0 as the new internal face.
96 label zoneID = faceZones.whichZone(face0);
97 bool zoneFlip = false;
101 const faceZone& fZone = faceZones[zoneID];
102 zoneFlip = fZone.flipMap()[fZone.whichFace(face0)];
105 meshMod.setAction(polyRemoveFace(face1));
110 faces[face0], // modified face
111 face0, // label of face being modified
115 -1, // patch for face
116 false, // remove from zone
117 zoneID, // zone for face
118 zoneFlip // face flip in zone
124 // Use face1 as the new internal face.
125 label zoneID = faceZones.whichZone(face1);
126 bool zoneFlip = false;
130 const faceZone& fZone = faceZones[zoneID];
131 zoneFlip = fZone.flipMap()[fZone.whichFace(face1)];
134 meshMod.setAction(polyRemoveFace(face0));
139 faces[face1], // modified face
140 face1, // label of face being modified
144 -1, // patch for face
145 false, // remove from zone
146 zoneID, // zone for face
147 zoneFlip // face flip in zone
156 labelList findBaffles(const polyMesh& mesh, const labelList& boundaryFaces)
158 // Get all duplicate face labels (in boundaryFaces indices!).
159 labelList duplicates = localPointRegion::findDuplicateFaces
166 // Check that none are on processor patches
167 const polyBoundaryMesh& patches = mesh.boundaryMesh();
169 forAll(duplicates, bFaceI)
171 if (duplicates[bFaceI] != -1)
173 label faceI = mesh.nInternalFaces() + bFaceI;
174 label patchI = patches.whichPatch(faceI);
176 if (isA<processorPolyPatch>(patches[patchI]))
178 FatalErrorIn("findBaffles(const polyMesh&, const labelList&)")
179 << "Duplicate face " << faceI
180 << " is on a processorPolyPatch."
181 << "This is not allowed." << nl
183 << " is on patch:" << patches[patchI].name()
184 << abort(FatalError);
190 // Write to faceSet for ease of postprocessing.
196 (mesh.nFaces() - mesh.nInternalFaces())/256
199 forAll(duplicates, bFaceI)
201 label otherFaceI = duplicates[bFaceI];
203 if (otherFaceI != -1 && otherFaceI > bFaceI)
205 duplicateSet.insert(mesh.nInternalFaces() + bFaceI);
206 duplicateSet.insert(mesh.nInternalFaces() + otherFaceI);
210 Pout<< "Writing " << duplicateSet.size()
211 << " duplicate faces to faceSet " << duplicateSet.objectPath()
213 duplicateSet.write();
222 int main(int argc, char *argv[])
226 "Detect faces that share points (baffles).\n"
227 "Merge them or duplicate the points."
230 #include "addOverwriteOption.H"
231 #include "addRegionOption.H"
232 argList::addBoolOption
235 "find baffles only, but do not merge or split them"
237 argList::addBoolOption
240 "topologically split duplicate surfaces"
243 #include "setRootCase.H"
244 #include "createTime.H"
245 runTime.functionObjects().off();
246 #include "createNamedMesh.H"
248 const word oldInstance = mesh.pointsInstance();
250 const bool split = args.optionFound("split");
251 const bool overwrite = args.optionFound("overwrite");
252 const bool detectOnly = args.optionFound("detectOnly");
254 // Collect all boundary faces
255 labelList boundaryFaces(mesh.nFaces() - mesh.nInternalFaces());
257 forAll(boundaryFaces, i)
259 boundaryFaces[i] = i+mesh.nInternalFaces();
265 findBaffles(mesh, boundaryFaces);
270 // Read objects in time directory
271 IOobjectList objects(mesh, runTime.timeName());
275 PtrList<volScalarField> vsFlds;
276 ReadFields(mesh, objects, vsFlds);
278 PtrList<volVectorField> vvFlds;
279 ReadFields(mesh, objects, vvFlds);
281 PtrList<volSphericalTensorField> vstFlds;
282 ReadFields(mesh, objects, vstFlds);
284 PtrList<volSymmTensorField> vsymtFlds;
285 ReadFields(mesh, objects, vsymtFlds);
287 PtrList<volTensorField> vtFlds;
288 ReadFields(mesh, objects, vtFlds);
290 // Read surface fields.
292 PtrList<surfaceScalarField> ssFlds;
293 ReadFields(mesh, objects, ssFlds);
295 PtrList<surfaceVectorField> svFlds;
296 ReadFields(mesh, objects, svFlds);
298 PtrList<surfaceSphericalTensorField> sstFlds;
299 ReadFields(mesh, objects, sstFlds);
301 PtrList<surfaceSymmTensorField> ssymtFlds;
302 ReadFields(mesh, objects, ssymtFlds);
304 PtrList<surfaceTensorField> stFlds;
305 ReadFields(mesh, objects, stFlds);
308 // Mesh change engine
309 polyTopoChange meshMod(mesh);
314 Pout<< "Topologically splitting duplicate surfaces"
315 << ", i.e. duplicating points internal to duplicate surfaces."
318 // Analyse which points need to be duplicated
319 localPointRegion regionSide(mesh);
321 // Point duplication engine
322 duplicatePoints pointDuplicator(mesh);
324 // Insert topo changes
325 pointDuplicator.setRefinement(regionSide, meshMod);
329 Pout<< "Merging duplicate faces."
332 // Get all duplicate face labels (in boundaryFaces indices!).
333 labelList duplicates(findBaffles(mesh, boundaryFaces));
335 // Merge into internal faces.
336 insertDuplicateMerge(mesh, duplicates, meshMod);
344 // Change the mesh. No inflation.
345 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
348 mesh.updateMesh(map);
350 // Move mesh (since morphing does not do this)
351 if (map().hasMotionPoints())
353 mesh.movePoints(map().preMotionPoints());
358 mesh.setInstance(oldInstance);
360 Pout<< "Writing mesh to time " << runTime.timeName() << endl;
363 // Dump duplicated points (if any)
366 const labelList& pointMap = map().pointMap();
368 labelList nDupPerPoint(map().nOldPoints(), 0);
370 pointSet dupPoints(mesh, "duplicatedPoints", 100);
372 forAll(pointMap, pointI)
374 label oldPointI = pointMap[pointI];
376 nDupPerPoint[oldPointI]++;
378 if (nDupPerPoint[oldPointI] > 1)
380 dupPoints.insert(map().reversePointMap()[oldPointI]);
381 dupPoints.insert(pointI);
385 Pout<< "Writing " << dupPoints.size()
386 << " duplicated points to pointSet "
387 << dupPoints.objectPath() << nl << endl;
392 Info<< "End\n" << endl;
398 // ************************************************************************* //