/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-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 .
Class
Foam::ensightCase
Description
Supports writing of ensight cases as well as providing common factory
methods to open new files.
SourceFiles
ensightCase.C
ensightCaseI.H
ensightCaseOptions.C
ensightCaseTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_ensightCase_H
#define Foam_ensightCase_H
#include "autoPtr.H"
#include "InfoProxy.H"
#include "HashSet.H"
#include "Map.H"
#include "Pstream.H"
#include "ensightGeoFile.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class bitSet;
class dictionary;
class ensightCase;
class instant;
class OSstream;
class Time;
/*---------------------------------------------------------------------------*\
Class ensightCase Declaration
\*---------------------------------------------------------------------------*/
class ensightCase
{
public:
// Forward Declarations
class options;
// Public Data
//- The name for data subdirectory: "data"
static const char* dataDirName;
//- The name for geometry files: "geometry"
static const char* geometryName;
private:
// Private Data
//- Case writing options
const std::unique_ptr options_;
//- Output stream (master only)
mutable std::unique_ptr os_;
//- Output path (absolute)
fileName ensightDir_;
//- Case name (with ".case" ending)
word caseName_;
//- 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 for 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_;
//- Remember fields that are to be treated as point data
mutable HashSet nodeVariables_;
//- 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 the geometry being used
void noteGeometry(const bool moving) const;
//- Note the cloud being used
void noteCloud(const word& cloudName) const;
//- Note the cloud/variable being used
void noteCloud
(
const word& cloudName,
const word& varName,
const char* ensightType
) const;
//- Note the 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& name) const;
//- Open stream for new cloud file (on master).
// File is without initial description lines.
autoPtr createCloudFile
(
const word& cloudName,
const word& name
) const;
public:
// Generated Methods
//- No copy construct
ensightCase(const ensightCase&) = delete;
//- No copy assignment
void operator=(const ensightCase&) = delete;
// 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 IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
);
//- Destructor
~ensightCase() = default;
// Static Functions
//- 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
static StringType expand_mask
(
const StringType& input,
const label index
);
// Member Functions
// Access
//- Reference to the case options
inline const ensightCase::options& option() const;
//- The output file format (ascii/binary)
inline IOstreamOption::streamFormat format() const;
//- The nominal path to the case file
inline const fileName& path() const noexcept;
//- The output '*' mask
inline const word& mask() const;
//- Consistent zero-padded integer value
inline word padded(const label i) const;
//- Force use of values per node 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
// \note 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
// \note 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).
//- Does not include beginGeometry() marker.
autoPtr newGeometry(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), with current index.
// Optionally marking as containing POINT_DATA
template
autoPtr 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
autoPtr newPointData(const word& varName) const;
//- Open stream for new cloud data file (on master), with 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& os) const;
// Output Helpers
//- Set output time format for ensight case file
static void setTimeFormat
(
OSstream& os,
IOstreamOption::floatFormat timeFmt,
const int timePrec
);
//- Set output time format for ensight case file
static void setTimeFormat
(
OSstream& os,
const ensightCase::options& opts
);
//- Print time-set for ensight case file with a single time
static void printTimeset
(
OSstream& os,
const label ts,
const scalar timeValue
);
//- Print time-set for ensight case file, with N times and 0-based
//- file numbering
//
// \verbatim
// TIME
// time set: ts
// number of steps: ns
// filename start number: 0
// filename increment: 1
// time values: time_1 time_2 ... time_ns
// \endverbatim
static void printTimeset
(
OSstream& os,
const label ts,
const UList& times
);
//- Print time-set for ensight case file, with N times, 0-based
//- file numbering but perhaps non-contiguous
//
// \verbatim
// TIME
// time set: ts
// number of steps: ns
// filename numbers: idx_1 idx_2 ... idx_ns
// time values: time_1 time_2 ... time_ns
// \endverbatim
static void printTimeset
(
OSstream& os,
const label ts,
const UList& times,
const bitSet& indices
);
};
/*---------------------------------------------------------------------------*\
Class ensightCase::options Declaration
\*---------------------------------------------------------------------------*/
//- Configuration options for the ensightCase
class ensightCase::options
{
// Private Data
//- The output file format (ascii/binary)
IOstreamOption::streamFormat format_;
//- Remove existing directory and sub-directories on creation
bool overwrite_;
//- Force use of values per node instead of per element
bool nodeValues_;
//- Write clouds into their own directory
bool separateCloud_;
//- Time format for case file (default: scientific)
IOstreamOption::floatFormat timeFormat_;
//- Time precision for case file (default: 5)
int timePrecision_;
//- Width of mask for subdirectories
int width_;
//- The '*' mask appropriate for subdirectories
word mask_;
//- The printf format for zero-padded subdirectory numbers
string printf_;
public:
// Constructors
//- Construct with the specified format (default is binary)
explicit options
(
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
);
//- If present, construct with the format specified in the dictionary
//- or use default (binary)
options
(
//! The lookup name for the format, typically 'format'
//! or 'writeFormat' etc.
const word& formatKeyword,
const dictionary& dict,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
);
// Member Functions
// Access
//- The output file format (ascii/binary)
IOstreamOption::streamFormat format() const noexcept { return format_; }
//- Time format for case file (general/fixed/scientific)
IOstreamOption::floatFormat timeFormat() const noexcept
{
return timeFormat_;
}
//- Time precision for case file
int timePrecision() const noexcept { return timePrecision_; }
//- The '*' mask appropriate for sub-directories
const word& mask() const noexcept { return mask_; }
//- Consistent zero-padded integer value
word padded(const label i) const;
//- Return current width of mask and padded.
int width() const noexcept { return width_; }
//- Remove existing directory and sub-directories on creation
bool overwrite() const noexcept { return overwrite_; }
//- Write clouds into their own directory instead in "data" directory
bool separateCloud() const noexcept { return separateCloud_; }
// Edit
//- Set width of mask and padded.
// Default width is 8 digits, max width is 31 digits.
void width(const int i);
//- Set the time format for case file
void timeFormat(IOstreamOption::floatFormat fmt) noexcept
{
timeFormat_ = fmt;
}
//- Set the time precision for case file
void timePrecision(int prec) noexcept { timePrecision_ = prec; }
//- Set the time format for case file
void timeFormat(const word& key, const dictionary& dict);
//- Set the time precision for case file
void timePrecision(const word& key, const dictionary& dict);
//- Remove existing directory and sub-directories on creation
void overwrite(bool on) noexcept { overwrite_ = on; }
//- Write clouds into their own directory instead in "data" directory
void separateCloud(bool on) noexcept { separateCloud_ = on; }
// Housekeeping
//- Forced use of values per node instead of per element
bool nodeValues() const noexcept { return nodeValues_; }
//- 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 on) noexcept { nodeValues_ = on; }
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "ensightCaseI.H"
#ifdef NoRepository
#include "ensightCaseTemplates.C"
#endif
#endif
// ************************************************************************* //