diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files
index 91c6affaf2..c972fde32e 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 0000000000..0ac968e799
--- /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 .
+
+\*---------------------------------------------------------------------------*/
+
+#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, 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());
+ }
+ 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::ensightCase::createDataFile
+(
+ const word& name
+) const
+{
+ autoPtr 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::ensightCase::createCloudFile
+(
+ const word& cloudName,
+ const word& name
+) const
+{
+ autoPtr output;
+
+ if (Pstream::master())
+ {
+ // Write
+ // eg -> "data/********/lagrangian//positions"
+ // or -> "lagrangian//********/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//positions"
+ // or -> "lagrangian//********/positions"
+ forAll(cloudNames, cloudNo)
+ {
+ const word& cloudName = cloudNames[cloudNo];
+ const fileName masked =
+ (
+ separateCloud()
+ ? (cloud::prefix / cloudName / mask())
+ : (dataMask / cloud::prefix / cloudName)
+ );
+
+ const HashTable& 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::ensightCase::newGeometry
+(
+ const bool moving
+) const
+{
+ autoPtr 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::ensightCase::newCloud
+(
+ const word& cloudName
+) const
+{
+ autoPtr 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 0000000000..e6603d9a10
--- /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 .
+
+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 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 variables_;
+
+ //- Cloud names and variables
+ mutable HashTable> 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 createDataFile(const word&) const;
+
+ //- Open stream for new cloud file (on master).
+ // File is without initial description lines.
+ autoPtr 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 newGeometry(const bool moving = false) const;
+
+
+ //- Open stream for new cloud positions (on master).
+ // Note the use of ensightFile, not ensightGeoFile.
+ autoPtr newCloud
+ (
+ const word& cloudName
+ ) const;
+
+
+ //- Open stream for new data file (on master), using the current index.
+ template
+ autoPtr newData(const word& varName) const;
+
+
+ //- Open stream for new cloud data file (on master), using the current index.
+ template
+ autoPtr 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 0000000000..b386f677b5
--- /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 .
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+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 0000000000..7977334466
--- /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 .
+
+\*---------------------------------------------------------------------------*/
+
+#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 0000000000..48d7c03ec3
--- /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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "cloud.H"
+#include "ensightPTraits.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+template
+Foam::autoPtr
+Foam::ensightCase::newData
+(
+ const word& name
+) const
+{
+ autoPtr output;
+
+ if (Pstream::master())
+ {
+ const ensight::VarName varName(name);
+ output = createDataFile(varName);
+
+ // description
+ output().write
+ (
+ string
+ (
+ padded(timeIndex_) / varName
+ + " <" + pTraits::typeName + ">"
+ )
+ );
+ output().newline();
+
+ // note variable for later use
+ noteVariable(varName, ensightPTraits::typeName);
+ }
+
+ return output;
+}
+
+
+template
+Foam::autoPtr
+Foam::ensightCase::newCloudData
+(
+ const word& cloudName,
+ const word& name
+) const
+{
+ autoPtr output;
+
+ if (Pstream::master())
+ {
+ const ensight::VarName varName(name);
+ output = createCloudFile(cloudName, varName);
+
+ // description
+ output().write
+ (
+ string
+ (
+ padded(timeIndex_) / cloudName / varName
+ + " <" + pTraits::typeName + ">"
+ )
+ );
+ output().newline();
+
+ // note cloud variable for later use
+ noteCloud(cloudName, varName, ensightPTraits::typeName);
+ }
+
+ return output;
+}
+
+
+// ************************************************************************* //