From e1240ece7bc74ea73f16d4afe5ce4c409acfa503 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@Germany> Date: Wed, 5 Oct 2016 12:59:24 +0200 Subject: [PATCH] ENH: add ensightCase management to fileFormats - part of generalizing the ensight infrastructure (issue #241) - General bookkeeping when creating ensight files. --- src/fileFormats/Make/files | 2 + src/fileFormats/ensight/file/ensightCase.C | 739 ++++++++++++++++++ src/fileFormats/ensight/file/ensightCase.H | 405 ++++++++++ src/fileFormats/ensight/file/ensightCaseI.H | 78 ++ .../ensight/file/ensightCaseOptions.C | 129 +++ .../ensight/file/ensightCaseTemplates.C | 99 +++ 6 files changed, 1452 insertions(+) create mode 100644 src/fileFormats/ensight/file/ensightCase.C create mode 100644 src/fileFormats/ensight/file/ensightCase.H create mode 100644 src/fileFormats/ensight/file/ensightCaseI.H create mode 100644 src/fileFormats/ensight/file/ensightCaseOptions.C create mode 100644 src/fileFormats/ensight/file/ensightCaseTemplates.C diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files index 91c6affaf2e..c972fde32e7 100644 --- a/src/fileFormats/Make/files +++ b/src/fileFormats/Make/files @@ -1,3 +1,5 @@ +ensight/file/ensightCase.C +ensight/file/ensightCaseOptions.C ensight/file/ensightFile.C ensight/file/ensightGeoFile.C ensight/part/ensightCells.C diff --git a/src/fileFormats/ensight/file/ensightCase.C b/src/fileFormats/ensight/file/ensightCase.C new file mode 100644 index 00000000000..0ac968e7993 --- /dev/null +++ b/src/fileFormats/ensight/file/ensightCase.C @@ -0,0 +1,739 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +\*---------------------------------------------------------------------------*/ + +#include "ensightCase.H" +#include "stringListOps.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 * * * * * * * * * * * * * // + +const char* Foam::ensightCase::dataDirName = "data"; +const char* Foam::ensightCase::geometryName = "geometry"; + + +// * * * * * * * * * * * * * Private Functions * * * * * * * * * * * * * * // + +Foam::fileName Foam::ensightCase::dataDir() const +{ + return ensightDir_/dataDirName; +} + + +void Foam::ensightCase::initialize() +{ + if (Pstream::master()) + { + // EnSight and EnSight/data directories must exist + + // We may wish to retain old data + // eg, convert new results or a particular time interva + // OR remove everything + + if (options_->overwrite()) + { + rmDir(ensightDir_); + } + else if (isDir(ensightDir_)) + { + Info<<"Warning: re-using existing directory" << nl + << " " << ensightDir_ << endl; + } + + // Create ensight and data directories + mkDir(dataDir()); + + // The case file is always ASCII + os_ = new OFstream(ensightDir_/caseName_, IOstream::ASCII); + + // Format options + os_->setf(ios_base::left); + os_->setf(ios_base::scientific, ios_base::floatfield); + os_->precision(5); + + writeHeader(); + } +} + + +Foam::label Foam::ensightCase::checkTimeset(const labelHashSet& lookup) const +{ + // assume the worst + label ts = -1; + + // work on a copy + labelHashSet tsTimes(lookup); + tsTimes.erase(-1); + + if (tsTimes.empty()) + { + // no times needed + ts = 0; + } + else if (tsTimes.size() == timesUsed_.size()) + { + forAllConstIter(Map<scalar>, timesUsed_, iter) + { + tsTimes.erase(iter.key()); + } + + // OR + // tsTimes -= timesUsed_.toc(); + // tsTimes -= timesUsed_; + + if (tsTimes.empty()) + { + ts = 1; // can use timeset 1 + } + } + + return ts; +} + + +void Foam::ensightCase::writeHeader() const +{ + if (os_) // master only + { + this->rewind(); + *os_ + << "FORMAT" << nl + << "type: ensight gold" << nl; + } +} + + +Foam::scalar Foam::ensightCase::writeTimeset() const +{ + const label ts = 1; + + const labelList indices = timesUsed_.sortedToc(); + label count = indices.size(); + + // correct for negative starting values + scalar timeCorrection = timesUsed_[indices[0]]; + if (timeCorrection < 0) + { + timeCorrection = -timeCorrection; + Info<< "Correcting time values. Adding " << timeCorrection << endl; + } + else + { + timeCorrection = 0; + } + + + *os_ + << "time set: " << ts << nl + << "number of steps: " << count << nl; + + if (indices[0] == 0 && indices[count-1] == count-1) + { + // looks to be contiguous numbering + *os_ + << "filename start number: " << 0 << nl + << "filename increment: " << 1 << nl; + } + else + { + *os_ + << "filename numbers:" << nl; + + count = 0; + forAll(indices, idx) + { + *os_ << " " << setw(12) << indices[idx]; + + if (++count % 6 == 0) + { + *os_ << nl; + } + } + + if (count) + { + *os_ << nl; + } + } + + + *os_ << "time values:" << nl; + + count = 0; + forAll(indices, idx) + { + *os_ << " " << setw(12) << timesUsed_[indices[idx]] + timeCorrection; + + if (++count % 6 == 0) + { + *os_ << nl; + } + } + if (count) + { + *os_ << nl; + } + + return timeCorrection; +} + + +void Foam::ensightCase::writeTimeset +( + const label ts, + const labelHashSet& lookup, + const scalar timeCorrection +) const +{ + // make a copy + labelHashSet hashed(lookup); + hashed.erase(-1); + + const labelList indices = hashed.sortedToc(); + label count = indices.size(); + + *os_ + << "time set: " << ts << nl + << "number of steps: " << count << nl + << "filename numbers:" << nl; + + count = 0; + forAll(indices, idx) + { + *os_ << " " << setw(12) << indices[idx]; + + if (++count % 6 == 0) + { + *os_ << nl; + } + } + + if (count) + { + *os_ << nl; + } + + *os_ << "time values:" << nl; + + count = 0; + forAll(indices, idx) + { + *os_ << " " << setw(12) << timesUsed_[indices[idx]] + timeCorrection; + + if (++count % 6 == 0) + { + *os_ << nl; + } + } + if (count) + { + *os_ << nl; + } +} + + +void Foam::ensightCase::noteGeometry(const bool moving) const +{ + if (moving) + { + geomTimes_.insert(timeIndex_); + } + else + { + geomTimes_.insert(-1); + } + + changed_ = true; +} + + +void Foam::ensightCase::noteCloud(const word& cloudName) const +{ + if (!cloudVars_.found(cloudName)) + { + cloudVars_.insert(cloudName, HashTable<string>()); + } + cloudTimes_.insert(timeIndex_); + + changed_ = true; +} + + +void Foam::ensightCase::noteCloud +( + const word& cloudName, + const word& varName, + const char* ensightType +) const +{ + if (cloudVars_.found(cloudName)) + { + if (cloudVars_[cloudName].insert(varName, ensightType)) + { + changed_ = true; + } + } + else + { + FatalErrorInFunction + << "Tried to add a cloud variable for writing without having added a cloud" + << abort(FatalError); + } +} + + +void Foam::ensightCase::noteVariable +( + const word& varName, + const char* ensightType +) const +{ + if (variables_.insert(varName, ensightType)) + { + changed_ = true; + } +} + + +Foam::autoPtr<Foam::ensightFile> +Foam::ensightCase::createDataFile +( + const word& name +) const +{ + autoPtr<ensightFile> output; + + if (Pstream::master()) + { + // the data/ITER subdirectory must exist + // Note that data/ITER is indeed a valid ensight::FileName + const fileName outdir = dataDir()/padded(timeIndex_); + mkDir(outdir); + + output.reset(new ensightFile(outdir, name, format())); + } + + return output; +} + + +Foam::autoPtr<Foam::ensightFile> +Foam::ensightCase::createCloudFile +( + const word& cloudName, + const word& name +) const +{ + autoPtr<Foam::ensightFile> output; + + if (Pstream::master()) + { + // Write + // eg -> "data/********/lagrangian/<cloudName>/positions" + // or -> "lagrangian/<cloudName>/********/positions" + // TODO? check that cloudName is a valid ensight filename + const fileName outdir = + ( + separateCloud() + ? (ensightDir_ / cloud::prefix / cloudName / padded(timeIndex_)) + : (dataDir() / padded(timeIndex_) / cloud::prefix / cloudName) + ); + + mkDir(outdir); // should be unnecessary after newCloud() + + output.reset(new ensightFile(outdir, name, format())); + } + + return output; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::ensightCase::ensightCase +( + const fileName& ensightDir, + const word& caseName, + const ensightCase::options& opts +) +: + options_(new options(opts)), + ensightDir_(ensightDir), + caseName_(caseName + ".case"), + os_(nullptr), + changed_(false), + timeIndex_(0), + timeValue_(0), + timesUsed_(), + geomTimes_(), + cloudTimes_(), + variables_(), + cloudVars_() +{ + initialize(); +} + + +Foam::ensightCase::ensightCase +( + const fileName& ensightDir, + const word& caseName, + const IOstream::streamFormat format +) +: + options_(new options(format)), + ensightDir_(ensightDir), + caseName_(caseName + ".case"), + os_(nullptr), + changed_(false), + timeIndex_(0), + timeValue_(0), + timesUsed_(), + geomTimes_(), + cloudTimes_(), + variables_(), + cloudVars_() +{ + initialize(); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::ensightCase::~ensightCase() +{ + deleteDemandDrivenData(options_); + deleteDemandDrivenData(os_); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::ensightCase::nextTime(const scalar value) +{ + // use next available index + setTime(value, timesUsed_.size()); +} + + +void Foam::ensightCase::nextTime(const instant& t) +{ + nextTime(t.value()); +} + + +void Foam::ensightCase::setTime(const scalar value, const label index) +{ + timeIndex_ = index; + timeValue_ = value; + + if (Pstream::master()) + { + // The data/ITER subdirectory must exist + // Note that data/ITER is indeed a valid ensight::FileName + + const fileName outdir = dataDir()/padded(timeIndex_); + mkDir(outdir); + + // place a timestamp in the directory for future reference + OFstream timeStamp(outdir/"time"); + timeStamp + << "# index time" << nl + << outdir.name() << ' ' << timeValue_ << nl; + } + + // Record of time index/value used + timesUsed_.set(index, value); +} + + +void Foam::ensightCase::setTime(const instant& t, const label index) +{ + setTime(t.value(), index); +} + + +void Foam::ensightCase::write() const +{ + if (!os_) return; // master only + + // geometry timeset + bool staticGeom = (geomTimes_.size() == 1 && geomTimes_.found(-1)); + label tsGeom = staticGeom ? 0 : checkTimeset(geomTimes_); + + // cloud timeset + label tsCloud = checkTimeset(cloudTimes_); + + // increment time-sets to the correct indices + if (tsGeom < 0) + { + tsGeom = 2; // next available timeset + } + if (tsCloud < 0) + { + tsCloud = tsGeom + 1; // next available timeset + } + + writeHeader(); + + + // data mask: eg "data/******" + const fileName dataMask = (dataDirName/mask()); + + // + // GEOMETRY + // + if (!geomTimes_.empty() || !cloudTimes_.empty()) + { + // start of variables + *os_ + << nl + << "GEOMETRY" << nl; + } + + if (staticGeom) + { + // steady + *os_ + << setw(16) << "model:" + << geometryName + << nl; + } + else if (!geomTimes_.empty()) + { + // moving + *os_ + << Foam::name("model: %-9d", tsGeom) // width 16 + << (dataMask/geometryName).c_str() + << nl; + } + + // clouds and cloud variables + const wordList cloudNames = cloudVars_.sortedToc(); + forAll(cloudNames, cloudNo) + { + const word& cloudName = cloudNames[cloudNo]; + + const fileName masked = + ( + separateCloud() + ? (cloud::prefix / cloudName / mask()) + : (dataMask / cloud::prefix / cloudName) + ); + + *os_ + << Foam::name("measured: %-6d", tsCloud) // width 16 + << (masked/"positions").c_str() + << nl; + } + + + // + // VARIABLE + // + if (variables_.size() || cloudVars_.size()) + { + // start of variables + *os_ + << nl + << "VARIABLE" << nl; + } + + + // field variables (always use timeset 1) + const wordList varNames = variables_.sortedToc(); + forAll(varNames, vari) + { + const word& varName = varNames[vari]; + const string& ensType = variables_[varName]; + + *os_ + << ensType.c_str() + << + ( + nodeValues() + ? " per node: 1 " // time-set 1 + : " per element: 1 " // time-set 1 + ) + << setw(15) << varName << ' ' + << (dataMask/varName).c_str() << nl; + } + + + // clouds and cloud variables (using cloud timeset) + // Write + // as -> "data/********/lagrangian/<cloudName>/positions" + // or -> "lagrangian/<cloudName>/********/positions" + forAll(cloudNames, cloudNo) + { + const word& cloudName = cloudNames[cloudNo]; + const fileName masked = + ( + separateCloud() + ? (cloud::prefix / cloudName / mask()) + : (dataMask / cloud::prefix / cloudName) + ); + + const HashTable<string>& vars = cloudVars_[cloudName]; + const wordList tocVars = vars.sortedToc(); + + forAll(tocVars, vari) + { + const word& varName = tocVars[vari]; + const string& ensType = vars[varName]; + + // prefix variables with 'c' (cloud) and cloud index + *os_ + << ensType.c_str() << " per " + << Foam::name("measured node: %-5d", tsCloud) // width 20 + << setw(15) + << ("c" + Foam::name(cloudNo) + varName).c_str() << ' ' + << (masked/varName).c_str() + << nl; + } + } + + + // + // TIME + // + + if (!timesUsed_.empty()) + { + *os_ + << nl << "TIME" << nl; + + // timeset 1 + const scalar timeCorrection = writeTimeset(); + + // timeset geometry + if (tsGeom > 1) + { + writeTimeset(tsGeom, geomTimes_, timeCorrection); + } + + // timeset cloud + if (tsCloud > 1) + { + writeTimeset(tsCloud, cloudTimes_, timeCorrection); + } + + *os_ + << "# end" << nl; + } + + *os_ << flush; + changed_ = false; +} + + +Foam::autoPtr<Foam::ensightGeoFile> +Foam::ensightCase::newGeometry +( + const bool moving +) const +{ + autoPtr<Foam::ensightGeoFile> output; + + if (Pstream::master()) + { + // set the path of the ensight file + fileName path; + + if (moving) + { + // Moving mesh: write as "data/********/geometry" + path = dataDir()/padded(timeIndex_); + mkDir(path); + } + else + { + // Static mesh: write as "geometry" + path = ensightDir_; + } + + output.reset(new ensightGeoFile(path, geometryName, format())); + + noteGeometry(moving); // note for later use + } + + return output; +} + + +Foam::autoPtr<Foam::ensightFile> +Foam::ensightCase::newCloud +( + const word& cloudName +) const +{ + autoPtr<Foam::ensightFile> output; + + if (Pstream::master()) + { + output = createCloudFile(cloudName, "positions"); + + // tag binary format (just like geometry files) + output().writeBinaryHeader(); + + // description + output().write(cloud::prefix/cloudName); + output().newline(); + + noteCloud(cloudName); // note for later use + } + + return output; +} + + +void Foam::ensightCase::rewind() const +{ + if (os_) // master only + { + os_->stdStream().seekp(0, std::ios_base::beg); + } +} + + +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; + + return os; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/file/ensightCase.H b/src/fileFormats/ensight/file/ensightCase.H new file mode 100644 index 00000000000..e6603d9a104 --- /dev/null +++ b/src/fileFormats/ensight/file/ensightCase.H @@ -0,0 +1,405 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +Class + Foam::ensightCase + +Description + Supports writing of ensight cases as well as providing common factory + methods to open new files. + +SourceFiles + ensightCase.C + +\*---------------------------------------------------------------------------*/ + +#ifndef ensightCase_H +#define ensightCase_H + +#include "autoPtr.H" +#include "HashSet.H" +#include "InfoProxy.H" +#include "Map.H" +#include "OSspecific.H" +#include "Pstream.H" + +#include "ensightGeoFile.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declarations +class ensightCase; +class instant; +class Time; + +/*---------------------------------------------------------------------------*\ + Class ensightCase Declaration +\*---------------------------------------------------------------------------*/ + +class ensightCase +{ +public: + + // Forward declarations + class options; + + // Public Data + + //- The name for "data" subdirectory + static const char* dataDirName; + + //- The name for geometry files + static const char* geometryName; + +private: + + // Private data + + //- Case writing options + const options* options_; + + //- Output path (absolute) + fileName ensightDir_; + + //- Case name (with ".case" ending) + word caseName_; + + //- Output stream + mutable OFstream* os_; + + //- Track state changes since last write + mutable bool changed_; + + //- Time index (timeset 1) + label timeIndex_; + + //- Time value (timeset 1) + scalar timeValue_; + + //- Record of time index/value used (eg, field values). + // These values will be used for timeset 1. + Map<scalar> timesUsed_; + + //- Record time indices when geometry is written. + // These values will be used to decide if timeset 1 + // or a separate timeset are used. + // The special index '-1' is used static geometry. + mutable labelHashSet geomTimes_; + + //- Record time indices when clouds are written. + // These values will be used to decide if timeset 1 + // or a separate timeset are used. + mutable labelHashSet cloudTimes_; + + //- Fields/Variables with the ensight type + mutable HashTable<string> variables_; + + //- Cloud names and variables + mutable HashTable<HashTable<string>> cloudVars_; + + + // Private Member Functions + + //- The data directory + fileName dataDir() const; + + //- Initial file management (master only) + void initialize(); + + //- Check if timeset uses different times than from time-set 1 + label checkTimeset(const labelHashSet& lookup) const; + + //- Write the header into the case file. + void writeHeader() const; + + //- Write the timeset 1 into the case file. + // Return the time correction in effect + scalar writeTimeset() const; + + //- Write the timeset into the case file. + void writeTimeset + ( + const label ts, + const labelHashSet& lookup, + const scalar timeCorrection = 0 + ) const; + + + //- Note geometry being used + void noteGeometry(const bool moving) const; + + //- Note cloud being used + void noteCloud(const word& cloudName) const; + + //- Note cloud/variable being used + void noteCloud + ( + const word& cloudName, + const word& varName, + const char* ensightType + ) const; + + //- Note field variable being used + void noteVariable + ( + const word& varName, + const char* ensightType + ) const; + + + //- Open stream for new data file (on master), using the current index. + // File is without initial description lines. + autoPtr<ensightFile> createDataFile(const word&) const; + + //- Open stream for new cloud file (on master). + // File is without initial description lines. + autoPtr<ensightFile> createCloudFile + ( + const word& cloudName, + const word& name + ) const; + + + //- Disallow default bitwise copy construct + ensightCase(const ensightCase&) = delete; + + //- Disallow default bitwise assignment + void operator=(const ensightCase&) = delete; + + +public: + + + // Constructors + + //- Construct from components + ensightCase + ( + const fileName& ensightDir, + const word& caseName, + const options& opts + ); + + //- Construct from components with all default options + ensightCase + ( + const fileName& ensightDir, + const word& caseName, + const IOstream::streamFormat format = IOstream::BINARY + ); + + + + //- Destructor + ~ensightCase(); + + + // Member Functions + + // Access + + //- Reference to the case options + inline const ensightCase::options& option() const; + + //- Ascii/Binary file output + inline IOstream::streamFormat format() const; + + //- The nominal path to the case file + inline const fileName& path() const; + + //- The output '*' mask + inline const word& mask() const; + + //- Consistent zero-padded integer value + inline word padded(const label i) const; + + //- Use values per nodes instead of per element + inline bool nodeValues() const; + + //- Write clouds into their own directory instead in "data" directory + inline bool separateCloud() const; + + + // Edit + + //- Set time for time-set 1, using next available index. + // Create corresponding sub-directory. + // Do not mix between nextTime and setTime in an application. + void nextTime(const scalar t); + + //- Set time for time-set 1, using next available index. + // Create corresponding sub-directory. + // Do not mix between nextTime and setTime in an application. + void nextTime(const instant& t); + + //- Set current index and time for time-set 1. + // Create corresponding sub-directory + // Do not mix between nextTime and setTime in an application. + void setTime(const scalar t, const label index); + + //- Set current index and time for time-set 1. + // Create corresponding sub-directory + // Do not mix between nextTime and setTime in an application. + void setTime(const instant& t, const label index); + + + // Addition of entries to case file + + //- Open stream for new geometry file (on master). + autoPtr<ensightGeoFile> newGeometry(const bool moving = false) const; + + + //- Open stream for new cloud positions (on master). + // Note the use of ensightFile, not ensightGeoFile. + autoPtr<ensightFile> newCloud + ( + const word& cloudName + ) const; + + + //- Open stream for new data file (on master), using the current index. + template<class Type> + autoPtr<ensightFile> newData(const word& varName) const; + + + //- Open stream for new cloud data file (on master), using the current index. + template<class Type> + autoPtr<ensightFile> newCloudData + ( + const word& cloudName, + const word& varName + ) const; + + + // Output + + //- Rewind the output stream (master only). + void rewind() const; + + //- Write the case file + void write() const; + + //- Output stream (master only). + inline Ostream& operator()() const; + + //- Print some general information. + Ostream& printInfo(Ostream&) const; +}; + + +//- Configuration options for the ensightCase +class ensightCase::options +{ +private: + + //- Ascii/Binary file output + IOstream::streamFormat format_; + + //- Width of mask for subdirectories + label width_; + + //- The '*' mask appropriate for subdirectories + word mask_; + + //- The printf format for zero-padded subdirectory numbers + string printf_; + + //- Remove existing directory and sub-directories on creation + bool overwrite_; + + //- Write values at nodes + bool nodeValues_; + + //- Write clouds into their own directory + bool separateCloud_; + +public: + + // Constructors + + //- Construct with the specified format (default is binary) + options(IOstream::streamFormat format = IOstream::BINARY); + + + // Member Functions + + // Access + + //- Ascii/Binary file output + IOstream::streamFormat format() const; + + //- The '*' mask appropriate for sub-directories + const word& mask() const; + + //- Consistent zero-padded integer value + word padded(const label i) const; + + //- Return current width of mask and padded. + label width() const; + + //- 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; + + + // Edit + + //- Set width of mask and padded. + // Default width is 8 digits, max width is 31 digits. + void width(const label i); + + //- 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); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "ensightCaseI.H" + +#ifdef NoRepository + #include "ensightCaseTemplates.C" +#endif + +#endif + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/file/ensightCaseI.H b/src/fileFormats/ensight/file/ensightCaseI.H new file mode 100644 index 00000000000..b386f677b5b --- /dev/null +++ b/src/fileFormats/ensight/file/ensightCaseI.H @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +inline const Foam::ensightCase::options& Foam::ensightCase::option() const +{ + return *options_; +} + + +inline Foam::IOstream::streamFormat Foam::ensightCase::format() const +{ + return options_->format(); +} + + +inline const Foam::fileName& Foam::ensightCase::path() const +{ + return ensightDir_; +} + + +inline const Foam::word& Foam::ensightCase::mask() const +{ + return options_->mask(); +} + + +inline Foam::word Foam::ensightCase::padded(const label i) const +{ + return options_->padded(i); +} + + +inline bool Foam::ensightCase::nodeValues() const +{ + return options_->nodeValues(); +} + + +inline bool Foam::ensightCase::separateCloud() const +{ + return options_->separateCloud(); +} + + +// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // + +inline Foam::Ostream& Foam::ensightCase::operator()() const +{ + return *os_; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/file/ensightCaseOptions.C b/src/fileFormats/ensight/file/ensightCaseOptions.C new file mode 100644 index 00000000000..7977334466c --- /dev/null +++ b/src/fileFormats/ensight/file/ensightCaseOptions.C @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +\*---------------------------------------------------------------------------*/ + +#include "ensightCase.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::ensightCase::options::options(IOstream::streamFormat format) +: + format_(format), + width_(0), + mask_(), + printf_(), + overwrite_(false), + nodeValues_(false), + separateCloud_(false) +{ + width(8); // ensures that the mask and printf-format are also resized +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::IOstream::streamFormat Foam::ensightCase::options::format() const +{ + return format_; +} + +const Foam::word& Foam::ensightCase::options::mask() const +{ + return mask_; +} + + +Foam::word Foam::ensightCase::options::padded(const label i) const +{ + // As per Foam::name, but with fixed length + char buf[32]; + + ::snprintf(buf, 32, printf_.c_str(), i); + buf[31] = 0; + + // no stripping required + return word(buf, false); +} + + +Foam::label Foam::ensightCase::options::width() const +{ + return width_; +} + + +void Foam::ensightCase::options::width(const label n) +{ + // enforce min/max sanity limits + if (n < 1 || n > 31) + { + return; + } + + // set mask accordingly + mask_.resize(n, '*'); + + // appropriate printf format + printf_ = "%0" + Foam::name(n) + "d"; +} + + + +bool Foam::ensightCase::options::overwrite() const +{ + return overwrite_; +} + + +void Foam::ensightCase::options::overwrite(bool b) +{ + overwrite_ = b; +} + + +bool Foam::ensightCase::options::nodeValues() const +{ + return nodeValues_; +} + + +void Foam::ensightCase::options::nodeValues(bool b) +{ + nodeValues_ = b; +} + + +bool Foam::ensightCase::options::separateCloud() const +{ + return separateCloud_; +} + + +void Foam::ensightCase::options::separateCloud(bool b) +{ + separateCloud_ = b; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/file/ensightCaseTemplates.C b/src/fileFormats/ensight/file/ensightCaseTemplates.C new file mode 100644 index 00000000000..48d7c03ec37 --- /dev/null +++ b/src/fileFormats/ensight/file/ensightCaseTemplates.C @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +\*---------------------------------------------------------------------------*/ + +#include "cloud.H" +#include "ensightPTraits.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +template<class Type> +Foam::autoPtr<Foam::ensightFile> +Foam::ensightCase::newData +( + const word& name +) const +{ + autoPtr<ensightFile> output; + + if (Pstream::master()) + { + const ensight::VarName varName(name); + output = createDataFile(varName); + + // description + output().write + ( + string + ( + padded(timeIndex_) / varName + + " <" + pTraits<Type>::typeName + ">" + ) + ); + output().newline(); + + // note variable for later use + noteVariable(varName, ensightPTraits<Type>::typeName); + } + + return output; +} + + +template<class Type> +Foam::autoPtr<Foam::ensightFile> +Foam::ensightCase::newCloudData +( + const word& cloudName, + const word& name +) const +{ + autoPtr<Foam::ensightFile> output; + + if (Pstream::master()) + { + const ensight::VarName varName(name); + output = createCloudFile(cloudName, varName); + + // description + output().write + ( + string + ( + padded(timeIndex_) / cloudName / varName + + " <" + pTraits<Type>::typeName + ">" + ) + ); + output().newline(); + + // note cloud variable for later use + noteCloud(cloudName, varName, ensightPTraits<Type>::typeName); + } + + return output; +} + + +// ************************************************************************* // -- GitLab