FreeFOAM The Cross-Platform CFD Toolkit
surfaceMeshTriangulate.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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
19  for more details.
20 
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/>.
23 
24 Application
25  surfaceMeshTriangulate
26 
27 Description
28  Extracts triSurface from a polyMesh.
29 
30  Triangulates all boundary faces. Region numbers on triangles are the patch
31  numbers of the polyMesh. Optionally only triangulates named patches.
32 
33  If run in parallel the processor patches get filtered out by default and
34  the mesh gets merged. (based on vertex position, not topology, so might go
35  wrong!).
36 
37 Usage
38 
39  - surfaceMeshTriangulate [OPTIONS] <output file>
40 
41  @param <output file> \n
42  @todo Detailed description of argument.
43 
44  @param -patches <(patch0 .. patchN)>\n
45  List of patches.
46 
47  @param -excludeProcPatches \n
48  If not run parallel, exclude processor patches.
49 
50  @param -case <dir>\n
51  Case directory.
52 
53  @param -parallel \n
54  Run in parallel.
55 
56  @param -help \n
57  Display help message.
58 
59  @param -doc \n
60  Display Doxygen API documentation page for this application.
61 
62  @param -srcDoc \n
63  Display Doxygen source documentation page for this application.
64 
65 \*---------------------------------------------------------------------------*/
66 
67 #include <OpenFOAM/argList.H>
68 #include <OpenFOAM/Time.H>
69 #include <OpenFOAM/polyMesh.H>
70 #include <triSurface/triSurface.H>
73 #include <OpenFOAM/ListListOps.H>
74 
75 using namespace Foam;
76 
77 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
78 
79 // Main program:
80 
81 int main(int argc, char *argv[])
82 {
83  argList::validArgs.append("output file");
85  argList::validOptions.insert("excludeProcPatches", "");
86  argList::validOptions.insert("patches", "(patch0 .. patchN)");
87 
88 # include <OpenFOAM/setRootCase.H>
89 # include <OpenFOAM/createTime.H>
90 
91  fileName outFileName(runTime.path()/args.additionalArgs()[0]);
92 
93  Info<< "Extracting triSurface from boundaryMesh ..."
94  << endl << endl;
95 
96  Pout<< "Reading mesh from time " << runTime.value() << endl;
97 
99 
100  bool includeProcPatches =
101  !(
102  args.optionFound("excludeProcPatches")
103  || Pstream::parRun()
104  );
105 
106  // Create local surface from:
107  // - explicitly named patches only (-patches option)
108  // - all patches (default in sequential mode)
109  // - all non-processor patches (default in parallel mode)
110  // - all non-processor patches (sequential mode, -excludeProcPatches option)
111 
112  // Construct table of patches to include.
114 
115  labelHashSet includePatches(bMesh.size());
116 
117  if (args.optionFound("patches"))
118  {
119  wordList patchNames(args.optionLookup("patches")());
120 
121  forAll(patchNames, patchNameI)
122  {
123  const word& patchName = patchNames[patchNameI];
124 
125  label patchI = bMesh.findPatchID(patchName);
126 
127  if (patchI == -1)
128  {
129  FatalErrorIn(args.executable()) << "No such patch "
130  << patchName << endl << "Patches are " << bMesh.names()
131  << exit(FatalError);
132  }
133  includePatches.insert(patchI);
134  }
135  }
136  else
137  {
138  forAll(bMesh, patchI)
139  {
140  const polyPatch& patch = bMesh[patchI];
141 
142  if (includeProcPatches || !isA<processorPolyPatch>(patch))
143  {
144  includePatches.insert(patchI);
145  }
146  else
147  {
148  Pout<< patch.name() << " : skipped since processorPatch"
149  << endl;
150  }
151  }
152  }
153 
154  triSurface localSurface
155  (
157  (
158  mesh.boundaryMesh(),
159  includePatches
160  )
161  );
162 
163 
164 
165  if (!Pstream::parRun())
166  {
167  Info<< "Writing surface to " << outFileName << endl;
168 
169  localSurface.write(outFileName);
170  }
171  else
172  {
173  // Write local surface
174  fileName localPath = runTime.path()/runTime.caseName() + ".ftr";
175 
176  Pout<< "Writing local surface to " << localPath << endl;
177 
178  localSurface.write(localPath);
179 
180  Info<< endl;
181 
182 
183  // Gather all points on master
184  List<pointField> gatheredPoints(Pstream::nProcs());
185 
186  gatheredPoints[Pstream::myProcNo()] = localSurface.points();
187 
188  Pstream::gatherList(gatheredPoints);
189 
190 
191  // Gather all localSurface patches
193 
194  gatheredPatches[Pstream::myProcNo()] = localSurface.patches();
195 
196  Pstream::gatherList(gatheredPatches);
197 
198 
199  // Gather all faces
200  List<List<labelledTri> > gatheredFaces(Pstream::nProcs());
201 
202  gatheredFaces[Pstream::myProcNo()] = localSurface;
203 
204  Pstream::gatherList(gatheredFaces);
205 
206 
207  if (Pstream::master())
208  {
209  // On master combine all points
210  pointField allPoints =
211  ListListOps::combine<pointField>
212  (
213  gatheredPoints,
215  );
216 
217  // Count number of patches.
218  label nPatches = 0;
219 
220  forAll(gatheredPatches, procI)
221  {
222  nPatches += gatheredPatches[procI].size();
223  }
224 
225  // Count number of faces.
226  label nFaces = 0;
227 
228  forAll(gatheredFaces, procI)
229  {
230  nFaces += gatheredFaces[procI].size();
231  }
232 
233 
234 
235  // Loop over all processors and
236  // - construct mapping from local to global patches
237  // - relabel faces (both points and regions)
238 
239  label newPatchI = 0;
240 
241  // Name to new patchI
242  HashTable<label> nameToIndex(2*nPatches);
243 
244  // Storage (oversized) for all patches
245  geometricSurfacePatchList allPatches(nPatches);
246 
247  label newFaceI = 0;
248 
249  // Storage for all faces
250  List<labelledTri> allFaces(nFaces);
251 
252  // Offset into allPoints for current processor
253  label pointOffset = 0;
254 
255  for (label procI = 0; procI < Pstream::nProcs(); procI++)
256  {
257  Info<< "Processor " << procI << endl
258  << "-----------" << endl;
259 
261  gatheredPatches[procI];
262 
263  // From local patch numbering to global
264  labelList localToGlobal(patches.size());
265 
266  forAll(patches, patchI)
267  {
268  const geometricSurfacePatch& sp = patches[patchI];
269 
270  if (!nameToIndex.found(sp.name()))
271  {
272  nameToIndex.insert(sp.name(), newPatchI);
273 
274  localToGlobal[patchI] = newPatchI;
275 
276  allPatches[newPatchI] = sp;
277 
278  newPatchI++;
279  }
280  else
281  {
282  localToGlobal[patchI] = nameToIndex[sp.name()];
283  }
284  }
285 
286  Info<< "Local patch to global patch mapping:"
287  << endl;
288 
289  forAll(patches, patchI)
290  {
291  Info<< " name : " << patches[patchI].name() << endl
292  << " local : " << patchI << endl
293  << " global : " << localToGlobal[patchI]
294  << endl;
295  }
296 
297  Info<< "Local points added in global points starting at "
298  << pointOffset
299  << endl;
300 
301 
302  // Collect and relabel faces
303  const List<labelledTri>& localFaces = gatheredFaces[procI];
304 
305 
306  forAll(localFaces, faceI)
307  {
308  const labelledTri& f = localFaces[faceI];
309 
310  allFaces[newFaceI++] =
312  (
313  f[0] + pointOffset,
314  f[1] + pointOffset,
315  f[2] + pointOffset,
316  localToGlobal[f.region()]
317  );
318  }
319 
320  pointOffset += gatheredPoints[procI].size();
321 
322  Info<< endl;
323  }
324  allPatches.setSize(newPatchI);
325 
326  // We now have allPoints, allFaces and allPatches.
327  // Construct overall (yet unmerged) surface from these.
328 
329  triSurface allSurf(allFaces, allPatches, allPoints);
330 
331  // Cleanup (which does point merge as well
332  allSurf.cleanup(false);
333 
334  // Write surface mesh
335 
336  label slashIndex = runTime.caseName().find_last_of('/');
337 
338  fileName globalCasePath(runTime.caseName().substr(0, slashIndex));
339 
340  Info<< "Writing merged surface to " << globalCasePath << endl;
341 
342  // create database for the sequential run
343  fileName globalPath
344  (
345  runTime.rootPath()
346  / globalCasePath
347  / args.additionalArgs()[0]
348  );
349 
350  allSurf.write(globalPath);
351  }
352  }
353 
354  Info << "End\n" << endl;
355 
356  return 0;
357 }
358 
359 
360 // ************************ vim: set sw=4 sts=4 et: ************************ //