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/>.
25 Extracts triSurface from a polyMesh. Triangulates all boundary faces.
26 Region numbers on triangles are the patch numbers of the polyMesh.
27 Optionally only triangulates named patches.
29 If run in parallel the processor patches get filtered out by default and
30 the mesh gets merged. (based on vertex position, not topology, so might go
33 \*---------------------------------------------------------------------------*/
38 #include "triSurface.H"
39 #include "triSurfaceTools.H"
40 #include "processorPolyPatch.H"
41 #include "ListListOps.H"
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 int main(int argc, char *argv[])
53 "extract surface from a polyMesh and triangulate boundary faces"
55 argList::validArgs.append("output file");
56 #include "addRegionOption.H"
57 argList::addBoolOption
60 "exclude processor patches"
66 "only triangulate named patches"
69 #include "setRootCase.H"
70 #include "createTime.H"
72 const fileName outFileName(runTime.path()/args[1]);
74 Info<< "Extracting triSurface from boundaryMesh ..."
77 Pout<< "Reading mesh from time " << runTime.value() << endl;
79 #include "createNamedPolyMesh.H"
81 const bool includeProcPatches =
83 args.optionFound("excludeProcPatches")
87 // Create local surface from:
88 // - explicitly named patches only (-patches (at your option)
89 // - all patches (default in sequential mode)
90 // - all non-processor patches (default in parallel mode)
91 // - all non-processor patches (sequential mode, -excludeProcPatches
94 // Construct table of patches to include.
95 const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
97 labelHashSet includePatches(bMesh.size());
99 if (args.optionFound("patches"))
101 const wordList patchNames
103 args.optionLookup("patches")()
106 forAll(patchNames, patchNameI)
108 const word& patchName = patchNames[patchNameI];
109 const label patchI = bMesh.findPatchID(patchName);
113 FatalErrorIn(args.executable()) << "No such patch "
114 << patchName << endl << "Patches are " << bMesh.names()
117 includePatches.insert(patchI);
122 forAll(bMesh, patchI)
124 const polyPatch& patch = bMesh[patchI];
126 if (includeProcPatches || !isA<processorPolyPatch>(patch))
128 includePatches.insert(patchI);
132 Pout<< patch.name() << " : skipped since processorPatch"
138 triSurface localSurface
140 triSurfaceTools::triangulate
149 if (!Pstream::parRun())
151 Info<< "Writing surface to " << outFileName << endl;
153 localSurface.write(outFileName);
157 // Write local surface
158 fileName localPath = runTime.path()/runTime.caseName() + ".obj";
160 Pout<< "Writing local surface to " << localPath << endl;
162 localSurface.write(localPath);
167 // Gather all points on master
168 List<pointField> gatheredPoints(Pstream::nProcs());
170 gatheredPoints[Pstream::myProcNo()] = localSurface.points();
172 Pstream::gatherList(gatheredPoints);
175 // Gather all localSurface patches
176 List<geometricSurfacePatchList> gatheredPatches(Pstream::nProcs());
178 gatheredPatches[Pstream::myProcNo()] = localSurface.patches();
180 Pstream::gatherList(gatheredPatches);
184 List<List<labelledTri> > gatheredFaces(Pstream::nProcs());
186 gatheredFaces[Pstream::myProcNo()] = localSurface;
188 Pstream::gatherList(gatheredFaces);
191 if (Pstream::master())
193 // On master combine all points
194 pointField allPoints =
195 ListListOps::combine<pointField>
198 accessOp<pointField>()
201 // Count number of patches.
204 forAll(gatheredPatches, procI)
206 nPatches += gatheredPatches[procI].size();
209 // Count number of faces.
212 forAll(gatheredFaces, procI)
214 nFaces += gatheredFaces[procI].size();
219 // Loop over all processors and
220 // - construct mapping from local to global patches
221 // - relabel faces (both points and regions)
225 // Name to new patchI
226 HashTable<label> nameToIndex(2*nPatches);
228 // Storage (oversized) for all patches
229 geometricSurfacePatchList allPatches(nPatches);
233 // Storage for all faces
234 List<labelledTri> allFaces(nFaces);
236 // Offset into allPoints for current processor
237 label pointOffset = 0;
239 for (label procI = 0; procI < Pstream::nProcs(); procI++)
241 Info<< "Processor " << procI << endl
242 << "-----------" << endl;
244 const geometricSurfacePatchList& patches =
245 gatheredPatches[procI];
247 // From local patch numbering to global
248 labelList localToGlobal(patches.size());
250 forAll(patches, patchI)
252 const geometricSurfacePatch& sp = patches[patchI];
254 if (!nameToIndex.found(sp.name()))
256 nameToIndex.insert(sp.name(), newPatchI);
258 localToGlobal[patchI] = newPatchI;
260 allPatches[newPatchI] = sp;
266 localToGlobal[patchI] = nameToIndex[sp.name()];
270 Info<< "Local patch to global patch mapping:"
273 forAll(patches, patchI)
275 Info<< " name : " << patches[patchI].name() << endl
276 << " local : " << patchI << endl
277 << " global : " << localToGlobal[patchI]
281 Info<< "Local points added in global points starting at "
286 // Collect and relabel faces
287 const List<labelledTri>& localFaces = gatheredFaces[procI];
290 forAll(localFaces, faceI)
292 const labelledTri& f = localFaces[faceI];
294 allFaces[newFaceI++] =
300 localToGlobal[f.region()]
304 pointOffset += gatheredPoints[procI].size();
308 allPatches.setSize(newPatchI);
310 // We now have allPoints, allFaces and allPatches.
311 // Construct overall (yet unmerged) surface from these.
313 triSurface allSurf(allFaces, allPatches, allPoints);
315 // Cleanup (which does point merge as well
316 allSurf.cleanup(false);
318 // Write surface mesh
320 label slashIndex = runTime.caseName().find_last_of('/');
322 fileName globalCasePath(runTime.caseName().substr(0, slashIndex));
324 Info<< "Writing merged surface to " << globalCasePath << endl;
326 // create database for the sequential run
334 allSurf.write(globalPath);
338 Info<< "End\n" << endl;
344 // ************************************************************************* //