ensightFile.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-2015 OpenFOAM Foundation
9  Copyright (C) 2016-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 "ensightFile.H"
30 #include "ensightReadFile.H"
31 #include "error.H"
32 #include "List.H"
33 #include <cstring>
34 #include <sstream>
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 bool Foam::ensightFile::allowUndef_ = false;
39 
40 float Foam::ensightFile::undefValue_ = Foam::floatScalarVGREAT;
41 
42 const char* const Foam::ensightFile::coordinates = "coordinates";
43 
44 
45 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
46 
47 namespace Foam
48 {
49 
50 // Put integers, floats etc in binary or ascii.
51 template<class Type>
52 static inline void putPrimitive
53 (
54  const Type& value,
55  OFstream& os,
56  const int fieldWidth
57 )
58 {
59  auto& oss = os.stdStream();
60 
62  {
63  oss.write(reinterpret_cast<const char*>(&value), sizeof(Type));
64  }
65  else
66  {
67  oss.width(fieldWidth);
68  oss << value;
69  }
70  os.syncState();
71 }
72 
73 } // End namespace Foam
74 
75 
76 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
77 
78 bool Foam::ensightFile::hasUndef(const UList<float>& field)
79 {
80  for (const float val : field)
81  {
82  if (std::isnan(val))
83  {
84  return true;
85  }
86  }
87 
88  return true;
89 }
90 
91 
92 bool Foam::ensightFile::hasUndef(const UList<double>& field)
93 {
94  for (const double val : field)
95  {
96  if (std::isnan(val))
97  {
98  return true;
99  }
100  }
101 
102  return true;
103 }
104 
105 
106 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
107 
108 void Foam::ensightFile::init()
109 {
110  // The ASCII formatting specs for ensight files
111  setf
112  (
114  std::ios_base::floatfield
115  );
116  precision(5);
117 
118  // Handle transient single-file timestep information
119  auto& oss = OFstream::stdStream();
120 
122  {
123  // Already positioned at the EOF (in append mode), but be certain
124  oss.seekp(0, std::ios_base::end);
125  origFileSize_ = oss.tellp();
126  }
127  else
128  {
129  origFileSize_ = 0;
130  }
131 
132  int64_t begin_footer(-1);
133  List<int64_t> offsets;
134 
136  {
137  // Temporarily open for reading as well.
138  // No race condition since no writing is done concurrently with the
139  // reading
140  IFstream is(OFstream::name(), OFstream::format());
141 
142  begin_footer =
144  (
145  is,
146  offsets
147  );
148  }
149 
150  timeStepOffsets_ = std::move(offsets);
151 
152  if (OFstream::is_appending() && begin_footer > 0)
153  {
154  oss.seekp(begin_footer);
156  }
157 
158  // InfoErr << "output at: " << label(begin_footer) << nl;
159  // InfoErr
160  // << "footer: " << label(begin_footer)
161  // << " time-steps: " << offsets.size() << nl;
162 }
163 
164 
165 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
166 
167 Foam::ensightFile::ensightFile
168 (
169  std::nullptr_t, // dispatch tag
171  const fileName& pathname,
173 )
174 :
175  OFstream
176  (
177  (
178  // Only use atomic when not appending
179  (append == IOstreamOption::NO_APPEND)
180  ? IOstreamOption::ATOMIC
181  : IOstreamOption::NON_ATOMIC
182  ),
183  pathname,
184  fmt,
185  (
186  // Change APPEND_APP -> APPEND_ATE (file rewriting)
187  (append == IOstreamOption::APPEND_APP)
188  ? IOstreamOption::APPEND_ATE
189  : append
190  )
191  ),
192  origFileSize_(0)
193 {
194  init();
195 }
196 
197 
198 Foam::ensightFile::ensightFile
199 (
201  const fileName& pathname,
203 )
204 :
206  (
207  nullptr,
208  append,
209  ensight::FileName(pathname),
210  fmt
211  )
212 {}
213 
214 
215 Foam::ensightFile::ensightFile
216 (
218  const fileName& path,
219  const fileName& name,
221 )
222 :
224  (
225  nullptr,
226  append,
227  path/ensight::FileName(name),
228  fmt
229  )
230 {}
231 
232 
233 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
234 
236 {
237  (void) writeTimeStepFooter();
238 }
239 
240 
241 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
242 
244 {
245  return allowUndef_;
246 }
247 
249 // float Foam::ensightFile::undefValue() noexcept
250 // {
251 // return undefValue_;
252 // }
253 
254 
256 {
257  bool old = allowUndef_;
258  allowUndef_ = on;
259  return old;
260 }
261 
262 
263 float Foam::ensightFile::undefValue(float value) noexcept
264 {
265  // enable its use too
266  allowUndef_ = true;
267 
268  float old = undefValue_;
269  undefValue_ = value;
270  return old;
271 }
272 
273 
274 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
275 
276 void Foam::ensightFile::writeString(const char* str, size_t len)
277 {
278  // Output 79 chars (ASCII) or 80 chars (BINARY)
279  char buf[80];
280  if (len > 80) len = 80;
281 
282  // TBD: truncate at newline? (shouldn't really occur anyhow)
283 
284  std::copy_n(str, len, buf);
285  std::fill_n(buf + len, (80 - len), '\0'); // Pad trailing with nul
286 
287  auto& oss = stdStream();
288 
290  {
291  oss.write(buf, 80);
292  }
293  else
294  {
295  buf[79] = 0; // Max 79 in ASCII
296 
297  // TBD: Extra safety - trap newline in ASCII?
298  // char* p = ::strchr(buf, '\n');
299  // if (p) *p = 0;
300 
301  oss << buf;
302  }
303 
304  syncState();
305 }
306 
308 void Foam::ensightFile::writeString(const char* str)
309 {
310  writeString(str, strlen(str));
311 }
312 
314 void Foam::ensightFile::writeString(const std::string& str)
315 {
316  writeString(str.data(), str.size());
317 }
318 
319 
321 {
322  writeString(str, strlen(str));
323  return *this;
324 }
325 
326 
328 {
329  writeString(str.data(), str.size());
330  return *this;
331 }
332 
333 
334 Foam::Ostream& Foam::ensightFile::write(const std::string& str)
335 {
336  writeString(str.data(), str.size());
337  return *this;
338 }
339 
340 
341 // Same as OFstream::writeRaw(buf, count)
343 (
344  const char* buf,
345  std::streamsize count
346 )
347 {
348  stdStream().write(buf, count);
349  syncState();
350  return *this;
351 }
352 
354 void Foam::ensightFile::writeInt(const int32_t val, const int fieldWidth)
355 {
356  putPrimitive<int32_t>(val, *this, fieldWidth);
357 }
358 
360 void Foam::ensightFile::writeInt(const int64_t val, const int fieldWidth)
361 {
362  putPrimitive<int32_t>(narrowInt32(val), *this, fieldWidth);
363 }
364 
366 void Foam::ensightFile::writeFloat(const float val, const int fieldWidth)
367 {
368  putPrimitive<float>(val, *this, fieldWidth);
369 }
370 
372 void Foam::ensightFile::writeFloat(const double val, const int fieldWidth)
373 {
374  putPrimitive<float>(narrowFloat(val), *this, fieldWidth);
375 }
376 
377 
378 Foam::Ostream& Foam::ensightFile::write(const int32_t val)
379 {
380  putPrimitive<int32_t>(val, *this, 10);
381 
382  return *this;
383 }
384 
385 
386 Foam::Ostream& Foam::ensightFile::write(const int64_t val)
387 {
388  putPrimitive<int32_t>(narrowInt32(val), *this, 10);
389 
390  return *this;
391 }
392 
393 
394 Foam::Ostream& Foam::ensightFile::write(const float val)
395 {
396  putPrimitive<float>(val, *this, 12);
397 
398  return *this;
399 }
400 
401 
402 Foam::Ostream& Foam::ensightFile::write(const double val)
403 {
404  putPrimitive<float>(narrowFloat(val), *this, 12);
405 
406  return *this;
407 }
408 
409 
411 {
413  {
414  OFstream::write('\n');
415  }
416 }
417 
420 {
421  write(undefValue_);
422 }
423 
424 
426 {
427  if (allowUndef_)
428  {
429  writeString(key + " undef");
430  newline();
431  write(undefValue_);
432  newline();
433  }
434  else
435  {
436  writeString(key);
437  newline();
438  }
439 
440  return *this;
441 }
442 
443 
445 {
447  {
448  writeString("C Binary");
449  // newline(); // A no-op in binary
450  }
451 }
452 
453 
454 // Footer information looks like this
455 //
456 /* |---------------|---------------|-----------------------|
457  * | ASCII | BINARY | element |
458  * |---------------|---------------|-----------------------|
459  * | "%20lld\n" | int32 | nSteps |
460  * | "%20lld\n" | int64 | offset step 1 |
461  * | "%20lld\n" | int64 | offset step 2 |
462  * | "%20lld\n" | .. | |
463  * | "%20lld\n" | int64 | offset step n |
464  * | "%20lld\n" | int32 | flag (unused) |
465  * | "%20lld\n" | int64 | offset to nSteps |
466  * | "%s\n" | char[80] | 'FILE_INDEX' |
467  * |---------------|---------------|-----------------------|
468  */
469 
471 {
472  if (timeStepOffsets_.empty())
473  {
474  return -1;
475  }
476 
477  auto& oss = OFstream::stdStream();
478 
479  // The footer begin, which is also the current position
480  const int64_t footer_begin(oss.tellp());
481 
482  // nSteps
483  putPrimitive<int32_t>(int32_t(timeStepOffsets_.size()), *this, 20);
484  newline();
485 
486  // offset step 1, 2, ... N
487  for (int64_t off : timeStepOffsets_)
488  {
489  putPrimitive<int64_t>(off, *this, 20);
490  newline();
491  }
492 
493  // flag (unused)
494  putPrimitive<int32_t>(0, *this, 20);
495  newline();
496 
497  // The footer begin == position of nSteps
498  putPrimitive<int64_t>(footer_begin, *this, 20);
499  newline();
500 
501  // FILE_INDEX is "%s\n", not "%79s\n"
502  // but our ASCII strings are truncated (nul-padded) anyhow
503 
504  writeString("FILE_INDEX");
505  newline();
506 
507  // Reposition to begin of footer so that any subsequent output
508  // will overwrite the footer too
509  oss.seekp(footer_begin);
510 
511  return footer_begin;
512 }
513 
514 
515 //
516 // Convenience Output Methods
517 //
518 
520 {
521  writeString("BEGIN TIME STEP");
522  newline();
523 
524  auto& oss = OFstream::stdStream();
525 
526  const int64_t curr_pos(oss.tellp());
527  timeStepOffsets_.push_back(curr_pos);
528 
529  // To avoid partly incomplete/incorrect footer information,
530  // overwrite original footer if needed.
531 
532  if (curr_pos >= 0 && curr_pos < origFileSize_)
533  {
534  const char fill[] = "deadbeef";
535 
536  for
537  (
538  int64_t pos = curr_pos;
539  pos < origFileSize_ && bool(oss);
540  pos += 8
541  )
542  {
543  // Overwrite with specified "junk" to avoid/detect corrupt
544  // files etc. Don't worry about slightly increasing the
545  // file size (ie, max 7 bytes) - it's unimportant
546  oss.write(fill, 8);
547  }
548 
549  // Maintain the original output position
550  oss.seekp(curr_pos);
551 
553  }
554 
555  return curr_pos;
556 }
557 
558 
560 {
561  writeString("END TIME STEP");
562  newline();
563 
564  return int64_t(stdStream().tellp());
565 }
566 
567 
568 void Foam::ensightFile::beginPart(const label index)
569 {
570  writeString("part");
571  newline();
572  write(index+1); // Ensight starts with 1
573  newline();
574 }
575 
576 
578 (
579  const label index,
580  const std::string& description
581 )
582 {
583  beginPart(index);
584  writeString(description);
585  newline();
586 }
587 
588 
589 void Foam::ensightFile::beginCoordinates(const label npoints)
590 {
591  writeString("coordinates");
592  newline();
593 
594  write(npoints);
595  newline();
596 }
597 
598 
599 void Foam::ensightFile::beginParticleCoordinates(const label nparticles)
600 {
601  writeString("particle coordinates");
602  newline();
603  writeInt(nparticles, 8); // Warning: unusual width
604  newline();
605 }
606 
607 
609 {
610  for (const label val : list)
611  {
612  write(val);
613  newline();
614  }
615 }
616 
617 
618 void Foam::ensightFile::writeList(const UList<label>& field)
619 {
620  for (const label val : field)
621  {
622  write(float(val));
623  newline();
624  }
625 }
626 
627 
628 void Foam::ensightFile::writeList(const UList<float>& field)
629 {
630  for (const float val : field)
631  {
632  if (std::isnan(val))
633  {
634  writeUndef();
635  }
636  else
637  {
638  write(val);
639  }
640  newline();
641  }
642 }
643 
644 
645 void Foam::ensightFile::writeList(const UList<double>& field)
646 {
647  for (const double val : field)
648  {
649  if (std::isnan(val))
650  {
651  writeUndef();
652  }
653  else
654  {
655  write(val);
656  }
657  newline();
658  }
659 }
660 
661 
662 // ************************************************************************* //
A variant of OFstream with specialised handling for Ensight writing of strings, integers and floats (...
Definition: ensightFile.H:47
void writeBinaryHeader()
Write "C Binary" string for binary files (eg, geometry/measured)
Definition: ensightFile.C:437
A class for handling keywords in dictionaries.
Definition: keyType.H:66
bool is_appending() const noexcept
True if opened in append mode and file already existed.
Definition: OFstream.H:191
int64_t endTimeStep()
Write "END TIME STEP" string and newline (for transient single-file format)
Definition: ensightFile.C:552
rDeltaTY field()
A class for handling file names.
Definition: fileName.H:72
float narrowFloat(const double val)
Type narrowing from double to float.
Definition: scalar.H:240
void syncState()
Set stream state to match that of the std::ostream.
Definition: OSstream.H:182
static void putPrimitive(const Type &value, OFstream &os, const int fieldWidth)
Definition: ensightFile.C:46
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
Definition: OFstream.H:71
"ascii" (normal default)
virtual const fileName & name() const override
Get the name of the output serial stream. (eg, the name of the Fstream file name) ...
Definition: OSstream.H:134
int64_t writeTimeStepFooter()
Transient single-file: write the time-step file-offsets as footer information.
Definition: ensightFile.C:463
static const char *const coordinates
The keyword "coordinates".
Definition: ensightFile.H:120
int64_t beginTimeStep()
Write "BEGIN TIME STEP" string and newline (for transient single-file format).
Definition: ensightFile.C:512
void beginPart(const label index)
Begin a part (0-based index internally).
Definition: ensightFile.C:561
virtual const std::ostream & stdStream() const override
Const access to underlying std::ostream.
Definition: OFstream.C:125
dimensionedScalar pos(const dimensionedScalar &ds)
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
int32_t narrowInt32(const int64_t val)
Type narrowing from int64_t to int32_t.
Definition: label.H:232
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void writeUndef()
Write undef value.
Definition: ensightFile.C:412
A class for handling words, derived from Foam::string.
Definition: word.H:63
~ensightFile()
Destructor. Commits the time-step footer information (if any)
Definition: ensightFile.C:228
void writeLabels(const UList< label > &list)
Write a list of integers.
Definition: ensightFile.C:601
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
const direction noexcept
Definition: Scalar.H:258
virtual bool write(const token &tok) override
Write token to stream or otherwise handle it.
Definition: OSstream.C:29
static int64_t getTimeStepFooter(IFstream &is, List< int64_t > &offsets)
Extract time step footer information (if any).
Smanip< std::ios_base::fmtflags > setf(std::ios_base::fmtflags flags)
Definition: IOmanip.H:169
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
OBJstream os(runTime.globalPath()/outputName)
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
void beginParticleCoordinates(const label nparticles)
Begin a "particle coordinates" block (measured data)
Definition: ensightFile.C:592
void beginCoordinates(const label nparticles)
Begin a "coordinates" block. Only used for geometry files.
Definition: ensightFile.C:582
appendType
File appending (NO_APPEND | APPEND_APP | APPEND_ATE)
void writeString(const char *str, size_t len)
Write character/string content as "%79s" or as binary (max 80 chars)
Definition: ensightFile.C:269
virtual bool write(const token &) override
Writing token does not make sense.
Definition: ensightFile.H:301
word format(conversionProperties.get< word >("format"))
void newline()
Add carriage return to ascii stream.
Definition: ensightFile.C:403
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
void writeList(const UList< label > &field)
Write a list of integers as float values.
Definition: ensightFile.C:611
void writeInt(const int32_t val, const int fieldWidth)
Write integer value with specified width or as binary.
Definition: ensightFile.C:347
streamFormat
Data format (ascii | binary)
constexpr floatScalar floatScalarVGREAT
Definition: floatScalar.H:56
static float undefValue(float value) noexcept
Assign the value to represent undef in the results.
Definition: ensightFile.C:256
static bool hasUndef(const UList< float > &field)
Check for any NaN in the field.
Definition: ensightFile.C:71
static bool allowUndef() noexcept
Return setting for whether &#39;undef&#39; values are allowed in results.
Definition: ensightFile.C:236
streamFormat format() const noexcept
Get the current stream format.
void writeFloat(const float val, const int fieldWidth)
Write floating-point with specified width or as binary.
Definition: ensightFile.C:359
IOstream & scientific(IOstream &io)
Definition: IOstream.H:578
virtual Ostream & writeKeyword(const keyType &key) override
Write element keyword with trailing newline, optionally with undef and the value for undefined...
Definition: ensightFile.C:418
Namespace for OpenFOAM.