ensightMesh.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) 2016-2024 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 \*---------------------------------------------------------------------------*/
28 
29 #include "ensightMesh.H"
30 #include "ensightGeoFile.H"
31 #include "polyMesh.H"
32 #include "emptyPolyPatch.H"
33 #include "processorPolyPatch.H"
34 #include "stringListOps.H" // For stringListOps::findMatching()
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 const Foam::label Foam::ensightMesh::internalZone = -1;
39 
40 
41 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45 
46 // Patch names without processor patches
48 {
49  #ifdef FULLDEBUG
50  // Patches are output. Check that they are synced.
51  bmesh.checkParallelSync(true);
52  #endif
53 
54  wordList patchNames(bmesh.names());
56 
57  return patchNames;
58 }
59 
60 
61 } // End namespace Foam
62 
63 
64 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
65 
66 void Foam::ensightMesh::clear()
67 {
68  cellZoneParts_.clear();
69  faceZoneParts_.clear();
70  boundaryParts_.clear();
71 }
72 
73 
74 void Foam::ensightMesh::renumber()
75 {
76  label partNo = 0;
77 
78  for (const label id : cellZoneParts_.sortedToc())
79  {
80  cellZoneParts_[id].index() = partNo++;
81  }
82 
83  for (const label id : boundaryParts_.sortedToc())
84  {
85  boundaryParts_[id].index() = partNo++;
86  }
87 
88  for (const label id : faceZoneParts_.sortedToc())
89  {
90  faceZoneParts_[id].index() = partNo++;
91  }
92 }
93 
94 
95 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
96 
97 Foam::ensightMesh::ensightMesh
98 (
99  const polyMesh& mesh
100 )
101 :
103 {}
104 
105 
106 Foam::ensightMesh::ensightMesh
107 (
108  const polyMesh& mesh,
109  const ensightMesh::options& opts
110 )
111 :
112  options_(new options(opts)),
113  mesh_(mesh),
114  needsUpdate_(true),
115  verbose_(0)
116 {
117  if (!option().lazy())
118  {
120  }
121 }
122 
123 
124 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
127 {
128  return verbose_;
129 }
130 
131 
132 int Foam::ensightMesh::verbose(const int level) noexcept
133 {
134  int old(verbose_);
135  verbose_ = level;
136  return old;
137 }
138 
139 
141 {
142  clear();
143 
144  const wordRes& czMatcher = option().cellZoneSelection();
145  const wordRes& fzMatcher = option().faceZoneSelection();
146 
147  // Possible cellZones
148  const wordList czNames =
149  (
150  (
151  option().useCellZones()
152  && (!czMatcher.empty() || option().useInternalMesh())
153  )
154  ? mesh_.cellZones().names()
155  : wordList()
156  );
157 
158  const labelList czoneIds =
159  (
160  czMatcher.empty()
161  ? identity(czNames.size()) // All
162  : czMatcher.matching(czNames) // Selected names
163  );
164 
165 
166  // Possible faceZones
167  const wordList fzNames =
168  (
169  option().useFaceZones()
170  ? mesh_.faceZones().names()
171  : wordList()
172  );
173 
174  const labelList fzoneIds =
175  (
176  fzMatcher.empty()
177  ? identity(fzNames.size()) // All
178  : fzMatcher.matching(fzNames) // Selected names
179  );
180 
181 
182  // Possible patchNames
183  const wordList patchNames =
184  (
185  option().useBoundaryMesh()
186  ? nonProcessorPatchNames(mesh_.boundaryMesh())
187  : wordList()
188  );
189 
190  const labelList patchIds =
191  (
192  option().useBoundaryMesh()
194  (
195  patchNames,
196  option().patchSelection(),
197  option().patchExclude()
198  )
199  : labelList()
200  );
201 
202 
203  // Track which cells are in a zone or not
204  bitSet cellSelection;
205 
206  // Faces to be excluded from export
207  bitSet excludeFace;
208 
209 
210  // cellZones first
211  for (const label zoneId : czoneIds)
212  {
213  const word& zoneName = czNames[zoneId];
214  const cellZone& zn = mesh_.cellZones()[zoneId];
215 
216  if (returnReduceOr(!zn.empty()))
217  {
218  // Ensure full mesh coverage
219  cellSelection.resize(mesh_.nCells());
220 
221  cellSelection.set(zn);
222 
223  ensightCells& part = cellZoneParts_(zoneId);
224 
225  part.clear();
226  part.identifier() = zoneId;
227  part.rename(zoneName);
228 
229  part.classify(mesh_, zn);
230 
231  // Finalize
232  part.reduce();
233  if (verbose_)
234  {
235  Info<< part.info();
236  }
237  }
238  }
239 
240  if (option().useInternalMesh() && czMatcher.empty())
241  {
242  // The internal mesh:
243  // Either the entire mesh (if no zones specified)
244  // or whatever is leftover as unzoned
245 
246  if (cellZoneParts_.empty())
247  {
248  ensightCells& part = cellZoneParts_(internalZone);
249 
250  part.clear();
251  part.identifier() = internalZone;
252  part.rename("internalMesh");
253 
254  part.classify(mesh_);
255 
256  // Finalize
257  part.reduce();
258  if (verbose_)
259  {
260  Info<< part.info();
261  }
262  }
263  else
264  {
265  // Unzoned cells - flip selection from zoned to unzoned
266  cellSelection.flip();
267 
268  if (returnReduceOr(cellSelection.any()))
269  {
270  ensightCells& part = cellZoneParts_(internalZone);
271 
272  part.clear();
273  part.identifier() = internalZone;
274  part.rename("internalMesh");
275 
276  part.classify(mesh_, cellSelection);
277 
278  // Finalize
279  part.reduce();
280  if (verbose_)
281  {
282  Info<< part.info();
283  }
284  }
285  }
286 
287  // Handled all cells
288  cellSelection.clearStorage();
289  }
290  else if (cellSelection.none())
291  {
292  // No internal, no cellZones selected - just ignore
293  cellSelection.clearStorage();
294  }
295 
296 
297  // Face exclusion based on cellZones
298 
299  if (returnReduceOr(!cellSelection.empty()))
300  {
301  // Ensure full mesh coverage
302  excludeFace.resize(mesh_.nFaces());
303 
304  const labelList& owner = mesh_.faceOwner();
305 
306  forAll(owner, facei)
307  {
308  const label celli = owner[facei];
309 
310  if (!cellSelection.test(celli))
311  {
312  excludeFace.set(facei);
313  }
314  }
315  }
316 
317 
318  // Face exclusion for empty types and neighbour side of coupled
319  // so they are ignored for face zones
320 
321  if (fzoneIds.size())
322  {
323  // Ensure full mesh coverage
324  excludeFace.resize(mesh_.nFaces());
325 
326  for (const polyPatch& p : mesh_.boundaryMesh())
327  {
328  const auto* cpp = isA<coupledPolyPatch>(p);
329 
330  if
331  (
332  isA<emptyPolyPatch>(p)
333  || (cpp && !cpp->owner())
334  )
335  {
336  // Ignore empty patch
337  // Ignore neighbour side of coupled
338  excludeFace.set(p.range());
339  }
340  }
341  }
342 
343 
344  // Patches
345  for (const label patchId : patchIds)
346  {
347  const word& patchName = patchNames[patchId];
348  const polyPatch& p = mesh_.boundaryMesh()[patchId];
349 
350  if (isA<emptyPolyPatch>(p))
351  {
352  // Skip empty patch types
353  continue;
354  }
355  else if (isA<processorPolyPatch>(p))
356  {
357  // Only real (non-processor) boundaries.
358  break;
359  }
360 
361  ensightFaces& part = boundaryParts_(patchId);
362 
363  part.clear();
364  part.identifier() = patchId;
365  part.rename(patchName);
366 
367  part.classify
368  (
369  mesh_.faces(),
370  identity(p.range()),
371  boolList(), // no flip map
372  excludeFace
373  );
374 
375  // Finalize
376  part.reduce();
377  if (verbose_)
378  {
379  Info<< part.info();
380  }
381  if (!part.total())
382  {
383  boundaryParts_.erase(patchId);
384  }
385  }
386 
387 
388  // Face zones
389 
390  for (const label zoneId : fzoneIds)
391  {
392  const word& zoneName = fzNames[zoneId];
393  const faceZone& zn = mesh_.faceZones()[zoneId];
394 
395  ensightFaces& part = faceZoneParts_(zoneId);
396 
397  part.clear();
398  part.identifier() = zoneId;
399  part.rename(zoneName);
400 
401  if (zn.size())
402  {
403  part.classify
404  (
405  mesh_.faces(),
406  zn,
407  zn.flipMap(),
408  excludeFace
409  );
410  }
411 
412  // Finalize
413  part.reduce();
414  if (verbose_)
415  {
416  Info<< part.info();
417  }
418  if (!part.total())
419  {
420  faceZoneParts_.erase(zoneId);
421  }
422  }
423 
425 
426  needsUpdate_ = false;
427 }
428 
429 
431 (
433  bool parallel
434 ) const
435 {
436  if (UPstream::master())
437  {
438  os.beginGeometry();
439  }
440 
441  // The internalMesh, cellZones
442  for (const label id : cellZoneParts_.sortedToc())
443  {
444  cellZoneParts_[id].write(os, mesh_, parallel);
445  }
446 
447  // Patches - sorted by index
448  for (const label id : boundaryParts_.sortedToc())
449  {
450  boundaryParts_[id].write(os, mesh_, parallel);
451  }
452 
453  // Requested faceZones - sorted by index
454  for (const label id : faceZoneParts_.sortedToc())
455  {
456  faceZoneParts_[id].write(os, mesh_, parallel);
457  }
458 
459  // No geometry parts written?
460  // - with lagrangian-only output the VTK EnsightReader still
461  // needs a volume geometry, and ensight usually does too
462  if
463  (
464  cellZoneParts_.empty()
465  && boundaryParts_.empty()
466  && faceZoneParts_.empty()
467  )
468  {
469  ensightCells::writeBox(os, mesh_.bounds());
470  }
471 }
472 
473 
474 // ************************************************************************* //
label patchId(-1)
labelList patchIds
void classify(const polyMesh &mesh)
Classify cell types and set the element lists.
Definition: ensightCells.C:235
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:498
virtual Ostream & write(const char c) override
Write character.
Definition: OBJstream.C:69
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:153
const ensightMesh::options & option() const
Reference to the writer/mesh options.
Definition: ensightMeshI.H:23
InfoProxy< ensightCells > info() const noexcept
Return info proxy, used to print information to a stream.
Definition: ensightCells.H:339
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
void flip()
Invert all bits in the addressable region.
Definition: bitSetI.H:542
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:675
A variant of ensightFile (Ensight writing) that includes the extra geometry file header information...
Operations on lists of strings.
bool any() const
True if any bits in this bitset are set.
Definition: bitSetI.H:408
void resize(const label numElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
Definition: PackedListI.H:455
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void correct()
Update for new mesh.
Definition: ensightMesh.C:133
static void writeBox(ensightGeoFile &os, const boundBox &bb, const label partIndex=0, const word &partName="geometry-box")
Write bounding box geometry. All parameters are only relevant on master No beginGeometry() marker...
dynamicFvMesh & mesh
static wordList nonProcessorPatchNames(const polyBoundaryMesh &bmesh)
Definition: ensightMesh.C:40
label identifier() const noexcept
OpenFOAM identifier (patch, zone, etc), -1 when not in use.
Definition: ensightPart.H:169
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
A class for handling words, derived from Foam::string.
Definition: word.H:63
Sorting/classification of cells (3D) into corresponding ensight element types.
Definition: ensightCells.H:50
void write(ensightGeoFile &os, bool parallel=UPstream::parRun()) const
Write geometry to file (normally in parallel). Adds beginGeometry() marker.
Definition: ensightMesh.C:424
static labelList matching(const wordRe &select, const UList< StringType > &input, const bool invert=false)
Determine the list indices for all matches.
wordList names() const
Return a list of patch names.
wordList patchNames(nPatches)
labelList findMatching(const StringListType &input, const wordRes::filter &pred, AccessOp aop=identityOp())
Return ids for items with matching names.
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:53
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition: bitSet.H:329
void reduce()
Sum element counts across all processes.
Definition: ensightCells.C:131
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const direction noexcept
Definition: Scalar.H:258
bool checkParallelSync(const bool report=false) const
Check whether all procs have all patches and in same order.
void clear()
Set addressable sizes to zero, free up addressing memory.
Definition: ensightCells.C:115
Encapsulation of volume meshes for writing in ensight format. It manages cellZones, facesZone, patches.
Definition: ensightMesh.H:78
OBJstream os(runTime.globalPath()/outputName)
A subset of mesh cells.
Definition: cellZone.H:58
List< word > wordList
List of word.
Definition: fileName.H:59
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition: PackedList.H:388
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
surface1 clear()
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
messageStream Info
Information stream (stdout output on master, null elsewhere)
static const label internalZone
The zone-id for internal mesh or unzoned cells.
Definition: ensightMesh.H:83
Configuration options for the ensightMesh.
Definition: ensightMesh.H:305
void clearStorage()
Clear the list and delete storage.
Definition: PackedListI.H:566
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
int verbose() const noexcept
Output verbosity level.
Definition: ensightMesh.C:119
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
label nNonProcessor() const
The number of patches before the first processor patch.
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
List< bool > boolList
A List of bools.
Definition: List.H:60
bool none() const
True if no bits in this bitset are set.
Definition: bitSetI.H:414
void rename(const string &value)
Change the part name or description.
Definition: ensightPart.H:209
Namespace for OpenFOAM.