foamVtkFileWriter.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) 2018-2021 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 
28 #include "foamVtkFileWriter.H"
29 #include "globalIndex.H"
30 #include "OSspecific.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 const Foam::Enum
35 <
37 >
39 ({
40  { outputState::CLOSED, "closed" },
41  { outputState::OPENED, "opened" },
42  { outputState::DECLARED, "declared" },
43  { outputState::FIELD_DATA, "FieldData" },
44  { outputState::PIECE, "Piece" },
45  { outputState::CELL_DATA, "CellData" },
46  { outputState::POINT_DATA, "PointData" },
47 });
48 
49 
50 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
51 
53 {
54  // In parallel can be unallocated on non-master nodes
55  if ((parallel_ ? Pstream::master() : true) && !format_)
56  {
58  << "unallocated formatter" << endl
59  << exit(FatalError);
60  }
61 }
62 
63 
65 (
66  Ostream& os,
67  outputState expected
68 ) const
69 {
70  os << "Bad writer state (" << stateNames[state_]
71  << ") - should be (" << stateNames[expected] << ')';
72  return os;
73 }
74 
75 
77 (
78  Ostream& os,
79  outputState expected,
80  outputState expected2
81 ) const
82 {
83  reportBadState(os, expected)
84  << " or (" << stateNames[expected2] << ')';
85  return os;
86 }
87 
88 
90 {
91  // Finish other output
92  endFieldData();
93 
94  if (isState(outputState::OPENED))
95  {
96  beginFile();
97  }
98  if (notState(outputState::DECLARED))
99  {
100  reportBadState(FatalErrorInFunction, outputState::DECLARED)
101  << exit(FatalError);
102  }
103  state_ = outputState::PIECE;
104  nCellData_ = nPointData_ = 0;
105 
106  return true;
107 }
108 
109 
111 {
112  // Finish other output
113  endCellData();
114  endPointData();
115 
116  if (notState(outputState::PIECE))
117  {
118  // Skip if not in Piece
119  return false;
120  }
121  state_ = outputState::DECLARED; // Mark as having been flushed
122 
123  if (format_)
124  {
125  format().endPiece();
126  }
127 
128  return true;
129 }
130 
131 
132 bool Foam::vtk::fileWriter::enter_CellData(label nEntries, label nFields)
133 {
134  // Already in CellData?
135  if (isState(outputState::CELL_DATA)) return false;
136 
137  // Finish other output
138  endPointData();
139 
140  if (notState(outputState::PIECE))
141  {
143  << exit(FatalError);
144  }
145 
146  nCellData_ = 0;
147 
148  // Do nothing for legacy when nFields == 0
149  if (legacy() && !nFields) return false;
150 
151  state_ = outputState::CELL_DATA;
152 
153  if (format_)
154  {
155  if (legacy())
156  {
157  legacy::beginCellData(format(), nEntries, nFields);
158  }
159  else
160  {
161  format().beginCellData();
162  }
163  }
164 
165  return true;
166 }
167 
168 
169 bool Foam::vtk::fileWriter::enter_PointData(label nEntries, label nFields)
170 {
171  // Already in PointData?
172  if (isState(outputState::POINT_DATA)) return false;
173 
174  // Finish other output
175  endCellData();
176 
177  if (notState(outputState::PIECE))
178  {
180  << exit(FatalError);
181  }
182 
183  nPointData_ = 0;
184 
185  // Do nothing for legacy when nFields == 0
186  if (legacy() && !nFields) return false;
187 
188  state_ = outputState::POINT_DATA;
189 
190  if (format_)
191  {
192  if (legacy())
193  {
194  legacy::beginPointData(format(), nEntries, nFields);
195  }
196  else
197  {
198  format().beginPointData();
199  }
200  }
201 
202  return true;
203 }
204 
205 
207 {
208  if (format_)
209  {
210  format().flush();
211  format().endDataArray();
212  }
213 }
214 
215 
217 {
218  if (format_)
219  {
220  if (legacy())
221  {
223  }
224  else
225  {
226  const uint64_t payLoad =
227  vtk::sizeofData<float, 3>(nPoints);
228 
229  format()
231  .beginDataArray<float, 3>(vtk::dataArrayAttr::POINTS);
232 
233  format().writeSize(payLoad);
234  }
235  }
236 }
237 
238 
240 {
241  if (format_)
242  {
243  format().flush();
244  format().endDataArray();
245 
246  if (!legacy())
247  {
248  format()
249  .endTag(vtk::fileTag::POINTS);
250  }
251  }
252 }
253 
254 
256 {
257  // Finish other output
258  endFieldData();
259  endPiece();
260 
261  if (isState(outputState::DECLARED))
262  {
263  if (format_ && !legacy())
264  {
265  format().endTag(contentType_).endVTKFile();
266  }
267  state_ = outputState::OPENED; // Mark as having been flushed
268  }
269 
270  // Must now be in CLOSED or OPENED states only
271 
272  if (isState(outputState::CLOSED) || isState(outputState::OPENED))
273  {
274  return true;
275  }
276 
277  reportBadState(WarningInFunction, outputState::CLOSED, outputState::OPENED)
278  << " for contentType (" << vtk::fileTagNames[contentType_] << ')'
279  << nl << endl;
280 
281  return false;
282 }
283 
284 
285 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
286 
288 (
289  const vtk::fileTag contentType,
290  const vtk::outputOptions opts
291 )
292 :
293  contentType_(contentType),
294  opts_(opts),
295  parallel_(false),
296  state_(outputState::CLOSED),
297  nCellData_(0),
298  nPointData_(0),
299  outputFile_(),
300  format_(nullptr),
301  os_()
302 {
303  // We do not currently support append mode at all
304  opts_.append(false);
305 }
306 
307 
308 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
309 
311 {
312  close();
313 }
314 
315 
316 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
317 
318 bool Foam::vtk::fileWriter::open(const fileName& file, bool parallel)
319 {
320  if (notState(outputState::CLOSED))
321  {
322  reportBadState(FatalErrorInFunction, outputState::CLOSED)
323  << exit(FatalError);
324  }
325 
326  if (format_)
327  {
328  format_.reset(nullptr);
329  os_.close();
330  }
331  nCellData_ = nPointData_ = 0;
332  outputFile_ = file;
333 
334  if
335  (
336  legacy()
337  ? outputFile_.hasExt(vtk::fileExtension[contentType_])
338  : outputFile_.hasExt(vtk::legacy::fileExtension)
339  )
340  {
341  // Inappropriate extension. Legacy instead of xml, or vice versa.
342 
343  outputFile_.removeExt();
344  }
345 
346  if (!outputFile_.hasExt(ext()))
347  {
348  // Add extension if required
349  outputFile_.ext(ext());
350  }
351 
352 
353  // Only set parallel flag if really is a parallel run.
354  parallel_ = parallel && Pstream::parRun();
355 
356  // Open a file and attach a formatter
357  // - on master (always)
358  // - on subproc (if not parallel)
359  //
360  // This means we can always check if format_ is defined to know if output
361  // is desired on any particular process.
362 
363  if (Pstream::master() || !parallel_)
364  {
365  mkDir(outputFile_.path());
366 
367  os_.open(outputFile_);
368 
369  format_ = opts_.newFormatter(os_);
370  }
371 
372  state_ = outputState::OPENED;
373  return true;
374 }
375 
376 
378 {
379  exit_File();
380 
381  if (format_)
382  {
383  format_.reset(nullptr);
384  os_.close();
385  }
386 
387  state_ = outputState::CLOSED;
388  outputFile_.clear();
389  nCellData_ = nPointData_ = 0;
390 }
391 
392 
393 bool Foam::vtk::fileWriter::beginFile(std::string title)
394 {
395  if (isState(outputState::DECLARED))
396  {
397  // Skip if already emitted
398  return false;
399  }
400  if (notState(outputState::OPENED))
401  {
402  reportBadState(FatalErrorInFunction, outputState::OPENED)
403  << exit(FatalError);
404  }
405  state_ = outputState::DECLARED;
406 
407  if (format_)
408  {
409  if (legacy())
410  {
411  legacy::fileHeader(format(), title, contentType_);
412  }
413  else
414  {
415  // XML (inline)
416 
417  format().xmlHeader();
418 
419  if (title.size())
420  {
421  format().xmlComment(title);
422  }
423 
424  format().beginVTKFile(contentType_);
425  }
426  }
427 
428  return true;
429 }
430 
431 
433 {
434  // Do nothing for legacy when nFields == 0
435  if (legacy() && !nFields) return false;
436 
437  if (isState(outputState::OPENED))
438  {
439  beginFile();
440  }
441  if (notState(outputState::DECLARED))
442  {
443  reportBadState(FatalErrorInFunction, outputState::DECLARED)
444  << exit(FatalError);
445  }
446  state_ = outputState::FIELD_DATA;
447 
448  if (format_)
449  {
450  if (legacy())
451  {
452  legacy::beginFieldData(format(), nFields);
453  }
454  else
455  {
456  format().beginFieldData();
457  }
458  }
459 
460  return true;
461 }
462 
463 
465 {
466  if (notState(outputState::FIELD_DATA))
467  {
468  // Skip if not in FieldData
469  return false;
470  }
471  state_ = outputState::DECLARED; // Toggle back to DECLARED
472 
473  if (format_ && !legacy())
474  {
475  format().endFieldData();
476  }
477 
478  return true;
479 }
480 
481 
483 {
484  if (notState(outputState::CELL_DATA))
485  {
486  // Skip if not in CellData
487  return false;
488  }
489  state_ = outputState::PIECE; // Toggle back to PIECE
490 
491  if (format_ && !legacy())
492  {
493  format().endCellData();
494  }
495 
496  return true;
497 }
498 
499 
501 {
502  if (notState(outputState::POINT_DATA))
503  {
504  // Skip if not in PointData
505  return false;
506  }
507  state_ = outputState::PIECE; // Toggle back to PIECE
508 
509  if (format_ && !legacy())
510  {
511  format().endPointData();
512  }
513 
514  return true;
515 }
516 
517 
519 {
520  // Convenience - switch to FieldData
521  if (isState(outputState::OPENED) || isState(outputState::DECLARED))
522  {
523  beginFieldData(1);
524  }
525  if (notState(outputState::FIELD_DATA))
526  {
528  << exit(FatalError);
529  }
530 
531  // No collectives - can skip on sub-procs
532  if (!format_) return;
533 
534  if (legacy())
535  {
536  legacy::writeTimeValue(format(), timeValue);
537  }
538  else
539  {
540  format().writeTimeValue(timeValue);
541  }
542 }
543 
544 
545 bool Foam::vtk::fileWriter::writeProcIDs(const label nValues)
546 {
547  // Write procIDs whenever running in parallel
548 
549  if (!Pstream::parRun())
550  {
551  return false; // Non-parallel: skip
552  }
553 
554  if (isState(outputState::CELL_DATA))
555  {
556  ++nCellData_;
557  }
558  else
559  {
561  << " for procID field" << nl << endl
562  << exit(FatalError);
563 
564  return false;
565  }
566 
567 
568  const globalIndex procSizes
569  (
570  parallel_
571  ? globalIndex(nValues)
572  : globalIndex()
573  );
574 
575  const label totalCount = (parallel_ ? procSizes.size() : nValues);
576 
577  this->beginDataArray<label>("procID", totalCount);
578 
579  bool good = false;
580 
581  if (parallel_)
582  {
583  if (Pstream::master())
584  {
585  // Per-processor ids
586  for (const int proci : Pstream::allProcs())
587  {
588  vtk::write(format(), label(proci), procSizes.localSize(proci));
589  }
590  good = true;
591  }
592  }
593  else
594  {
595  vtk::write(format(), label(Pstream::myProcNo()), totalCount);
596  good = true;
597  }
598 
599 
600  this->endDataArray();
601 
602  // MPI barrier
603  return parallel_ ? returnReduce(good, orOp<bool>()) : good;
604 }
605 
606 
607 // ************************************************************************* //
Foam::vtk::outputOptions
Encapsulated combinations of output format options. This is primarily useful when defining the output...
Definition: foamVtkOutputOptions.H:59
Foam::vtk::fileWriter::enter_Piece
bool enter_Piece()
Trigger change state to Piece. Resets nCellData_, nPointData_.
Definition: foamVtkFileWriter.C:89
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::Enum
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: IOstreamOption.H:57
Foam::vtk::fileWriter::close
void close()
End the file contents and close the file after writing.
Definition: foamVtkFileWriter.C:377
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::vtk::legacy::fileExtension
const word fileExtension
Legacy file extension ("vtk")
Foam::vtk::fileWriter::enter_CellData
bool enter_CellData(label nEntries, label nFields)
Trigger change state to CellData.
Definition: foamVtkFileWriter.C:132
Foam::vtk::fileExtension
const Foam::Enum< fileTag > fileExtension
File extension (without ".") for some vtk XML file content types.
Foam::vtk::fileWriter::endCellData
bool endCellData()
Explicitly end CellData output and switch to PIECE state.
Definition: foamVtkFileWriter.C:482
globalIndex.H
Foam::vtk::fileWriter::writeTimeValue
void writeTimeValue(scalar timeValue)
Write "TimeValue" FieldData (name as per Catalyst output)
Definition: foamVtkFileWriter.C:518
foamVtkFileWriter.H
Foam::vtk::fileWriter::beginFieldData
bool beginFieldData(label nFields=0)
Begin FieldData output section for specified number of fields.
Definition: foamVtkFileWriter.C:432
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
Foam::vtk::legacy::beginPointData
void beginPointData(vtk::formatter &fmt, label nPoints, label nFields)
Emit legacy POINT_DATA nPoints, FIELD FieldData nFields.
Definition: foamVtkOutputI.H:187
Foam::globalIndex::localSize
label localSize() const
My local size.
Definition: globalIndexI.H:187
Foam::vtk::fileWriter::beginFile
virtual bool beginFile(std::string title="")
Write file header (non-collective)
Definition: foamVtkFileWriter.C:393
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::vtk::legacy::beginFieldData
void beginFieldData(vtk::formatter &fmt, label nFields)
Emit legacy FIELD FieldData nFields.
Definition: foamVtkOutputI.H:162
Foam::vtk::fileWriter::stateNames
static const Enum< outputState > stateNames
Names for the output state (for messages, not for file output).
Definition: foamVtkFileWriter.H:85
Foam::vtk::fileWriter::format_
autoPtr< vtk::formatter > format_
The VTK formatter in use (only valid on master process)
Definition: foamVtkFileWriter.H:110
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::vtk::fileWriter::open
bool open(const fileName &file, bool parallel=Pstream::parRun())
Open file for writing (creates parent directory).
Definition: foamVtkFileWriter.C:318
format
word format(conversionProperties.get< word >("format"))
Foam::vtk::fileWriter::fileWriter
fileWriter(const fileWriter &)=delete
No copy construct.
Foam::vtk::legacy::writeTimeValue
void writeTimeValue(vtk::formatter &fmt, scalar timeValue)
Emit "TimeValue" for a FIELD entry (name as per Catalyst output)
Definition: foamVtkOutputI.H:202
Foam::vtk::fileWriter::enter_PointData
bool enter_PointData(label nEntries, label nFields)
Trigger change state to PointData.
Definition: foamVtkFileWriter.C:169
Foam::fileName::removeExt
bool removeExt()
Remove extension, returning true if string changed.
Definition: stringI.H:96
Foam::vtk::fileWriter::~fileWriter
virtual ~fileWriter()
Destructor.
Definition: foamVtkFileWriter.C:310
Foam::vtk::fileWriter::endPiece
bool endPiece()
Explicitly end Piece output and switch to DECLARED state.
Definition: foamVtkFileWriter.C:110
Foam::vtk::fileWriter::checkFormatterValidity
void checkFormatterValidity() const
Verify that formatter in either allocated or not required.
Definition: foamVtkFileWriter.C:52
Foam::vtk::legacy::beginPoints
void beginPoints(std::ostream &os, label nPoints)
Emit header for POINTS (with trailing newline).
Definition: foamVtkOutputI.H:113
Foam::vtk::fileWriter::parallel_
bool parallel_
Writing in parallel (via master)
Definition: foamVtkFileWriter.H:95
Foam::FatalError
error FatalError
Foam::vtk::legacy::fileHeader
void fileHeader(std::ostream &os, const std::string &title, bool binary)
Emit header for legacy file (vtk DataFile Version 2.0)
Definition: foamVtkOutput.C:188
os
OBJstream os(runTime.globalPath()/outputName)
Foam::vtk::fileTag::FIELD_DATA
"FieldData"
Foam::vtk::fileWriter::endPointData
bool endPointData()
Explicitly end PointData output and switch to PIECE state.
Definition: foamVtkFileWriter.C:500
Foam::vtk::fileTag::POINTS
"Points"
Foam::vtk::fileTag
fileTag
Some common XML tags for vtk files.
Definition: foamVtkCore.H:113
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::vtk::fileTagNames
const Foam::Enum< fileTag > fileTagNames
Strings corresponding to the vtk XML tags.
Foam::vtk::fileTag::POINT_DATA
"PointData"
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::vtk::legacy::beginCellData
void beginCellData(vtk::formatter &fmt, label nCells, label nFields)
Emit legacy CELL_DATA nCells, FIELD FieldData nFields.
Definition: foamVtkOutputI.H:172
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::UPstream::allProcs
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:508
Foam::vtk::fileWriter::exit_File
bool exit_File()
Emit file footer (end data, end piece, end file)
Definition: foamVtkFileWriter.C:255
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::globalIndex::size
label size() const
Global sum of localSizes.
Definition: globalIndexI.H:151
Foam::vtk::fileWriter::reportBadState
Ostream & reportBadState(Ostream &, outputState expected) const
Generate message reporting bad writer state.
Definition: foamVtkFileWriter.C:65
Foam::UPstream::parRun
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Foam::vtk::fileWriter::endPoints
void endPoints()
End of a POINTS DataArray.
Definition: foamVtkFileWriter.C:239
Foam::expressions::POINT_DATA
Point data.
Definition: exprFieldAssociation.H:46
Foam::vtk::fileWriter::writeProcIDs
bool writeProcIDs(const label nValues)
Write nValues of processor ids as CellData (no-op in serial)
Definition: foamVtkFileWriter.C:545
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:36
Foam::vtk::fileTag::CELL_DATA
"CellData"
Foam::vtk::fileWriter::endDataArray
void endDataArray()
Flush formatter and end of DataArray output (non-legacy)
Definition: foamVtkFileWriter.C:206
Foam::vtk::fileTag::PIECE
"Piece"
Foam::vtk::fileWriter::outputState
outputState
Internal tracking of the output state.
Definition: foamVtkFileWriter.H:73
Foam::vtk::fileWriter::endFieldData
bool endFieldData()
Explicitly end FieldData output and switch to DECLARED state.
Definition: foamVtkFileWriter.C:464
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::vtk::dataArrayAttr::POINTS
"Points"
Foam::orOp
Definition: ops.H:234
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::vtk::fileWriter::beginPoints
void beginPoints(const label nPoints)
Start of a POINTS DataArray.
Definition: foamVtkFileWriter.C:216