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-2022 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
28#include "foamVtkFileWriter.H"
29#include "globalIndex.H"
30#include "OSspecific.H"
31
32// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33
34const 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
132bool 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 {
142 reportBadState(FatalErrorInFunction, outputState::PIECE)
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
169bool 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 {
179 reportBadState(FatalErrorInFunction, outputState::PIECE)
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 state_(outputState::CLOSED),
294 contentType_(contentType),
295 parallel_(false),
296 opts_(opts),
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
318bool 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 (!parallel_ || Pstream::master())
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
393bool 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 {
527 reportBadState(FatalErrorInFunction, outputState::FIELD_DATA)
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
545bool 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 {
560 reportBadState(FatalErrorInFunction, outputState::CELL_DATA)
561 << " for procID field" << nl << endl
562 << exit(FatalError);
563
564 return false;
565 }
566
567
569 (
570 parallel_
573 );
574
575 const label totalCount = procAddr.totalSize();
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 label proci : procAddr.allProcs())
587 {
588 vtk::write(format(), proci, procAddr.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// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
globalIndex procAddr(aMesh.nFaces())
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: Enum.H:61
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
A class for handling file names.
Definition: fileName.H:76
bool removeExt()
Remove extension, returning true if string changed.
Definition: stringI.H:96
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
int myProcNo() const noexcept
Return processor number.
splitCell * master() const
Definition: splitCell.H:113
Base class for VTK output writers that handle geometry and fields (eg, vtp, vtu data)....
bool enter_Piece()
Trigger change state to Piece. Resets nCellData_, nPointData_.
bool enter_CellData(label nEntries, label nFields)
Trigger change state to CellData.
static const Enum< outputState > stateNames
Names for the output state (for messages, not for file output).
void beginPoints(const label nPoints)
Start of a POINTS DataArray.
bool endCellData()
Explicitly end CellData output and switch to PIECE state.
autoPtr< vtk::formatter > format_
The VTK formatter in use (only valid on master process)
void close()
End the file contents and close the file after writing.
bool parallel_
Parallel writing (via master)
void endPoints()
End of a POINTS DataArray.
void checkFormatterValidity() const
Verify that formatter in either allocated or not required.
void endDataArray()
Flush formatter and end of DataArray output (non-legacy)
bool exit_File()
Emit file footer (end data, end piece, end file)
bool enter_PointData(label nEntries, label nFields)
Trigger change state to PointData.
bool endFieldData()
Explicitly end FieldData output and switch to DECLARED state.
bool endPointData()
Explicitly end PointData output and switch to PIECE state.
virtual ~fileWriter()
Destructor.
vtk::outputOptions opts_
Requested output options.
virtual bool beginFile(std::string title="")
Write file header (non-collective)
outputState
Internal tracking of the output state.
Ostream & reportBadState(Ostream &, outputState expected) const
Generate message reporting bad writer state.
bool endPiece()
Explicitly end Piece output and switch to DECLARED state.
formatter & beginFieldData()
Begin "FieldData" XML section.
void writeTimeValue()
Write the currently set time as "TimeValue" FieldData.
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.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
label nPoints
#define WarningInFunction
Report a warning using Foam::Warning.
const word fileExtension
Legacy file extension ("vtk")
void beginPoints(std::ostream &os, label nPoints)
Emit header for POINTS (with trailing newline).
void beginCellData(vtk::formatter &fmt, label nCells, label nFields)
Emit legacy CELL_DATA nCells, FIELD FieldData nFields.
void fileHeader(std::ostream &os, const std::string &title, bool binary)
Emit header for legacy file (vtk DataFile Version 2.0)
void beginPointData(vtk::formatter &fmt, label nPoints, label nFields)
Emit legacy POINT_DATA nPoints, FIELD FieldData nFields.
void writeTimeValue(vtk::formatter &fmt, scalar timeValue)
Emit "TimeValue" for a FIELD entry (name as per Catalyst output)
void beginFieldData(vtk::formatter &fmt, label nFields)
Emit legacy FIELD FieldData nFields.
fileTag
Some common XML tags for vtk files.
Definition: foamVtkCore.H:114
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
const Foam::Enum< fileTag > fileExtension
File extension (without ".") for some vtk XML file content types.
const Foam::Enum< fileTag > fileTagNames
Strings corresponding to the vtk XML tags.
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:515
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
error FatalError
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
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"))
static constexpr char open
Definition: FlatOutput.H:73