mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: read support for EnSight single-file transient (#3154)
- the ensightReadFile init() now automatically sets up binary/ascii
(for geometry files) and checks for the transient "BEGIN TIME STEP"
marker. If found, will also populate the file offsets for each of
the timesteps. If no corresponding footer is found (which would be
very inefficient), it simply pretends that there is only a single
time step instead of performing a costly file scan.
- parsing of the ensight case file now also supports the use of
filename numbers:
as an alternative to
filename start number:
filename increment:
- improved parsing robustness of "time values:" entry.
Can now also have contents on the same line as the introducer.
ENH: base-level adjustments for writing transient single-file
- beginGeometry() is now separated out from file creation.
- in append mode, ensightFile and ensightGeoFile will attempt to
parse existing time-step information.
This commit is contained in:
committed by
Kutalmış Berçin
parent
ee895577ae
commit
dfc9a8923a
@ -1,3 +0,0 @@
|
||||
Test-ensightFile.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-ensightFile
|
||||
@ -1,8 +0,0 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/conversion/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-lconversion
|
||||
3
applications/test/ensightFile1/Make/files
Normal file
3
applications/test/ensightFile1/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-ensightFile1.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-ensightFile1
|
||||
5
applications/test/ensightFile1/Make/options
Normal file
5
applications/test/ensightFile1/Make/options
Normal file
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lfileFormats
|
||||
137
applications/test/ensightFile1/Test-ensightFile1.cxx
Normal file
137
applications/test/ensightFile1/Test-ensightFile1.cxx
Normal file
@ -0,0 +1,137 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
Test-ensightFile
|
||||
|
||||
Description
|
||||
check cleanup of ensight file and variable names
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "ensightFile.H"
|
||||
#include "ensightGeoFile.H"
|
||||
#include "Switch.H"
|
||||
#include "IOstreams.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noBanner();
|
||||
argList::noParallel();
|
||||
argList::addBoolOption("ascii", "open as ascii instead of binary");
|
||||
argList::addBoolOption("binary", "(default)");
|
||||
argList::addBoolOption("clear", "force clear of time-steps");
|
||||
argList::addBoolOption("no-end", "skip use of endTimeStep");
|
||||
argList::addBoolOption("append", "open in append mode");
|
||||
argList::addOption("geom", "geometry file");
|
||||
argList::addOption("field", "field file");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
const bool with_ascii = args.found("ascii") && !args.found("binary");
|
||||
// const bool with_binary = args.found("binary");
|
||||
const bool with_append = args.found("append");
|
||||
const bool with_clear = args.found("clear");
|
||||
const bool without_end = args.found("no-end");
|
||||
|
||||
const IOstreamOption::streamFormat fmt =
|
||||
(
|
||||
with_ascii
|
||||
? IOstreamOption::ASCII
|
||||
: IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
const IOstreamOption::appendType append =
|
||||
(
|
||||
with_append
|
||||
? IOstreamOption::APPEND_ATE
|
||||
: IOstreamOption::NO_APPEND
|
||||
);
|
||||
|
||||
|
||||
fileName file;
|
||||
if (args.readIfPresent("geom", file))
|
||||
{
|
||||
Info<< "Open " << file << " as geometry "
|
||||
<< " format:" << (with_ascii ? "ASCII" : "BINARY")
|
||||
<< " append:" << Switch::name(with_append) << nl;
|
||||
|
||||
ensightGeoFile ensFile(append, file, fmt);
|
||||
|
||||
if (append)
|
||||
{
|
||||
ensFile.beginTimeStep();
|
||||
|
||||
// At the moment need to pair begin/end time-step calls
|
||||
if (!without_end)
|
||||
{
|
||||
ensFile.endTimeStep();
|
||||
}
|
||||
}
|
||||
|
||||
if (with_clear)
|
||||
{
|
||||
ensFile.clearTimeSteps();
|
||||
}
|
||||
}
|
||||
|
||||
if (args.readIfPresent("field", file))
|
||||
{
|
||||
Info<< "Open " << file << " as field"
|
||||
<< " format:" << (with_ascii ? "ASCII" : "BINARY")
|
||||
<< " append:" << Switch::name(with_append) << nl;
|
||||
|
||||
ensightFile ensFile(append, file, fmt);
|
||||
|
||||
if (append)
|
||||
{
|
||||
ensFile.beginTimeStep();
|
||||
|
||||
// At the moment need to pair begin/end time-step calls
|
||||
if (!without_end)
|
||||
{
|
||||
ensFile.endTimeStep();
|
||||
}
|
||||
}
|
||||
|
||||
if (with_clear)
|
||||
{
|
||||
ensFile.clearTimeSteps();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
3
applications/test/ensightFileName/Make/files
Normal file
3
applications/test/ensightFileName/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-ensightFileName.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-ensightFileName
|
||||
5
applications/test/ensightFileName/Make/options
Normal file
5
applications/test/ensightFileName/Make/options
Normal file
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lfileFormats
|
||||
@ -24,10 +24,10 @@ License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
Test-ensightFile
|
||||
Test-ensightFileName
|
||||
|
||||
Description
|
||||
check cleanup of ensight file and variable names
|
||||
Check cleanup of ensight file and variable names
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2022-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -93,29 +93,34 @@ void Foam::fileFormats::ensightMeshReader::readIDs
|
||||
(
|
||||
ensightReadFile& is,
|
||||
const bool doRead,
|
||||
const label nShapes,
|
||||
const label elemCount,
|
||||
labelList& foamToElem,
|
||||
Map<label>& elemToFoam
|
||||
) const
|
||||
{
|
||||
const label sz = foamToElem.size();
|
||||
foamToElem.resize(sz+nShapes);
|
||||
const label begElem = foamToElem.size();
|
||||
const label endElem = begElem + elemCount;
|
||||
|
||||
foamToElem.resize(foamToElem.size()+elemCount);
|
||||
|
||||
if (doRead)
|
||||
{
|
||||
elemToFoam.reserve(elemToFoam.size()+nShapes);
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
elemToFoam.reserve(elemToFoam.size()+elemCount);
|
||||
|
||||
for (label elemi = begElem; elemi < endElem; ++elemi)
|
||||
{
|
||||
label elemi;
|
||||
is.read(elemi);
|
||||
foamToElem[sz+shapei] = elemi;
|
||||
elemToFoam.insert(elemi, sz+shapei);
|
||||
label id;
|
||||
is.read(id);
|
||||
foamToElem[elemi] = id;
|
||||
elemToFoam.insert(id, elemi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
// identity
|
||||
for (label elemi = begElem; elemi < endElem; ++elemi)
|
||||
{
|
||||
foamToElem[sz+shapei] = sz+shapei;
|
||||
foamToElem[elemi] = elemi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,37 +214,54 @@ bool Foam::fileFormats::ensightMeshReader::readGoldPart
|
||||
// Work
|
||||
DynamicList<label> verts;
|
||||
|
||||
string line;
|
||||
string buffer;
|
||||
while (is.good())
|
||||
{
|
||||
do
|
||||
{
|
||||
is.readKeyword(line);
|
||||
// Get entire line/string
|
||||
is.read(buffer);
|
||||
}
|
||||
while (line.empty() && is.good());
|
||||
while (buffer.empty() && is.good());
|
||||
|
||||
const auto split = stringOps::splitSpace(line);
|
||||
if (!is.good())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (buffer.contains("BEGIN TIME STEP"))
|
||||
{
|
||||
// Graciously handle a miscued start
|
||||
continue;
|
||||
}
|
||||
else if (buffer.contains("END TIME STEP"))
|
||||
{
|
||||
// END TIME STEP is a valid means to terminate input
|
||||
break;
|
||||
}
|
||||
const auto split = stringOps::splitSpace(buffer);
|
||||
|
||||
if (split.size() == 0)
|
||||
if (split.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (split[0] == "part")
|
||||
const auto keyword(split[0].str());
|
||||
|
||||
if (keyword == "part")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (split[0] == "node_ids")
|
||||
else if (keyword == "node_ids")
|
||||
{
|
||||
const label nPoints = points.size();
|
||||
// Ignore for now
|
||||
for (label i = 0; i < nPoints; i++)
|
||||
// Ignore point ids
|
||||
for (label pointi = 0; pointi < nPoints; ++pointi)
|
||||
{
|
||||
label index;
|
||||
is.read(index);
|
||||
label id;
|
||||
is.read(id);
|
||||
}
|
||||
}
|
||||
else if (split[0] == "coordinates")
|
||||
else if (keyword == "coordinates")
|
||||
{
|
||||
label nPoints;
|
||||
is.read(nPoints);
|
||||
@ -257,207 +279,205 @@ bool Foam::fileFormats::ensightMeshReader::readGoldPart
|
||||
nodeIdToPoints
|
||||
);
|
||||
|
||||
points.setSize(nPoints);
|
||||
|
||||
for (label pointi = 0; pointi < nPoints; pointi++)
|
||||
{
|
||||
is.read(points[pointi].x());
|
||||
is.readPoints(nPoints, points);
|
||||
}
|
||||
for (label pointi = 0; pointi < nPoints; pointi++)
|
||||
else if (keyword == "tetra4")
|
||||
{
|
||||
is.read(points[pointi].y());
|
||||
}
|
||||
for (label pointi = 0; pointi < nPoints; pointi++)
|
||||
{
|
||||
is.read(points[pointi].z());
|
||||
}
|
||||
}
|
||||
else if (split[0] == "tetra4")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent<< "tetra4 " << nShapes
|
||||
Pout<< indent<< "tetra4 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label celli = cells.size();
|
||||
cells.resize(celli+nShapes);
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
cellToElemIds,
|
||||
elemIdToCells
|
||||
);
|
||||
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
cells.resize(startElemi+elemCount);
|
||||
faceListList::subList myElements = cells.slice(startElemi);
|
||||
|
||||
const auto& model = cellModel::ref(cellModel::TET);
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
readVerts(is, 4, nodeIdToPoints, verts);
|
||||
if (setHandedness_)
|
||||
{
|
||||
setHandedness(model, verts, points);
|
||||
}
|
||||
const cellShape cellVerts(model, verts);
|
||||
cells[celli+shapei] = cellVerts.faces();
|
||||
cellFaces = cellShape(model, verts).faces();
|
||||
}
|
||||
}
|
||||
else if (split[0] == "pyramid5")
|
||||
else if (keyword == "pyramid5")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent<< "pyramid5 " << nShapes
|
||||
Pout<< indent<< "pyramid5 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label celli = cells.size();
|
||||
cells.resize(celli+nShapes);
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
cellToElemIds,
|
||||
elemIdToCells
|
||||
);
|
||||
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
cells.resize(startElemi+elemCount);
|
||||
faceListList::subList myElements = cells.slice(startElemi);
|
||||
|
||||
const auto& model = cellModel::ref(cellModel::PYR);
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
readVerts(is, 5, nodeIdToPoints, verts);
|
||||
if (setHandedness_)
|
||||
{
|
||||
setHandedness(model, verts, points);
|
||||
}
|
||||
const cellShape cellVerts(model, verts);
|
||||
cells[celli+shapei] = cellVerts.faces();
|
||||
cellFaces = cellShape(model, verts).faces();
|
||||
}
|
||||
}
|
||||
else if (split[0] == "penta6")
|
||||
else if (keyword == "penta6")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent<< "penta6 " << nShapes
|
||||
Pout<< indent<< "penta6 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label celli = cells.size();
|
||||
cells.resize(celli+nShapes);
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
cellToElemIds,
|
||||
elemIdToCells
|
||||
);
|
||||
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
cells.resize(startElemi+elemCount);
|
||||
faceListList::subList myElements = cells.slice(startElemi);
|
||||
|
||||
const auto& model = cellModel::ref(cellModel::PRISM);
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
readVerts(is, 6, nodeIdToPoints, verts);
|
||||
if (setHandedness_)
|
||||
{
|
||||
setHandedness(model, verts, points);
|
||||
}
|
||||
const cellShape cellVerts(model, verts);
|
||||
cells[celli+shapei] = cellVerts.faces();
|
||||
cellFaces = cellShape(model, verts).faces();
|
||||
}
|
||||
}
|
||||
else if (split[0] == "hexa8")
|
||||
else if (keyword == "hexa8")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent<< "hexa8 " << nShapes
|
||||
Pout<< indent<< "hexa8 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label celli = cells.size();
|
||||
cells.resize(celli+nShapes);
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
cellToElemIds,
|
||||
elemIdToCells
|
||||
);
|
||||
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
cells.resize(startElemi+elemCount);
|
||||
faceListList::subList myElements = cells.slice(startElemi);
|
||||
|
||||
const auto& model = cellModel::ref(cellModel::HEX);
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
readVerts(is, 8, nodeIdToPoints, verts);
|
||||
if (setHandedness_)
|
||||
{
|
||||
setHandedness(model, verts, points);
|
||||
}
|
||||
const cellShape cellVerts(model, verts);
|
||||
cells[celli+shapei] = cellVerts.faces();
|
||||
cellFaces = cellShape(model, verts).faces();
|
||||
}
|
||||
}
|
||||
else if (split[0] == "nfaced")
|
||||
else if (keyword == "nfaced")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent<< "nfaced " << nShapes
|
||||
Pout<< indent<< "nfaced " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label celli = cells.size();
|
||||
cells.resize(celli+nShapes);
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
cellToElemIds,
|
||||
elemIdToCells
|
||||
);
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
cells.resize(startElemi+elemCount);
|
||||
faceListList::subList myElements = cells.slice(startElemi);
|
||||
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
label nFaces;
|
||||
is.read(nFaces);
|
||||
faceList& cellFaces = cells[celli+shapei];
|
||||
cellFaces.setSize(nFaces);
|
||||
cellFaces.resize(nFaces);
|
||||
}
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (auto& cellFaces : myElements)
|
||||
{
|
||||
faceList& cellFaces = cells[celli+shapei];
|
||||
forAll(cellFaces, cellFacei)
|
||||
for (face& f : cellFaces)
|
||||
{
|
||||
label nVerts;
|
||||
is.read(nVerts);
|
||||
cellFaces[cellFacei].setSize(nVerts);
|
||||
f.resize(nVerts);
|
||||
}
|
||||
}
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (faceList& cellFaces : myElements)
|
||||
{
|
||||
faceList& cellFaces = cells[celli+shapei];
|
||||
forAll(cellFaces, cellFacei)
|
||||
for (face& f : cellFaces)
|
||||
{
|
||||
face& f = cellFaces[cellFacei];
|
||||
readVerts(is, f.size(), nodeIdToPoints, verts);
|
||||
f.labelList::operator=(verts);
|
||||
}
|
||||
}
|
||||
|
||||
forAll(f, fp)
|
||||
// Full check
|
||||
forAll(myElements, elemi)
|
||||
{
|
||||
if (f[fp] < 0 || f[fp] >= points.size())
|
||||
for (const face& f : myElements[elemi])
|
||||
{
|
||||
FatalErrorInFunction<< "Face:" << shapei
|
||||
for (label pointi : f)
|
||||
{
|
||||
if (pointi < 0 || pointi >= points.size())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Face:" << elemi
|
||||
<< " verts:" << f
|
||||
<< " indexes outside points:" << points.size()
|
||||
<< exit(FatalError);
|
||||
@ -466,107 +486,104 @@ bool Foam::fileFormats::ensightMeshReader::readGoldPart
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (split[0] == "tria3")
|
||||
else if (keyword == "tria3")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent << "tria3 " << nShapes
|
||||
Pout<< indent << "tria3 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label facei = faces.size();
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
faceToElemIDs,
|
||||
elemIdToFaces
|
||||
);
|
||||
|
||||
faces.setSize(facei+nShapes);
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
faces.resize(startElemi+elemCount, face(3)); // <- tria3
|
||||
faceList::subList myElements = faces.slice(startElemi);
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (face& f : myElements)
|
||||
{
|
||||
auto& f = faces[facei+shapei];
|
||||
f.setSize(3);
|
||||
readVerts(is, f.size(), nodeIdToPoints, verts);
|
||||
f.labelList::operator=(verts);
|
||||
}
|
||||
}
|
||||
else if (split[0] == "quad4")
|
||||
else if (keyword == "quad4")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent << "quad4 " << nShapes
|
||||
Pout<< indent << "quad4 " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label facei = faces.size();
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
faceToElemIDs,
|
||||
elemIdToFaces
|
||||
);
|
||||
|
||||
faces.setSize(facei+nShapes);
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
faces.resize(startElemi+elemCount, face(4)); // <- quad4
|
||||
faceList::subList myElements = faces.slice(startElemi);
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (face& f : myElements)
|
||||
{
|
||||
auto& f = faces[facei+shapei];
|
||||
f.setSize(4);
|
||||
readVerts(is, f.size(), nodeIdToPoints, verts);
|
||||
f.labelList::operator=(verts);
|
||||
}
|
||||
}
|
||||
else if (split[0] == "nsided")
|
||||
else if (keyword == "nsided")
|
||||
{
|
||||
label nShapes;
|
||||
is.read(nShapes);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
Pout<< indent << "nsided " << nShapes
|
||||
Pout<< indent << "nsided " << elemCount
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
|
||||
const label facei = faces.size();
|
||||
|
||||
readIDs
|
||||
(
|
||||
is,
|
||||
read_elem_ids,
|
||||
nShapes,
|
||||
elemCount,
|
||||
faceToElemIDs,
|
||||
elemIdToFaces
|
||||
);
|
||||
|
||||
faces.setSize(facei+nShapes);
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = cells.size();
|
||||
faces.resize(startElemi+elemCount);
|
||||
faceList::subList myElements = faces.slice(startElemi);
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (face& f : myElements)
|
||||
{
|
||||
auto& f = faces[facei+shapei];
|
||||
label nVerts;
|
||||
is.read(nVerts);
|
||||
f.setSize(nVerts);
|
||||
f.resize(nVerts);
|
||||
}
|
||||
|
||||
for (label shapei = 0; shapei < nShapes; shapei++)
|
||||
for (face& f : myElements)
|
||||
{
|
||||
auto& f = faces[facei+shapei];
|
||||
readVerts(is, f.size(), nodeIdToPoints, verts);
|
||||
f.labelList::operator=(verts);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WarningInFunction << "Unhandled key " << string(split[0])
|
||||
<< " from line " << line
|
||||
WarningInFunction << "Unhandled key " << keyword
|
||||
<< " from line " << buffer
|
||||
<< " starting at line " << is.lineNumber()
|
||||
<< " position " << is.stdStream().tellg() << endl;
|
||||
}
|
||||
@ -584,16 +601,21 @@ bool Foam::fileFormats::ensightMeshReader::readGeometry
|
||||
const scalar scaleFactor
|
||||
)
|
||||
{
|
||||
// Auto-detect ascii/binary format,
|
||||
// skips any initial "BEGIN TIME STEP"
|
||||
|
||||
ensightReadFile is(geometryFile_);
|
||||
|
||||
// Skip 'binary' tag
|
||||
is.readBinaryHeader();
|
||||
|
||||
string header;
|
||||
is.read(header);
|
||||
Info<< "Ensight : " << header << endl;
|
||||
is.read(header);
|
||||
Info<< "Ensight : " << header << endl;
|
||||
string buffer;
|
||||
|
||||
// Ensight Geometry File
|
||||
is.read(buffer);
|
||||
Info<< "Ensight : " << buffer << nl;
|
||||
|
||||
// Description - 1
|
||||
is.read(buffer);
|
||||
Info<< "Ensight : " << buffer << nl;
|
||||
|
||||
|
||||
bool read_node_ids = false;
|
||||
@ -623,61 +645,72 @@ bool Foam::fileFormats::ensightMeshReader::readGeometry
|
||||
|
||||
|
||||
// Parse all
|
||||
string line;
|
||||
SubStrings<string> split;
|
||||
|
||||
while (is.good())
|
||||
{
|
||||
do
|
||||
{
|
||||
is.readKeyword(line);
|
||||
// Get entire line/string
|
||||
is.read(buffer);
|
||||
}
|
||||
while (line.empty() && is.good());
|
||||
const auto split = stringOps::splitSpace(line);
|
||||
while (buffer.empty() && is.good());
|
||||
if (buffer.contains("END TIME STEP"))
|
||||
{
|
||||
// END TIME STEP is a valid means to terminate input
|
||||
break;
|
||||
}
|
||||
split = stringOps::splitSpace(buffer);
|
||||
|
||||
if (split[0] == "extents")
|
||||
if (split.empty())
|
||||
{
|
||||
point min;
|
||||
point max;
|
||||
is.read(min.x());
|
||||
is.read(max.x());
|
||||
is.read(min.y());
|
||||
is.read(max.y());
|
||||
is.read(min.z());
|
||||
is.read(max.z());
|
||||
Pout<< indent
|
||||
<< "Read extents " << boundBox(min, max)
|
||||
<< endl;
|
||||
continue;
|
||||
}
|
||||
else if (split[0] == "node")
|
||||
|
||||
const auto keyword(split[0].str());
|
||||
|
||||
if (keyword == "extents")
|
||||
{
|
||||
word id(split[1]);
|
||||
word op(split[2]);
|
||||
// Optional extents (xmin, xmax, ymin, ymax, zmin, zmax)
|
||||
|
||||
boundBox bb;
|
||||
point& min = bb.min();
|
||||
point& max = bb.max();
|
||||
|
||||
is.read(min.x()); is.read(max.x());
|
||||
is.read(min.y()); is.read(max.y());
|
||||
is.read(min.z()); is.read(max.z());
|
||||
|
||||
Pout<< indent << "Read extents " << bb << endl;
|
||||
}
|
||||
else if (keyword == "node")
|
||||
{
|
||||
// "node id (off|assign|given|ignore)"
|
||||
std::string op(split[2]);
|
||||
if (op == "given" || op == "ignore")
|
||||
{
|
||||
Pout<< indent << "Reading node ids" << endl;
|
||||
read_node_ids = true;
|
||||
}
|
||||
}
|
||||
else if (split[0] == "element")
|
||||
else if (keyword == "element")
|
||||
{
|
||||
word id(split[1]);
|
||||
word op(split[2]);
|
||||
// "element id (off|assign|given|ignore)"
|
||||
std::string op(split[2]);
|
||||
if (op == "given" || op == "ignore")
|
||||
{
|
||||
Pout<< indent << "Reading element ids" << endl;
|
||||
read_elem_ids = true;
|
||||
}
|
||||
}
|
||||
else if (split[0] == "part")
|
||||
else if (keyword == "part")
|
||||
{
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
// Make space
|
||||
partIDs.emplace_back();
|
||||
is.read(partIDs.back());
|
||||
|
||||
partNames.emplace_back();
|
||||
is.read(partNames.back());
|
||||
// Read part id and name
|
||||
is.read(partIDs.emplace_back());
|
||||
is.read(partNames.emplace_back());
|
||||
|
||||
Pout<< indent
|
||||
<< "Reading part " << partIDs.back()
|
||||
@ -954,7 +987,7 @@ bool Foam::fileFormats::ensightMeshReader::readGeometry
|
||||
const face& f = rotateFace(cFaces[cFacei], rotatedFace);
|
||||
|
||||
const auto fFnd = vertsToCell.find(f);
|
||||
if (fFnd)
|
||||
if (fFnd.good())
|
||||
{
|
||||
// Already inserted. Internal face.
|
||||
vertsToCell.erase(fFnd);
|
||||
@ -1026,7 +1059,12 @@ bool Foam::fileFormats::ensightMeshReader::readGeometry
|
||||
)
|
||||
);
|
||||
|
||||
if (!cAndF)
|
||||
if (cAndF.good())
|
||||
{
|
||||
partCellAndFace[patchFacei++] = cAndF.val();
|
||||
vertsToCell.erase(cAndF);
|
||||
}
|
||||
else
|
||||
{
|
||||
//WarningInFunction
|
||||
// << "Did not find face " << facei
|
||||
@ -1036,11 +1074,6 @@ bool Foam::fileFormats::ensightMeshReader::readGeometry
|
||||
// << " in part " << parti
|
||||
// << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
partCellAndFace[patchFacei++] = cAndF();
|
||||
vertsToCell.erase(cAndF);
|
||||
}
|
||||
}
|
||||
partCellAndFace.setSize(patchFacei);
|
||||
}
|
||||
|
||||
@ -554,7 +554,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
autoPtr<ensightGeoFile> os =
|
||||
ensCase.newGeometry(hasMovingMesh);
|
||||
ensMesh.write(os);
|
||||
|
||||
ensMesh.write(os.ref());
|
||||
}
|
||||
|
||||
// finite-area
|
||||
@ -562,7 +563,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
autoPtr<ensightGeoFile> os =
|
||||
ensFaCasePtr->newGeometry(hasMovingMesh);
|
||||
ensFaMeshPtr->write(os);
|
||||
|
||||
ensFaMeshPtr->write(os.ref());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -26,7 +26,6 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "ensightCase.H"
|
||||
#include "ensightGeoFile.H"
|
||||
#include "Time.H"
|
||||
#include "cloud.H"
|
||||
#include "IOmanip.H"
|
||||
@ -42,15 +41,26 @@ const char* Foam::ensightCase::geometryName = "geometry";
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
Foam::word Foam::ensightCase::padded(const int nwidth, const label value)
|
||||
Foam::word Foam::ensightCase::mask(const int nwidth)
|
||||
{
|
||||
if (nwidth < 1)
|
||||
{
|
||||
return Foam::name(value);
|
||||
return word();
|
||||
}
|
||||
|
||||
return word(std::string(nwidth, '*'), false); // stripping=false
|
||||
}
|
||||
|
||||
|
||||
Foam::word Foam::ensightCase::padded(const int nwidth, const label index)
|
||||
{
|
||||
if (nwidth < 1)
|
||||
{
|
||||
return Foam::name(index);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::setfill('0') << std::setw(nwidth) << value;
|
||||
oss << std::setfill('0') << std::setw(nwidth) << index;
|
||||
|
||||
return word(oss.str(), false); // stripping=false
|
||||
}
|
||||
@ -230,7 +240,7 @@ void Foam::ensightCase::initialize()
|
||||
// eg, convert new results or a particular time interval
|
||||
// OR remove everything
|
||||
|
||||
if (isDir(ensightDir_))
|
||||
if (Foam::isDir(ensightDir_))
|
||||
{
|
||||
if (options_->overwrite())
|
||||
{
|
||||
@ -245,7 +255,7 @@ void Foam::ensightCase::initialize()
|
||||
}
|
||||
|
||||
// Create ensight and data directories
|
||||
mkDir(dataDir());
|
||||
Foam::mkDir(dataDir());
|
||||
|
||||
// The case file is always ASCII
|
||||
os_.reset(new OFstream(ensightDir_/caseName_, IOstreamOption::ASCII));
|
||||
@ -508,7 +518,7 @@ Foam::ensightCase::createDataFile
|
||||
// Note that data/ITER is indeed a valid ensight::FileName
|
||||
|
||||
const fileName outdir = dataDir()/padded(timeIndex_);
|
||||
mkDir(outdir);
|
||||
Foam::mkDir(outdir);
|
||||
|
||||
return autoPtr<ensightFile>::New(outdir, name, format());
|
||||
}
|
||||
@ -537,7 +547,7 @@ Foam::ensightCase::createCloudFile
|
||||
: (dataDir() / padded(timeIndex_) / cloud::prefix / cloudName)
|
||||
);
|
||||
|
||||
mkDir(outdir); // should be unnecessary after newCloud()
|
||||
Foam::mkDir(outdir); // should be unnecessary after newCloud()
|
||||
|
||||
return autoPtr<ensightFile>::New(outdir, name, format());
|
||||
}
|
||||
@ -561,13 +571,7 @@ Foam::ensightCase::ensightCase
|
||||
caseName_(caseName + ".case"),
|
||||
changed_(false),
|
||||
timeIndex_(0),
|
||||
timeValue_(0),
|
||||
timesUsed_(),
|
||||
geomTimes_(),
|
||||
cloudTimes_(),
|
||||
variables_(),
|
||||
nodeVariables_(),
|
||||
cloudVars_()
|
||||
timeValue_(0)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
@ -586,13 +590,7 @@ Foam::ensightCase::ensightCase
|
||||
caseName_(caseName + ".case"),
|
||||
changed_(false),
|
||||
timeIndex_(0),
|
||||
timeValue_(0),
|
||||
timesUsed_(),
|
||||
geomTimes_(),
|
||||
cloudTimes_(),
|
||||
variables_(),
|
||||
nodeVariables_(),
|
||||
cloudVars_()
|
||||
timeValue_(0)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
@ -624,7 +622,7 @@ void Foam::ensightCase::setTime(const scalar value, const label index)
|
||||
// Note that data/ITER is indeed a valid ensight::FileName
|
||||
|
||||
const fileName outdir = dataDir()/padded(timeIndex_);
|
||||
mkDir(outdir);
|
||||
Foam::mkDir(outdir);
|
||||
|
||||
// place a timestamp in the directory for future reference
|
||||
OFstream timeStamp(outdir/"time");
|
||||
@ -842,7 +840,7 @@ Foam::ensightCase::newGeometry
|
||||
bool moving
|
||||
) const
|
||||
{
|
||||
autoPtr<Foam::ensightGeoFile> output;
|
||||
autoPtr<ensightGeoFile> filePtr;
|
||||
|
||||
if (UPstream::master())
|
||||
{
|
||||
@ -859,14 +857,16 @@ Foam::ensightCase::newGeometry
|
||||
// Static mesh: write as "data/constant/geometry"
|
||||
path = dataDir()/word("constant");
|
||||
}
|
||||
mkDir(path);
|
||||
Foam::mkDir(path);
|
||||
|
||||
noteGeometry(moving); // note for later use
|
||||
|
||||
return autoPtr<ensightGeoFile>::New(path, geometryName, format());
|
||||
filePtr.reset(new ensightGeoFile(path, geometryName, format()));
|
||||
|
||||
// Before 2024-05 also implicitly called beginGeometry()
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return filePtr;
|
||||
}
|
||||
|
||||
|
||||
@ -876,23 +876,24 @@ Foam::ensightCase::newCloud
|
||||
const word& cloudName
|
||||
) const
|
||||
{
|
||||
autoPtr<Foam::ensightFile> output;
|
||||
autoPtr<ensightFile> filePtr;
|
||||
|
||||
if (UPstream::master())
|
||||
{
|
||||
output = createCloudFile(cloudName, "positions");
|
||||
filePtr = createCloudFile(cloudName, "positions");
|
||||
auto& os = filePtr();
|
||||
|
||||
// Tag binary format (just like geometry files)
|
||||
output().writeBinaryHeader();
|
||||
os.writeBinaryHeader();
|
||||
|
||||
// Description
|
||||
output().write(cloud::prefix/cloudName);
|
||||
output().newline();
|
||||
os.write(cloud::prefix/cloudName);
|
||||
os.newline();
|
||||
|
||||
noteCloud(cloudName); // note for later use
|
||||
}
|
||||
|
||||
return output;
|
||||
return filePtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -42,13 +42,11 @@ SourceFiles
|
||||
#define Foam_ensightCase_H
|
||||
|
||||
#include "autoPtr.H"
|
||||
#include "HashSet.H"
|
||||
#include "InfoProxy.H"
|
||||
#include "Map.H"
|
||||
#include "HashSet.H"
|
||||
#include "Map.H"
|
||||
#include "Pstream.H"
|
||||
#include "ensightGeoFile.H"
|
||||
#include <memory>
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -195,6 +193,10 @@ private:
|
||||
) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
ensightCase(const ensightCase&) = delete;
|
||||
|
||||
@ -202,8 +204,6 @@ private:
|
||||
void operator=(const ensightCase&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from components
|
||||
@ -229,8 +229,19 @@ public:
|
||||
|
||||
// Static Functions
|
||||
|
||||
//- Stringified zero-padded integer value
|
||||
static word padded(const int nwidth, const label value);
|
||||
//- A '*' mask of specified width
|
||||
static word mask(const int nwidth);
|
||||
|
||||
//- Stringified zero-padded integer value of specified width
|
||||
static word padded(const int nwidth, const label index);
|
||||
|
||||
//- Replace the '*' mask chars with zero-padded integer value
|
||||
template<class StringType>
|
||||
static StringType expand_mask
|
||||
(
|
||||
const StringType& input,
|
||||
const label index
|
||||
);
|
||||
|
||||
|
||||
// Member Functions
|
||||
@ -285,6 +296,7 @@ public:
|
||||
// Addition of entries to case file
|
||||
|
||||
//- Open stream for new geometry file (on master).
|
||||
//- Does not include beginGeometry() marker.
|
||||
autoPtr<ensightGeoFile> newGeometry(bool moving = false) const;
|
||||
|
||||
//- Open stream for new cloud positions (on master).
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -73,7 +73,7 @@ inline bool Foam::ensightCase::separateCloud() const
|
||||
|
||||
inline Foam::Ostream& Foam::ensightCase::operator()() const
|
||||
{
|
||||
return *os_;
|
||||
return (os_ ? *os_ : Foam::Snull);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,6 +28,35 @@ License
|
||||
#include "cloud.H"
|
||||
#include "ensightPTraits.H"
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
template<class StringType>
|
||||
StringType Foam::ensightCase::expand_mask
|
||||
(
|
||||
const StringType& input,
|
||||
const label timeIndex
|
||||
)
|
||||
{
|
||||
StringType result(input);
|
||||
|
||||
const auto nMask = std::count(input.begin(), input.end(), '*');
|
||||
|
||||
// If there are any '*' chars, they are assumed to be contiguous
|
||||
// Eg, data/******/geometry
|
||||
|
||||
if (nMask)
|
||||
{
|
||||
result.replace
|
||||
(
|
||||
ensightCase::mask(nMask),
|
||||
ensightCase::padded(nMask, timeIndex)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
|
||||
@ -27,6 +27,7 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "ensightFile.H"
|
||||
#include "ensightReadFile.H"
|
||||
#include "error.H"
|
||||
#include "List.H"
|
||||
#include <cstring>
|
||||
@ -41,6 +42,37 @@ float Foam::ensightFile::undefValue_ = Foam::floatScalarVGREAT;
|
||||
const char* const Foam::ensightFile::coordinates = "coordinates";
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Put integers, floats etc in binary or ascii.
|
||||
template<class Type>
|
||||
static inline void putPrimitive
|
||||
(
|
||||
const Type& value,
|
||||
OFstream& os,
|
||||
const int fieldWidth
|
||||
)
|
||||
{
|
||||
auto& oss = os.stdStream();
|
||||
|
||||
if (os.format() == IOstreamOption::BINARY)
|
||||
{
|
||||
oss.write(reinterpret_cast<const char*>(&value), sizeof(Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
oss.width(fieldWidth);
|
||||
oss << value;
|
||||
}
|
||||
os.syncState();
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::ensightFile::hasUndef(const UList<float>& field)
|
||||
@ -82,6 +114,51 @@ void Foam::ensightFile::init()
|
||||
std::ios_base::floatfield
|
||||
);
|
||||
precision(5);
|
||||
|
||||
// Handle transient single-file timestep information
|
||||
auto& oss = OFstream::stdStream();
|
||||
|
||||
if (OFstream::is_appending())
|
||||
{
|
||||
// Already positioned at the EOF (in append mode), but be certain
|
||||
oss.seekp(0, std::ios_base::end);
|
||||
origFileSize_ = oss.tellp();
|
||||
}
|
||||
else
|
||||
{
|
||||
origFileSize_ = 0;
|
||||
}
|
||||
|
||||
int64_t begin_footer(-1);
|
||||
List<int64_t> offsets;
|
||||
|
||||
if (OFstream::is_appending())
|
||||
{
|
||||
// Temporarily open for reading as well.
|
||||
// No race condition since no writing is done concurrently with the
|
||||
// reading
|
||||
IFstream is(OFstream::name(), OFstream::format());
|
||||
|
||||
begin_footer =
|
||||
ensightReadFile::getTimeStepFooter
|
||||
(
|
||||
is,
|
||||
offsets
|
||||
);
|
||||
}
|
||||
|
||||
timeStepOffsets_ = std::move(offsets);
|
||||
|
||||
if (OFstream::is_appending() && begin_footer > 0)
|
||||
{
|
||||
oss.seekp(begin_footer);
|
||||
OFstream::syncState();
|
||||
}
|
||||
|
||||
// InfoErr << "output at: " << label(begin_footer) << nl;
|
||||
// InfoErr
|
||||
// << "footer: " << label(begin_footer)
|
||||
// << " time-steps: " << offsets.size() << nl;
|
||||
}
|
||||
|
||||
|
||||
@ -89,11 +166,30 @@ void Foam::ensightFile::init()
|
||||
|
||||
Foam::ensightFile::ensightFile
|
||||
(
|
||||
std::nullptr_t, // dispatch tag
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
OFstream(IOstreamOption::ATOMIC, ensight::FileName(pathname), fmt)
|
||||
OFstream
|
||||
(
|
||||
(
|
||||
// Only use atomic when not appending
|
||||
(append == IOstreamOption::NO_APPEND)
|
||||
? IOstreamOption::ATOMIC
|
||||
: IOstreamOption::NON_ATOMIC
|
||||
),
|
||||
pathname,
|
||||
fmt,
|
||||
(
|
||||
// Change APPEND_APP -> APPEND_ATE (file rewriting)
|
||||
(append == IOstreamOption::APPEND_APP)
|
||||
? IOstreamOption::APPEND_ATE
|
||||
: append
|
||||
)
|
||||
),
|
||||
origFileSize_(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
@ -101,14 +197,44 @@ Foam::ensightFile::ensightFile
|
||||
|
||||
Foam::ensightFile::ensightFile
|
||||
(
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
ensightFile
|
||||
(
|
||||
nullptr,
|
||||
append,
|
||||
ensight::FileName(pathname),
|
||||
fmt
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
Foam::ensightFile::ensightFile
|
||||
(
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
OFstream(IOstreamOption::ATOMIC, path/ensight::FileName(name), fmt)
|
||||
ensightFile
|
||||
(
|
||||
nullptr,
|
||||
append,
|
||||
path/ensight::FileName(name),
|
||||
fmt
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::ensightFile::~ensightFile()
|
||||
{
|
||||
init();
|
||||
(void) writeTimeStepFooter();
|
||||
}
|
||||
|
||||
|
||||
@ -158,9 +284,11 @@ void Foam::ensightFile::writeString(const char* str, size_t len)
|
||||
std::copy_n(str, len, buf);
|
||||
std::fill_n(buf + len, (80 - len), '\0'); // Pad trailing with nul
|
||||
|
||||
auto& oss = stdStream();
|
||||
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
write(buf, 80);
|
||||
oss.write(buf, 80);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -170,9 +298,10 @@ void Foam::ensightFile::writeString(const char* str, size_t len)
|
||||
// char* p = ::strchr(buf, '\n');
|
||||
// if (p) *p = 0;
|
||||
|
||||
stdStream() << buf;
|
||||
syncState();
|
||||
oss << buf;
|
||||
}
|
||||
|
||||
syncState();
|
||||
}
|
||||
|
||||
|
||||
@ -209,6 +338,7 @@ Foam::Ostream& Foam::ensightFile::write(const std::string& str)
|
||||
}
|
||||
|
||||
|
||||
// Same as OFstream::writeRaw(buf, count)
|
||||
Foam::Ostream& Foam::ensightFile::write
|
||||
(
|
||||
const char* buf,
|
||||
@ -223,82 +353,56 @@ Foam::Ostream& Foam::ensightFile::write
|
||||
|
||||
void Foam::ensightFile::writeInt(const int32_t val, const int fieldWidth)
|
||||
{
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
write
|
||||
(
|
||||
reinterpret_cast<const char *>(&val),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdStream().width(fieldWidth);
|
||||
stdStream() << val;
|
||||
syncState();
|
||||
}
|
||||
putPrimitive<int32_t>(val, *this, fieldWidth);
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::writeInt(const int64_t val, const int fieldWidth)
|
||||
{
|
||||
int32_t work(narrowInt32(val));
|
||||
|
||||
writeInt(work, fieldWidth);
|
||||
putPrimitive<int32_t>(narrowInt32(val), *this, fieldWidth);
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::writeFloat(const float val, const int fieldWidth)
|
||||
{
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
write
|
||||
(
|
||||
reinterpret_cast<const char *>(&val),
|
||||
sizeof(float)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdStream().width(fieldWidth);
|
||||
stdStream() << val;
|
||||
syncState();
|
||||
}
|
||||
putPrimitive<float>(val, *this, fieldWidth);
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::writeFloat(const double val, const int fieldWidth)
|
||||
{
|
||||
float work(narrowFloat(val));
|
||||
|
||||
writeFloat(work, fieldWidth);
|
||||
putPrimitive<float>(narrowFloat(val), *this, fieldWidth);
|
||||
}
|
||||
|
||||
|
||||
Foam::Ostream& Foam::ensightFile::write(const int32_t val)
|
||||
{
|
||||
writeInt(val, 10);
|
||||
putPrimitive<int32_t>(val, *this, 10);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Ostream& Foam::ensightFile::write(const int64_t val)
|
||||
{
|
||||
writeInt(val, 10);
|
||||
putPrimitive<int32_t>(narrowInt32(val), *this, 10);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Ostream& Foam::ensightFile::write(const float val)
|
||||
{
|
||||
writeFloat(val, 12);
|
||||
putPrimitive<float>(val, *this, 12);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Ostream& Foam::ensightFile::write(const double val)
|
||||
{
|
||||
writeFloat(val, 12);
|
||||
putPrimitive<float>(narrowFloat(val), *this, 12);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -307,8 +411,7 @@ void Foam::ensightFile::newline()
|
||||
{
|
||||
if (format() == IOstreamOption::ASCII)
|
||||
{
|
||||
stdStream() << nl;
|
||||
syncState();
|
||||
OFstream::write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,22 +446,69 @@ void Foam::ensightFile::writeBinaryHeader()
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
writeString("C Binary");
|
||||
// Is binary: newline() is a no-op
|
||||
// newline(); // A no-op in binary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::beginTimeStep()
|
||||
// Footer information looks like this
|
||||
//
|
||||
/* |---------------|---------------|-----------------------|
|
||||
* | ASCII | BINARY | element |
|
||||
* |---------------|---------------|-----------------------|
|
||||
* | "%20lld\n" | int32 | nSteps |
|
||||
* | "%20lld\n" | int64 | offset step 1 |
|
||||
* | "%20lld\n" | int64 | offset step 2 |
|
||||
* | "%20lld\n" | .. | |
|
||||
* | "%20lld\n" | int64 | offset step n |
|
||||
* | "%20lld\n" | int32 | flag (unused) |
|
||||
* | "%20lld\n" | int64 | offset to nSteps |
|
||||
* | "%s\n" | char[80] | 'FILE_INDEX' |
|
||||
* |---------------|---------------|-----------------------|
|
||||
*/
|
||||
|
||||
int64_t Foam::ensightFile::writeTimeStepFooter()
|
||||
{
|
||||
writeString("BEGIN TIME STEP");
|
||||
if (timeStepOffsets_.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto& oss = OFstream::stdStream();
|
||||
|
||||
// The footer begin, which is also the current position
|
||||
const int64_t footer_begin(oss.tellp());
|
||||
|
||||
// nSteps
|
||||
putPrimitive<int32_t>(int32_t(timeStepOffsets_.size()), *this, 20);
|
||||
newline();
|
||||
|
||||
// offset step 1, 2, ... N
|
||||
for (int64_t off : timeStepOffsets_)
|
||||
{
|
||||
putPrimitive<int64_t>(off, *this, 20);
|
||||
newline();
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::endTimeStep()
|
||||
{
|
||||
writeString("END TIME STEP");
|
||||
// flag (unused)
|
||||
putPrimitive<int32_t>(0, *this, 20);
|
||||
newline();
|
||||
|
||||
// The footer begin == position of nSteps
|
||||
putPrimitive<int64_t>(footer_begin, *this, 20);
|
||||
newline();
|
||||
|
||||
// FILE_INDEX is "%s\n", not "%79s\n"
|
||||
// but our ASCII strings are truncated (nul-padded) anyhow
|
||||
|
||||
writeString("FILE_INDEX");
|
||||
newline();
|
||||
|
||||
// Reposition to begin of footer so that any subsequent output
|
||||
// will overwrite the footer too
|
||||
oss.seekp(footer_begin);
|
||||
|
||||
return footer_begin;
|
||||
}
|
||||
|
||||
|
||||
@ -366,6 +516,55 @@ void Foam::ensightFile::endTimeStep()
|
||||
// Convenience Output Methods
|
||||
//
|
||||
|
||||
int64_t Foam::ensightFile::beginTimeStep()
|
||||
{
|
||||
writeString("BEGIN TIME STEP");
|
||||
newline();
|
||||
|
||||
auto& oss = OFstream::stdStream();
|
||||
|
||||
const int64_t curr_pos(oss.tellp());
|
||||
timeStepOffsets_.push_back(curr_pos);
|
||||
|
||||
// To avoid partly incomplete/incorrect footer information,
|
||||
// overwrite original footer if needed.
|
||||
|
||||
if (curr_pos >= 0 && curr_pos < origFileSize_)
|
||||
{
|
||||
const char fill[] = "deadbeef";
|
||||
|
||||
for
|
||||
(
|
||||
int64_t pos = curr_pos;
|
||||
pos < origFileSize_ && bool(oss);
|
||||
pos += 8
|
||||
)
|
||||
{
|
||||
// Overwrite with specified "junk" to avoid/detect corrupt
|
||||
// files etc. Don't worry about slightly increasing the
|
||||
// file size (ie, max 7 bytes) - it's unimportant
|
||||
oss.write(fill, 8);
|
||||
}
|
||||
|
||||
// Maintain the original output position
|
||||
oss.seekp(curr_pos);
|
||||
|
||||
OFstream::syncState();
|
||||
}
|
||||
|
||||
return curr_pos;
|
||||
}
|
||||
|
||||
|
||||
int64_t Foam::ensightFile::endTimeStep()
|
||||
{
|
||||
writeString("END TIME STEP");
|
||||
newline();
|
||||
|
||||
return int64_t(stdStream().tellp());
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::beginPart(const label index)
|
||||
{
|
||||
writeString("part");
|
||||
@ -375,6 +574,28 @@ void Foam::ensightFile::beginPart(const label index)
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::beginPart
|
||||
(
|
||||
const label index,
|
||||
const std::string& description
|
||||
)
|
||||
{
|
||||
beginPart(index);
|
||||
writeString(description);
|
||||
newline();
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::beginCoordinates(const label npoints)
|
||||
{
|
||||
writeString("coordinates");
|
||||
newline();
|
||||
|
||||
write(npoints);
|
||||
newline();
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightFile::beginParticleCoordinates(const label nparticles)
|
||||
{
|
||||
writeString("particle coordinates");
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,8 +28,8 @@ Class
|
||||
Foam::ensightFile
|
||||
|
||||
Description
|
||||
Ensight output with specialized write() for strings, integers and floats.
|
||||
Correctly handles binary write as well.
|
||||
A variant of OFstream with specialised handling for Ensight writing
|
||||
of strings, integers and floats (ASCII and BINARY).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -39,6 +39,7 @@ Description
|
||||
#include "OFstream.H"
|
||||
#include "ensightFileName.H"
|
||||
#include "ensightVarName.H"
|
||||
#include "DynamicList.H"
|
||||
#include "IndirectListBase.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
@ -62,17 +63,36 @@ class ensightFile
|
||||
//- Value to represent undef in results (default: 1e+37, floatVGREAT)
|
||||
static float undefValue_;
|
||||
|
||||
//- Transient single-file:
|
||||
//- the original file size when opened in append mode, zero otherwise
|
||||
int64_t origFileSize_;
|
||||
|
||||
//- Transient single-file:
|
||||
//- the time-step file-offsets (position after "BEGIN TIME STEP").
|
||||
// Set on initial reading and added to by beginTimeStep().
|
||||
DynamicList<int64_t> timeStepOffsets_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Initialize sets the ASCII output formatting
|
||||
//- Set the ASCII output formatting etc,
|
||||
//- and handle transient single-file timestep information
|
||||
void init();
|
||||
|
||||
//- No copy construct
|
||||
ensightFile(const ensightFile&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const ensightFile&) = delete;
|
||||
// Constructors
|
||||
|
||||
//- Construct with file name, no ensight file naming adjustment.
|
||||
// Created as an atomic or in append-mode (single-file format).
|
||||
// In append-mode, attempts to parse existing time-step information.
|
||||
// Changes APPEND_APP to APPEND_ATE (file rewriting).
|
||||
ensightFile
|
||||
(
|
||||
std::nullptr_t, // dispatch tag
|
||||
IOstreamOption::appendType append, // (NO_APPEND or APPEND_ATE)
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt
|
||||
);
|
||||
|
||||
|
||||
public:
|
||||
@ -98,30 +118,70 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
ensightFile(const ensightFile&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const ensightFile&) = delete;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from path-name.
|
||||
// The path-name is adjusted for valid ensight file naming.
|
||||
// Always created as an atomic
|
||||
explicit ensightFile
|
||||
// Created as an atomic or in append mode (single-file format).
|
||||
// In append mode, attempts to parse existing time-step information.
|
||||
ensightFile
|
||||
(
|
||||
//! Append mode: NO_APPEND or APPEND_ATE
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
//- Construct from path and name.
|
||||
// Only the name portion is adjusted for valid ensight file naming.
|
||||
// Always created as an atomic
|
||||
// Created as an atomic or in append mode (single-file format).
|
||||
// In append mode, attempts to parse existing time-step information.
|
||||
ensightFile
|
||||
(
|
||||
//! Append mode: NO_APPEND or APPEND_ATE
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
//- Construct from path-name.
|
||||
// The path-name is adjusted for valid ensight file naming.
|
||||
// Created as an atomic, non-append mode.
|
||||
explicit ensightFile
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
)
|
||||
:
|
||||
ensightFile(IOstreamOption::NO_APPEND, pathname, fmt)
|
||||
{}
|
||||
|
||||
//- Destructor
|
||||
~ensightFile() = default;
|
||||
//- Construct from path and name.
|
||||
// Only the name portion is adjusted for valid ensight file naming.
|
||||
// Created as an atomic, non-append mode.
|
||||
ensightFile
|
||||
(
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
)
|
||||
:
|
||||
ensightFile(IOstreamOption::NO_APPEND, path, name, fmt)
|
||||
{}
|
||||
|
||||
|
||||
//- Destructor. Commits the time-step footer information (if any)
|
||||
~ensightFile();
|
||||
|
||||
|
||||
// Member Functions
|
||||
@ -148,12 +208,6 @@ public:
|
||||
//- Write "C Binary" string for binary files (eg, geometry/measured)
|
||||
void writeBinaryHeader();
|
||||
|
||||
//- Write "BEGIN TIME STEP" string and newline
|
||||
void beginTimeStep();
|
||||
|
||||
//- Write "END TIME STEP" string and newline
|
||||
void endTimeStep();
|
||||
|
||||
//- Write character/string content as "%79s" or as binary (max 80 chars)
|
||||
void writeString(const char* str, size_t len);
|
||||
|
||||
@ -225,11 +279,59 @@ public:
|
||||
void newline();
|
||||
|
||||
|
||||
// Transient single-file format
|
||||
|
||||
//- Write "BEGIN TIME STEP" string and newline
|
||||
//- (for transient single-file format).
|
||||
// \returns file position after the write
|
||||
int64_t beginTimeStep();
|
||||
|
||||
//- Write "END TIME STEP" string and newline
|
||||
//- (for transient single-file format)
|
||||
// \returns file position after the write
|
||||
int64_t endTimeStep();
|
||||
|
||||
//- Transient single-file:
|
||||
//- write the time-step file-offsets as footer information.
|
||||
// Maintains the current file position to allow manual use
|
||||
// and seamless overwriting.
|
||||
// \return the output file position at the start of the footer
|
||||
int64_t writeTimeStepFooter();
|
||||
|
||||
//- Transient single-file:
|
||||
//- forget time-step file positions (advanced use)
|
||||
void clearTimeSteps() noexcept
|
||||
{
|
||||
timeStepOffsets_.clear();
|
||||
}
|
||||
|
||||
//- Transient single-file:
|
||||
//- the current number of time steps
|
||||
label nTimes() const noexcept
|
||||
{
|
||||
return timeStepOffsets_.size();
|
||||
}
|
||||
|
||||
//- Transient single-file:
|
||||
//- the current file-offsets for time steps within the file
|
||||
const UList<int64_t>& timeStepOffets() const noexcept
|
||||
{
|
||||
return timeStepOffsets_;
|
||||
}
|
||||
|
||||
|
||||
// Convenience Output Methods
|
||||
|
||||
//- Begin a part (0-based index internally).
|
||||
void beginPart(const label index);
|
||||
|
||||
//- Begin a part (0-based index internally), with a description.
|
||||
//- Only used for geometry files
|
||||
void beginPart(const label index, const std::string& description);
|
||||
|
||||
//- Begin a "coordinates" block. Only used for geometry files.
|
||||
void beginCoordinates(const label nparticles);
|
||||
|
||||
//- Begin a "particle coordinates" block (measured data)
|
||||
void beginParticleCoordinates(const label nparticles);
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2016-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -29,15 +29,56 @@ License
|
||||
#include "ensightGeoFile.H"
|
||||
#include "foamVersion.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::ensightGeoFile::init()
|
||||
Foam::ensightGeoFile::ensightGeoFile
|
||||
(
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
ensightFile(append, pathname, fmt)
|
||||
{
|
||||
writeBinaryHeader();
|
||||
beginGeometry();
|
||||
if (!OFstream::is_appending())
|
||||
{
|
||||
writeBinaryHeader(); // Mandatory for geometry files
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::ensightGeoFile::ensightGeoFile
|
||||
(
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
ensightFile(append, path, name, fmt)
|
||||
{
|
||||
if (!OFstream::is_appending())
|
||||
{
|
||||
writeBinaryHeader(); // Mandatory for geometry files
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::Ostream& Foam::ensightGeoFile::writeKeyword(const keyType& key)
|
||||
{
|
||||
writeString(key);
|
||||
newline();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Convenience Output Methods
|
||||
//
|
||||
|
||||
void Foam::ensightGeoFile::beginGeometry()
|
||||
{
|
||||
// Description line 1
|
||||
@ -56,72 +97,4 @@ void Foam::ensightGeoFile::beginGeometry()
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightGeoFile::endGeometry()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::ensightGeoFile::ensightGeoFile
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
ensightFile(pathname, fmt)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
Foam::ensightGeoFile::ensightGeoFile
|
||||
(
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
ensightFile(path, name, fmt)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::Ostream& Foam::ensightGeoFile::writeKeyword(const keyType& key)
|
||||
{
|
||||
writeString(key);
|
||||
newline();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Convenience Output Methods
|
||||
//
|
||||
|
||||
void Foam::ensightGeoFile::beginPart
|
||||
(
|
||||
const label index,
|
||||
const std::string& description
|
||||
)
|
||||
{
|
||||
beginPart(index);
|
||||
writeString(description);
|
||||
newline();
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightGeoFile::beginCoordinates(const label npoints)
|
||||
{
|
||||
writeString(ensightFile::coordinates);
|
||||
newline();
|
||||
|
||||
write(npoints);
|
||||
newline();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||
Copyright (C) 2016-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,7 +28,8 @@ Class
|
||||
Foam::ensightGeoFile
|
||||
|
||||
Description
|
||||
Specialized Ensight output with extra geometry file header
|
||||
A variant of ensightFile (Ensight writing) that includes
|
||||
the extra geometry file header information.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -50,23 +51,6 @@ class ensightGeoFile
|
||||
:
|
||||
public ensightFile
|
||||
{
|
||||
// Private Member Functions
|
||||
|
||||
//- Initialize outputs the header information and beginGeometry
|
||||
void init();
|
||||
|
||||
//- Start of geometry information
|
||||
void beginGeometry();
|
||||
|
||||
//- End of geometry information
|
||||
void endGeometry();
|
||||
|
||||
//- No copy construct
|
||||
ensightGeoFile(const ensightGeoFile&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const ensightGeoFile&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
// Static Functions
|
||||
@ -78,24 +62,66 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
ensightGeoFile(const ensightGeoFile&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const ensightGeoFile&) = delete;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from path-name.
|
||||
//- Construct from path-name and initialise the binary header.
|
||||
// The path-name is adjusted for valid ensight file naming.
|
||||
explicit ensightGeoFile
|
||||
// Created as an atomic or in append mode (single-file format).
|
||||
ensightGeoFile
|
||||
(
|
||||
//! Append mode: NO_APPEND or APPEND_ATE
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
//- Construct from path and name.
|
||||
//- Construct from path / name and initialise the binary header.
|
||||
// Only the name portion is adjusted for valid ensight file naming.
|
||||
// Created as an atomic or in append mode (single-file format).
|
||||
ensightGeoFile
|
||||
(
|
||||
//! Append mode: NO_APPEND or APPEND_ATE
|
||||
IOstreamOption::appendType append,
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
//- Construct from path-name and initialise the binary header.
|
||||
// The path-name is adjusted for valid ensight file naming.
|
||||
// Created as an atomic, non-append mode.
|
||||
// \note Since 2024-05 does \em not call beginGeometry() !!
|
||||
explicit ensightGeoFile
|
||||
(
|
||||
const fileName& pathname,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
)
|
||||
:
|
||||
ensightGeoFile(IOstreamOption::NO_APPEND, pathname, fmt)
|
||||
{}
|
||||
|
||||
//- Construct from path / name and initialise the binary header.
|
||||
// Only the name portion is adjusted for valid ensight file naming.
|
||||
// Created as an atomic, non-append mode.
|
||||
// \note Since 2024-05 does \em not call beginGeometry() !!
|
||||
ensightGeoFile
|
||||
(
|
||||
const fileName& path,
|
||||
const fileName& name,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
)
|
||||
:
|
||||
ensightGeoFile(IOstreamOption::NO_APPEND, path, name, fmt)
|
||||
{}
|
||||
|
||||
|
||||
//- Destructor
|
||||
@ -107,19 +133,13 @@ public:
|
||||
// Output
|
||||
|
||||
//- Write keyword with trailing newline
|
||||
virtual Ostream& writeKeyword(const keyType& key);
|
||||
virtual Ostream& writeKeyword(const keyType& key) override;
|
||||
|
||||
|
||||
// Convenience Output Methods
|
||||
|
||||
//- Begin a part (0-based index).
|
||||
using ensightFile::beginPart;
|
||||
|
||||
//- Begin a "part" (0-based index), with a description.
|
||||
void beginPart(const label index, const std::string& description);
|
||||
|
||||
//- Begin a "coordinates" block
|
||||
void beginCoordinates(const label npoints);
|
||||
//- Start of geometry information
|
||||
void beginGeometry();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -433,6 +433,11 @@ void Foam::ensightMesh::write
|
||||
bool parallel
|
||||
) const
|
||||
{
|
||||
if (UPstream::master())
|
||||
{
|
||||
os.beginGeometry();
|
||||
}
|
||||
|
||||
// The internalMesh, cellZones
|
||||
for (const label id : cellZoneParts_.sortedToc())
|
||||
{
|
||||
|
||||
@ -217,6 +217,7 @@ public:
|
||||
// Output
|
||||
|
||||
//- Write geometry to file (normally in parallel).
|
||||
//- Adds beginGeometry() marker.
|
||||
// If all geometry is disabled, it will simply writes the mesh
|
||||
// bounding box (to ensure that the geometry file is non-empty)
|
||||
void write
|
||||
@ -226,8 +227,8 @@ public:
|
||||
) const;
|
||||
|
||||
//- Write geometry to file (normally in parallel).
|
||||
// If all geometry is disabled, it will simply writes the mesh
|
||||
// bounding box (to ensure that the geometry file is non-empty)
|
||||
//- Adds beginGeometry() marker.
|
||||
FOAM_DEPRECATED_FOR(2024-05, "write(ensightGeoFile&, ...")
|
||||
inline void write
|
||||
(
|
||||
autoPtr<ensightGeoFile>& os,
|
||||
|
||||
@ -41,8 +41,8 @@ Note
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ensightFileName_H
|
||||
#define ensightFileName_H
|
||||
#ifndef Foam_ensightFileName_H
|
||||
#define Foam_ensightFileName_H
|
||||
|
||||
#include "fileName.H"
|
||||
#include "word.H"
|
||||
@ -81,6 +81,9 @@ public:
|
||||
//- Copy construct from std::string
|
||||
inline explicit FileName(const std::string& s);
|
||||
|
||||
//- Move construct from std::string
|
||||
inline explicit FileName(std::string&& s);
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
|
||||
@ -46,6 +46,14 @@ inline Foam::ensight::FileName::FileName(const std::string& s)
|
||||
}
|
||||
|
||||
|
||||
inline Foam::ensight::FileName::FileName(std::string&& s)
|
||||
:
|
||||
fileName(std::move(s), false)
|
||||
{
|
||||
stripInvalid();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
inline bool Foam::ensight::FileName::valid(char c)
|
||||
@ -65,11 +73,11 @@ inline void Foam::ensight::FileName::stripInvalid()
|
||||
|
||||
// Avoid characters that upset Windows or others
|
||||
string::replaceAny(":<>[]", '_');
|
||||
removeRepeated('_');
|
||||
string::removeRepeated('_');
|
||||
|
||||
// Minor cleanup of fileName
|
||||
removeRepeated('/');
|
||||
removeEnd('/');
|
||||
string::removeRepeated('/');
|
||||
string::removeEnd('/');
|
||||
|
||||
if (empty())
|
||||
{
|
||||
|
||||
@ -41,8 +41,8 @@ Description
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ensightVarName_H
|
||||
#define ensightVarName_H
|
||||
#ifndef Foam_ensightVarName_H
|
||||
#define Foam_ensightVarName_H
|
||||
|
||||
#include "word.H"
|
||||
|
||||
@ -80,6 +80,9 @@ public:
|
||||
//- Copy construct from std::string
|
||||
inline explicit VarName(const std::string& s);
|
||||
|
||||
//- Move construct from std::string
|
||||
inline explicit VarName(std::string&& s);
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
|
||||
@ -46,6 +46,14 @@ inline Foam::ensight::VarName::VarName(const std::string& s)
|
||||
}
|
||||
|
||||
|
||||
inline Foam::ensight::VarName::VarName(std::string&& s)
|
||||
:
|
||||
word(std::move(s), false)
|
||||
{
|
||||
stripInvalid();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
inline bool Foam::ensight::VarName::valid(char c)
|
||||
@ -73,7 +81,7 @@ inline bool Foam::ensight::VarName::valid(char c)
|
||||
|
||||
inline void Foam::ensight::VarName::stripInvalid()
|
||||
{
|
||||
string::stripInvalid<VarName>(*this);
|
||||
string::stripInvalid<ensight::VarName>(*this);
|
||||
|
||||
if (empty())
|
||||
{
|
||||
@ -83,10 +91,9 @@ inline void Foam::ensight::VarName::stripInvalid()
|
||||
}
|
||||
|
||||
// Prefix with '_' to avoid starting with leading digits
|
||||
std::string::iterator iter = begin();
|
||||
if (isdigit(*iter))
|
||||
if (std::isdigit(front()))
|
||||
{
|
||||
insert(iter, '_');
|
||||
insert(0, 1, '_');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -274,6 +274,7 @@ public:
|
||||
virtual void writeDict(Ostream& os, const bool full=false) const;
|
||||
|
||||
//- Write geometry, using a mesh reference (serial only)
|
||||
//- No beginGeometry() marker.
|
||||
virtual void write
|
||||
(
|
||||
ensightGeoFile& os,
|
||||
@ -283,6 +284,7 @@ public:
|
||||
|
||||
//- Write bounding box geometry.
|
||||
//- All parameters are only relevant on master
|
||||
//- No beginGeometry() marker.
|
||||
static void writeBox
|
||||
(
|
||||
ensightGeoFile& os,
|
||||
|
||||
@ -54,7 +54,7 @@ namespace
|
||||
{
|
||||
|
||||
// Trivial shape classifier
|
||||
inline Foam::ensightFaces::elemType whatType(const Foam::face& f)
|
||||
inline Foam::ensightFaces::elemType whatType(const Foam::face& f) noexcept
|
||||
{
|
||||
return
|
||||
(
|
||||
|
||||
@ -266,6 +266,7 @@ public:
|
||||
virtual void writeDict(Ostream& os, const bool full=false) const;
|
||||
|
||||
//- Write geometry, using a mesh reference
|
||||
//- No beginGeometry() marker.
|
||||
virtual void write
|
||||
(
|
||||
ensightGeoFile& os,
|
||||
|
||||
@ -61,9 +61,7 @@ void Foam::ensightPart::decrAddressing(const label off)
|
||||
Foam::ensightPart::ensightPart()
|
||||
:
|
||||
index_(0),
|
||||
identifier_(-1),
|
||||
name_(),
|
||||
address_()
|
||||
identifier_(-1)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
@ -35,8 +35,8 @@ SourceFiles
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ensightPart_H
|
||||
#define ensightPart_H
|
||||
#ifndef Foam_ensightPart_H
|
||||
#define Foam_ensightPart_H
|
||||
|
||||
#include "ensightGeoFile.H"
|
||||
#include "labelList.H"
|
||||
|
||||
@ -42,8 +42,8 @@ SourceFiles
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ensightOutputSurface_H
|
||||
#define ensightOutputSurface_H
|
||||
#ifndef Foam_ensightOutputSurface_H
|
||||
#define Foam_ensightOutputSurface_H
|
||||
|
||||
#include "ensightFaces.H"
|
||||
|
||||
@ -69,7 +69,9 @@ class ensightOutputSurface
|
||||
const faceList& faces_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
public:
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
ensightOutputSurface(const ensightOutputSurface&) = delete;
|
||||
@ -78,8 +80,6 @@ class ensightOutputSurface
|
||||
void operator=(const ensightOutputSurface&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from points and faces.
|
||||
@ -98,7 +98,8 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Write processor-local geometry (serial-only)
|
||||
//- Write processor-local geometry (serial-only).
|
||||
//- No beginGeometry() marker.
|
||||
void write(ensightGeoFile& os) const;
|
||||
|
||||
//- Write a field of face or point values (serial-only)
|
||||
@ -121,7 +122,8 @@ public:
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- Cannot write geometry with a mesh reference
|
||||
//- Cannot write geometry with a mesh reference.
|
||||
//- No beginGeometry() marker.
|
||||
virtual void write(ensightGeoFile&, const polyMesh&, bool) const
|
||||
{}
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -26,50 +26,300 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "ensightReadFile.H"
|
||||
#include "stringOps.H"
|
||||
#include "defineDebugSwitch.H"
|
||||
#include "registerSwitch.H"
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
Foam::IOstreamOption::streamFormat
|
||||
Foam::ensightReadFile::detectBinaryHeader(const fileName& pathname)
|
||||
defineDebugSwitchWithName(Foam::ensightReadFile, "ensightReadFile", 0);
|
||||
|
||||
registerDebugSwitchWithName(Foam::ensightReadFile, ensight, "ensightReadFile");
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
IOstreamOption::streamFormat fmt(IOstreamOption::BINARY);
|
||||
|
||||
// Detect BINARY vs ASCII by testing for initial "(C|Fortran) Binary"
|
||||
// Get integers, floats etc in binary or ascii.
|
||||
template<class Type>
|
||||
static inline Type getPrimitive(IFstream& is)
|
||||
{
|
||||
IFstream ifs(pathname, IOstreamOption::BINARY);
|
||||
Type value(0);
|
||||
|
||||
if (!ifs.good())
|
||||
auto& iss = is.stdStream();
|
||||
|
||||
if (is.format() == IOstreamOption::BINARY)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Cannot read file " << ifs.name() << nl
|
||||
<< exit(FatalError);
|
||||
iss.read(reinterpret_cast<char*>(&value), sizeof(Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
iss >> value;
|
||||
}
|
||||
is.syncState();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
istream& iss = ifs.stdStream();
|
||||
|
||||
// Get an Ensight string value (binary or ascii).
|
||||
static inline void readEnsightString(IFstream& is, std::string& value)
|
||||
{
|
||||
if (is.format() == IOstreamOption::BINARY)
|
||||
{
|
||||
auto& iss = is.stdStream();
|
||||
|
||||
// Binary string is *exactly* 80 characters
|
||||
string buf(size_t(80), '\0');
|
||||
iss.read(&buf[0], 80);
|
||||
value.resize(80, '\0');
|
||||
iss.read(&value[0], 80);
|
||||
const std::streamsize gcount = iss.gcount();
|
||||
buf.erase(gcount <= 0 ? 0 : gcount); // Truncated?
|
||||
value.erase(gcount <= 0 ? 0 : gcount); // Truncated?
|
||||
|
||||
// Could exit on truncated input, but no real advantage
|
||||
|
||||
// Truncate at the first embedded '\0'
|
||||
const auto endp = buf.find('\0');
|
||||
const auto endp = value.find('\0');
|
||||
|
||||
if (endp != std::string::npos)
|
||||
{
|
||||
buf.erase(endp);
|
||||
value.erase(endp);
|
||||
}
|
||||
|
||||
// ASCII if it does not contain "C Binary"
|
||||
if (!buf.contains("Binary") && !buf.contains("binary"))
|
||||
// May have been padded with trailing spaces - remove those
|
||||
stringOps::inplaceTrimRight(value);
|
||||
|
||||
is.syncState();
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt = IOstreamOption::ASCII;
|
||||
value.clear();
|
||||
while (value.empty() && !is.eof())
|
||||
{
|
||||
is.getLine(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt;
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
// Footer information looks like this
|
||||
//
|
||||
/* |---------------|---------------|-----------------------|
|
||||
* | ASCII | BINARY | element |
|
||||
* |---------------|---------------|-----------------------|
|
||||
* | "%20lld\n" | int32 | nSteps |
|
||||
* | "%20lld\n" | int64 | offset step 1 |
|
||||
* | "%20lld\n" | int64 | offset step 2 |
|
||||
* | "%20lld\n" | .. | |
|
||||
* | "%20lld\n" | int64 | offset step n |
|
||||
* | "%20lld\n" | int32 | flag (unused) |
|
||||
* | "%20lld\n" | int64 | offset to nSteps |
|
||||
* | "%s\n" | char[80] | 'FILE_INDEX' |
|
||||
* |---------------|---------------|-----------------------|
|
||||
*/
|
||||
|
||||
int64_t Foam::ensightReadFile::getTimeStepFooter
|
||||
(
|
||||
IFstream& is,
|
||||
// File offsets for each time step (if any)
|
||||
List<int64_t>& offsets
|
||||
)
|
||||
{
|
||||
std::string buffer;
|
||||
|
||||
auto& iss = is.stdStream();
|
||||
const auto lineNum = is.lineNumber();
|
||||
const auto curr_pos = iss.tellg();
|
||||
|
||||
if (curr_pos < 0)
|
||||
{
|
||||
// Impossible positioning - exit
|
||||
is.lineNumber(lineNum); // Restore line number
|
||||
offsets.clear();
|
||||
return -1;
|
||||
}
|
||||
|
||||
iss.seekg(0, std::ios_base::end);
|
||||
const auto end_pos = iss.tellg();
|
||||
|
||||
// As a minimum, expect at least 1 time step, so have four integers
|
||||
// (nSteps, offset step 1, flag, file offset) and the string (10 chars).
|
||||
// Thus always at least 80+ chars.
|
||||
|
||||
if (end_pos <= 80)
|
||||
{
|
||||
// Looks quite impossible - exit
|
||||
|
||||
is.lineNumber(lineNum); // Restore line number
|
||||
iss.seekg(curr_pos); // Restore file position
|
||||
|
||||
offsets.clear();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the last 80 chars as a character string
|
||||
iss.seekg(-80, std::ios_base::end);
|
||||
|
||||
const auto fmt = is.format(IOstreamOption::BINARY);
|
||||
readEnsightString(is, buffer);
|
||||
is.format(fmt);
|
||||
|
||||
int64_t footer_begin(0);
|
||||
|
||||
const auto endp = buffer.find("FILE_INDEX");
|
||||
|
||||
if (endp == std::string::npos)
|
||||
{
|
||||
// Not found
|
||||
|
||||
is.lineNumber(lineNum); // Restore line number
|
||||
iss.seekg(curr_pos); // Restore file position
|
||||
|
||||
offsets.clear();
|
||||
return -1;
|
||||
}
|
||||
else if (fmt == IOstreamOption::ASCII)
|
||||
{
|
||||
// In ASCII, the last 80 chars will also include a few integers
|
||||
buffer.erase(endp); // Remove FILE_INDEX ...
|
||||
auto split = stringOps::splitSpace(buffer);
|
||||
|
||||
if (!split.empty())
|
||||
{
|
||||
footer_begin = Foam::readInt64(split.back().str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Position before string (80 bytes) and int64 value (8 bytes)
|
||||
iss.seekg(-88, std::ios_base::end);
|
||||
footer_begin = getPrimitive<int64_t>(is);
|
||||
}
|
||||
|
||||
|
||||
// The number of steps is stored as int32 at the beginning of the footer
|
||||
int32_t nSteps(0);
|
||||
|
||||
if (footer_begin)
|
||||
{
|
||||
iss.seekg(footer_begin);
|
||||
nSteps = getPrimitive<int32_t>(is);
|
||||
}
|
||||
|
||||
offsets.resize_nocopy(nSteps);
|
||||
|
||||
// Next footer entries are the offsets per time-step
|
||||
for (int32_t step = 0; step < nSteps; ++step)
|
||||
{
|
||||
offsets[step] = getPrimitive<int64_t>(is);
|
||||
}
|
||||
|
||||
is.lineNumber(lineNum); // Restore line number
|
||||
iss.seekg(curr_pos); // Restore file position
|
||||
|
||||
return footer_begin;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::ensightReadFile::readString(std::string& value)
|
||||
{
|
||||
readEnsightString(*this, value);
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightReadFile::init(bool detectFormat)
|
||||
{
|
||||
if (!IFstream::good())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Cannot read file " << IFstream::name() << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
auto& iss = stdStream();
|
||||
|
||||
auto lineNum = lineNumber();
|
||||
auto curr_pos = iss.tellg(); // The starting position (should be 0)
|
||||
|
||||
string buffer;
|
||||
|
||||
if (detectFormat)
|
||||
{
|
||||
// Read initial string as BINARY
|
||||
IFstream::format(IOstreamOption::BINARY);
|
||||
|
||||
readEnsightString(*this, buffer);
|
||||
|
||||
// Detect BINARY vs ASCII by testing for initial "(C|Fortran) Binary"
|
||||
if (buffer.contains("Binary") || buffer.contains("binary"))
|
||||
{
|
||||
// Format is BINARY
|
||||
IFstream::format(IOstreamOption::BINARY);
|
||||
|
||||
// New backtracking point is after the initial "C Binary" string
|
||||
curr_pos = iss.tellg();
|
||||
|
||||
// Get the next (optional) line after the "C Binary" (if any)
|
||||
// and before the description.
|
||||
readEnsightString(*this, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not binary => ASCII
|
||||
IFstream::format(IOstreamOption::ASCII);
|
||||
|
||||
// Rewind to the beginning again
|
||||
iss.seekg(curr_pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the next line.
|
||||
// It is either the description line or "BEGIN TIME STEP".
|
||||
readEnsightString(*this, buffer);
|
||||
}
|
||||
|
||||
|
||||
// The buffer string now either contains the description line
|
||||
// or "BEGIN TIME STEP"
|
||||
|
||||
if (buffer.starts_with("BEGIN TIME STEP"))
|
||||
{
|
||||
// Transient single file.
|
||||
// File position is now after the "BEGIN TIME STEP" string
|
||||
|
||||
curr_pos = iss.tellg(); // Fallback value
|
||||
|
||||
timeStepFooterBegin_ = getTimeStepFooter(*this, timeStepOffsets_);
|
||||
|
||||
if (timeStepOffsets_.empty())
|
||||
{
|
||||
// Treat like a single time step
|
||||
timeStepOffsets_.resize(1, int64_t(curr_pos));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A description line and not "BEGIN TIME STEP"
|
||||
// so backtrack to before it was read
|
||||
|
||||
lineNumber(lineNum); // Restore line number
|
||||
iss.seekg(curr_pos); // Restore file position
|
||||
|
||||
timeStepFooterBegin_ = -1; // safety
|
||||
timeStepOffsets_.clear(); // safety
|
||||
}
|
||||
|
||||
DebugInfo<< "Time-steps: " << timeStepOffsets_.size() << endl;
|
||||
|
||||
syncState();
|
||||
}
|
||||
|
||||
|
||||
@ -80,8 +330,11 @@ Foam::ensightReadFile::ensightReadFile
|
||||
const fileName& pathname
|
||||
)
|
||||
:
|
||||
IFstream(pathname, ensightReadFile::detectBinaryHeader(pathname))
|
||||
{}
|
||||
IFstream(pathname, IOstreamOption::BINARY), // Start as BINARY
|
||||
timeStepFooterBegin_(-1)
|
||||
{
|
||||
init(true); // detectFormat = true
|
||||
}
|
||||
|
||||
|
||||
Foam::ensightReadFile::ensightReadFile
|
||||
@ -90,12 +343,16 @@ Foam::ensightReadFile::ensightReadFile
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
IFstream(pathname, fmt)
|
||||
{}
|
||||
IFstream(pathname, fmt),
|
||||
timeStepFooterBegin_(-1)
|
||||
{
|
||||
init(false); // detectFormat = false
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
// Same as IFstream::readRaw(buf, count)
|
||||
Foam::Istream& Foam::ensightReadFile::read
|
||||
(
|
||||
char* buf,
|
||||
@ -108,113 +365,39 @@ Foam::Istream& Foam::ensightReadFile::read
|
||||
}
|
||||
|
||||
|
||||
// TBD
|
||||
// Foam::Istream& Foam::ensightReadFile::read(word& value)
|
||||
// {
|
||||
// readString(value);
|
||||
// string::stripInvalid<word>(value);
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
Foam::Istream& Foam::ensightReadFile::read(string& value)
|
||||
{
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
auto& iss = stdStream();
|
||||
|
||||
// Binary string is *exactly* 80 characters
|
||||
value.resize(80, '\0');
|
||||
iss.read(&value[0], 80);
|
||||
const std::streamsize gcount = iss.gcount();
|
||||
value.erase(gcount <= 0 ? 0 : gcount); // Truncated?
|
||||
|
||||
// Could exit on truncated input, but no real advantage
|
||||
|
||||
syncState();
|
||||
|
||||
// Truncate at the first embedded '\0'
|
||||
auto endp = value.find('\0');
|
||||
|
||||
if (endp != std::string::npos)
|
||||
{
|
||||
value.erase(endp);
|
||||
}
|
||||
|
||||
// May have been padded with trailing spaces - remove those
|
||||
endp = value.find_last_not_of(" \t\f\v\n\r");
|
||||
|
||||
if (endp != std::string::npos)
|
||||
{
|
||||
value.erase(endp + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.clear();
|
||||
while (value.empty() && !eof())
|
||||
{
|
||||
getLine(value);
|
||||
}
|
||||
}
|
||||
|
||||
readString(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Istream& Foam::ensightReadFile::read(label& value)
|
||||
{
|
||||
int ivalue;
|
||||
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
read
|
||||
(
|
||||
reinterpret_cast<char*>(&ivalue),
|
||||
sizeof(ivalue)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdStream() >> ivalue;
|
||||
syncState();
|
||||
}
|
||||
|
||||
value = ivalue;
|
||||
value = getPrimitive<int>(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Istream& Foam::ensightReadFile::read(float& value)
|
||||
{
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
read
|
||||
(
|
||||
reinterpret_cast<char*>(&value),
|
||||
sizeof(value)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdStream() >> value;
|
||||
syncState();
|
||||
}
|
||||
|
||||
value = getPrimitive<float>(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Foam::Istream& Foam::ensightReadFile::read(double& value)
|
||||
{
|
||||
float fvalue;
|
||||
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
{
|
||||
read
|
||||
(
|
||||
reinterpret_cast<char*>(&fvalue),
|
||||
sizeof(fvalue)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdStream() >> fvalue;
|
||||
syncState();
|
||||
}
|
||||
|
||||
value = fvalue;
|
||||
value = getPrimitive<float>(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -226,15 +409,79 @@ Foam::Istream& Foam::ensightReadFile::readKeyword(string& key)
|
||||
}
|
||||
|
||||
|
||||
Foam::Istream& Foam::ensightReadFile::readBinaryHeader()
|
||||
void Foam::ensightReadFile::readPoints
|
||||
(
|
||||
const label nPoints,
|
||||
List<floatVector>& points
|
||||
)
|
||||
{
|
||||
if (format() == IOstreamOption::BINARY)
|
||||
points.resize_nocopy(nPoints);
|
||||
|
||||
for (auto& p : points)
|
||||
{
|
||||
string buffer;
|
||||
read(buffer);
|
||||
read(p.x());
|
||||
}
|
||||
for (auto& p : points)
|
||||
{
|
||||
read(p.y());
|
||||
}
|
||||
for (auto& p : points)
|
||||
{
|
||||
read(p.z());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
||||
void Foam::ensightReadFile::readPoints
|
||||
(
|
||||
const label nPoints,
|
||||
List<doubleVector>& points
|
||||
)
|
||||
{
|
||||
points.resize_nocopy(nPoints);
|
||||
|
||||
for (auto& p : points)
|
||||
{
|
||||
read(p.x());
|
||||
}
|
||||
for (auto& p : points)
|
||||
{
|
||||
read(p.y());
|
||||
}
|
||||
for (auto& p : points)
|
||||
{
|
||||
read(p.z());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::ensightReadFile::seekTime(const label timeIndex)
|
||||
{
|
||||
if (timeIndex >= 0 && timeIndex < timeStepOffsets_.size())
|
||||
{
|
||||
auto& iss = stdStream();
|
||||
|
||||
iss.seekg(timeStepOffsets_[timeIndex]);
|
||||
syncState();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< "seek time "
|
||||
<< timeIndex << '/' << nTimes()
|
||||
<< " offset:" << label(timeStepOffsets_[timeIndex]) << nl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< "seek time "
|
||||
<< timeIndex << '/' << nTimes()
|
||||
<< " ignored" << nl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2016-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -27,9 +27,8 @@ Class
|
||||
Foam::ensightReadFile
|
||||
|
||||
Description
|
||||
A variant of IFstream with specialised read() for
|
||||
strings, integers and floats.
|
||||
Correctly handles binary read as well.
|
||||
A variant of IFstream with specialised handling for Ensight reading
|
||||
of strings, integers and floats (ASCII and BINARY).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -38,6 +37,7 @@ Description
|
||||
|
||||
#include "IFstream.H"
|
||||
#include "IOstream.H"
|
||||
#include "vector.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -52,9 +52,28 @@ class ensightReadFile
|
||||
:
|
||||
public IFstream
|
||||
{
|
||||
public:
|
||||
// Private Data
|
||||
|
||||
// Generated Methods
|
||||
//- Transient single-file:
|
||||
//- beginning of time-step footer
|
||||
//- as read from the file
|
||||
int64_t timeStepFooterBegin_;
|
||||
|
||||
//- Transient single-file:
|
||||
//- the time-step file-offsets (position after "BEGIN TIME STEP")
|
||||
//- as read from the file
|
||||
List<int64_t> timeStepOffsets_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Read string as "%80s" or as binary
|
||||
void readString(std::string& value);
|
||||
|
||||
//- Initializes read information
|
||||
//- (optional detection of "C Binary" header)
|
||||
//- and scan for transient single-file format.
|
||||
void init(bool detectFormat);
|
||||
|
||||
//- No copy construct
|
||||
ensightReadFile(const ensightReadFile&) = delete;
|
||||
@ -63,10 +82,20 @@ public:
|
||||
void operator=(const ensightReadFile&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Debug switch
|
||||
static int debug;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from pathname, auto-detect the format
|
||||
explicit ensightReadFile(const fileName& pathname);
|
||||
//- Construct a geometry reader, auto-detecting the "C Binary" header
|
||||
//- for binary files and skipping past it.
|
||||
explicit ensightReadFile
|
||||
(
|
||||
const fileName& pathname
|
||||
);
|
||||
|
||||
//- Construct from pathname, use the specified (ascii/binary) format
|
||||
ensightReadFile
|
||||
@ -82,11 +111,13 @@ public:
|
||||
|
||||
// Static Functions
|
||||
|
||||
//- Detect if the file is \em binary by testing for initial
|
||||
//- "(C|Fortran) Binary"
|
||||
static IOstreamOption::streamFormat detectBinaryHeader
|
||||
//- Extract time step footer information (if any).
|
||||
// \return the begin of footer position.
|
||||
static int64_t getTimeStepFooter
|
||||
(
|
||||
const fileName& pathname
|
||||
IFstream& is,
|
||||
//! [out] File offsets for each time step (if any)
|
||||
List<int64_t>& offsets
|
||||
);
|
||||
|
||||
|
||||
@ -101,7 +132,7 @@ public:
|
||||
//- Read string as "%80s" or as binary
|
||||
virtual Istream& read(string& value) override;
|
||||
|
||||
//- Read integer as "%10d" or as binary
|
||||
//- Read integer as "%10d" or as binary (narrowed) int
|
||||
virtual Istream& read(label& value) override;
|
||||
|
||||
//- Read floating-point as "%12.5e" or as binary
|
||||
@ -113,8 +144,68 @@ public:
|
||||
//- Read element keyword. Currently the same as read(string)
|
||||
Istream& readKeyword(string& key);
|
||||
|
||||
//- Read "C Binary" for binary files (eg, geometry/measured)
|
||||
Istream& readBinaryHeader();
|
||||
|
||||
// Special Read Functions
|
||||
|
||||
//- Component-wise reading of points/coordinates.
|
||||
//- Read all x components, y components and z components.
|
||||
void readPoints(const label nPoints, List<floatVector>& points);
|
||||
|
||||
//- Component-wise reading of points/coordinates.
|
||||
//- Reads x components, y components and z components.
|
||||
void readPoints(const label nPoints, List<doubleVector>& points);
|
||||
|
||||
//- Read and discard specified number of elements
|
||||
template<class Type>
|
||||
void skip(label n = 1)
|
||||
{
|
||||
Type dummy;
|
||||
for (; n > 0; --n)
|
||||
{
|
||||
this->read(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Transient single-file format
|
||||
|
||||
//- Transient single-file:
|
||||
//- the position of the FILE_INDEX footer
|
||||
int64_t timeStepFooterBegin() const noexcept
|
||||
{
|
||||
return timeStepFooterBegin_;
|
||||
}
|
||||
|
||||
//- Transient single-file:
|
||||
//- the number of time steps within the file
|
||||
label nTimes() const noexcept
|
||||
{
|
||||
return timeStepOffsets_.size();
|
||||
}
|
||||
|
||||
//- Transient single-file:
|
||||
//- the file-offsets for time steps within the file
|
||||
const UList<int64_t>& timeStepOffets() const noexcept
|
||||
{
|
||||
return timeStepOffsets_;
|
||||
}
|
||||
|
||||
//- Transient single-file:
|
||||
//- seek to the file position corresponding to the given time index.
|
||||
bool seekTime(const label timeIndex);
|
||||
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- Detect if the file is \em binary by testing for initial
|
||||
//- "(C|Fortran) Binary"
|
||||
FOAM_DEPRECATED_FOR(2024-05, "detected on construct")
|
||||
static IOstreamOption::streamFormat
|
||||
detectBinaryHeader(const fileName& pathname)
|
||||
{
|
||||
ensightReadFile reader(pathname);
|
||||
return reader.format();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2021-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -125,6 +125,11 @@ void Foam::ensightFaMesh::write
|
||||
bool parallel
|
||||
) const
|
||||
{
|
||||
if (UPstream::master())
|
||||
{
|
||||
os.beginGeometry();
|
||||
}
|
||||
|
||||
// Area meshes (currently only one)
|
||||
// const label areaId = 0;
|
||||
areaPart_.write(os, mesh_.mesh(), parallel);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2021-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -147,14 +147,17 @@ public:
|
||||
|
||||
// Output
|
||||
|
||||
//- Write geometry to file. Normally in parallel
|
||||
//- Write geometry to file (normally in parallel).
|
||||
//- Adds beginGeometry() marker.
|
||||
void write
|
||||
(
|
||||
ensightGeoFile& os,
|
||||
bool parallel = UPstream::parRun()
|
||||
) const;
|
||||
|
||||
//- Write geometry to file. Normally in parallel
|
||||
//- Write geometry to file (normally in parallel).
|
||||
//- Adds beginGeometry() marker.
|
||||
FOAM_DEPRECATED_FOR(2024-05, "write(ensightGeoFile&, ...")
|
||||
inline void write
|
||||
(
|
||||
autoPtr<ensightGeoFile>& os,
|
||||
|
||||
@ -391,6 +391,11 @@ bool Foam::functionObjects::ensightCloudWriteObject::write()
|
||||
// Generate a (non-moving) dummy geometry
|
||||
// - ParaView ensight-reader needs this, and usually ensight does too
|
||||
autoPtr<ensightGeoFile> os = ensCase().newGeometry(false);
|
||||
|
||||
if (os)
|
||||
{
|
||||
os->beginGeometry();
|
||||
}
|
||||
ensightCells::writeBox(os.ref(), mesh_.bounds());
|
||||
}
|
||||
|
||||
|
||||
@ -237,7 +237,7 @@ bool Foam::functionObjects::ensightWrite::write()
|
||||
// Treat all geometry as moving, since we do not know a priori
|
||||
// if the simulation has mesh motion later on.
|
||||
autoPtr<ensightGeoFile> os = ensCase_().newGeometry(true);
|
||||
ensMesh_().write(os);
|
||||
ensMesh_().write(os.ref());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -92,9 +92,9 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
|
||||
merge();
|
||||
|
||||
{
|
||||
if (!isDir(outputFile.path()))
|
||||
if (!Foam::isDir(outputFile.path()))
|
||||
{
|
||||
mkDir(outputFile.path());
|
||||
Foam::mkDir(outputFile.path());
|
||||
}
|
||||
|
||||
const bool stateChanged =
|
||||
@ -131,12 +131,12 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
|
||||
);
|
||||
|
||||
// As per mkdir -p "data/00000000"
|
||||
mkDir(dataDir);
|
||||
Foam::mkDir(dataDir);
|
||||
|
||||
|
||||
const fileName geomFile(baseDir/geometryName);
|
||||
|
||||
if (!exists(geomFile))
|
||||
if (!Foam::exists(geomFile))
|
||||
{
|
||||
if (verbose_)
|
||||
{
|
||||
@ -151,6 +151,7 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
|
||||
caseOpts_.format()
|
||||
);
|
||||
|
||||
osGeom.beginGeometry();
|
||||
writeGeometry(osGeom, elemOutput);
|
||||
}
|
||||
|
||||
@ -176,7 +177,12 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
|
||||
// Update case file
|
||||
if (stateChanged)
|
||||
{
|
||||
OFstream osCase(outputFile, IOstreamOption::ASCII);
|
||||
OFstream osCase
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
outputFile,
|
||||
IOstreamOption::ASCII
|
||||
);
|
||||
ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
|
||||
|
||||
if (verbose_)
|
||||
|
||||
@ -91,9 +91,9 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeUncollated
|
||||
merge();
|
||||
|
||||
{
|
||||
if (!isDir(outputFile.path()))
|
||||
if (!Foam::isDir(outputFile.path()))
|
||||
{
|
||||
mkDir(outputFile.path());
|
||||
Foam::mkDir(outputFile.path());
|
||||
}
|
||||
|
||||
// Two-argument form for path-name to avoid validating base-dir
|
||||
@ -110,6 +110,7 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeUncollated
|
||||
caseOpts_.format()
|
||||
);
|
||||
|
||||
osGeom.beginGeometry();
|
||||
writeGeometry(osGeom, elemOutput);
|
||||
|
||||
// Write field (serial only)
|
||||
@ -118,7 +119,12 @@ Foam::fileName Foam::coordSetWriters::ensightWriter::writeUncollated
|
||||
|
||||
// Update case file
|
||||
{
|
||||
OFstream osCase(outputFile, IOstreamOption::ASCII);
|
||||
OFstream osCase
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
outputFile,
|
||||
IOstreamOption::ASCII
|
||||
);
|
||||
ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
|
||||
|
||||
osCase
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -44,54 +44,57 @@ namespace Foam
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Read and discard specified number of elements
|
||||
template<class Type>
|
||||
static inline void discard(label n, ensightReadFile& is)
|
||||
// Extract timeset and fileset from split line information
|
||||
// when the minElements has been satisfied.
|
||||
// For example,
|
||||
// ----
|
||||
// model: 1 some-geometry
|
||||
// model: 1 1 some-geometry
|
||||
// ----
|
||||
// would be split *after* the 'model:' resulting in these sub-strings:
|
||||
//
|
||||
// ("1" "some-geometry")
|
||||
// ("1" "1" some-geometry")
|
||||
//
|
||||
// thus call extractTimeset with minElements == 2
|
||||
//
|
||||
template<class StringType>
|
||||
static inline labelPair extractTimeset
|
||||
(
|
||||
const SubStrings<StringType>& split,
|
||||
const std::size_t minElements
|
||||
)
|
||||
{
|
||||
Type val;
|
||||
ISpanStream is;
|
||||
|
||||
while (n > 0)
|
||||
labelPair result(-1, -1);
|
||||
if (split.size() >= minElements)
|
||||
{
|
||||
is.read(val);
|
||||
--n;
|
||||
is.reset(split[0]);
|
||||
is >> result.first();
|
||||
|
||||
if (split.size() > minElements)
|
||||
{
|
||||
is.reset(split[1]);
|
||||
is >> result.second();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * //
|
||||
|
||||
void Foam::ensightSurfaceReader::skip(const label n, Istream& is) const
|
||||
{
|
||||
label i = 0;
|
||||
token tok;
|
||||
while (is.good() && (i < n))
|
||||
{
|
||||
is >> tok;
|
||||
++i;
|
||||
|
||||
DebugInfo
|
||||
<< "Skipping token " << tok << nl;
|
||||
}
|
||||
|
||||
if (i != n)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Requested to skip " << n << " tokens, but stream exited after "
|
||||
<< i << " tokens. Last token read: " << tok
|
||||
<< nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightSurfaceReader::readLine(ISstream& is, string& line) const
|
||||
bool Foam::ensightSurfaceReader::readLine(ISstream& is, std::string& line)
|
||||
{
|
||||
do
|
||||
{
|
||||
is.getLine(line);
|
||||
|
||||
// Trim out any '#' comments
|
||||
// Trim out any '#' comments (trailing or otherwise)
|
||||
const auto pos = line.find('#');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
@ -100,6 +103,32 @@ void Foam::ensightSurfaceReader::readLine(ISstream& is, string& line) const
|
||||
stringOps::inplaceTrimRight(line);
|
||||
}
|
||||
while (line.empty() && is.good());
|
||||
|
||||
return !line.empty();
|
||||
}
|
||||
|
||||
|
||||
void Foam::ensightSurfaceReader::checkSection
|
||||
(
|
||||
const word& expected,
|
||||
const string& buffer,
|
||||
const ISstream& is
|
||||
)
|
||||
{
|
||||
// Be more generous with our expectations.
|
||||
// Eg, ensight specifies the "VARIABLE" entry,
|
||||
// but accepts "VARIABLES" as well.
|
||||
|
||||
if (!expected.empty() && !buffer.starts_with(expected))
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Expected section header '" << expected
|
||||
<< "' but read " << buffer << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
DebugInfo
|
||||
<< "Read section header: " << buffer.c_str() << nl;
|
||||
}
|
||||
|
||||
|
||||
@ -107,54 +136,23 @@ void Foam::ensightSurfaceReader::debugSection
|
||||
(
|
||||
const word& expected,
|
||||
ISstream& is
|
||||
) const
|
||||
{
|
||||
string actual;
|
||||
readLine(is, actual);
|
||||
|
||||
if (expected != actual)
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Expected section header '" << expected
|
||||
<< "' but read " << actual << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
DebugInfo
|
||||
<< "Read section header: " << expected << nl;
|
||||
}
|
||||
|
||||
|
||||
Foam::fileName Foam::ensightSurfaceReader::replaceMask
|
||||
(
|
||||
const fileName& fName,
|
||||
const label timeIndex
|
||||
)
|
||||
{
|
||||
fileName result(fName);
|
||||
string buffer;
|
||||
readLine(is, buffer);
|
||||
|
||||
const auto nMask = stringOps::count(fName, '*');
|
||||
|
||||
// If there are any '*' chars, they are assumed to be contiguous
|
||||
// Eg, data/******/geometry
|
||||
|
||||
if (nMask)
|
||||
{
|
||||
const std::string maskStr(nMask, '*');
|
||||
const Foam::word indexStr(ensightCase::padded(nMask, timeIndex));
|
||||
result.replace(maskStr, indexStr);
|
||||
checkSection(expected, buffer, is);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::Pair<Foam::ensightSurfaceReader::idTypes>
|
||||
Foam::ensightSurfaceReader::readGeometryHeader(ensightReadFile& is) const
|
||||
Foam::ensightSurfaceReader::readGeometryHeader
|
||||
(
|
||||
ensightReadFile& is
|
||||
) const
|
||||
{
|
||||
// Binary flag string if applicable
|
||||
is.readBinaryHeader();
|
||||
|
||||
string buffer;
|
||||
|
||||
Pair<idTypes> idHandling(idTypes::NONE, idTypes::NONE);
|
||||
@ -203,17 +201,17 @@ Foam::ensightSurfaceReader::readGeometryHeader(ensightReadFile& is) const
|
||||
// Optional extents - read and discard 6 floats
|
||||
// (xmin, xmax, ymin, ymax, zmin, zmax)
|
||||
|
||||
discard<scalar>(6, is);
|
||||
is.skip<scalar>(6);
|
||||
|
||||
// Part
|
||||
// "part"
|
||||
is.read(buffer);
|
||||
DebugInfo<< "buffer [" << buffer.length() << "] " << buffer << nl;
|
||||
}
|
||||
|
||||
// The part number
|
||||
label ivalue;
|
||||
is.read(ivalue);
|
||||
DebugInfo<< "ivalue: " << ivalue << nl;
|
||||
label intValue;
|
||||
is.read(intValue);
|
||||
DebugInfo<< "part number: " << intValue << nl;
|
||||
|
||||
// Part description / name
|
||||
is.read(buffer);
|
||||
@ -231,6 +229,8 @@ void Foam::ensightSurfaceReader::readCase(ISstream& is)
|
||||
{
|
||||
DebugInFunction << endl;
|
||||
|
||||
enum ParseSection { UNKNOWN, FORMAT, GEOMETRY, VARIABLE, TIME, FILE };
|
||||
|
||||
if (!is.good())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
@ -239,99 +239,366 @@ void Foam::ensightSurfaceReader::readCase(ISstream& is)
|
||||
}
|
||||
|
||||
string buffer;
|
||||
SubStrings<string> split;
|
||||
|
||||
// Read the file
|
||||
ParseSection parseState = ParseSection::UNKNOWN;
|
||||
|
||||
// FORMAT
|
||||
// ~~~~~~
|
||||
|
||||
debugSection("FORMAT", is);
|
||||
readLine(is, buffer); // type: ensight gold
|
||||
parseState = ParseSection::FORMAT;
|
||||
|
||||
// GEOMETRY
|
||||
// ~~~~~~~~
|
||||
debugSection("GEOMETRY", is);
|
||||
parseState = ParseSection::GEOMETRY;
|
||||
|
||||
do
|
||||
{
|
||||
readLine(is, buffer);
|
||||
|
||||
// GEOMETRY with any of these
|
||||
// model: 1 xxx.0000.mesh
|
||||
// model: xxx.0000.mesh
|
||||
// model: data/directory/geometry
|
||||
if (buffer.starts_with("VARIABLE"))
|
||||
{
|
||||
parseState = ParseSection::VARIABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer.contains("change_coords_only"))
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "No support for moving points, only topology change" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
// Extract filename from GEOMETRY section
|
||||
// ====
|
||||
// model: [ts] [fs] filename [change_coords_only [cstep]]
|
||||
//
|
||||
// - use the last entry
|
||||
meshFileName_ = stringOps::splitSpace(buffer).back().str();
|
||||
// ====
|
||||
|
||||
// TBD:
|
||||
// check for "model:" vs "measured:" ?
|
||||
|
||||
const auto pos_colon = buffer.find(':');
|
||||
|
||||
if
|
||||
(
|
||||
(pos_colon == std::string::npos)
|
||||
)
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Error reading geometry 'model:'" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
split = stringOps::splitSpace(buffer, pos_colon+1);
|
||||
|
||||
if (split.empty())
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Error reading geometry 'model:'" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
// With timeset? - need at least 2 entries
|
||||
meshTimeset_ = extractTimeset(split, 2);
|
||||
meshFileName_ = split[split.size()-1].str();
|
||||
|
||||
DebugInfo << "mesh file:" << meshFileName_ << endl;
|
||||
}
|
||||
while (false);
|
||||
|
||||
|
||||
if (parseState != ParseSection::VARIABLE)
|
||||
{
|
||||
debugSection("VARIABLE", is);
|
||||
parseState = ParseSection::VARIABLE;
|
||||
}
|
||||
|
||||
// Read the field description
|
||||
DynamicList<word> fieldNames(16);
|
||||
DynamicList<string> fieldFileNames(16);
|
||||
DynamicList<labelPair> dynFieldTimesets(16);
|
||||
DynamicList<word> dynFieldNames(16);
|
||||
DynamicList<string> dynFieldFileNames(16);
|
||||
|
||||
// VARIABLE
|
||||
// ~~~~~~~~
|
||||
|
||||
while (is.good())
|
||||
{
|
||||
readLine(is, buffer);
|
||||
|
||||
if (buffer == "TIME")
|
||||
if (buffer.starts_with("TIME"))
|
||||
{
|
||||
parseState = ParseSection::TIME;
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the field name and associated file name. Eg,
|
||||
// scalar per element: 1 p data/********/p
|
||||
// Read the field name and associated file name.
|
||||
// Eg,
|
||||
// scalar per element: [ts] [fs] p data/********/p
|
||||
// but ignore
|
||||
// scalar per node: [ts] [fs] other data/********/other
|
||||
|
||||
const auto parsed = stringOps::splitSpace(buffer);
|
||||
const auto pos_colon = buffer.find(':');
|
||||
|
||||
if (!buffer.contains(':') || parsed.size() < 4)
|
||||
if (pos_colon == std::string::npos)
|
||||
{
|
||||
DebugInfo<< "ignore variable line: " << buffer << nl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO? handle variable descriptions with spaces (they are quoted)
|
||||
|
||||
split = stringOps::splitSpace(buffer, pos_colon+1);
|
||||
|
||||
if (split.size() < 2)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Error reading field file name. Current buffer: "
|
||||
<< "Error reading field file name, variable line: "
|
||||
<< buffer << endl;
|
||||
continue;
|
||||
}
|
||||
else if (debug)
|
||||
|
||||
auto pos_key = buffer.find("element");
|
||||
if ((pos_key == std::string::npos) || (pos_colon < pos_key))
|
||||
{
|
||||
Info<< "variable line: " << parsed.size();
|
||||
for (const auto& s : parsed)
|
||||
{
|
||||
Info<< " " << s.str();
|
||||
}
|
||||
Info<< nl;
|
||||
DebugInfo<< "ignore variable line: " << buffer << nl;
|
||||
continue;
|
||||
}
|
||||
|
||||
fieldNames.push_back(parsed[parsed.size()-2].str());
|
||||
fieldFileNames.push_back(parsed.back().str());
|
||||
DebugInfo<< "variable line: " << buffer << nl;
|
||||
|
||||
// With timeset? - need at least 3 entries
|
||||
dynFieldTimesets.push_back(extractTimeset(split, 3));
|
||||
|
||||
dynFieldNames.push_back(split[split.size()-2].str());
|
||||
dynFieldFileNames.push_back(split[split.size()-1].str());
|
||||
}
|
||||
fieldNames_.transfer(fieldNames);
|
||||
fieldFileNames_.transfer(fieldFileNames);
|
||||
fieldTimesets_.transfer(dynFieldTimesets);
|
||||
fieldNames_.transfer(dynFieldNames);
|
||||
fieldFileNames_.transfer(dynFieldFileNames);
|
||||
|
||||
DebugInfo
|
||||
<< "fieldNames: " << fieldNames_ << nl
|
||||
<< "fieldFileNames: " << fieldFileNames_ << nl;
|
||||
|
||||
// Start reading time information
|
||||
readLine(is, buffer); // time set: <int>
|
||||
|
||||
readLine(is, buffer);
|
||||
readFromLine(3, buffer, nTimeSteps_); // number of steps: <int>
|
||||
readLine(is, buffer);
|
||||
readFromLine(3, buffer, timeStartIndex_); // filename start number: <int>
|
||||
readLine(is, buffer);
|
||||
readFromLine(2, buffer, timeIncrement_); // filename increment: <int>
|
||||
if (parseState != ParseSection::TIME)
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Did not find section header 'TIME'" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
|
||||
// Determine which unique timeset or fileset to expect
|
||||
|
||||
labelHashSet expectTimeset;
|
||||
labelHashSet expectFileset;
|
||||
|
||||
expectTimeset.insert(meshTimeset_.first());
|
||||
expectFileset.insert(meshTimeset_.second());
|
||||
|
||||
for (const auto& tup : fieldTimesets_)
|
||||
{
|
||||
expectTimeset.insert(tup.first());
|
||||
expectFileset.insert(tup.second());
|
||||
}
|
||||
|
||||
// Remove placeholders
|
||||
expectTimeset.erase(-1);
|
||||
expectFileset.erase(-1);
|
||||
|
||||
|
||||
DebugInfo
|
||||
<< "nTimeSteps: " << nTimeSteps_ << nl
|
||||
<< "timeStartIndex: " << timeStartIndex_ << nl
|
||||
<< "timeIncrement: " << timeIncrement_ << nl;
|
||||
<< "expect timesets: " << flatOutput(expectTimeset) << nl
|
||||
<< "expect filesets: " << flatOutput(expectFileset) << nl;
|
||||
|
||||
// Read the time values
|
||||
readLine(is, buffer); // time values:
|
||||
timeValues_.resize_nocopy(nTimeSteps_);
|
||||
for (label i = 0; i < nTimeSteps_; ++i)
|
||||
|
||||
// TIME
|
||||
// ~~~~
|
||||
// style 1:
|
||||
// ====
|
||||
// time set: <int> [description]
|
||||
// number of steps: <int>
|
||||
// filename start number: <int>
|
||||
// filename increment: <int>
|
||||
// time values: time_1 .. time_N
|
||||
// ====
|
||||
//
|
||||
// style 2:
|
||||
// ====
|
||||
// time set: <int> [description]
|
||||
// number of steps: <int>
|
||||
// filename numbers: int_1 .. int_N
|
||||
// time values: time_1 .. time_N
|
||||
// ====
|
||||
//
|
||||
// style 3:
|
||||
// ====
|
||||
// time set: <int> [description]
|
||||
// number of steps: <int>
|
||||
// filename numbers file: <filename>
|
||||
// time values file: <filename>
|
||||
// ====
|
||||
|
||||
|
||||
// Currently only handling style 1, style 2
|
||||
// and only a single time set
|
||||
|
||||
// time set = 1
|
||||
{
|
||||
scalar t(readScalar(is));
|
||||
|
||||
timeValues_[i].value() = t;
|
||||
// TODO: use character representation of t directly instead of
|
||||
// regenerating from scalar value
|
||||
timeValues_[i].name() = Foam::name(t);
|
||||
// time set: <int>
|
||||
{
|
||||
readLine(is, buffer);
|
||||
}
|
||||
|
||||
// number of steps: <int>
|
||||
label nTimes = 0;
|
||||
{
|
||||
readLine(is, buffer);
|
||||
split = stringOps::splitSpace(buffer);
|
||||
readFrom(split.back(), nTimes);
|
||||
}
|
||||
|
||||
// filename start number: <int>
|
||||
// filename increment: <int>
|
||||
//
|
||||
// OR:
|
||||
// filename numbers: ...
|
||||
|
||||
readLine(is, buffer);
|
||||
auto pos_colon = buffer.find(':');
|
||||
|
||||
if (buffer.contains("numbers:"))
|
||||
{
|
||||
// Split out trailing values...
|
||||
split = stringOps::splitSpace(buffer, pos_colon+1);
|
||||
|
||||
fileNumbers_.resize_nocopy(nTimes);
|
||||
|
||||
label numRead = 0;
|
||||
while (numRead < nTimes)
|
||||
{
|
||||
for (const auto& chunk : split)
|
||||
{
|
||||
std::string str(chunk.str());
|
||||
|
||||
if (!Foam::readLabel(str, fileNumbers_[numRead]))
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Could not parse label: " << str << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
++numRead;
|
||||
|
||||
if (numRead == nTimes)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get more input
|
||||
if (numRead < nTimes)
|
||||
{
|
||||
readLine(is, buffer);
|
||||
split = stringOps::splitSpace(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
timeStartIndex_ = 0;
|
||||
timeIncrement_ = 0;
|
||||
fileNumbers_.resize(numRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
// filename start number: <int>
|
||||
split = stringOps::splitSpace(buffer);
|
||||
readFrom(split.back(), timeStartIndex_);
|
||||
|
||||
// filename increment: <int>
|
||||
readLine(is, buffer);
|
||||
split = stringOps::splitSpace(buffer);
|
||||
readFrom(split.back(), timeIncrement_);
|
||||
|
||||
fileNumbers_.clear();
|
||||
}
|
||||
|
||||
DebugInfo
|
||||
<< "nTimes: " << nTimes
|
||||
<< " start-index: " << timeStartIndex_
|
||||
<< " increment: " << timeIncrement_
|
||||
<< " file numbers: " << flatOutput(fileNumbers_) << nl;
|
||||
|
||||
|
||||
// time values: time_1 .. time_N
|
||||
readLine(is, buffer);
|
||||
|
||||
// Split out trailing values...
|
||||
{
|
||||
const auto pos_colon = buffer.find(':');
|
||||
const auto pos_key = buffer.find("values");
|
||||
|
||||
if
|
||||
(
|
||||
(pos_colon == std::string::npos)
|
||||
|| (pos_key == std::string::npos) || (pos_colon < pos_key)
|
||||
)
|
||||
{
|
||||
split.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
split = stringOps::splitSpace(buffer, pos_colon+1);
|
||||
}
|
||||
}
|
||||
|
||||
timeValues_.resize_nocopy(nTimes);
|
||||
|
||||
label numRead = 0;
|
||||
while (numRead < nTimes)
|
||||
{
|
||||
for (const auto& chunk : split)
|
||||
{
|
||||
auto& inst = timeValues_[numRead];
|
||||
|
||||
// Retain character representation
|
||||
inst.name() = word(chunk.str());
|
||||
|
||||
if (!Foam::readScalar(inst.name(), inst.value()))
|
||||
{
|
||||
FatalIOErrorInFunction(is)
|
||||
<< "Could not parse scalar: " << inst.name() << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
++numRead;
|
||||
|
||||
if (numRead == nTimes)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get more input
|
||||
if (numRead < nTimes)
|
||||
{
|
||||
readLine(is, buffer);
|
||||
split = stringOps::splitSpace(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
timeValues_.resize(numRead);
|
||||
}
|
||||
|
||||
// Not yet:
|
||||
|
||||
// FILE
|
||||
// ~~~~
|
||||
// file set: <int>
|
||||
// filename index: <int> - file index number in the file name
|
||||
// number of steps: <int>
|
||||
}
|
||||
|
||||
|
||||
@ -351,14 +618,9 @@ Foam::ensightSurfaceReader::ensightSurfaceReader
|
||||
),
|
||||
readFormat_(IOstreamOption::ASCII), // Placeholder value
|
||||
baseDir_(fName.path()),
|
||||
meshFileName_(),
|
||||
fieldNames_(),
|
||||
fieldFileNames_(),
|
||||
nTimeSteps_(0),
|
||||
meshTimeset_(-1,-1),
|
||||
timeStartIndex_(0),
|
||||
timeIncrement_(1),
|
||||
timeValues_(),
|
||||
surfPtr_(nullptr)
|
||||
timeIncrement_(1)
|
||||
{
|
||||
if (options.getOrDefault("debug", false))
|
||||
{
|
||||
@ -376,12 +638,14 @@ Foam::ensightSurfaceReader::ensightSurfaceReader
|
||||
Pstream::broadcasts
|
||||
(
|
||||
UPstream::worldComm,
|
||||
meshTimeset_,
|
||||
meshFileName_,
|
||||
fieldTimesets_,
|
||||
fieldNames_,
|
||||
fieldFileNames_,
|
||||
nTimeSteps_,
|
||||
timeStartIndex_,
|
||||
timeIncrement_,
|
||||
fileNumbers_,
|
||||
timeValues_
|
||||
);
|
||||
}
|
||||
@ -392,7 +656,8 @@ Foam::ensightSurfaceReader::ensightSurfaceReader
|
||||
|
||||
Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
(
|
||||
const fileName& geometryFile
|
||||
const fileName& geometryFile,
|
||||
const label timeIndex
|
||||
)
|
||||
{
|
||||
DebugInFunction << endl;
|
||||
@ -404,6 +669,9 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
// Format detected from the geometry
|
||||
readFormat_ = is.format();
|
||||
|
||||
// For transient single-file
|
||||
is.seekTime(timeIndex);
|
||||
|
||||
DebugInfo
|
||||
<< "File: " << is.name()
|
||||
<< " format: "
|
||||
@ -433,52 +701,59 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
<< "Ignore " << nPoints << " node ids" << nl;
|
||||
|
||||
// Read and discard labels
|
||||
discard<label>(nPoints, is);
|
||||
is.skip<label>(nPoints);
|
||||
}
|
||||
|
||||
pointField points(nPoints);
|
||||
for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
|
||||
{
|
||||
for (point& p : points)
|
||||
{
|
||||
is.read(p[cmpt]);
|
||||
}
|
||||
}
|
||||
pointField points;
|
||||
is.readPoints(nPoints, points);
|
||||
|
||||
|
||||
// Read faces - may be a mix of tria3, quad4, nsided
|
||||
DynamicList<face> dynFaces(nPoints/3);
|
||||
DynamicList<faceInfoTuple> faceTypeInfo(16);
|
||||
|
||||
string faceType;
|
||||
label faceCount = 0;
|
||||
string buffer;
|
||||
|
||||
while (is.good()) // (is.peek() != EOF)
|
||||
while (is.good())
|
||||
{
|
||||
// The element type
|
||||
is.read(faceType);
|
||||
is.read(buffer);
|
||||
|
||||
if (!is.good())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (buffer.contains("BEGIN TIME STEP"))
|
||||
{
|
||||
// Graciously handle a miscued start
|
||||
continue;
|
||||
}
|
||||
else if (buffer.contains("END TIME STEP"))
|
||||
{
|
||||
// END TIME STEP is a valid means to terminate input
|
||||
break;
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
faceType
|
||||
buffer
|
||||
== ensightFaces::elemNames[ensightFaces::elemType::TRIA3]
|
||||
)
|
||||
{
|
||||
is.read(faceCount);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
faceTypeInfo.push_back
|
||||
faceTypeInfo.emplace_back
|
||||
(
|
||||
faceInfoTuple(ensightFaces::elemType::TRIA3, faceCount)
|
||||
ensightFaces::elemType::TRIA3,
|
||||
elemCount
|
||||
);
|
||||
|
||||
DebugInfo
|
||||
<< "faceType <" << faceType.c_str() << "> count: "
|
||||
<< faceCount << nl;
|
||||
<< "faceType <"
|
||||
<< ensightFaces::elemNames[ensightFaces::elemType::TRIA3]
|
||||
<< "> count: "
|
||||
<< elemCount << nl;
|
||||
|
||||
if
|
||||
(
|
||||
@ -487,39 +762,45 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
)
|
||||
{
|
||||
DebugInfo
|
||||
<< "Ignore " << faceCount << " element ids" << nl;
|
||||
<< "Ignore " << elemCount << " element ids" << nl;
|
||||
|
||||
// Read and discard labels
|
||||
discard<label>(faceCount, is);
|
||||
is.skip<label>(elemCount);
|
||||
}
|
||||
|
||||
for (label facei = 0; facei < faceCount; ++facei)
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = dynFaces.size();
|
||||
dynFaces.resize(startElemi+elemCount, face(3)); // tria3
|
||||
faceList::subList myElements = dynFaces.slice(startElemi);
|
||||
|
||||
for (auto& f : myElements)
|
||||
{
|
||||
face f(3);
|
||||
for (label& fp : f)
|
||||
{
|
||||
is.read(fp);
|
||||
}
|
||||
|
||||
dynFaces.push_back(std::move(f));
|
||||
}
|
||||
}
|
||||
else if
|
||||
(
|
||||
faceType
|
||||
buffer
|
||||
== ensightFaces::elemNames[ensightFaces::elemType::QUAD4]
|
||||
)
|
||||
{
|
||||
is.read(faceCount);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
faceTypeInfo.push_back
|
||||
faceTypeInfo.emplace_back
|
||||
(
|
||||
faceInfoTuple(ensightFaces::elemType::QUAD4, faceCount)
|
||||
ensightFaces::elemType::QUAD4,
|
||||
elemCount
|
||||
);
|
||||
|
||||
DebugInfo
|
||||
<< "faceType <" << faceType.c_str() << "> count: "
|
||||
<< faceCount << nl;
|
||||
<< "faceType <"
|
||||
<< ensightFaces::elemNames[ensightFaces::elemType::QUAD4]
|
||||
<< "> count: "
|
||||
<< elemCount << nl;
|
||||
|
||||
if
|
||||
(
|
||||
@ -528,39 +809,44 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
)
|
||||
{
|
||||
DebugInfo
|
||||
<< "Ignore " << faceCount << " element ids" << nl;
|
||||
<< "Ignore " << elemCount << " element ids" << nl;
|
||||
|
||||
// Read and discard labels
|
||||
discard<label>(faceCount, is);
|
||||
is.skip<label>(elemCount);
|
||||
}
|
||||
|
||||
for (label facei = 0; facei < faceCount; ++facei)
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = dynFaces.size();
|
||||
dynFaces.resize(startElemi + elemCount, face(4)); // quad4
|
||||
faceList::subList myElements = dynFaces.slice(startElemi);
|
||||
|
||||
for (auto& f : myElements)
|
||||
{
|
||||
face f(4);
|
||||
for (label& fp : f)
|
||||
{
|
||||
is.read(fp);
|
||||
}
|
||||
|
||||
dynFaces.push_back(std::move(f));
|
||||
}
|
||||
}
|
||||
else if
|
||||
(
|
||||
faceType
|
||||
buffer
|
||||
== ensightFaces::elemNames[ensightFaces::elemType::NSIDED]
|
||||
)
|
||||
{
|
||||
is.read(faceCount);
|
||||
label elemCount;
|
||||
is.read(elemCount);
|
||||
|
||||
faceTypeInfo.push_back
|
||||
faceTypeInfo.emplace_back
|
||||
(
|
||||
faceInfoTuple(ensightFaces::elemType::NSIDED, faceCount)
|
||||
ensightFaces::elemType::NSIDED,
|
||||
elemCount
|
||||
);
|
||||
|
||||
DebugInfo
|
||||
<< "faceType <" << faceType.c_str() << "> count: "
|
||||
<< faceCount << nl;
|
||||
<< "faceType <"
|
||||
<< ensightFaces::elemNames[ensightFaces::elemType::NSIDED]
|
||||
<< "> count: " << elemCount << nl;
|
||||
|
||||
if
|
||||
(
|
||||
@ -569,26 +855,31 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
)
|
||||
{
|
||||
DebugInfo
|
||||
<< "Ignore " << faceCount << " element ids" << nl;
|
||||
<< "Ignore " << elemCount << " element ids" << nl;
|
||||
|
||||
// Read and discard labels
|
||||
discard<label>(faceCount, is);
|
||||
is.skip<label>(elemCount);
|
||||
}
|
||||
|
||||
labelList np(faceCount);
|
||||
for (label facei = 0; facei < faceCount; ++facei)
|
||||
// Extend and fill the new trailing portion
|
||||
const label startElemi = dynFaces.size();
|
||||
dynFaces.resize(startElemi + elemCount);
|
||||
faceList::subList myElements = dynFaces.slice(startElemi);
|
||||
|
||||
for (auto& f : myElements)
|
||||
{
|
||||
is.read(np[facei]);
|
||||
label nVerts;
|
||||
is.read(nVerts);
|
||||
|
||||
f.resize(nVerts);
|
||||
}
|
||||
for (label facei = 0; facei < faceCount; ++facei)
|
||||
|
||||
for (auto& f : myElements)
|
||||
{
|
||||
face f(np[facei]);
|
||||
for (label& fp : f)
|
||||
{
|
||||
is.read(fp);
|
||||
}
|
||||
|
||||
dynFaces.push_back(std::move(f));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -596,7 +887,7 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
if (debug)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Unknown face type: <" << faceType.c_str()
|
||||
<< "Unknown face type: <" << buffer.c_str()
|
||||
<< ">. Stopping read and continuing with current "
|
||||
<< "elements only" << endl;
|
||||
}
|
||||
@ -605,7 +896,7 @@ Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
|
||||
}
|
||||
|
||||
// From 1-based Ensight addressing to 0-based OF addressing
|
||||
for (face& f : dynFaces)
|
||||
for (auto& f : dynFaces)
|
||||
{
|
||||
for (label& fp : f)
|
||||
{
|
||||
@ -637,11 +928,15 @@ const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry
|
||||
surfPtr_.reset(new meshedSurface);
|
||||
auto& surf = *surfPtr_;
|
||||
|
||||
fileName geomFile(baseDir_/replaceMask(meshFileName_, timeIndex));
|
||||
fileName geomFile
|
||||
(
|
||||
baseDir_
|
||||
/ ensightCase::expand_mask(meshFileName_, timeIndex)
|
||||
);
|
||||
|
||||
if (!masterOnly_ || UPstream::master(UPstream::worldComm))
|
||||
{
|
||||
surf = readGeometry(geomFile);
|
||||
surf = readGeometry(geomFile, timeIndex);
|
||||
}
|
||||
|
||||
if (masterOnly_ && UPstream::parRun())
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -57,6 +57,7 @@ SourceFiles
|
||||
#define Foam_ensightSurfaceReader_H
|
||||
|
||||
#include "surfaceReader.H"
|
||||
#include "ensightCase.H"
|
||||
#include "ensightFaces.H"
|
||||
#include "ensightReadFile.H"
|
||||
#include "Pair.H"
|
||||
@ -103,24 +104,30 @@ protected:
|
||||
//- Base directory
|
||||
fileName baseDir_;
|
||||
|
||||
//- The timeset/fileset (if any) associated with the mesh
|
||||
labelPair meshTimeset_;
|
||||
|
||||
//- Name of mesh file, including any subdirectory
|
||||
fileName meshFileName_;
|
||||
|
||||
//- The timeset/fileset (if any) associated with fields
|
||||
List<labelPair> fieldTimesets_;
|
||||
|
||||
//- Field names
|
||||
List<word> fieldNames_;
|
||||
|
||||
//- Field file names
|
||||
List<string> fieldFileNames_;
|
||||
|
||||
//- Number of time steps
|
||||
label nTimeSteps_;
|
||||
|
||||
//- Start time index
|
||||
label timeStartIndex_;
|
||||
|
||||
//- Time increment
|
||||
label timeIncrement_;
|
||||
|
||||
//- Numbers for files
|
||||
labelList fileNumbers_;
|
||||
|
||||
//- Times
|
||||
instantList timeValues_;
|
||||
|
||||
@ -131,23 +138,30 @@ protected:
|
||||
List<faceInfoTuple> faceTypeInfo_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
// Static Member Functions
|
||||
|
||||
//- Helper function to skip forward n steps in stream
|
||||
void skip(const label n, Istream& is) const;
|
||||
//- Helper function to read an ascii line from file,
|
||||
//- skipping blank lines and comments.
|
||||
// \return True if reading was successful
|
||||
static bool readLine(ISstream& is, std::string& line);
|
||||
|
||||
//- Helper function to read an ascii line from file
|
||||
void readLine(ISstream& is, string& buffer) const;
|
||||
//- Check a section header
|
||||
static void checkSection
|
||||
(
|
||||
const word& expected,
|
||||
const string& buffer,
|
||||
const ISstream& is // For errors
|
||||
);
|
||||
|
||||
//- Read and check a section header
|
||||
void debugSection(const word& expected, ISstream& is) const;
|
||||
static void debugSection(const word& expected, ISstream& is);
|
||||
|
||||
//- Replace the '*' mask chars with a 0 padded string.
|
||||
static fileName replaceMask
|
||||
(
|
||||
const fileName& fName,
|
||||
const label timeIndex
|
||||
);
|
||||
//- Helper function to return Type from string
|
||||
template<class Type>
|
||||
static void readFrom(const std::string& buffer, Type& value);
|
||||
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Read (and discard) geometry file header.
|
||||
// \return information about node/element id handling
|
||||
@ -157,27 +171,20 @@ protected:
|
||||
void readCase(ISstream& is);
|
||||
|
||||
//- Read and return surface geometry. Updates faceTypeInfo_
|
||||
meshedSurface readGeometry(const fileName& geometryFile);
|
||||
|
||||
//- Helper function to return Type after skipping n tokens
|
||||
template<class Type>
|
||||
void readFromLine(const label nSkip, Istream& is, Type& value) const;
|
||||
|
||||
//- Helper function to return Type after skipping n tokens
|
||||
template<class Type>
|
||||
void readFromLine
|
||||
meshedSurface readGeometry
|
||||
(
|
||||
const label nSkip,
|
||||
const string& buffer,
|
||||
Type& value
|
||||
) const;
|
||||
const fileName& geometryFile,
|
||||
//! Optional index for transient single-file format
|
||||
const label timeIndex = 0
|
||||
);
|
||||
|
||||
//- Helper function to return a field
|
||||
template<class Type>
|
||||
tmp<Field<Type>> readField
|
||||
(
|
||||
const fileName& dataFile,
|
||||
const word& fieldName
|
||||
const word& fieldName,
|
||||
const label timeIndex = 0
|
||||
) const;
|
||||
|
||||
//- Helper function to return a field
|
||||
@ -191,6 +198,15 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
// Generated Methods
|
||||
|
||||
//- No copy construct
|
||||
ensightSurfaceReader(const ensightSurfaceReader&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const ensightSurfaceReader&) = delete;
|
||||
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("ensight");
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,41 +28,28 @@ License
|
||||
#include "SpanStream.H"
|
||||
#include "ensightPTraits.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
void Foam::ensightSurfaceReader::readFromLine
|
||||
void Foam::ensightSurfaceReader::readFrom
|
||||
(
|
||||
const label nSkip,
|
||||
Istream& is,
|
||||
const std::string& buffer,
|
||||
Type& value
|
||||
) const
|
||||
)
|
||||
{
|
||||
skip(nSkip, is);
|
||||
|
||||
ISpanStream is(buffer.data(), buffer.size());
|
||||
is >> value;
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::ensightSurfaceReader::readFromLine
|
||||
(
|
||||
const label nSkip,
|
||||
const string& buffer,
|
||||
Type& value
|
||||
) const
|
||||
{
|
||||
ISpanStream is(buffer.data(), buffer.length());
|
||||
|
||||
readFromLine(nSkip, is, value);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
|
||||
(
|
||||
const fileName& dataFile,
|
||||
const word& fieldName
|
||||
const word& fieldName,
|
||||
const label timeIndex
|
||||
) const
|
||||
{
|
||||
auto tfield = tmp<Field<Type>>::New(surfPtr_->nFaces(), Zero);
|
||||
@ -81,6 +68,10 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// If transient single-file
|
||||
is.seekTime(timeIndex);
|
||||
|
||||
|
||||
// Check that data type is as expected
|
||||
// (assuming OpenFOAM generated the data set)
|
||||
string primitiveType;
|
||||
@ -104,11 +95,11 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
|
||||
}
|
||||
|
||||
string strValue;
|
||||
label iValue;
|
||||
label intValue;
|
||||
|
||||
// Read header info: part index, e.g. part 1
|
||||
is.read(strValue);
|
||||
is.read(iValue);
|
||||
is.read(intValue);
|
||||
|
||||
label begFace = 0;
|
||||
|
||||
@ -183,11 +174,18 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
|
||||
}
|
||||
|
||||
const word& fieldName = fieldNames_[fieldIndex];
|
||||
const label fileIndex = timeStartIndex_ + timeIndex*timeIncrement_;
|
||||
|
||||
const label fileIndex =
|
||||
(
|
||||
(timeIndex >= 0 && timeIndex < fileNumbers_.size())
|
||||
? fileNumbers_[timeIndex]
|
||||
: (timeStartIndex_ + timeIndex*timeIncrement_)
|
||||
);
|
||||
|
||||
const fileName dataFile
|
||||
(
|
||||
baseDir_/replaceMask(fieldFileNames_[fieldIndex], fileIndex)
|
||||
baseDir_
|
||||
/ ensightCase::expand_mask(fieldFileNames_[fieldIndex], fileIndex)
|
||||
);
|
||||
|
||||
if (debug)
|
||||
@ -196,7 +194,7 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
|
||||
<< dataFile << endl;
|
||||
}
|
||||
|
||||
return readField<Type>(dataFile, fieldName);
|
||||
return readField<Type>(dataFile, fieldName, timeIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -99,9 +99,9 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
|
||||
if (UPstream::master() || !parallel_)
|
||||
{
|
||||
if (!isDir(outputFile.path()))
|
||||
if (!Foam::isDir(outputFile.path()))
|
||||
{
|
||||
mkDir(outputFile.path());
|
||||
Foam::mkDir(outputFile.path());
|
||||
}
|
||||
|
||||
const bool stateChanged =
|
||||
@ -138,7 +138,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
);
|
||||
|
||||
// As per mkdir -p "data/00000000"
|
||||
mkDir(dataDir);
|
||||
Foam::mkDir(dataDir);
|
||||
|
||||
|
||||
const fileName geomFile(baseDir/geometryName);
|
||||
@ -151,7 +151,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
geomFile.name()
|
||||
);
|
||||
|
||||
if (!exists(geomFile))
|
||||
if (!Foam::exists(geomFile))
|
||||
{
|
||||
if (verbose_)
|
||||
{
|
||||
@ -165,6 +165,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
geomFile.name(),
|
||||
caseOpts_.format()
|
||||
);
|
||||
|
||||
osGeom.beginGeometry();
|
||||
part.write(osGeom); // serial
|
||||
}
|
||||
|
||||
@ -190,7 +192,12 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
// Update case file
|
||||
if (stateChanged)
|
||||
{
|
||||
OFstream osCase(outputFile, IOstreamOption::ASCII);
|
||||
OFstream osCase
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
outputFile,
|
||||
IOstreamOption::ASCII
|
||||
);
|
||||
ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
|
||||
|
||||
if (verbose_)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2023 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2024 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -64,11 +64,20 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
||||
|
||||
if (UPstream::master() || !parallel_)
|
||||
{
|
||||
if (!isDir(outputDir))
|
||||
if (!Foam::isDir(outputDir))
|
||||
{
|
||||
mkDir(outputDir);
|
||||
Foam::mkDir(outputDir);
|
||||
}
|
||||
|
||||
// The geometry
|
||||
ensightOutputSurface part
|
||||
(
|
||||
surf.points(),
|
||||
surf.faces(),
|
||||
baseName
|
||||
);
|
||||
|
||||
// Two-argument form for path-name to avoid validating outputDir
|
||||
ensightGeoFile osGeom
|
||||
(
|
||||
outputDir,
|
||||
@ -76,16 +85,16 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
||||
caseOpts_.format()
|
||||
);
|
||||
|
||||
ensightOutputSurface part
|
||||
(
|
||||
surf.points(),
|
||||
surf.faces(),
|
||||
osGeom.name().name()
|
||||
);
|
||||
osGeom.beginGeometry();
|
||||
part.write(osGeom); // serial
|
||||
|
||||
// Update case file
|
||||
OFstream osCase(outputFile, IOstreamOption::ASCII);
|
||||
OFstream osCase
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
outputFile,
|
||||
IOstreamOption::ASCII
|
||||
);
|
||||
ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
|
||||
|
||||
osCase
|
||||
@ -168,11 +177,19 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
|
||||
|
||||
if (UPstream::master() || !parallel_)
|
||||
{
|
||||
if (!isDir(outputFile.path()))
|
||||
if (!Foam::isDir(outputFile.path()))
|
||||
{
|
||||
mkDir(outputFile.path());
|
||||
Foam::mkDir(outputFile.path());
|
||||
}
|
||||
|
||||
// The geometry
|
||||
ensightOutputSurface part
|
||||
(
|
||||
surf.points(),
|
||||
surf.faces(),
|
||||
baseName
|
||||
);
|
||||
|
||||
// Two-argument form for path-name to avoid validating base-dir
|
||||
ensightGeoFile osGeom
|
||||
(
|
||||
@ -187,13 +204,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
|
||||
caseOpts_.format()
|
||||
);
|
||||
|
||||
// Ensight Geometry
|
||||
ensightOutputSurface part
|
||||
(
|
||||
surf.points(),
|
||||
surf.faces(),
|
||||
osGeom.name().name()
|
||||
);
|
||||
osGeom.beginGeometry();
|
||||
part.write(osGeom); // serial
|
||||
|
||||
// Write field (serial)
|
||||
@ -204,7 +215,12 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
|
||||
|
||||
// Update case file
|
||||
{
|
||||
OFstream osCase(outputFile, IOstreamOption::ASCII);
|
||||
OFstream osCase
|
||||
(
|
||||
IOstreamOption::ATOMIC,
|
||||
outputFile,
|
||||
IOstreamOption::ASCII
|
||||
);
|
||||
ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
|
||||
|
||||
osCase
|
||||
|
||||
Reference in New Issue
Block a user