Commit c7e8f22b authored by Mark Olesen's avatar Mark Olesen Committed by Andrew Heather
Browse files

ENH: improve ensightFile output support (#1579)

- indirect lists, lists of labels
- writeString() methods to avoid any ambiguities

- support handling of mixed element/node data in ensightCase
parent 4fea7b3b
......@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2018 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -26,15 +26,10 @@ License
\*---------------------------------------------------------------------------*/
#include "ensightCase.H"
#include "stringListOps.H"
#include "ensightGeoFile.H"
#include "Time.H"
#include "cloud.H"
#include "IOmanip.H"
#include "globalIndex.H"
#include "ensightFile.H"
#include "ensightGeoFile.H"
#include "demandDrivenData.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
......@@ -69,7 +64,7 @@ void Foam::ensightCase::initialize()
else
{
DetailInfo
<<"Warning: re-using existing directory" << nl
<< "Warning: re-using existing directory" << nl
<< " " << ensightDir_ << endl;
}
}
......@@ -78,7 +73,7 @@ void Foam::ensightCase::initialize()
mkDir(dataDir());
// The case file is always ASCII
os_ = new OFstream(ensightDir_/caseName_, IOstream::ASCII);
os_.reset(new OFstream(ensightDir_/caseName_, IOstream::ASCII));
// Format options
os_->setf(ios_base::left);
......@@ -126,7 +121,7 @@ Foam::label Foam::ensightCase::checkTimeset(const labelHashSet& lookup) const
void Foam::ensightCase::writeHeader() const
{
if (os_) // master only
if (os_) // True on master only
{
this->rewind();
*os_
......@@ -218,7 +213,7 @@ void Foam::ensightCase::writeTimeset
const scalar timeCorrection
) const
{
// make a copy
// Make a copy
labelHashSet hashed(lookup);
hashed.erase(-1);
......@@ -282,9 +277,10 @@ void Foam::ensightCase::noteGeometry(const bool moving) const
void Foam::ensightCase::noteCloud(const word& cloudName) const
{
// Force into existence
if (!cloudVars_.found(cloudName))
{
cloudVars_.insert(cloudName, HashTable<string>());
cloudVars_.emplace(cloudName);
}
cloudTimes_.insert(timeIndex_);
......@@ -388,9 +384,9 @@ Foam::ensightCase::ensightCase
)
:
options_(new options(opts)),
os_(nullptr),
ensightDir_(ensightDir),
caseName_(caseName + ".case"),
os_(nullptr),
changed_(false),
timeIndex_(0),
timeValue_(0),
......@@ -398,6 +394,7 @@ Foam::ensightCase::ensightCase
geomTimes_(),
cloudTimes_(),
variables_(),
nodeVariables_(),
cloudVars_()
{
initialize();
......@@ -412,9 +409,9 @@ Foam::ensightCase::ensightCase
)
:
options_(new options(format)),
os_(nullptr),
ensightDir_(ensightDir),
caseName_(caseName + ".case"),
os_(nullptr),
changed_(false),
timeIndex_(0),
timeValue_(0),
......@@ -422,21 +419,13 @@ Foam::ensightCase::ensightCase
geomTimes_(),
cloudTimes_(),
variables_(),
nodeVariables_(),
cloudVars_()
{
initialize();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::ensightCase::~ensightCase()
{
deleteDemandDrivenData(options_);
deleteDemandDrivenData(os_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::ensightCase::nextTime(const scalar value)
......@@ -580,7 +569,7 @@ void Foam::ensightCase::write() const
//
if (variables_.size() || cloudVars_.size())
{
// start of variables
// Start of variables
*os_
<< nl
<< "VARIABLE" << nl;
......@@ -598,7 +587,7 @@ void Foam::ensightCase::write() const
<< ensType.c_str()
<<
(
nodeValues()
(nodeVariables_.found(varName) || nodeValues())
? " per node: 1 " // time-set 1
: " per element: 1 " // time-set 1
)
......@@ -678,7 +667,7 @@ void Foam::ensightCase::write() const
Foam::autoPtr<Foam::ensightGeoFile>
Foam::ensightCase::newGeometry
(
const bool moving
bool moving
) const
{
autoPtr<Foam::ensightGeoFile> output;
......@@ -749,8 +738,12 @@ Foam::Ostream& Foam::ensightCase::printInfo(Ostream& os) const
os << "Ensight case:" << nl
<< " path: " << ensightDir_ << nl
<< " name: " << caseName_ << nl
<< " format: " << format() << nl
<< " values per " << (nodeValues() ? "node" : "element") << nl;
<< " format: " << format() << nl;
if (nodeValues())
{
os << " values per node" << nl;
}
return os;
}
......
......@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -32,6 +32,9 @@ Description
SourceFiles
ensightCase.C
ensightCaseI.H
ensightCaseOptions.C
ensightCaseTemplates.C
\*---------------------------------------------------------------------------*/
......@@ -42,17 +45,18 @@ SourceFiles
#include "HashSet.H"
#include "InfoProxy.H"
#include "Map.H"
#include "HashSet.H"
#include "OSspecific.H"
#include "Pstream.H"
#include "ensightGeoFile.H"
#include <memory>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declarations
// Forward Declarations
class ensightCase;
class instant;
class Time;
......@@ -65,7 +69,7 @@ class ensightCase
{
public:
// Forward declarations
// Forward Declarations
class options;
// Public Data
......@@ -76,12 +80,16 @@ public:
//- The name for geometry files
static const char* geometryName;
private:
// Private data
// Private Data
//- Case writing options
const options* options_;
const std::unique_ptr<options> options_;
//- Output stream (master only)
mutable std::unique_ptr<OFstream> os_;
//- Output path (absolute)
fileName ensightDir_;
......@@ -89,9 +97,6 @@ private:
//- Case name (with ".case" ending)
word caseName_;
//- Output stream (master only)
mutable OFstream* os_;
//- Track state changes since last write
mutable bool changed_;
......@@ -119,6 +124,9 @@ private:
//- Fields/Variables with the ensight type
mutable HashTable<string> variables_;
//- Remember fields that are to be treated as point data
mutable HashSet<string> nodeVariables_;
//- Cloud names and variables
mutable HashTable<HashTable<string>> cloudVars_;
......@@ -214,7 +222,7 @@ public:
//- Destructor
~ensightCase();
~ensightCase() = default;
// Member Functions
......@@ -236,7 +244,7 @@ public:
//- Consistent zero-padded integer value
inline word padded(const label i) const;
//- Use values per nodes instead of per element
//- Force use of values per node instead of per element
inline bool nodeValues() const;
//- Write clouds into their own directory instead in "data" directory
......@@ -269,8 +277,7 @@ public:
// Addition of entries to case file
//- Open stream for new geometry file (on master).
autoPtr<ensightGeoFile> newGeometry(const bool moving = false) const;
autoPtr<ensightGeoFile> newGeometry(bool moving = false) const;
//- Open stream for new cloud positions (on master).
// Note the use of ensightFile, not ensightGeoFile.
......@@ -279,11 +286,19 @@ public:
const word& cloudName
) const;
//- Open stream for new data file (on master), with current index.
// Optionally marking as containing POINT_DATA
template<class Type>
autoPtr<ensightFile> newData(const word& varName) const;
autoPtr<ensightFile> newData
(
const word& varName,
const bool isPointData = false
) const;
//- Open stream for new data file (on master), with current index
//- and marking as containing POINT_DATA
template<class Type>
autoPtr<ensightFile> newPointData(const word& varName) const;
//- Open stream for new cloud data file (on master), with current index.
template<class Type>
......@@ -313,28 +328,29 @@ public:
//- Configuration options for the ensightCase
class ensightCase::options
{
private:
// Private Data
//- Ascii/Binary file output
IOstream::streamFormat format_;
//- Ascii/Binary file output
IOstream::streamFormat format_;
//- Remove existing directory and sub-directories on creation
bool overwrite_;
//- Width of mask for subdirectories
label width_;
//- Force use of values per node instead of per element
bool nodeValues_;
//- The '*' mask appropriate for subdirectories
word mask_;
//- Write clouds into their own directory
bool separateCloud_;
//- The printf format for zero-padded subdirectory numbers
string printf_;
//- Width of mask for subdirectories
label width_;
//- Remove existing directory and sub-directories on creation
bool overwrite_;
//- The '*' mask appropriate for subdirectories
word mask_;
//- Write values at nodes
bool nodeValues_;
//- The printf format for zero-padded subdirectory numbers
string printf_;
//- Write clouds into their own directory
bool separateCloud_;
public:
......@@ -363,9 +379,6 @@ public:
//- Remove existing directory and sub-directories on creation
bool overwrite() const;
//- Use values per nodes instead of per element
bool nodeValues() const;
//- Write clouds into their own directory instead in "data" directory
bool separateCloud() const;
......@@ -379,12 +392,20 @@ public:
//- Remove existing directory and sub-directories on creation
void overwrite(bool);
//- Use values per nodes instead of per element
void nodeValues(bool);
//- Write clouds into their own directory instead in "data" directory
void separateCloud(bool);
// Housekeeping
//- Force use of values per node instead of per element
bool nodeValues() const;
//- Force use of values per node instead of per element
// Deprecated(2020-02) - The newData() method with a second parameter
// is more flexible.
// \deprecated(2020-02) - newData() with second parameter
void nodeValues(bool);
};
......
......@@ -32,14 +32,14 @@ License
Foam::ensightCase::options::options(IOstream::streamFormat format)
:
format_(format),
width_(0),
mask_(),
printf_(),
overwrite_(false),
nodeValues_(false),
separateCloud_(false)
separateCloud_(false),
width_(0),
mask_(),
printf_()
{
width(8); // Ensures that mask and printf-format are properly resized
width(8); // Fill mask and setup printf-format
}
......
......@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -34,7 +34,8 @@ template<class Type>
Foam::autoPtr<Foam::ensightFile>
Foam::ensightCase::newData
(
const word& name
const word& name,
const bool isPointData
) const
{
autoPtr<ensightFile> output;
......@@ -42,9 +43,10 @@ Foam::ensightCase::newData
if (Pstream::master())
{
const ensight::VarName varName(name);
output = createDataFile(varName);
// description
// Description
output().write
(
string
......@@ -55,14 +57,31 @@ Foam::ensightCase::newData
);
output().newline();
// note field variable for later use
// Remember the field variable for later use
noteVariable(varName, ensightPTraits<Type>::typeName);
// Could warn about existing variables that changed representation
if (isPointData)
{
nodeVariables_.set(varName);
}
}
return output;
}
template<class Type>
Foam::autoPtr<Foam::ensightFile>
Foam::ensightCase::newPointData
(
const word& name
) const
{
return newData<Type>(name, true); // POINT_DATA
}
template<class Type>
Foam::autoPtr<Foam::ensightFile>
Foam::ensightCase::newCloudData
......@@ -78,7 +97,7 @@ Foam::ensightCase::newCloudData
const ensight::VarName varName(name);
output = createCloudFile(cloudName, varName);
// description
// Description
output().write
(
string
......@@ -89,7 +108,7 @@ Foam::ensightCase::newCloudData
);
output().newline();
// note cloud variable for later use
// Remember the cloud variable for later use
noteCloud(cloudName, varName, ensightPTraits<Type>::typeName);
}
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -29,7 +29,6 @@ License
#include "ensightFile.H"
#include "error.H"
#include "UList.H"
#include <cstring>
#include <sstream>
......@@ -39,10 +38,12 @@ bool Foam::ensightFile::allowUndef_ = false;
Foam::scalar Foam::ensightFile::undefValue_ = Foam::floatScalarVGREAT;
// default is width 8
// Default is width 8
Foam::string Foam::ensightFile::mask_ = "********";
Foam::string Foam::ensightFile::dirFmt_ = "%08d";
const char* const Foam::ensightFile::coordinates = "coordinates";
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
......@@ -85,6 +86,20 @@ Foam::label Foam::ensightFile::subDirWidth()
}
bool Foam::ensightFile::isUndef(const UList<scalar>& field)
{
for (const scalar& val : field)
{
if (std::isnan(val))
{
return true;
}
}
return true;
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::ensightFile::initialize()
......@@ -153,24 +168,13 @@ Foam::scalar Foam::ensightFile::undefValue(const scalar value)
}
Foam::Ostream& Foam::ensightFile::write
(
const char* buf,
std::streamsize count
)
{
stdStream().write(buf, count);
return *this;
}
Foam::Ostream& Foam::ensightFile::write(const char* value)
Foam::Ostream& Foam::ensightFile::writeString(const char* str)
{
// Output 80 chars, but allocate for trailing nul character
// to avoid -Wstringop-truncation warnings/errors.
char buf[80+1];
strncpy(buf, value, 80); // max 80 chars or padded with nul if smaller
strncpy(buf, str, 80); // max 80 chars or padded with nul if smaller
if (format() == IOstream::BINARY)
{
......@@ -186,9 +190,38 @@ Foam::Ostream& Foam::ensightFile::write(const char* value)
}
Foam::Ostream& Foam::ensightFile::write(const string& value)
Foam::Ostream& Foam::ensightFile::writeString(const std::string& str)
{
return writeString(str.c_str());
}
Foam::Ostream& Foam::ensightFile::write(const char* str)
{
return write(value.c_str());
return writeString(str);
}
Foam::Ostream& Foam::ensightFile::write(const word& str)
{
return writeString(str);
}
Foam::Ostream& Foam::ensightFile::write(const string& str)
{
return writeString(str);
}
Foam::Ostream& Foam::ensightFile::write
(
const char* buf,
std::streamsize count
)
{
stdStream().write(buf, count);
return *this;
}
......@@ -244,6 +277,14 @@ Foam::Ostream& Foam::ensightFile::write(const scalar value)
{
float fvalue(value);
// TBD: limit range?
// #if defined(WM_DP)
// if (mag(value) < scalar(floatScalarVSMALL))
// {
// fvalue = 0;
// }
// #endif
if (format() == IOstream::BINARY)
{
write
......@@ -282,17 +323,17 @@ Foam::Ostream& Foam::ensightFile::writeKeyword(const keyType& key)
{
if (allowUndef_)
{
write(string(static_cast<const string&>(key) + " undef"));
writeString(key + " undef");
newline();
write(undefValue_);
newline();
}
else
{
// ensure we get ensightFile::write(const string&)
write(static_cast<const string&>(key));
writeString(key);
newline();
}
return *this;
}
......@@ -301,7 +342,7 @@ Foam::Ostream& Foam::ensightFile::writeBinaryHeader()
{
if (format() == IOstream::BINARY)
{
write("C Binary");
writeString("C Binary");
}
return *this;