Loading...
Searching...
No Matches
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-2025 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "ListOps.H"
35
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37
38const Foam::label Foam::ensightMesh::internalZone = -1;
39
40
41// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42
43void Foam::ensightMesh::clear()
44{
45 cellZoneParts_.clear();
46 faceZoneParts_.clear();
47 boundaryParts_.clear();
48}
49
50
51void Foam::ensightMesh::renumber()
52{
53 label partNo = 0;
54
55 for (const label id : cellZoneParts_.sortedToc())
56 {
57 cellZoneParts_[id].index() = partNo++;
58 }
59
60 for (const label id : boundaryParts_.sortedToc())
61 {
62 boundaryParts_[id].index() = partNo++;
63 }
64
65 for (const label id : faceZoneParts_.sortedToc())
66 {
67 faceZoneParts_[id].index() = partNo++;
68 }
69}
70
71
72// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
73
74Foam::ensightMesh::ensightMesh
75(
77)
78:
79 ensightMesh(mesh, ensightMesh::options())
80{}
81
82
83Foam::ensightMesh::ensightMesh
84(
85 const polyMesh& mesh,
86 const ensightMesh::options& opts
87)
88:
89 options_(new options(opts)),
90 mesh_(mesh),
91 needsUpdate_(true),
92 verbose_(0)
93{
94 if (!option().lazy())
95 {
97 }
98}
99
100
101// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
104{
105 return verbose_;
106}
107
108
109int Foam::ensightMesh::verbose(const int level) noexcept
111 int old(verbose_);
112 verbose_ = level;
113 return old;
114}
115
116
118{
119 clear();
120
121 const auto& pbm = mesh_.boundaryMesh();
122
123 // Selected patch indices
125
126 if (option().useBoundaryMesh())
127 {
128 patchIds = pbm.indices
129 (
130 option().patchSelection(),
131 option().patchExclude()
132 );
133
134 // Prune undesirable patches - empty and processor patches
135 label count = 0;
136 for (const label patchi : patchIds)
137 {
138 const auto& pp = pbm[patchi];
139
141 {
142 continue;
143 }
144 else if (isA<processorPolyPatch>(pp))
145 {
146 break; // No processor patches
147 }
148
149 patchIds[count] = patchi;
150 ++count;
151 }
152 patchIds.resize(count);
153 }
154
155
156 // Selection of cellZones
157 const auto& czMatcher = option().cellZoneSelection();
158
159 // Selected cell zone indices
160 labelList czoneIds;
161
162 if (option().useCellZones())
163 {
164 // Use allow/deny to have desired behaviour with empty selection
165 czoneIds = mesh_.cellZones().indices
166 (
167 option().cellZoneSelection(),
168 option().cellZoneExclude()
169 );
170 }
171
172 // Selected face zone indices
173 labelList fzoneIds;
174
175 if (option().useFaceZones())
176 {
177 // Use allow/deny to have desired behaviour with empty selection
178 fzoneIds = mesh_.faceZones().indices
179 (
180 option().faceZoneSelection(),
181 option().faceZoneExclude()
182 );
183 }
184
185
186 // Track which cells are in a zone or not
187 bitSet cellSelection;
188
189 // Faces to be excluded from export
190 bitSet excludeFace;
191
192
193 // cellZones first
194 for (const label zoneId : czoneIds)
195 {
196 const auto& zn = mesh_.cellZones()[zoneId];
197 const auto& zoneName = zn.name();
198
199 if (returnReduceOr(!zn.empty()))
200 {
201 // Ensure full mesh coverage
202 cellSelection.resize(mesh_.nCells());
203
204 cellSelection.set(zn);
205
206 ensightCells& part = cellZoneParts_(zoneId);
207
208 part.clear();
209 part.identifier() = zoneId;
210 part.rename(zoneName);
211
212 part.classify(mesh_, zn);
213
214 // Finalize
215 part.reduce();
216 if (verbose_)
217 {
218 Info<< part.info();
219 }
220 }
221 }
222
223 if (option().useInternalMesh() && czMatcher.empty())
224 {
225 // The internal mesh:
226 // Either the entire mesh (if no zones specified)
227 // or whatever is leftover as unzoned
228
229 if (cellZoneParts_.empty())
230 {
231 ensightCells& part = cellZoneParts_(internalZone);
232
233 part.clear();
234 part.identifier() = internalZone;
235 part.rename("internalMesh");
236
237 part.classify(mesh_);
238
239 // Finalize
240 part.reduce();
241 if (verbose_)
242 {
243 Info<< part.info();
244 }
245 }
246 else
247 {
248 // Unzoned cells - flip selection from zoned to unzoned
249 cellSelection.flip();
250
251 if (returnReduceOr(cellSelection.any()))
252 {
253 ensightCells& part = cellZoneParts_(internalZone);
254
255 part.clear();
256 part.identifier() = internalZone;
257 part.rename("internalMesh");
258
259 part.classify(mesh_, cellSelection);
260
261 // Finalize
262 part.reduce();
263 if (verbose_)
264 {
265 Info<< part.info();
266 }
267 }
268 }
269
270 // Handled all cells
271 cellSelection.clearStorage();
272 }
273 else if (cellSelection.none())
274 {
275 // No internal, no cellZones selected - just ignore
276 cellSelection.clearStorage();
277 }
278
279
280 // Face exclusion based on cellZones
281
282 if (returnReduceOr(!cellSelection.empty()))
283 {
284 // Ensure full mesh coverage
285 excludeFace.resize(mesh_.nFaces());
286
287 const labelList& owner = mesh_.faceOwner();
288
289 forAll(owner, facei)
290 {
291 const label celli = owner[facei];
292
293 if (!cellSelection.test(celli))
294 {
295 excludeFace.set(facei);
296 }
297 }
298 }
299
300
301 // Face exclusion for empty types and neighbour side of coupled
302 // so they are ignored for face zones
303
304 if (fzoneIds.size())
305 {
306 // Ensure full mesh coverage
307 excludeFace.resize(mesh_.nFaces());
308
309 for (const polyPatch& p : pbm)
310 {
311 const auto* cpp = isA<coupledPolyPatch>(p);
312
313 if
314 (
316 || (cpp && !cpp->owner())
317 )
318 {
319 // Ignore empty patch
320 // Ignore neighbour side of coupled
321 excludeFace.set(p.range());
322 }
323 }
324 }
325
326
327 // Patches
328 for (const label patchId : patchIds)
329 {
330 const auto& p = pbm[patchId];
331 const auto& patchName = p.name();
332
334 {
335 // Skip empty patch types
336 continue;
337 }
338 else if (isA<processorPolyPatch>(p))
339 {
340 // Only real (non-processor) boundaries.
341 break;
342 }
343
344 ensightFaces& part = boundaryParts_(patchId);
345
346 part.clear();
347 part.identifier() = patchId;
348 part.rename(patchName);
349
350 part.classify
351 (
352 mesh_.faces(),
353 identity(p.range()),
354 boolList(), // no flip map
355 excludeFace
356 );
357
358 // Finalize
359 part.reduce();
360 if (verbose_)
361 {
362 Info<< part.info();
363 }
364 if (!part.total())
365 {
366 boundaryParts_.erase(patchId);
367 }
368 }
369
370
371 // Face zones
372 for (const label zoneId : fzoneIds)
373 {
374 const auto& zn = mesh_.faceZones()[zoneId];
375 const auto& zoneName = zn.name();
376
377 ensightFaces& part = faceZoneParts_(zoneId);
378
379 part.clear();
380 part.identifier() = zoneId;
381 part.rename(zoneName);
382
383 if (zn.size())
384 {
385 part.classify
386 (
387 mesh_.faces(),
388 zn,
389 zn.flipMap(),
390 excludeFace
391 );
392 }
393
394 // Finalize
395 part.reduce();
396 if (verbose_)
397 {
398 Info<< part.info();
399 }
400 if (!part.total())
401 {
402 faceZoneParts_.erase(zoneId);
403 }
404 }
406 renumber();
407
408 needsUpdate_ = false;
409}
410
411
413(
415 bool parallel
416) const
417{
418 if (UPstream::master())
419 {
420 os.beginGeometry();
421 }
422
423 // The internalMesh, cellZones
424 for (const label id : cellZoneParts_.sortedToc())
425 {
426 cellZoneParts_[id].write(os, mesh_, parallel);
427 }
428
429 // Patches - sorted by index
430 for (const label id : boundaryParts_.sortedToc())
431 {
432 boundaryParts_[id].write(os, mesh_, parallel);
433 }
434
435 // Requested faceZones - sorted by index
436 for (const label id : faceZoneParts_.sortedToc())
437 {
438 faceZoneParts_[id].write(os, mesh_, parallel);
439 }
440
441 // No geometry parts written?
442 // - with lagrangian-only output the VTK EnsightReader still
443 // needs a volume geometry, and ensight usually does too
444 if
445 (
446 cellZoneParts_.empty()
447 && boundaryParts_.empty()
448 && faceZoneParts_.empty()
449 )
450 {
451 ensightCells::writeBox(os, mesh_.bounds());
452 }
453}
454
455
456// ************************************************************************* //
Various functions to operate on Lists.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
const word & name() const noexcept
Return the object name.
Definition IOobjectI.H:205
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition PackedList.H:387
void resize(const label numElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
void clearStorage()
Clear the list and delete storage.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
void flip()
Invert all bits in the addressable region.
Definition bitSetI.H:546
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
bool none() const
True if no bits in this bitset are set.
Definition bitSetI.H:414
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition bitSet.H:334
bool any() const
True if any bits in this bitset are set.
Definition bitSetI.H:408
Sorting/classification of cells (3D) into corresponding ensight element types.
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.
void reduce()
Sum element counts across all processes.
void classify(const polyMesh &mesh)
Classify cell types and set the element lists.
InfoProxy< ensightCells > info() const noexcept
Return info proxy, used to print information to a stream.
void clear()
Set addressable sizes to zero, free up addressing memory.
Sorting/classification of faces (2D) into corresponding ensight types.
void classify(const UList< face > &faces)
Classify the face types and set the element lists.
label total() const noexcept
Same as totalSize.
void reduce()
Sum element counts across all processes.
InfoProxy< ensightFaces > info() const noexcept
Return info proxy, used to print information to a stream.
void clear()
Set addressable sizes to zero, free up addressing memory.
A variant of ensightFile (Ensight writing) that includes the extra geometry file header information.
Configuration options for the ensightMesh.
void write(ensightGeoFile &os, bool parallel=UPstream::parRun()) const
Write geometry to file (normally in parallel). Adds beginGeometry() marker.
void correct()
Update for new mesh.
int verbose() const noexcept
Output verbosity level.
Definition ensightMesh.C:96
const ensightMesh::options & option() const
Reference to the writer/mesh options.
static const label internalZone
The zone-id for internal mesh or unzoned cells.
Definition ensightMesh.H:88
const polyMesh & mesh() const noexcept
Reference to the underlying polyMesh.
void rename(const string &value)
Change the part name or description.
label identifier() const noexcept
OpenFOAM identifier (patch, zone, etc), -1 when not in use.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
volScalarField & p
labelList patchIds
dynamicFvMesh & mesh
OBJstream os(runTime.globalPath()/outputName)
label patchId(-1)
surface1 clear()
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
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...
List< bool > boolList
A List of bools.
Definition List.H:60
const direction noexcept
Definition scalarImpl.H:265
bool isType(const U &obj)
Check if typeid of the object and Type are identical.
Definition typeInfo.H:112
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299