ensightSurfaceReader.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) 2015-2020 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
32// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33
34namespace Foam
35{
38}
39
40
41// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
42
43namespace Foam
44{
45
46// Read and discard specified number of elements
47template<class Type>
48static inline void discard(label n, ensightReadFile& is)
49{
50 Type val;
51
52 while (n > 0)
53 {
54 is.read(val);
55 --n;
56 }
57}
58
59} // End namespace Foam
60
61
62// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
63
64void Foam::ensightSurfaceReader::skip(const label n, Istream& is) const
65{
66 label i = 0;
67 token tok;
68 while (is.good() && (i < n))
69 {
70 is >> tok;
71 ++i;
72
74 << "Skipping token " << tok << nl;
75 }
76
77 if (i != n)
78 {
80 << "Requested to skip " << n << " tokens, but stream exited after "
81 << i << " tokens. Last token read: " << tok
82 << nl;
83 }
84}
85
86
88{
89 do
90 {
91 is.getLine(line);
92
93 // Trim out any '#' comments
94 const auto pos = line.find('#');
95 if (pos != std::string::npos)
96 {
97 line.erase(pos);
98 }
100 }
101 while (line.empty() && is.good());
102}
103
104
106(
107 const word& expected,
108 IFstream& is
109) const
110{
111 string actual;
112 readLine(is, actual);
113
114 if (expected != actual)
115 {
117 << "Expected section header '" << expected
118 << "' but read " << actual << nl
119 << exit(FatalIOError);
120 }
121
123 << "Read section header: " << expected << nl;
124}
125
126
128(
129 const fileName& fName,
130 const label timeIndex
131)
132{
133 fileName result(fName);
134
135 const auto nMask = stringOps::count(fName, '*');
136
137 // If there are any '*' chars, they are assumed to be contiguous
138 // Eg, data/******/geometry
139
140 if (nMask)
141 {
142 std::ostringstream oss;
143 oss << std::setfill('0') << std::setw(nMask) << timeIndex;
144
145 const std::string maskStr(nMask, '*');
146 const std::string indexStr = oss.str();
147 result.replace(maskStr, indexStr);
148 }
149
150 return result;
151}
152
153
156{
157 // Binary flag string if applicable
158 is.readBinaryHeader();
159
160 string buffer;
161
162 Pair<idTypes> idHandling(idTypes::NONE, idTypes::NONE);
163
164 // Ensight Geometry File
165 is.read(buffer);
166 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
167
168 // Description - 1
169 is.read(buffer);
170 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
171
172 // "node id (off|assign|given|ignore)" - "given" is not actually supported
173 is.read(buffer);
174 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
175
176 if (buffer.find("ignore") != std::string::npos)
177 {
178 idHandling.first() = idTypes::IGNORE;
179 }
180 else if (buffer.find("given") != std::string::npos)
181 {
182 idHandling.first() = idTypes::GIVEN;
183 }
184
185 // "element id (off|assign|given|ignore)"
186 is.read(buffer);
187 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
188
189 if (buffer.find("ignore") != std::string::npos)
190 {
191 idHandling.second() = idTypes::IGNORE;
192 }
193 else if (buffer.find("given") != std::string::npos)
194 {
195 idHandling.second() = idTypes::GIVEN;
196 }
197
198
199 // "part" - but could also be an optional "extents"
200 is.read(buffer);
201 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
202
203 if (buffer.find("extents") != std::string::npos)
204 {
205 // Optional extents - read and discard 6 floats
206 // (xmin, xmax, ymin, ymax, zmin, zmax)
207
208 discard<scalar>(6, is);
209
210 // Part
211 is.read(buffer);
212 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
213 }
214
215 // The part number
216 label ivalue;
217 is.read(ivalue);
218 DebugInfo<< "ivalue: " << ivalue << nl;
219
220 // Part description / name
221 is.read(buffer);
222 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
223
224 // "coordinates"
225 is.read(buffer);
226 DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
227
228 return idHandling;
229}
230
231
233{
235
236 if (!is.good())
237 {
239 << "Cannot read file " << is.name()
240 << exit(FatalError);
241 }
242
243 string buffer;
244
245 // Read the file
246
247 debugSection("FORMAT", is);
248 readLine(is, buffer); // type: ensight gold
249
250 debugSection("GEOMETRY", is);
251 readLine(is, buffer);
252
253 // GEOMETRY with any of these
254 // model: 1 xxx.0000.mesh
255 // model: xxx.0000.mesh
256 // model: data/directory/geometry
257 //
258 // - use the last entry
259 meshFileName_ = stringOps::splitSpace(buffer).last().str();
260
261 DebugInfo << "mesh file:" << meshFileName_ << endl;
262
263 debugSection("VARIABLE", is);
264
265 // Read the field description
266 DynamicList<word> fieldNames(16);
267 DynamicList<string> fieldFileNames(16);
268
269 while (is.good())
270 {
271 readLine(is, buffer);
272
273 if (buffer == "TIME")
274 {
275 break;
276 }
277
278 // Read the field name and associated file name. Eg,
279 // scalar per element: 1 p data/********/p
280
281 const auto parsed = stringOps::splitSpace(buffer);
282
283 if (buffer.find(':') == string::npos || parsed.size() < 4)
284 {
286 << "Error reading field file name. Current buffer: "
287 << buffer << endl;
288 continue;
289 }
290 else if (debug)
291 {
292 Info<< "variable line: " << parsed.size();
293 for (const auto& s : parsed)
294 {
295 Info<< " " << s.str();
296 }
297 Info<< nl;
298 }
299
300 fieldNames.append(parsed[parsed.size()-2].str());
301 fieldFileNames.append(parsed.last().str());
302 }
303 fieldNames_.transfer(fieldNames);
304 fieldFileNames_.transfer(fieldFileNames);
305
307 << "fieldNames: " << fieldNames_ << nl
308 << "fieldFileNames: " << fieldFileNames_ << nl;
309
310 // Start reading time information
311 readLine(is, buffer); // time set: <int>
312
313 readLine(is, buffer);
314 readFromLine(3, buffer, nTimeSteps_); // number of steps: <int>
315 readLine(is, buffer);
316 readFromLine(3, buffer, timeStartIndex_); // filename start number: <int>
317 readLine(is, buffer);
318 readFromLine(2, buffer, timeIncrement_); // filename increment: <int>
319
321 << "nTimeSteps: " << nTimeSteps_ << nl
322 << "timeStartIndex: " << timeStartIndex_ << nl
323 << "timeIncrement: " << timeIncrement_ << nl;
324
325 // Read the time values
326 readLine(is, buffer); // time values:
327 timeValues_.setSize(nTimeSteps_);
328 for (label i = 0; i < nTimeSteps_; ++i)
329 {
330 scalar t(readScalar(is));
331
332 timeValues_[i].value() = t;
333 // TODO: use character representation of t directly instead of
334 // regenerating from scalar value
335 timeValues_[i].name() = Foam::name(t);
336 }
337}
338
339
340// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
341
343:
344 surfaceReader(fName),
345 streamFormat_(IOstream::ASCII),
346 baseDir_(fName.path()),
347 meshFileName_(),
348 fieldNames_(),
349 fieldFileNames_(),
350 nTimeSteps_(0),
351 timeStartIndex_(0),
352 timeIncrement_(1),
353 timeValues_(),
354 surfPtr_(nullptr)
355{
356 IFstream is(fName);
357 readCase(is);
358}
359
360
361// * * * * * * * * * * * * * Public Member Functions * * * * * * * * * * * //
362
364(
365 const label timeIndex
366)
367{
369
370 if (!surfPtr_)
371 {
372 fileName meshInstance(replaceMask(meshFileName_, timeIndex));
373 IFstream isBinary(baseDir_/meshInstance, IOstream::BINARY);
374
375 if (!isBinary.good())
376 {
378 << "Cannot read file " << isBinary.name()
379 << exit(FatalError);
380 }
381
382 streamFormat_ = IOstream::BINARY;
383 {
384 istream& iss = isBinary.stdStream();
385
386 // Binary string is *exactly* 80 characters
387 string buf(size_t(80), '\0');
388 iss.read(&buf[0], 80);
389
390 if (!iss)
391 {
392 // Truncated?
393 buf.erase(iss.gcount());
394 }
395
396 // Truncate at the first embedded '\0'
397 const auto endp = buf.find('\0');
398 if (endp != std::string::npos)
399 {
400 buf.erase(endp);
401 }
402
403 // Contains "C Binary" ?
404 if
405 (
406 (buf.find("binary") == std::string::npos)
407 && (buf.find("Binary") == std::string::npos)
408 )
409 {
410 streamFormat_ = IOstream::ASCII;
411 }
412 }
413
414 if (debug)
415 {
416 Info<< "stream format: ";
417 if (streamFormat_ == IOstream::ASCII)
418 {
419 Info<< "ascii" << endl;
420 }
421 else
422 {
423 Info<< "binary" << endl;
424 }
425 }
426
427
428 ensightReadFile is(baseDir_/meshInstance, streamFormat_);
429
431 << "File: " << is.name() << nl;
432
433 Pair<idTypes> idHandling = readGeometryHeader(is);
434
435 label nPoints;
436 is.read(nPoints);
437
439 << "nPoints: " << nPoints << nl;
440
441 if (idHandling.first() == idTypes::GIVEN)
442 {
444 << "Treating node id 'given' as being 'ignore'" << nl
445 << "If something fails, this could be the reason" << nl
446 << endl;
447
448 idHandling.first() = idTypes::IGNORE;
449 }
450
451 if (idHandling.first() == idTypes::IGNORE)
452 {
454 << "Ignore " << nPoints << " node ids" << nl;
455
456 // Read and discard labels
457 discard<label>(nPoints, is);
458 }
459
461 for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
462 {
463 for (point& pt : points)
464 {
465 is.read(pt[cmpt]);
466 }
467 }
468
469
470 // Read faces - may be a mix of tris, quads and polys
471 DynamicList<face> faces(ceil(nPoints/3));
473 string faceType;
474 while (is.good()) // (is.peek() != EOF)
475 {
476 is.read(faceType);
477
478 if (!is.good())
479 {
480 break;
481 }
482
483 label nFace = 0;
484
485 if (faceType == "tria3")
486 {
487 is.read(nFace);
488
490 << "faceType <" << faceType.c_str() << "> count: "
491 << nFace << nl;
492
493 if
494 (
495 idHandling.second() == idTypes::IGNORE
496 || idHandling.second() == idTypes::GIVEN
497 )
498 {
500 << "Ignore " << nFace << " element ids" << nl;
501
502 // Read and discard labels
503 discard<label>(nFace, is);
504 }
505
506 face f(3);
507 for (label facei = 0; facei < nFace; ++facei)
508 {
509 for (label& fp : f)
510 {
511 is.read(fp);
512 }
513
514 faces.append(f);
515 }
516 }
517 else if (faceType == "quad4")
518 {
519 is.read(nFace);
520
522 << "faceType <" << faceType.c_str() << "> count: "
523 << nFace << nl;
524
525 if
526 (
527 idHandling.second() == idTypes::IGNORE
528 || idHandling.second() == idTypes::GIVEN
529 )
530 {
532 << "Ignore " << nFace << " element ids" << nl;
533
534 // Read and discard labels
535 discard<label>(nFace, is);
536 }
537
538 face f(4);
539 for (label facei = 0; facei < nFace; ++facei)
540 {
541 for (label& fp : f)
542 {
543 is.read(fp);
544 }
545
546 faces.append(f);
547 }
548 }
549 else if (faceType == "nsided")
550 {
551 is.read(nFace);
552
554 << "faceType <" << faceType.c_str() << "> count: "
555 << nFace << nl;
556
557 if
558 (
559 idHandling.second() == idTypes::IGNORE
560 || idHandling.second() == idTypes::GIVEN
561 )
562 {
564 << "Ignore " << nFace << " element ids" << nl;
565
566 // Read and discard labels
567 discard<label>(nFace, is);
568 }
569
570 labelList np(nFace);
571 for (label facei = 0; facei < nFace; ++facei)
572 {
573 is.read(np[facei]);
574 }
575 for (label facei = 0; facei < nFace; ++facei)
576 {
577 face f(np[facei]);
578 for (label& fp : f)
579 {
580 is.read(fp);
581 }
582
583 faces.append(f);
584 }
585 }
586 else
587 {
588 if (debug)
589 {
591 << "Unknown face type: <" << faceType.c_str()
592 << ">. Stopping read and continuing with current "
593 << "elements only" << endl;
594 }
595 break;
596 }
597 schema.append(Tuple2<string, label>(faceType, nFace));
598 }
599
600 schema_.transfer(schema);
601
603 << "read nFaces: " << faces.size() << nl
604 << "file schema: " << schema_ << nl;
605
606 // Convert from 1-based Ensight addressing to 0-based OF addressing
607 for (face& f : faces)
608 {
609 for (label& pointi : f)
610 {
611 --pointi;
612 }
613 }
614
615 surfPtr_.reset(new meshedSurface(std::move(points), std::move(faces)));
616 }
617
618 return *surfPtr_;
619}
620
621
623{
624 return timeValues_;
625}
626
627
629(
630 const label timeIndex
631) const
632{
633 return fieldNames_;
634}
635
636
638(
639 const label timeIndex,
640 const label fieldIndex,
641 const scalar& refValue
642) const
643{
644 return readField<scalar>(timeIndex, fieldIndex);
645}
646
647
649(
650 const label timeIndex,
651 const label fieldIndex,
652 const vector& refValue
653) const
654{
655 return readField<vector>(timeIndex, fieldIndex);
656}
657
658
661(
662 const label timeIndex,
663 const label fieldIndex,
664 const sphericalTensor& refValue
665) const
666{
667 return readField<sphericalTensor>(timeIndex, fieldIndex);
668}
669
670
672(
673 const label timeIndex,
674 const label fieldIndex,
675 const symmTensor& refValue
676) const
677{
678 return readField<symmTensor>(timeIndex, fieldIndex);
679}
680
681
683(
684 const label timeIndex,
685 const label fieldIndex,
686 const tensor& refValue
687) const
688{
689 return readField<tensor>(timeIndex, fieldIndex);
690}
691
692
693// ************************************************************************* //
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
const Field< Type > & field() const
Return field.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
T & first() noexcept
The first element of the list, position [0].
Definition: FixedListI.H:207
Input from file stream, using an ISstream.
Definition: IFstream.H:57
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: ISstream.H:113
virtual std::istream & stdStream()
Access to underlying std::istream.
Definition: IFstream.C:94
An IOstream is an abstract base class for all input/output systems; be they streams,...
Definition: IOstream.H:82
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:233
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: ISstreamI.H:76
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:69
const T & second() const noexcept
Return second element, which is also the last element.
Definition: PairI.H:120
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:58
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Ensight output with specialized read() for strings, integers and floats. Correctly handles binary rea...
virtual Istream & read(char *buf, std::streamsize count)
Binary read.
Istream & readBinaryHeader()
Read "C Binary" for binary files (eg, geometry/measured)
Ensight format surface reader.
void debugSection(const word &expected, IFstream &is) const
Read and check a section header.
void skip(const label n, Istream &is) const
Helper function to skip forward n steps in stream.
static fileName replaceMask(const fileName &fName, const label timeIndex)
Replace the '*' mask chars with a 0 padded string.
virtual instantList times() const
Return a list of the available times.
Pair< idTypes > readGeometryHeader(ensightReadFile &is) const
Read (and discard) geometry file header.
void readCase(IFstream &is)
Read the case file.
void readLine(IFstream &is, string &buffer) const
Helper function to read an ascii line from file.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
A class for handling file names.
Definition: fileName.H:76
A line primitive.
Definition: line.H:68
static constexpr direction nComponents
Number of components in bool is 1.
Definition: bool.H:98
virtual const wordRes & fieldNames() const noexcept
Return names of fields to probe.
Definition: probes.H:335
string & replace(const std::string &s1, const std::string &s2, size_type pos=0)
Definition: string.C:108
virtual const fvGeometryScheme & geometry() const
Return reference to geometry calculation scheme.
Base class for surface readers.
Definition: surfaceReader.H:54
A class for managing temporary objects.
Definition: tmp.H:65
A token holds an item read from Istream.
Definition: token.H:69
static constexpr uint64_t npos
Out of range position or size.
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const pointField & points
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugInFunction
Report an information message using Foam::Info.
Foam::SubStrings< StringType > splitSpace(const StringType &str)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
std::string::size_type count(const std::string &s, const char c)
Count the number of occurrences of the specified character.
Definition: stringOps.C:697
void inplaceTrimRight(std::string &s)
Trim trailing whitespace inplace.
Definition: stringOps.C:992
Namespace for OpenFOAM.
dimensionedScalar pos(const dimensionedScalar &ds)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
static void discard(label n, ensightReadFile &is)
MeshedSurface< face > meshedSurface
uint8_t direction
Definition: direction.H:56
IOerror FatalIOError
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
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
label timeIndex
Definition: getTimeIndex.H:30
labelList f(nPoints)