foamVtkInternalMeshWriter.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) 2017-2021 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
29#include "globalIndex.H"
30#include "Time.H"
31
32// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33
35
36
37// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38
39void Foam::vtk::internalMeshWriter::beginPiece()
40{
41 // Basic sizes
42
43 numberOfPoints_ = vtuCells_.nFieldPoints(); // With addPointCellLabels
44 numberOfCells_ = vtuCells_.nFieldCells(); // With decomposed cells
45
46 if (parallel_)
47 {
48 if (debug > 1)
49 {
51 << ": nPoints=" << numberOfPoints_
52 << " nCells=" << numberOfCells_ << nl;
53 }
54
55 reduce(numberOfPoints_, sumOp<label>());
56 reduce(numberOfCells_, sumOp<label>());
57 }
58
60 << "nPoints=" << numberOfPoints_
61 << " nCells=" << numberOfCells_ << nl;
62
63 // Nothing else to do for legacy
64 if (legacy()) return;
65
66 if (format_)
67 {
68 format()
69 .tag
70 (
74 );
75 }
76}
77
78
79void Foam::vtk::internalMeshWriter::writePoints()
80{
81 this->beginPoints(numberOfPoints_);
82
83 if (parallel_)
84 {
86 (
87 format_.ref(),
88 mesh_.points(),
89 mesh_.cellCentres(),
90 vtuCells_.addPointCellLabels()
91 );
92 }
93 else
94 {
96 (
97 format(),
98 mesh_.points(),
99 mesh_.cellCentres(),
100 vtuCells_.addPointCellLabels()
101 );
102 }
103
104
105 this->endPoints();
106}
107
108
109void Foam::vtk::internalMeshWriter::writeCellsLegacy(const label pointOffset)
110{
111 const List<uint8_t>& cellTypes = vtuCells_.cellTypes();
112 const labelList& vertLabels = vtuCells_.vertLabels();
113
114 label nCells = cellTypes.size();
115 label nVerts = vertLabels.size();
116
117 if (parallel_)
118 {
119 reduce(nCells, sumOp<label>());
120 reduce(nVerts, sumOp<label>());
121 }
122
123 if (nCells != numberOfCells_)
124 {
126 << "Expecting " << numberOfCells_
127 << " cells, but found " << nCells
128 << exit(FatalError);
129 }
130
131
132 // CELLS
133 {
134 if (format_)
135 {
136 os_ << nl
137 << "CELLS " << nCells << ' ' << nVerts << nl;
138 }
139
140 if (parallel_)
141 {
143 (
144 format_.ref(),
146 (
147 vertLabels,
148 pointOffset
149 )
150 );
151 }
152 else
153 {
154 vtk::writeList(format(), vertLabels);
155 }
156
157 if (format_)
158 {
159 format().flush();
160 }
161 }
162
163
164 // CELL_TYPES
165 {
166 if (format_)
167 {
168 os_ << nl
169 << "CELL_TYPES " << nCells << nl;
170 }
171
172 if (parallel_)
173 {
174 vtk::writeListParallel(format_.ref(), cellTypes);
175 }
176 else
177 {
179 }
180
181 if (format_)
182 {
183 format().flush();
184 }
185 }
186}
187
188
189void Foam::vtk::internalMeshWriter::writeCellsConnectivity
190(
191 const label pointOffset
192)
193{
194 //
195 // 'connectivity'
196 //
197 {
198 const labelList& vertLabels = vtuCells_.vertLabels();
199 label nVerts = vertLabels.size();
200
201 if (parallel_)
202 {
203 reduce(nVerts, sumOp<label>());
204 }
205
206 if (format_)
207 {
208 const uint64_t payLoad = vtk::sizeofData<label>(nVerts);
209
210 format().beginDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY);
211 format().writeSize(payLoad);
212 }
213
214 if (parallel_)
215 {
217 (
218 format_.ref(),
220 (
221 vertLabels,
222 pointOffset
223 )
224 );
225 }
226 else
227 {
228 vtk::writeList(format(), vertLabels);
229 }
230
231 if (format_)
232 {
233 format().flush();
234 format().endDataArray();
235 }
236 }
237
238
239 //
240 // 'offsets' (connectivity offsets)
241 //
242 {
243 const labelList& vertOffsets = vtuCells_.vertOffsets();
244 label nOffs = vertOffsets.size();
245
246 if (parallel_)
247 {
248 reduce(nOffs, sumOp<label>());
249 }
250
251 if (format_)
252 {
253 const uint64_t payLoad =
254 vtk::sizeofData<label>(nOffs);
255
256 format().beginDataArray<label>(vtk::dataArrayAttr::OFFSETS);
257 format().writeSize(payLoad);
258 }
259
260 if (parallel_)
261 {
262 // processor-local connectivity offsets
263 const globalIndex procOffset
264 (
265 vertOffsets.empty() ? 0 : vertOffsets.last()
266 );
267
268 vtk::writeListParallel(format_.ref(), vertOffsets, procOffset);
269 }
270 else
271 {
272 vtk::writeList(format(), vertOffsets);
273 }
274
275 if (format_)
276 {
277 format().flush();
278 format().endDataArray();
279 }
280 }
281
282
283 //
284 // 'types' (cell types)
285 //
286 {
287 const List<uint8_t>& cellTypes = vtuCells_.cellTypes();
288 label nCells = cellTypes.size();
289
290 if (parallel_)
291 {
292 reduce(nCells, sumOp<label>());
293 }
294
295 if (nCells != numberOfCells_)
296 {
298 << "Expecting " << numberOfCells_
299 << " cells, but found " << nCells
300 << exit(FatalError);
301 }
302
303 if (format_)
304 {
305 const uint64_t payLoad =
306 vtk::sizeofData<uint8_t>(nCells);
307
308 format().beginDataArray<uint8_t>(vtk::dataArrayAttr::TYPES);
309 format().writeSize(payLoad);
310 }
311
312 if (parallel_)
313 {
314 vtk::writeListParallel(format_.ref(), cellTypes);
315 }
316 else
317 {
318// FIXME: clang-13 optimization jumps into incorrect branch
319 #ifdef __clang__
320 checkFormatterValidity();
321 #endif
322
324 }
325
326 if (format_)
327 {
328 format().flush();
329 format().endDataArray();
330 }
331 }
332}
333
334
335void Foam::vtk::internalMeshWriter::writeCellsFaces
336(
337 const label pointOffset
338)
339{
340 label nFaceLabels = vtuCells_.faceLabels().size();
341
342 if (parallel_)
343 {
344 reduce(nFaceLabels, sumOp<label>());
345 }
346
347 // Can quit now if there are NO face streams
348 if (!nFaceLabels)
349 {
350 return;
351 }
352
353 // --------------------------------------------------
354
355 //
356 // 'faces' (face streams)
357 //
358 const labelList& faceLabels = vtuCells_.faceLabels();
359
360 {
361 // Already have nFaceLabels (above)
362
363 if (format_)
364 {
365 const uint64_t payLoad =
366 vtk::sizeofData<label>(nFaceLabels);
367
368 format().beginDataArray<label>(vtk::dataArrayAttr::FACES);
369 format().writeSize(payLoad);
370 }
371
372
373 if (parallel_)
374 {
376 (
377 format_.ref(),
379 (
380 faceLabels,
381 pointOffset
382 )
383 );
384 }
385 else
386 {
387 vtk::writeList(format(), faceLabels);
388 }
389
390
391 if (format_)
392 {
393 format().flush();
394 format().endDataArray();
395 }
396 }
397
398 // 'faceoffsets' (face stream offsets)
399 // -1 to indicate that the cell is a primitive type that does not
400 // have a face stream
401
402 // If the processor-local mesh has any polyhedrals, we have a list with
403 // the faceoffsets and we just need to renumber.
404 // If the processor-local mesh has NO polyhedrals (but others do), we
405 // need to generate a list of -1 for that processor.
406 //
407 // Result: A face offset value for each cell.
408 {
409 const labelList& faceOffsets = vtuCells_.faceOffsets();
410 const label nLocalCells = vtuCells_.cellTypes().size();
411
412 label nCells = nLocalCells;
413
414 if (parallel_)
415 {
416 reduce(nCells, sumOp<label>());
417 }
418
419 if (format_)
420 {
421 const uint64_t payLoad =
422 vtk::sizeofData<label>(nCells);
423
424 format().beginDataArray<label>(vtk::dataArrayAttr::FACEOFFSETS);
425 format().writeSize(payLoad);
426 }
427
428
429 if (parallel_)
430 {
431 const List<uint8_t>& cellTypes = vtuCells_.cellTypes();
432 const label nLocalCells = cellTypes.size();
433
434 const globalIndex procOffset(faceLabels.size());
435
436 labelList faceOffsetsRenumber;
437
438 if (faceOffsets.size()) // Or check procOffset.localSize()
439 {
440 faceOffsetsRenumber =
442 (
443 faceOffsets,
444 procOffset.localStart()
445 );
446 }
447 else
448 {
449 faceOffsetsRenumber.resize(nLocalCells, -1);
450 }
451
452 vtk::writeListParallel(format_.ref(), faceOffsetsRenumber);
453 }
454 else
455 {
456 vtk::writeList(format(), faceOffsets);
457 }
458
459
460 if (format_)
461 {
462 format().flush();
463 format().endDataArray();
464 }
465 }
466}
467
468
469// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
470
472(
473 const polyMesh& mesh,
474 const vtk::vtuCells& cells,
475 const vtk::outputOptions opts
476)
477:
478 vtk::fileWriter(vtk::fileTag::UNSTRUCTURED_GRID, opts),
479 numberOfPoints_(0),
480 numberOfCells_(0),
481
482 mesh_(mesh),
483 vtuCells_(cells)
484{
485 // We do not currently support append mode
486 opts_.append(false);
487}
488
489
491(
492 const polyMesh& mesh,
493 const vtk::vtuCells& cells,
494 const fileName& file,
495 bool parallel
496)
497:
499{
500 open(file, parallel);
501}
502
503
505(
506 const polyMesh& mesh,
507 const vtk::vtuCells& cells,
508 const vtk::outputOptions opts,
509 const fileName& file,
510 bool parallel
511)
512:
514{
515 open(file, parallel);
516}
517
518
519// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
520
522{
523 if (title.size())
524 {
525 return vtk::fileWriter::beginFile(title);
526 }
527
528 // Provide default title
529
531 << "case=" << mesh_.time().caseName()
532 << " region=" << mesh_.name()
533 << " time=" << mesh_.time().timeName()
534 << " index=" << mesh_.time().timeIndex() << endl;
535
536
537 if (legacy())
538 {
540 (
541 mesh_.time().globalCaseName()
542 );
543 }
544
545
546 // XML (inline)
547
549 (
550 "case='" + mesh_.time().globalCaseName()
551 + "' region='" + mesh_.name()
552 + "' time='" + mesh_.time().timeName()
553 + "' index='" + Foam::name(mesh_.time().timeIndex())
554 + "'"
555 );
556}
557
558
560{
561 enter_Piece();
562
563 beginPiece();
564
565 writePoints();
566
567 // Include addPointCellLabels for the point offsets
568 const label pointOffset =
569 (
570 parallel_ ? globalIndex(vtuCells_.nFieldPoints()).localStart() : 0
571 );
572
573 if (legacy())
574 {
575 writeCellsLegacy(pointOffset);
576 return true;
577 }
578
579 if (format_)
580 {
582 }
583
584 writeCellsConnectivity(pointOffset);
585 writeCellsFaces(pointOffset);
586
587 if (format_)
588 {
589 format().endTag(vtk::fileTag::CELLS);
590 }
591
592 return true;
593}
594
595
597{
598 return enter_CellData(numberOfCells_, nFields);
599}
600
601
603{
604 return enter_PointData(numberOfPoints_, nFields);
605}
606
607
609{
610 if (isState(outputState::CELL_DATA))
611 {
612 ++nCellData_;
613 }
614 else
615 {
616 reportBadState(FatalErrorInFunction, outputState::CELL_DATA)
617 << " for cellID field" << nl << endl
618 << exit(FatalError);
619 }
620
621 const labelList& cellMap = vtuCells_.cellMap();
622
623
624 this->beginDataArray<label>("cellID", numberOfCells_);
625
626 if (parallel_)
627 {
628 // With decomposed cells for the cell offsets
629 const globalIndex globalCellOffset(vtuCells_.nFieldCells());
630
631 vtk::writeListParallel(format_.ref(), cellMap, globalCellOffset);
632 }
633 else
634 {
635 vtk::writeList(format(), cellMap);
636 }
637
638 this->endDataArray();
639}
640
641
643{
644 if (!parallel_)
645 {
646 // Disabled in serial output (meaningless)
647 return false;
648 }
649
650 return vtk::fileWriter::writeProcIDs(vtuCells_.nFieldCells());
651}
652
653
655{
656 if (isState(outputState::POINT_DATA))
657 {
658 ++nPointData_;
659 }
660 else
661 {
662 reportBadState(FatalErrorInFunction, outputState::POINT_DATA)
663 << " for pointID field" << nl << endl
664 << exit(FatalError);
665 }
666
667
668 this->beginDataArray<label>("pointID", numberOfPoints_);
669
670 // Point offset for regular mesh points (without decomposed)
671 const label pointOffset =
672 (
673 parallel_ ? globalIndex(vtuCells_.nPoints()).localStart() : 0
674 );
675
676 // Cell offset for *regular* mesh cells (without decomposed)
677 const label cellOffset =
678 (
679 parallel_ ? globalIndex(vtuCells_.nCells()).localStart() : 0
680 );
681
682
683 labelList pointIds = identity(vtuCells_.nFieldPoints(), pointOffset);
684
685 // The pointID for added points is the cellID, tag as a negative number
686 label pointi = vtuCells_.nPoints();
687 for (const label celli : vtuCells_.addPointCellLabels())
688 {
689 pointIds[pointi] = (-1 - celli - cellOffset);
690 ++pointi;
691 }
692
693 if (parallel_)
694 {
695 vtk::writeListParallel(format_.ref(), pointIds);
696 }
697 else
698 {
699 vtk::writeList(format(), pointIds);
700 }
701
702 this->endDataArray();
703}
704
705
706// ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A class for handling file names.
Definition: fileName.H:76
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
label localStart() const
My local start.
Definition: globalIndexI.H:195
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
Base class for VTK output writers that handle geometry and fields (eg, vtp, vtu data)....
bool legacy() const noexcept
Commonly used query.
autoPtr< vtk::formatter > format_
The VTK formatter in use (only valid on master process)
bool parallel_
Parallel writing (via master)
bool parallel() const noexcept
Parallel output requested?
vtk::outputOptions opts_
Requested output options.
virtual bool open(const fileName &file, bool parallel=Pstream::parRun())
Open file for writing (creates parent directory).
virtual bool beginFile(std::string title="")
Write file header (non-collective)
vtk::formatter & format()
The VTK formatter in use. FatalError for off-processor.
formatter & beginPointData()
Begin "PointData" XML section.
formatter & tag(const word &t, Args &&... args)
Write XML tag without any attributes. Combines openTag/closeTag.
formatter & beginCellData()
Begin "CellData" XML section.
Write an OpenFOAM volume (internal) geometry and internal fields as a vtu file or a legacy vtk file.
void writePointIDs()
Write point ids as PointData.
label numberOfPoints_
The number of field points for the current Piece.
label numberOfCells_
The number of field cells for the current Piece.
bool writeProcIDs()
Write processor ids as CellData. This is no-op in serial.
static int debug
Debug information.
virtual bool writeGeometry()
Write mesh topology.
virtual bool beginFile(std::string title="")
Write file header (non-collective)
const vtuCells & vtuCells_
The volume cells (internalMesh)
void writeCellIDs()
Write cell ids as CellData.
Encapsulated combinations of output format options. This is primarily useful when defining the output...
bool append() const noexcept
True if output format uses an append mode.
A deep-copy description of an OpenFOAM volume mesh in data structures suitable for VTK UnstructuredGr...
Definition: foamVtuCells.H:73
static labelList copyFaceLabelsXml(const labelUList &faceLabels, const label globalPointOffset)
Copy faces stream labels with a global point offset - XML format.
static labelList copyFaceOffsetsXml(const labelUList &faceOffsets, const label prevOffset)
Copy face offsets with an offset from previous - XML format.
static labelList copyVertLabelsXml(const labelUList &connectivity, const label globalPointOffset)
Copy vertex labels with a global point offset - XML format.
static labelList copyVertLabelsLegacy(const labelUList &connectivity, const label globalPointOffset)
Copy vertex labels with a global point offset - legacy format.
label nFieldPoints() const noexcept
Number of field points = nPoints + nAddPoints.
label nFieldCells() const noexcept
Number of field cells = nCells + nAddCells.
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const cellShapeList & cells
#define PoutInFunction
Report using Foam::Pout with FUNCTION_NAME prefix.
#define DebugInFunction
Report an information message using Foam::Info.
void beginPoints(std::ostream &os, label nPoints)
Emit header for POINTS (with trailing newline).
@ NUMBER_OF_CELLS
"NumberOfCells"
@ NUMBER_OF_POINTS
"NumberOfPoints"
@ FACEOFFSETS
"faceoffsets"
@ CONNECTIVITY
"connectivity"
fileTag
Some common XML tags for vtk files.
Definition: foamVtkCore.H:114
@ UNSTRUCTURED_GRID
"UnstructuredGrid"
void writeListsParallel(vtk::formatter &fmt, const UList< Type > &values1, const UList< Type > &values2)
Write a list of values and another list of values.
void writeLists(vtk::formatter &fmt, const UList< Type > &values1, const UList< Type > &values2, const labelUList &addressing)
Write a list of values and a list of values via indirect addressing.
void writeList(vtk::formatter &fmt, const UList< uint8_t > &values)
Write a list of uint8_t values.
void writeListParallel(vtk::formatter &fmt, const UList< Type > &values)
Write a list of values.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
List< label > labelList
A List of labels.
Definition: List.H:66
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
word format(conversionProperties.get< word >("format"))
const labelList & cellTypes
Definition: setCellMask.H:33