ensightReadFile.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) 2016-2024 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 "ensightReadFile.H"
29 #include "stringOps.H"
30 #include "defineDebugSwitch.H"
31 #include "registerSwitch.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
36 
37 registerDebugSwitchWithName(Foam::ensightReadFile, ensight, "ensightReadFile");
38 
39 
40 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44 
45 // Get integers, floats etc in binary or ascii.
46 template<class Type>
47 static inline Type getPrimitive(IFstream& is)
48 {
49  Type value(0);
50 
51  auto& iss = is.stdStream();
52 
53  if (is.format() == IOstreamOption::BINARY)
54  {
55  iss.read(reinterpret_cast<char*>(&value), sizeof(Type));
56  }
57  else
58  {
59  iss >> value;
60  }
61  is.syncState();
62 
63  return value;
64 }
65 
66 
67 // Get an Ensight string value (binary or ascii).
68 static inline void readEnsightString(IFstream& is, std::string& value)
69 {
70  if (is.format() == IOstreamOption::BINARY)
71  {
72  auto& iss = is.stdStream();
73 
74  // Binary string is *exactly* 80 characters
75  value.resize(80, '\0');
76  iss.read(&value[0], 80);
77  const std::streamsize gcount = iss.gcount();
78  value.erase(gcount <= 0 ? 0 : gcount); // Truncated?
79 
80  // Could exit on truncated input, but no real advantage
81 
82  // Truncate at the first embedded '\0'
83  const auto endp = value.find('\0');
84 
85  if (endp != std::string::npos)
86  {
87  value.erase(endp);
88  }
89 
90  // May have been padded with trailing spaces - remove those
92 
93  is.syncState();
94  }
95  else
96  {
97  value.clear();
98  while (value.empty() && !is.eof())
99  {
100  is.getLine(value);
101  }
102  }
103 }
104 
105 
106 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
107 
108 // Footer information looks like this
109 //
110 /* |---------------|---------------|-----------------------|
111  * | ASCII | BINARY | element |
112  * |---------------|---------------|-----------------------|
113  * | "%20lld\n" | int32 | nSteps |
114  * | "%20lld\n" | int64 | offset step 1 |
115  * | "%20lld\n" | int64 | offset step 2 |
116  * | "%20lld\n" | .. | |
117  * | "%20lld\n" | int64 | offset step n |
118  * | "%20lld\n" | int32 | flag (unused) |
119  * | "%20lld\n" | int64 | offset to nSteps |
120  * | "%s\n" | char[80] | 'FILE_INDEX' |
121  * |---------------|---------------|-----------------------|
122  */
123 
125 (
126  IFstream& is,
127  // File offsets for each time step (if any)
128  List<int64_t>& offsets
129 )
130 {
131  std::string buffer;
132 
133  auto& iss = is.stdStream();
134  const auto lineNum = is.lineNumber();
135  const auto curr_pos = iss.tellg();
136 
137  if (curr_pos < 0)
138  {
139  // Impossible positioning - exit
140  is.lineNumber(lineNum); // Restore line number
141  offsets.clear();
142  return -1;
143  }
144 
145  iss.seekg(0, std::ios_base::end);
146  const auto end_pos = iss.tellg();
147 
148  // As a minimum, expect at least 1 time step, so have four integers
149  // (nSteps, offset step 1, flag, file offset) and the string (10 chars).
150  // Thus always at least 80+ chars.
151 
152  if (end_pos <= 80)
153  {
154  // Looks quite impossible - exit
155 
156  is.lineNumber(lineNum); // Restore line number
157  iss.seekg(curr_pos); // Restore file position
158 
159  offsets.clear();
160  return -1;
161  }
162 
163  // Get the last 80 chars as a character string
164  iss.seekg(-80, std::ios_base::end);
165 
166  const auto fmt = is.format(IOstreamOption::BINARY);
167  readEnsightString(is, buffer);
168  is.format(fmt);
169 
170  int64_t footer_begin(0);
171 
172  const auto endp = buffer.find("FILE_INDEX");
173 
174  if (endp == std::string::npos)
175  {
176  // Not found
177 
178  is.lineNumber(lineNum); // Restore line number
179  iss.seekg(curr_pos); // Restore file position
180 
181  offsets.clear();
182  return -1;
183  }
184  else if (fmt == IOstreamOption::ASCII)
185  {
186  // In ASCII, the last 80 chars will also include a few integers
187  buffer.erase(endp); // Remove FILE_INDEX ...
188  auto split = stringOps::splitSpace(buffer);
189 
190  if (!split.empty())
191  {
192  footer_begin = Foam::readInt64(split.back().str());
193  }
194  }
195  else
196  {
197  // Position before string (80 bytes) and int64 value (8 bytes)
198  iss.seekg(-88, std::ios_base::end);
199  footer_begin = getPrimitive<int64_t>(is);
200  }
201 
202 
203  // The number of steps is stored as int32 at the beginning of the footer
204  int32_t nSteps(0);
205 
206  if (footer_begin)
207  {
208  iss.seekg(footer_begin);
209  nSteps = getPrimitive<int32_t>(is);
210  }
211 
212  offsets.resize_nocopy(nSteps);
213 
214  // Next footer entries are the offsets per time-step
215  for (int32_t step = 0; step < nSteps; ++step)
216  {
217  offsets[step] = getPrimitive<int64_t>(is);
218  }
219 
220  is.lineNumber(lineNum); // Restore line number
221  iss.seekg(curr_pos); // Restore file position
222 
223  return footer_begin;
224 }
225 
226 } // End namespace Foam
227 
228 
229 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
230 
231 void Foam::ensightReadFile::readString(std::string& value)
232 {
233  readEnsightString(*this, value);
234 }
235 
236 
237 void Foam::ensightReadFile::init(bool detectFormat)
238 {
239  if (!IFstream::good())
240  {
242  << "Cannot read file " << IFstream::name() << nl
243  << exit(FatalError);
244  }
245 
246  auto& iss = stdStream();
247 
248  auto lineNum = lineNumber();
249  auto curr_pos = iss.tellg(); // The starting position (should be 0)
250 
251  string buffer;
252 
253  if (detectFormat)
254  {
255  // Read initial string as BINARY
257 
258  readEnsightString(*this, buffer);
259 
260  // Detect BINARY vs ASCII by testing for initial "(C|Fortran) Binary"
261  if (buffer.contains("Binary") || buffer.contains("binary"))
262  {
263  // Format is BINARY
265 
266  // New backtracking point is after the initial "C Binary" string
267  curr_pos = iss.tellg();
268 
269  // Get the next (optional) line after the "C Binary" (if any)
270  // and before the description.
271  readEnsightString(*this, buffer);
272  }
273  else
274  {
275  // Not binary => ASCII
277 
278  // Rewind to the beginning again
279  iss.seekg(curr_pos);
280  }
281  }
282  else
283  {
284  // Get the next line.
285  // It is either the description line or "BEGIN TIME STEP".
286  readEnsightString(*this, buffer);
287  }
288 
289 
290  // The buffer string now either contains the description line
291  // or "BEGIN TIME STEP"
292 
293  if (buffer.starts_with("BEGIN TIME STEP"))
294  {
295  // Transient single file.
296  // File position is now after the "BEGIN TIME STEP" string
297 
298  curr_pos = iss.tellg(); // Fallback value
299 
300  timeStepFooterBegin_ = getTimeStepFooter(*this, timeStepOffsets_);
301 
302  if (timeStepOffsets_.empty())
303  {
304  // Treat like a single time step
305  timeStepOffsets_.resize(1, int64_t(curr_pos));
306  }
307  }
308  else
309  {
310  // A description line and not "BEGIN TIME STEP"
311  // so backtrack to before it was read
312 
313  lineNumber(lineNum); // Restore line number
314  iss.seekg(curr_pos); // Restore file position
315 
316  timeStepFooterBegin_ = -1; // safety
317  timeStepOffsets_.clear(); // safety
318  }
319 
320  DebugInfo<< "Time-steps: " << timeStepOffsets_.size() << endl;
321 
322  syncState();
323 }
324 
325 
326 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
327 
328 Foam::ensightReadFile::ensightReadFile
329 (
330  const fileName& pathname
331 )
332 :
333  IFstream(pathname, IOstreamOption::BINARY), // Start as BINARY
334  timeStepFooterBegin_(-1)
335 {
336  init(true); // detectFormat = true
337 }
338 
339 
340 Foam::ensightReadFile::ensightReadFile
341 (
342  const fileName& pathname,
344 )
345 :
346  IFstream(pathname, fmt),
347  timeStepFooterBegin_(-1)
348 {
349  init(false); // detectFormat = false
350 }
351 
352 
353 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
354 
355 // Same as IFstream::readRaw(buf, count)
357 (
358  char* buf,
359  std::streamsize count
360 )
361 {
362  stdStream().read(buf, count);
363  syncState();
364  return *this;
365 }
366 
367 
368 // TBD
369 // Foam::Istream& Foam::ensightReadFile::read(word& value)
370 // {
371 // readString(value);
372 // string::stripInvalid<word>(value);
373 // return *this;
374 // }
375 
376 
378 {
379  readString(value);
380  return *this;
381 }
382 
383 
385 {
386  value = getPrimitive<int>(*this);
387  return *this;
388 }
389 
390 
392 {
393  value = getPrimitive<float>(*this);
394  return *this;
395 }
396 
397 
399 {
400  value = getPrimitive<float>(*this);
401  return *this;
402 }
403 
404 
406 {
407  read(key);
408  return *this;
409 }
410 
411 
413 (
414  const label nPoints,
416 )
417 {
419 
420  for (auto& p : points)
421  {
422  read(p.x());
423  }
424  for (auto& p : points)
425  {
426  read(p.y());
427  }
428  for (auto& p : points)
429  {
430  read(p.z());
431  }
432 }
433 
434 
436 (
437  const label nPoints,
438  List<doubleVector>& points
439 )
440 {
442 
443  for (auto& p : points)
444  {
445  read(p.x());
446  }
447  for (auto& p : points)
448  {
449  read(p.y());
450  }
451  for (auto& p : points)
452  {
453  read(p.z());
454  }
455 }
456 
457 
459 {
460  if (timeIndex >= 0 && timeIndex < timeStepOffsets_.size())
461  {
462  auto& iss = stdStream();
463 
464  iss.seekg(timeStepOffsets_[timeIndex]);
465  syncState();
466 
467  if (debug)
468  {
469  Info<< "seek time "
470  << timeIndex << '/' << nTimes()
471  << " offset:" << label(timeStepOffsets_[timeIndex]) << nl;
472  }
473 
474  return true;
475  }
476 
477  if (debug)
478  {
479  Info<< "seek time "
480  << timeIndex << '/' << nTimes()
481  << " ignored" << nl;
482  }
483 
484  return false;
485 }
486 
487 
488 // ************************************************************************* //
static void readEnsightString(IFstream &is, std::string &value)
virtual Istream & read(char *buf, std::streamsize count) override
Binary read.
A class for handling file names.
Definition: fileName.H:72
bool seekTime(const label timeIndex)
Transient single-file: seek to the file position corresponding to the given time index.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
void readPoints(const label nPoints, List< floatVector > &points)
Component-wise reading of points/coordinates. Read all x components, y components and z components...
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
"ascii" (normal default)
void syncState()
Set stream state to match that of the std::istream.
Definition: ISstream.H:195
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
A simple container for options an IOstream can normally have.
static Type getPrimitive(IFstream &is)
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
registerDebugSwitchWithName(Foam::ensightReadFile, ensight, "ensightReadFile")
int64_t readInt64(Istream &is)
Read int64_t from stream.
Definition: int64IO.C:74
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
void inplaceTrimRight(std::string &s)
Trim trailing whitespace inplace.
Definition: stringOps.C:979
virtual Istream & read(token &)=0
Return next token from stream.
const pointField & points
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
label nPoints
A variant of IFstream with specialised handling for Ensight reading of strings, integers and floats (...
virtual const fileName & name() const override
The name of the input serial stream. (eg, the name of the Fstream file name)
Definition: ISstream.H:147
#define DebugInfo
Report an information message using Foam::Info.
static int64_t getTimeStepFooter(IFstream &is, List< int64_t > &offsets)
Extract time step footer information (if any).
virtual std::istream & stdStream() override
Access to underlying std::istream.
Definition: IFstream.C:239
int debug
Static debugging option.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
defineDebugSwitchWithName(Foam::ensightReadFile, "ensightReadFile", 0)
Input from file stream as an ISstream, normally using std::ifstream for the actual input...
Definition: IFstream.H:51
Istream & readKeyword(string &key)
Read element keyword. Currently the same as read(string)
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:390
static bool split(const std::string &line, std::string &key, std::string &val)
Definition: cpuInfo.C:32
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
Macro definitions for debug switches.
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:281
streamFormat
Data format (ascii | binary)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::SubStrings< StringType > splitSpace(const StringType &str, std::string::size_type pos=0)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
volScalarField & p
streamFormat format() const noexcept
Get the current stream format.
Namespace for OpenFOAM.
label timeIndex
Definition: getTimeIndex.H:24