surfaceMeshExtract.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2017-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Application
28  surfaceMeshExtract
29 
30 Group
31  grpSurfaceUtilities
32 
33 Description
34  Extract patch or faceZone surfaces from a polyMesh.
35  Depending on output surface format triangulates faces.
36 
37  Region numbers on faces no guaranteed to be the same as the patch indices.
38 
39  Optionally only extracts named patches.
40 
41  If run in parallel, processor patches get filtered out by default and
42  the mesh is merged (based on topology).
43 
44 \*---------------------------------------------------------------------------*/
45 
46 #include "MeshedSurface.H"
47 #include "UnsortedMeshedSurface.H"
48 #include "argList.H"
49 #include "Time.H"
50 #include "polyMesh.H"
51 #include "emptyPolyPatch.H"
52 #include "processorPolyPatch.H"
53 #include "ListListOps.H"
55 #include "globalMeshData.H"
56 #include "globalIndex.H"
57 #include "timeSelector.H"
58 
59 using namespace Foam;
60 
61 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
62 
63 labelList getSelectedPatches
64 (
66  const wordRes& whitelist,
67  const wordRes& blacklist
68 )
69 {
70  // Name-based selection
71  labelList indices
72  (
74  (
75  patches,
76  whitelist,
77  blacklist,
79  )
80  );
81 
82 
83  // Remove undesirable patches
84 
85  label count = 0;
86  for (const label patchi : indices)
87  {
88  const polyPatch& pp = patches[patchi];
89 
90  if (isType<emptyPolyPatch>(pp))
91  {
92  continue;
93  }
94  else if (Pstream::parRun() && bool(isA<processorPolyPatch>(pp)))
95  {
96  break; // No processor patches for parallel output
97  }
98 
99  indices[count] = patchi;
100  ++count;
101  }
102 
103  indices.resize(count);
104 
105  return indices;
106 }
107 
108 
109 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
110 
111 int main(int argc, char *argv[])
112 {
114  (
115  "Extract patch or faceZone surfaces from a polyMesh."
116  " The name is historical, it only triangulates faces"
117  " when the output format requires it."
118  );
120 
121  // Less frequently used - reduce some clutter
122  argList::setAdvanced("decomposeParDict");
123  argList::setAdvanced("noFunctionObjects");
124 
125  argList::addArgument("output", "The output surface file");
126 
127  #include "addRegionOption.H"
129  (
130  "excludeProcPatches",
131  "Exclude processor patches"
132  );
134  (
135  "faceZones",
136  "wordRes",
137  "Specify single or multiple faceZones to extract\n"
138  "Eg, 'cells' or '( slice \"mfp-.*\" )'"
139  );
141  (
142  "patches",
143  "wordRes",
144  "Specify single patch or multiple patches to extract.\n"
145  "Eg, 'top' or '( front \".*back\" )'"
146  );
148  (
149  "excludePatches",
150  "wordRes",
151  "Specify single patch or multiple patches to exclude from writing."
152  " Eg, 'outlet' or '( inlet \".*Wall\" )'",
153  true // mark as an advanced option
154  );
155 
156  #include "setRootCase.H"
157  #include "createTime.H"
158 
159  const fileName userOutFileName(args[1]);
160 
161  if (!userOutFileName.hasExt())
162  {
164  << "Missing extension on output name " << userOutFileName
165  << exit(FatalError);
166  }
167 
168  Info<< "Extracting surface from boundaryMesh ..." << nl << nl;
169 
170  const bool includeProcPatches =
171  !(
172  args.found("excludeProcPatches")
173  || Pstream::parRun()
174  );
175 
176  if (includeProcPatches)
177  {
178  Info<< "Including all processor patches." << nl << endl;
179  }
180  else if (Pstream::parRun())
181  {
182  Info<< "Excluding all processor patches." << nl << endl;
183  }
184 
185  wordRes includePatches, excludePatches;
186  if (args.readListIfPresent<wordRe>("patches", includePatches))
187  {
188  Info<< "Including patches " << flatOutput(includePatches)
189  << nl << endl;
190  }
191  if (args.readListIfPresent<wordRe>("excludePatches", excludePatches))
192  {
193  Info<< "Excluding patches " << flatOutput(excludePatches)
194  << nl << endl;
195  }
196 
197  // Non-mandatory
198  const wordRes selectedFaceZones(args.getList<wordRe>("faceZones", false));
199  if (selectedFaceZones.size())
200  {
201  Info<< "Including faceZones " << flatOutput(selectedFaceZones)
202  << nl << endl;
203  }
204 
205  Info<< "Reading mesh from time " << runTime.value() << endl;
206 
207  #include "createNamedPolyMesh.H"
208 
209  // User specified times
211 
212  forAll(timeDirs, timeIndex)
213  {
214  runTime.setTime(timeDirs[timeIndex], timeIndex);
215  Info<< "Time [" << timeIndex << "] = " << runTime.timeName();
216 
217  fileName outFileName;
218  if (timeDirs.size() == 1)
219  {
220  outFileName = userOutFileName;
221  }
222  else
223  {
225  if (timeIndex && meshState == polyMesh::UNCHANGED)
226  {
227  Info<<" ... no mesh change." << nl;
228  continue;
229  }
230 
231  // The filename based on the original, but with additional
232  // time information. The extension was previously checked that
233  // it exists
234  const auto dot = userOutFileName.rfind('.');
235 
236  outFileName =
237  userOutFileName.substr(0, dot) + "_"
238  + Foam::name(runTime.value()) + "."
239  + userOutFileName.ext();
240  }
241 
242  Info<< nl;
243 
244  // Create local surface from:
245  // - explicitly named patches only (-patches (at your option)
246  // - all patches (default in sequential mode)
247  // - all non-processor patches (default in parallel mode)
248  // - all non-processor patches (sequential mode, -excludeProcPatches
249  // (at your option)
250 
251  // Construct table of patches to include.
253 
255  (
256  (includePatches.size() || excludePatches.size())
257  ? getSelectedPatches(bMesh, includePatches, excludePatches)
258  : includeProcPatches
259  ? identity(bMesh.size())
260  : identity(bMesh.nNonProcessor())
261  );
262 
263  labelList faceZoneIds;
264 
265  const faceZoneMesh& fzm = mesh.faceZones();
266 
267  if (selectedFaceZones.size())
268  {
269  faceZoneIds = fzm.indices(selectedFaceZones);
270 
271  Info<< "Additionally extracting faceZones "
272  << fzm.names(selectedFaceZones) << nl;
273  }
274 
275 
276  // From (name of) patch to compact 'zone' index
277  HashTable<label> compactZoneID(1024);
278  // Mesh face and compact zone indx
279  DynamicList<label> faceLabels;
280  DynamicList<label> compactZones;
281 
282  {
283  // Collect sizes. Hash on names to handle local-only patches (e.g.
284  // processor patches)
285  HashTable<label> patchSize(1024);
286  label nFaces = 0;
287  for (const label patchi : patchIds)
288  {
289  const polyPatch& pp = bMesh[patchi];
290  patchSize.insert(pp.name(), pp.size());
291  nFaces += pp.size();
292  }
293 
294  HashTable<label> zoneSize(1024);
295  for (const label zonei : faceZoneIds)
296  {
297  const faceZone& pp = fzm[zonei];
298  zoneSize.insert(pp.name(), pp.size());
299  nFaces += pp.size();
300  }
301 
302 
305 
306 
307  // Allocate compact numbering for all patches/faceZones
308  forAllConstIters(patchSize, iter)
309  {
310  compactZoneID.insert(iter.key(), compactZoneID.size());
311  }
312 
313  forAllConstIters(zoneSize, iter)
314  {
315  compactZoneID.insert(iter.key(), compactZoneID.size());
316  }
317 
318 
319  Pstream::mapCombineScatter(compactZoneID);
320 
321 
322  // Rework HashTable into labelList just for speed of conversion
323  labelList patchToCompactZone(bMesh.size(), -1);
324  labelList faceZoneToCompactZone(bMesh.size(), -1);
325  forAllConstIters(compactZoneID, iter)
326  {
327  label patchi = bMesh.findPatchID(iter.key());
328  if (patchi != -1)
329  {
330  patchToCompactZone[patchi] = iter.val();
331  }
332  else
333  {
334  label zoneI = fzm.findZoneID(iter.key());
335  faceZoneToCompactZone[zoneI] = iter.val();
336  }
337  }
338 
339 
340  faceLabels.setCapacity(nFaces);
341  compactZones.setCapacity(nFaces);
342 
343  // Collect faces on patches
344  for (const label patchi : patchIds)
345  {
346  const polyPatch& pp = bMesh[patchi];
347  forAll(pp, i)
348  {
349  faceLabels.append(pp.start()+i);
350  compactZones.append(patchToCompactZone[pp.index()]);
351  }
352  }
353  // Collect faces on faceZones
354  for (const label zonei : faceZoneIds)
355  {
356  const faceZone& pp = fzm[zonei];
357  forAll(pp, i)
358  {
359  faceLabels.append(pp[i]);
360  compactZones.append(faceZoneToCompactZone[pp.index()]);
361  }
362  }
363  }
364 
365 
366  // Addressing engine for all faces
367  uindirectPrimitivePatch allBoundary
368  (
369  UIndirectList<face>(mesh.faces(), faceLabels),
370  mesh.points()
371  );
372 
373 
374  // Find correspondence to master points
375  labelList pointToGlobal;
376  labelList uniqueMeshPoints;
378  (
379  allBoundary.meshPoints(),
380  allBoundary.meshPointMap(),
381  pointToGlobal,
382  uniqueMeshPoints
383  );
384 
385  // Gather all unique points on master
386  List<pointField> gatheredPoints(Pstream::nProcs());
387  gatheredPoints[Pstream::myProcNo()] = pointField
388  (
389  mesh.points(),
390  uniqueMeshPoints
391  );
392  Pstream::gatherList(gatheredPoints);
393 
394  // Gather all faces
395  List<faceList> gatheredFaces(Pstream::nProcs());
396  gatheredFaces[Pstream::myProcNo()] = allBoundary.localFaces();
397  forAll(gatheredFaces[Pstream::myProcNo()], i)
398  {
400  (
401  pointToGlobal,
402  gatheredFaces[Pstream::myProcNo()][i]
403  );
404  }
405  Pstream::gatherList(gatheredFaces);
406 
407  // Gather all ZoneIDs
408  List<labelList> gatheredZones(Pstream::nProcs());
409  gatheredZones[Pstream::myProcNo()].transfer(compactZones);
410  Pstream::gatherList(gatheredZones);
411 
412  // On master combine all points, faces, zones
413  if (Pstream::master())
414  {
415  pointField allPoints = ListListOps::combine<pointField>
416  (
417  gatheredPoints,
419  );
420  gatheredPoints.clear();
421 
422  faceList allFaces = ListListOps::combine<faceList>
423  (
424  gatheredFaces,
426  );
427  gatheredFaces.clear();
428 
429  labelList allZones = ListListOps::combine<labelList>
430  (
431  gatheredZones,
433  );
434  gatheredZones.clear();
435 
436 
437  // Zones
438  surfZoneIdentifierList surfZones(compactZoneID.size());
439  forAllConstIters(compactZoneID, iter)
440  {
441  surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter);
442  Info<< "surfZone " << *iter
443  << " : " << surfZones[*iter].name()
444  << endl;
445  }
446 
447  UnsortedMeshedSurface<face> unsortedFace
448  (
449  std::move(allPoints),
450  std::move(allFaces),
451  std::move(allZones),
452  surfZones
453  );
454 
455 
456  MeshedSurface<face> sortedFace(unsortedFace);
457 
458  fileName globalCasePath
459  (
460  outFileName.isAbsolute()
461  ? outFileName
462  : (
464  ? runTime.globalPath()/outFileName
465  : runTime.path()/outFileName
466  )
467  );
468 
469  Info<< "Writing merged surface to " << globalCasePath << endl;
470 
471  sortedFace.write(globalCasePath);
472  }
473  }
474 
475  Info<< "End\n" << endl;
476 
477  return 0;
478 }
479 
480 
481 // ************************************************************************* //
Foam::Pstream::mapCombineGather
static void mapCombineGather(const List< commsStruct > &comms, Container &Values, const CombineOp &cop, const int tag, const label comm)
Definition: combineGatherScatter.C:551
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1038
Foam::accessOp
Definition: UList.H:614
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
uindirectPrimitivePatch.H
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::DynamicList< label >
ListListOps.H
globalMeshData.H
globalIndex.H
Foam::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:427
Foam::UPstream::parRun
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:415
Foam::Time::timeName
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:785
Foam::dot
void dot(FieldField< Field1, typename innerProduct< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
Definition: FieldFieldFunctions.C:944
Foam::argList::addNote
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:413
Foam::argList::readListIfPresent
bool readListIfPresent(const word &optName, List< T > &list) const
Definition: argListI.H:373
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:435
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::dimensioned::value
const Type & value() const
Return const reference to value.
Definition: dimensionedType.C:434
Foam::word::ext
word ext() const
Return file name extension (part after last .)
Definition: word.C:126
polyMesh.H
Foam::wordRe
A wordRe is a Foam::word, but can contain a regular expression for matching words or strings.
Definition: wordRe.H:72
createNamedPolyMesh.H
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::surfZoneIdentifier
Identifies a surface patch/zone by name, patch index and geometricType.
Definition: surfZoneIdentifier.H:59
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::polyMesh::faceZones
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:477
Foam::globalMeshData::mergePoints
autoPtr< globalIndex > mergePoints(labelList &pointToGlobal, labelList &uniquePoints) const
Helper for merging (collocated!) mesh point data.
Definition: globalMeshData.C:2394
Foam::fvMesh::readUpdate
virtual readUpdateState readUpdate()
Update the mesh based on the mesh files saved in time.
Definition: fvMesh.C:519
UnsortedMeshedSurface.H
Foam::argList::addArgument
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:302
patchIds
labelList patchIds
Definition: convertProcessorPatches.H:67
Foam::Field< vector >
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
Foam::UnsortedMeshedSurface
A surface geometry mesh, in which the surface zone information is conveyed by the 'zoneId' associated...
Definition: MeshedSurface.H:83
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:67
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:472
argList.H
addRegionOption.H
Foam::ZoneMesh< faceZone, polyMesh >
Foam::polyMesh::UNCHANGED
Definition: polyMesh.H:93
Foam::nameOp
Extract name (as a word) from an object, typically using its name() method.
Definition: word.H:238
Foam::stringListOps::findMatching
labelList findMatching(const StringListType &input, const wordRes &whitelist, const wordRes &blacklist=wordRes(), AccessOp aop=noOp())
Return ids for items with matching names.
Foam::argList::setAdvanced
static void setAdvanced(const word &optName, bool advanced=true)
Set an existing option as being 'advanced' or normal.
Definition: argList.C:355
Foam::FatalError
error FatalError
processorPolyPatch.H
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::zone::name
const word & name() const
Return name.
Definition: zone.H:158
Foam::ZoneMesh::findZoneID
label findZoneID(const word &zoneName) const
Find zone index given a name, return -1 if not found.
Definition: ZoneMesh.C:484
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:312
emptyPolyPatch.H
Foam::ZoneMesh::names
wordList names() const
A list of the zone names.
Definition: ZoneMesh.C:340
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::DynamicList::setCapacity
void setCapacity(const label nElem)
Alter the size of the underlying storage.
Definition: DynamicListI.H:232
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:445
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:439
Foam::polyMesh::readUpdateState
readUpdateState
Enumeration defining the state of the mesh after a read update.
Definition: polyMesh.H:91
Foam::HashTable< label >
Foam::argList::addBoolOption
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:325
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
setRootCase.H
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1063
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:358
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::Pstream::mapCombineScatter
static void mapCombineScatter(const List< commsStruct > &comms, Container &Values, const int tag, const label comm)
Scatter data. Reverse of combineGather.
Definition: combineGatherScatter.C:666
Foam::flatOutput
FlatOutput< Container > flatOutput(const Container &obj, label len=0)
Global flatOutput function.
Definition: FlatOutput.H:85
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:74
Foam::timeSelector::addOptions
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:108
Foam::List< label >
Foam::Time::setTime
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:1006
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::wordRes
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:51
timeSelector.H
createTime.H
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::argList::getList
List< T > getList(const label index) const
Get a List of values from the argument at index.
Foam::TimePaths::globalPath
fileName globalPath() const
Return global path for the case.
Definition: TimePathsI.H:72
Foam::UIndirectList
A List with indirect addressing.
Definition: fvMatrix.H:109
Foam::DelaunayMeshTools::allPoints
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
timeIndex
label timeIndex
Definition: getTimeIndex.H:4
Foam::plusEqOp
Definition: ops.H:72
Foam::polyMesh::globalData
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1234
Foam::TimePaths::processorCase
bool processorCase() const
Return true if this is a processor case.
Definition: TimePathsI.H:36
Foam::timeSelector::select0
static instantList select0(Time &runTime, const argList &args)
Definition: timeSelector.C:241
Foam::ZoneMesh::indices
labelList indices(const keyType &key) const
Return zone indices for all matches.
Definition: ZoneMesh.C:409
Foam::MeshedSurface< face >
Foam::argList::addOption
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:336
args
Foam::argList args(argc, argv)
Foam::zone::index
label index() const
Return the index of this zone in zone list.
Definition: zone.H:169
Foam::patchIdentifier::name
const word & name() const
The patch name.
Definition: patchIdentifier.H:134
Foam::patchIdentifier::index
label index() const
The index of this patch in the boundaryMesh.
Definition: patchIdentifier.H:158
Foam::fileName::isAbsolute
static bool isAbsolute(const std::string &str)
Return true if string starts with a '/'.
Definition: fileNameI.H:136
Foam::argList::found
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:157
MeshedSurface.H
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:85