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-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
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 
39 void 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 
79 void 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 
109 void 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 
189 void 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.back()
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 
335 void 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  {
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  // processor-local offsets for faceLabels
435  const label labelsOffset =
437 
438  labelList faceOffsetsRenumber;
439 
440  if (faceOffsets.size()) // Or check faceLabels.size()
441  {
442  faceOffsetsRenumber =
444  (
445  faceOffsets,
446  labelsOffset
447  );
448  }
449  else
450  {
451  faceOffsetsRenumber.resize(nLocalCells, -1);
452  }
453 
454  vtk::writeListParallel(format_.ref(), faceOffsetsRenumber);
455  }
456  else
457  {
458  vtk::writeList(format(), faceOffsets);
459  }
460 
461 
462  if (format_)
463  {
464  format().flush();
465  format().endDataArray();
466  }
467  }
468 }
469 
470 
471 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
472 
473 Foam::vtk::internalMeshWriter::internalMeshWriter
474 (
475  const polyMesh& mesh,
476  const vtk::vtuCells& cells,
477  const vtk::outputOptions opts
478 )
479 :
480  vtk::fileWriter(vtk::fileTag::UNSTRUCTURED_GRID, opts),
481  numberOfPoints_(0),
482  numberOfCells_(0),
483 
484  mesh_(mesh),
485  vtuCells_(cells)
486 {
487  // We do not currently support append mode
488  opts_.append(false);
489 }
490 
491 
492 Foam::vtk::internalMeshWriter::internalMeshWriter
493 (
494  const polyMesh& mesh,
495  const vtk::vtuCells& cells,
496  const fileName& file,
497  bool parallel
498 )
499 :
501 {
502  open(file, parallel);
503 }
504 
505 
506 Foam::vtk::internalMeshWriter::internalMeshWriter
507 (
508  const polyMesh& mesh,
509  const vtk::vtuCells& cells,
510  const vtk::outputOptions opts,
511  const fileName& file,
512  bool parallel
513 )
514 :
516 {
517  open(file, parallel);
518 }
519 
520 
521 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
522 
523 bool Foam::vtk::internalMeshWriter::beginFile(std::string title)
524 {
525  if (title.size())
526  {
527  return vtk::fileWriter::beginFile(title);
528  }
529 
530  // Provide default title
531 
533  << "case=" << mesh_.time().caseName()
534  << " region=" << mesh_.name()
535  << " time=" << mesh_.time().timeName()
536  << " index=" << mesh_.time().timeIndex() << endl;
537 
538 
539  if (legacy())
540  {
542  (
543  mesh_.time().globalCaseName()
544  );
545  }
546 
547 
548  // XML (inline)
549 
551  (
552  "case='" + mesh_.time().globalCaseName()
553  + "' region='" + mesh_.name()
554  + "' time='" + mesh_.time().timeName()
555  + "' index='" + Foam::name(mesh_.time().timeIndex())
556  + "'"
557  );
558 }
559 
560 
562 {
563  enter_Piece();
564 
565  beginPiece();
566 
567  writePoints();
568 
569  // Include addPointCellLabels for the point offsets
570  const label pointOffset =
571  (
572  parallel_ ? globalIndex::calcOffset(vtuCells_.nFieldPoints()) : 0
573  );
574 
575  if (legacy())
576  {
577  writeCellsLegacy(pointOffset);
578  return true;
579  }
580 
581  if (format_)
582  {
584  }
585 
586  writeCellsConnectivity(pointOffset);
587  writeCellsFaces(pointOffset);
588 
589  if (format_)
590  {
592  }
593 
594  return true;
595 }
596 
599 {
600  return enter_CellData(numberOfCells_, nFields);
601 }
602 
605 {
606  return enter_PointData(numberOfPoints_, nFields);
607 }
608 
609 
611 {
612  if (isState(outputState::CELL_DATA))
613  {
614  ++nCellData_;
615  }
616  else
617  {
619  << " for cellID field" << nl << endl
620  << exit(FatalError);
621  }
622 
623  const labelList& cellMap = vtuCells_.cellMap();
624 
625 
626  this->beginDataArray<label>("cellID", numberOfCells_);
627 
628  if (parallel_)
629  {
630  // With decomposed cells for the cell offsets
631  const globalIndex globalCellOffset(vtuCells_.nFieldCells());
632 
633  vtk::writeListParallel(format_.ref(), cellMap, globalCellOffset);
634  }
635  else
636  {
637  vtk::writeList(format(), cellMap);
638  }
639 
640  this->endDataArray();
641 }
642 
643 
645 {
646  if (!parallel_)
647  {
648  // Disabled in serial output (meaningless)
649  return false;
650  }
651 
652  return vtk::fileWriter::writeProcIDs(vtuCells_.nFieldCells());
653 }
654 
655 
657 {
658  if (isState(outputState::POINT_DATA))
659  {
660  ++nPointData_;
661  }
662  else
663  {
665  << " for pointID field" << nl << endl
666  << exit(FatalError);
667  }
668 
669 
670  this->beginDataArray<label>("pointID", numberOfPoints_);
671 
672  // Point offset for regular mesh points (without decomposed)
673  const label pointOffset =
674  (
675  parallel_ ? globalIndex::calcOffset(vtuCells_.nPoints()) : 0
676  );
677 
678  // Cell offset for *regular* mesh cells (without decomposed)
679  const label cellOffset =
680  (
681  parallel_ ? globalIndex::calcOffset(vtuCells_.nCells()) : 0
682  );
683 
684 
685  labelList pointIds = identity(vtuCells_.nFieldPoints(), pointOffset);
686 
687  // The pointID for added points is the cellID, tag as a negative number
688  label pointi = vtuCells_.nPoints();
689  for (const label celli : vtuCells_.addPointCellLabels())
690  {
691  pointIds[pointi] = (-1 - celli - cellOffset);
692  ++pointi;
693  }
694 
695  if (parallel_)
696  {
697  vtk::writeListParallel(format_.ref(), pointIds);
698  }
699  else
700  {
701  vtk::writeList(format(), pointIds);
702  }
703 
704  this->endDataArray();
705 }
706 
707 
708 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
autoPtr< vtk::formatter > format_
The VTK formatter in use (only valid on master process)
A class for handling file names.
Definition: fileName.H:72
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 writePointIDs()
Write point ids as PointData.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
vtk::formatter & format()
The VTK formatter in use. FatalError for off-processor.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
static int debug
Debug information.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void writeListsParallel(vtk::formatter &fmt, const UList< Type > &values1, const UList< Type > &values2)
Write a list of values and another list of values.
virtual bool beginCellData(label nFields=0)
Begin CellData output section for specified number of fields.
label nFieldPoints() const noexcept
Number of field points = nPoints + nAddPoints.
virtual bool beginPointData(label nFields=0)
Begin PointData for specified number of fields.
labelList faceLabels(nFaceLabels)
bool parallel_
Parallel writing (via master)
bool writeProcIDs()
Write processor ids as CellData. This is no-op in serial.
bool legacy() const noexcept
Commonly used query.
const vtuCells & vtuCells_
The volume cells (internalMesh)
label numberOfPoints_
The number of field points for the current Piece.
Encapsulated combinations of output format options. This is primarily useful when defining the output...
void beginPoints(std::ostream &os, label nPoints)
Emit header for POINTS (with trailing newline).
label numberOfCells_
The number of field cells for the current Piece.
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const cellShapeList & cells
static labelList copyFaceLabelsXml(const labelUList &faceLabels, const label globalPointOffset)
Copy faces stream labels with a global point offset - XML format.
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
bool writeProcIDs(const label nValues)
Write nValues of processor ids as CellData or PointData (no-op in serial)
#define DebugInFunction
Report an information message using Foam::Info.
label nFaceLabels
static labelList copyVertLabelsLegacy(const labelUList &connectivity, const label globalPointOffset)
Copy vertex labels with a global point offset - legacy format.
const labelList & cellTypes
Definition: setCellMask.H:27
static labelList copyVertLabelsXml(const labelUList &connectivity, const label globalPointOffset)
Copy vertex labels with a global point offset - XML format.
void writeList(vtk::formatter &fmt, const UList< uint8_t > &values)
Write a list of uint8_t values.
label nFieldCells() const noexcept
Number of field cells = nCells + nAddCells.
Write an OpenFOAM volume (internal) geometry and internal fields as a vtu file or a legacy vtk file...
word format(conversionProperties.get< word >("format"))
virtual bool beginFile(std::string title="")
Write file header (non-collective)
fileTag
Some common XML tags for vtk files.
Definition: foamVtkCore.H:122
static labelList copyFaceOffsetsXml(const labelUList &faceOffsets, const label prevOffset)
Copy face offsets with an offset from previous - XML format.
#define PoutInFunction
Report using Foam::Pout with FUNCTION_NAME prefix.
void writeListParallel(vtk::formatter &fmt, const UList< Type > &values)
Write a list of values.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
List< label > labelList
A List of labels.
Definition: List.H:62
virtual bool writeGeometry()
Write mesh topology.
static label calcOffset(const label localSize, const label comm=UPstream::worldComm, const bool checkOverflow=false)
Calculate globally-consistent local start offset based on the local input size(s).
Definition: globalIndex.C:125
formatter & tag(const word &t, Args &&... args)
Write XML tag without any attributes. Combines openTag/closeTag.
virtual bool beginFile(std::string title="")
Write file header (non-collective)
A deep-copy description of an OpenFOAM volume mesh in data structures suitable for VTK UnstructuredGr...
Definition: foamVtuCells.H:66
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
void writeCellIDs()
Write cell ids as CellData.