Loading...
Searching...
No Matches
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-2025 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
29#include "stringOps.H"
31#include "registerSwitch.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
36
37registerDebugSwitchWithName(Foam::ensightReadFile, ensight, "ensightReadFile");
38
39
40// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
41
42namespace Foam
43{
44
45// Get integers, floats etc in binary or ascii.
46template<class Type>
47static inline Type getPrimitive(IFstream& is)
48{
49 Type value(0);
50
51 auto& iss = is.stdStream();
52
54 {
55 iss.read(reinterpret_cast<char*>(&value), sizeof(Type));
56 }
57 else
58 {
59 iss >> value;
60 }
62
63 return value;
64}
65
66
67// Get an Ensight string value (binary or ascii).
68static 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
231void Foam::ensightReadFile::readString(std::string& value)
232{
233 readEnsightString(*this, value);
234}
235
236
237void 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;
322 syncState();
323}
324
325
326// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
327
328Foam::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
340Foam::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<int>(*this);
394 return *this;
395}
396
397
399{
401 return *this;
402}
403
404
406{
408 return *this;
409}
410
411
413{
414 value = getPrimitive<float>(*this);
415 return *this;
416}
417
418
420{
421 value = getPrimitive<float>(*this);
422 return *this;
423}
424
425
427{
428 read(key);
429 return *this;
430}
431
432
434(
435 const label nPoints,
437)
438{
439 points.resize_nocopy(nPoints);
440
441 for (auto& p : points)
442 {
443 read(p.x());
444 }
445 for (auto& p : points)
446 {
447 read(p.y());
448 }
449 for (auto& p : points)
450 {
451 read(p.z());
452 }
453}
454
455
457(
458 const label nPoints,
459 List<doubleVector>& points
460)
461{
462 points.resize_nocopy(nPoints);
463
464 for (auto& p : points)
465 {
466 read(p.x());
467 }
468 for (auto& p : points)
469 {
470 read(p.y());
471 }
472 for (auto& p : points)
473 {
474 read(p.z());
475 }
476}
477
478
480{
481 if (timeIndex >= 0 && timeIndex < timeStepOffsets_.size())
482 {
483 auto& iss = stdStream();
484
485 iss.seekg(timeStepOffsets_[timeIndex]);
486 syncState();
487
488 if (debug)
489 {
490 Info<< "seek time "
491 << timeIndex << '/' << nTimes()
492 << " offset:" << label(timeStepOffsets_[timeIndex]) << nl;
493 }
494
495 return true;
496 }
497
498 if (debug)
499 {
500 Info<< "seek time "
501 << timeIndex << '/' << nTimes()
502 << " ignored" << nl;
503 }
504
505 return false;
506}
507
508
509// ************************************************************************* //
Input from file stream as an ISstream, normally using std::ifstream for the actual input.
Definition IFstream.H:55
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition ISstream.H:147
IFstream(const fileName &pathname, IOstreamOption streamOpt=IOstreamOption())
Construct from pathname, default or specified stream options.
Definition IFstream.C:149
virtual std::istream & stdStream() override
Access to underlying std::istream.
Definition IFstream.C:239
A simple container for options an IOstream can normally have.
streamFormat format() const noexcept
Get the current stream format.
streamFormat
Data format (ascii | binary | coherent).
@ ASCII
"ascii" (normal default)
label lineNumber() const noexcept
Const access to the current stream line number.
Definition IOstream.H:409
bool good() const noexcept
True if next operation might succeed.
Definition IOstream.H:281
bool eof() const noexcept
True if end of input seen.
Definition IOstream.H:289
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition ISstreamI.H:69
void syncState()
Set stream state to match that of the std::istream.
Definition ISstream.H:195
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
virtual Istream & read(token &)=0
Return next token from stream.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
A variant of IFstream with specialised handling for Ensight reading of strings, integers and floats (...
bool seekTime(const label timeIndex)
Transient single-file: seek to the file position corresponding to the given time index.
void readPoints(const label nPoints, List< floatVector > &points)
Component-wise reading of points/coordinates. Read all x components, y components and z components.
static int64_t getTimeStepFooter(IFstream &is, List< int64_t > &offsets)
Extract time step footer information (if any).
label nTimes() const noexcept
Transient single-file: the number of time steps within the file.
static int debug
Debug switch.
Istream & readKeyword(string &key)
Read element keyword. Currently the same as read(string).
virtual Istream & read(char *buf, std::streamsize count) override
Binary read.
A class for handling file names.
Definition fileName.H:75
volScalarField & p
static bool split(const std::string &line, std::string &key, std::string &val)
Definition cpuInfo.C:32
Macro definitions for debug switches.
#define registerDebugSwitchWithName(Type, Tag, Name)
Define the debug information, lookup as Name.
#define defineDebugSwitchWithName(Type, Name, Value)
Define the debug information, lookup as Name.
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition error.H:688
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
label nPoints
#define DebugInfo
Report an information message using Foam::Info.
Namespace for handling debugging switches.
Definition debug.C:45
Foam::SubStrings splitSpace(const std::string &str, std::string::size_type pos=0)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC).
void inplaceTrimRight(std::string &s)
Trim trailing whitespace inplace.
Namespace for OpenFOAM.
static Type getPrimitive(IFstream &is)
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition int32.H:127
static void readEnsightString(IFstream &is, std::string &value)
messageStream Info
Information stream (stdout output on master, null elsewhere).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
int64_t readInt64(Istream &is)
Read int64_t from stream.
Definition int64IO.C:74
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
label timeIndex