ENH: vtk::seriesWriter to encapsulate writing file series (issue #926)

This commit is contained in:
Mark Olesen
2018-10-02 14:06:34 +02:00
parent 42009c168e
commit 0e47b0717d
14 changed files with 1299 additions and 0 deletions

View File

@ -0,0 +1,3 @@
Test-vtkSeriesWriter.C
EXE = $(FOAM_APPBIN)/Test-vtkSeriesWriter

View File

@ -0,0 +1,5 @@
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude
EXE_LIBS = \
-lfileFormats

View File

@ -0,0 +1,118 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2018 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/>.
Application
Test-vtkSeriesWriter
Description
Basic functionality tests for vtk::seriesWriter
\*---------------------------------------------------------------------------*/
#include "foamVtkSeriesWriter.H"
#include "argList.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addBoolOption("sort", "Sort value / name");
argList::addBoolOption("check", "Check for existence of files");
argList::addOption("time", "value", "Filter based on given time");
argList::addOption("scan", "series", "Scan directory to create series");
argList args(argc, argv, false, true);
const scalar currTime = args.lookupOrDefault<scalar>("time", GREAT);
Info<< "Using currTime = " << currTime << nl
<< "when loading " << (args.size()-1) << " files" << nl << nl;
for (label argi=1; argi < args.size(); ++argi)
{
const auto& input = args[argi];
Info << "load from " << input << nl;
vtk::seriesWriter writer;
writer.load(input);
writer.print(Info);
Info<< nl << nl;
if (writer.removeNewer(currTime))
{
Info<< "removed entries with time >= " << currTime << nl;
writer.print(Info);
Info<< nl << nl;
}
if (args.found("sort"))
{
writer.sort();
Info<< "sorted" << nl;
writer.print(Info);
Info<< nl << nl;
}
if (args.found("check"))
{
writer.load(input, true);
Info<< "reload, checking the existance of files" << nl;
writer.print(Info);
Info<< nl << nl;
}
if (writer.empty())
{
Info<< "No entries" << nl;
}
else
{
Info<< writer.size() << " entries" << nl;
}
}
if (args.found("scan"))
{
vtk::seriesWriter writer;
writer.scan(args.opt<fileName>("scan"));
Info<< "scanned for files" << nl;
writer.print(Info);
Info<< nl << nl;
}
Info<< "\nEnd\n" << nl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- case='abc' time='0' index='0' -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- case='abc' time='0.00125' index='679' -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- case='abc' time="0.5250" index='1025' -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- note="no time entry" -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- case='abc' time= index='1234' note="degenerate time entry" -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<!-- case='abc' time=0.0145 index='1234' note="unquoted time entry" -->
<VTKFile type='vtkMultiBlockDataSet' version='1.0' byte_order='LittleEndian' header_type='UInt64'>
<vtkMultiBlockDataSet>

View File

@ -0,0 +1,20 @@
{
"file-series-version" : "1.0",
"files": [
{ "name" : "file_00001742.vtm", "time" : 50 },
{ "name" : "file_00001025.vtm", "time" : 30 },
{
"time" : 40,
"name" : "file_00001380.vtm", ,,,,
},
{ "name" : "file_00000679.vtm", "time" : 20 },
{ "name" : "file_00002110.vtm", "time" : 60 },
{ "name" : "file_00001234.vtm", "time" : 60 },
{ "name" : "file_00001742.vtm", "time" : 150 },
{ "name" : "file_00001742.vtm", "time" : 5 },
{ "name" : "file_1000.vtm", "badTime" : 60 },
{ "" : "", "" : 60, "" : false },
{ "name" : "", "time" : 10 },
]
}

View File

@ -17,6 +17,7 @@ stl/STLAsciiParseManual.C
stl/STLAsciiParseRagel.C
vtk/file/foamVtkFileWriter.C
vtk/file/foamVtkSeriesWriter.C
vtk/file/foamVtmWriter.C
vtk/core/foamVtkCore.C
vtk/core/foamVtkPTraits.C

View File

@ -0,0 +1,753 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2018 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 "foamVtkSeriesWriter.H"
#include "Fstream.H"
#include "ListOps.H"
#include "stringOpsSort.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Get any single token.
static inline bool getToken(ISstream& is, token& tok)
{
return (!is.read(tok).bad() && tok.good());
}
// Get two tokens.
// The first one must be a ':' token, the second one is any value
//
// This corrsponds to the JSON "key" : value syntax,
// we trigger after reading the "key".
static inline bool getValueToken(ISstream& is, token& tok)
{
return
(
// Token 1 = ':' separator
(
getToken(is, tok)
&& tok.isPunctuation() && tok.pToken() == token::COLON
)
// Token 2 is the value
&& getToken(is, tok)
);
}
// Sorting for fileNameInstant
// 1. sort by value (time)
// 2. natural sort (name)
struct seriesLess
{
bool operator()(const fileNameInstant a, const fileNameInstant b) const
{
scalar val = compareOp<scalar>()(a.value(), b.value());
if (val == 0)
{
return
stringOps::natural_sort::compare(a.name(), b.name()) < 0;
}
return val < 0;
}
};
// Check if value is less than upper, with some tolerance.
static inline bool lessThan(const scalar& val, const scalar& upper)
{
return (val < upper && Foam::mag(val - upper) > ROOTVSMALL);
}
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::fileName Foam::vtk::seriesWriter::base
(
const fileName& outputName,
char sep
)
{
const auto dash = outputName.rfind(sep);
// No separator? Or separator in path() instead of name()?
if
(
std::string::npos == dash
|| std::string::npos != outputName.find('/', dash)
)
{
// Warn?
return outputName;
}
const auto dot = outputName.find('.', dash);
if (std::string::npos == dot)
{
return outputName.substr(0, dash);
}
return outputName.substr(0, dash) + outputName.substr(dot);
}
Foam::word Foam::vtk::seriesWriter::suffix
(
const fileName& file,
char sep
)
{
const auto dash = file.rfind(sep);
// No separator? Or separator in path() instead of name()?
if
(
std::string::npos == dash
|| std::string::npos != file.find('/', dash)
)
{
// Warn?
return "";
}
const auto dot = file.find('.', dash);
if (std::string::npos == dot)
{
return file.substr(dash);
}
return file.substr(dash, (dot-dash));
}
Foam::Ostream& Foam::vtk::seriesWriter::print
(
Ostream& os,
const fileName& base,
const UList<instant>& series,
const char sep
)
{
// Split the base into (stem, ext) components
//
// base = "path/file.vtm"
//
// stem = "file"
// ext = ".vtm"
const word stem = base.nameLessExt();
const word ext = "." + base.ext();
// Begin file-series (JSON)
os << "{\n \"file-series-version\" : \"1.0\",\n \"files\" : [\n";
// Track how many entries are remaining
// - trailing commas on all but the final entry (JSON requirement)
label nremain = series.size();
// Each entry
// { "name" : "<stem><sep>name<ext>", "time" : value }
for (const instant& inst : series)
{
os << " { \"name\" : \""
<< stem << sep << inst.name() << ext
<< "\", \"time\" : " << inst.value() << " }";
if (--nremain)
{
os << ',';
}
os << nl;
}
os << " ]\n}\n";
return os;
}
Foam::Ostream& Foam::vtk::seriesWriter::print
(
Ostream& os,
const UList<fileNameInstant>& series
)
{
// Begin file-series (JSON)
os << "{\n \"file-series-version\" : \"1.0\",\n \"files\" : [\n";
// Track how many entries are remaining
// - trailing commas on all but the final entry (JSON requirement)
label nremain = series.size();
// Each entry
// { "name" : "<file>", "time" : <value> }
for (const fileNameInstant& inst : series)
{
os << " { \"name\" : \""
<< inst.name().name()
<< "\", \"time\" : " << inst.value() << " }";
if (--nremain)
{
os << ',';
}
os << nl;
}
os << " ]\n}\n";
return os;
}
void Foam::vtk::seriesWriter::write
(
const fileName& seriesName,
const UList<instant>& series,
const char sep
)
{
mkDir(seriesName.path());
autoPtr<OFstream> osPtr =
(
seriesName.hasExt("series")
? autoPtr<OFstream>::New(seriesName)
: autoPtr<OFstream>::New(seriesName + ".series")
);
print(*osPtr, seriesName, series, sep);
}
void Foam::vtk::seriesWriter::write
(
const fileName& seriesName,
const UList<fileNameInstant>& series
)
{
mkDir(seriesName.path());
autoPtr<OFstream> osPtr =
(
seriesName.hasExt("series")
? autoPtr<OFstream>::New(seriesName)
: autoPtr<OFstream>::New(seriesName + ".series")
);
print(*osPtr, series);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::vtk::seriesWriter::appendCheck(fileNameInstant inst)
{
if (inst.name().empty())
{
return false;
}
const auto iter = existing_.find(inst.name());
if (iter.found())
{
for (fileNameInstant& dst : entries_)
{
if (dst.name() == inst.name())
{
// Replace value
dst.value() = inst.value();
return true;
}
}
}
entries_.append(inst);
existing_.insert(inst.name());
return true;
}
bool Foam::vtk::seriesWriter::removeDuplicates()
{
const label nElem = entries_.size();
HashTable<label, fileName> filesSeen(2*nElem);
bool changed = false;
for (label elemi=0; elemi < nElem; ++elemi)
{
fileNameInstant& inst = entries_[elemi];
if (inst.name().empty())
{
changed = true;
}
else
{
auto iter = filesSeen.find(inst.name());
if (iter.found())
{
// Mark previous location as being superseded
entries_[*iter].name().clear();
changed = true;
*iter = elemi; // The latest with this name
}
else
{
filesSeen.insert(inst.name(), elemi);
}
}
}
if (changed)
{
label dsti = 0;
for (label elemi=0; elemi < nElem; ++elemi)
{
fileNameInstant& src = entries_[elemi];
if (!src.name().empty())
{
if (dsti != elemi)
{
entries_[dsti] = std::move(src);
}
++dsti;
}
}
entries_.resize(dsti);
}
return (nElem != entries_.size());
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::vtk::seriesWriter::load
(
const fileName& seriesName,
const bool checkFiles,
const scalar restartTime
)
{
clear();
fileName seriesFile(seriesName);
if (!seriesFile.hasExt("series"))
{
seriesFile.ext("series");
}
if (!isFile(seriesFile))
{
return size();
}
HashSet<fileName> filesOnDisk;
if (checkFiles)
{
filesOnDisk.insert(Foam::readDir(seriesFile.path()));
}
// Parse JSON content:
//
// {
// "file-series-version" : "1.0",
// "files" : [
// { "name" : "abc", "time" : 123 },
// { "name" : "def", "time" : 345 }
// ]
// }
// Parsing states
enum parse
{
NONE, // Looking for "files"
FILES_ARRAY, // Saw "file" : '['
ENTRY, // Parsing in { "name" : ... }
DONE, // Saw a ']' while in FILES_ARRAY
FAIL // Something bad happened
};
// Track if "file" and "time" keys have been located
unsigned instStatus = 0;
fileNameInstant inst;
token tok;
IFstream is(seriesFile);
for
(
parse state = parse::NONE;
(state != parse::DONE && state != parse::FAIL)
&& getToken(is, tok);
/*nil*/
)
{
switch (state)
{
// Still scanning for initial "files" entry
case parse::NONE :
{
if (tok.isString() && tok.stringToken() == "files")
{
// Expect "files" : [ ...
if
(
getValueToken(is, tok)
&& tok.isPunctuation()
&& tok.pToken() == token::BEGIN_SQR
)
{
state = parse::FILES_ARRAY;
}
else
{
state = parse::FAIL;
}
}
}
break;
// Parsing entries within "files" array
case parse::FILES_ARRAY :
{
if (tok.isPunctuation())
{
switch (tok.pToken())
{
// ',' - keep going (another entry)
case token::COMMA :
break;
// '{' - begin entry
case token::BEGIN_BLOCK :
state = parse::ENTRY;
instStatus = 0;
break;
// ']' - done array
case token::END_SQR :
state = parse::DONE;
break;
default:
state = parse::FAIL;
break;
}
}
else
{
state = parse::FAIL;
}
}
break;
// Parsing an individual entry within "files"
case parse::ENTRY :
{
if (tok.isPunctuation())
{
switch (tok.pToken())
{
// ',' - keep going (another key/value pair)
case token::COMMA :
break;
// '}'
case token::END_BLOCK :
{
// Verify instant was properly parsed and
// is also valid
if
(
instStatus == 0x03
&& lessThan(inst.value(), restartTime)
&&
(
checkFiles
? filesOnDisk.found(inst.name())
: true
)
)
{
appendCheck(inst);
}
state = parse::FILES_ARRAY;
instStatus = 0;
}
break;
default:
state = parse::FAIL;
break;
}
}
else if (tok.isString())
{
// Expect "key" : value
const string key(tok.stringToken());
if (getValueToken(is, tok))
{
if ("name" == key)
{
if (tok.isString())
{
inst.name() = tok.stringToken();
instStatus |= 0x01;
}
else
{
state = parse::FAIL;
}
}
else if ("time" == key)
{
if (tok.isNumber())
{
inst.value() = tok.number();
instStatus |= 0x02;
}
else
{
state = parse::FAIL;
}
}
}
else
{
state = parse::FAIL;
}
}
else
{
state = parse::FAIL;
}
}
break;
default:
break;
}
}
return size();
}
Foam::label Foam::vtk::seriesWriter::scan
(
const fileName& seriesName,
const scalar restartTime
)
{
clear();
const fileName path = seriesName.path();
if (!isDir(path))
{
return size();
}
fileName seriesFile(seriesName);
if (seriesName.hasExt("series"))
{
seriesFile.removeExt();
}
const word stem = seriesFile.nameLessExt();
const word ext = seriesFile.ext();
// Accept "fileN.ext", "fileNN.ext", but reject "file.ext"
const auto minLen = stem.length() + ext.length() + 1;
const auto acceptName =
[=](const fileName& file) -> bool
{
return
(
minLen < file.length()
&& file.hasExt(ext) && file.startsWith(stem)
);
};
fileNameList files = subsetList(Foam::readDir(path), acceptName);
// Names sorted so warnings appear less random
Foam::sort(files, stringOps::natural_sort());
// Scratch space for reading some of the file
std::string header;
scalar timeValue;
bool warnings = false;
for (const fileName& file : files)
{
std::ifstream is(path/file);
if (!is)
{
continue;
}
// Read directly into the string
// 1024 (12 lines of 80 chars) is plenty for all comments
header.resize(1024);
is.read(&(header.front()), header.size());
header.resize(is.gcount());
// DebugInfo
// << "got header:\n=====\n" << header << "\n=====\n" << nl;
// Look for time="...", time='...', or even time=... attribute
auto begAttr = header.find("time=");
if (string::npos == begAttr)
{
if (!warnings)
{
Info<< "No 'time=' comment attribute found:\n(" << nl;
warnings = true;
}
Info<< " " << file << nl;
continue;
}
// Skip past the 'time='
begAttr += 5;
const char quote = header[begAttr];
// Info<< "have time=" << int(begAttr) << nl;
auto endAttr =
(
(quote == '"' || quote == '\'')
?
// Quoted
header.find(quote, ++begAttr)
:
// Unquoted
header.find_first_of("\t\n\v\f\r ", begAttr)
);
if
(
string::npos != endAttr && begAttr < endAttr
&& readScalar
(
header.substr(begAttr, endAttr-begAttr),
timeValue
)
&& lessThan(timeValue, restartTime)
)
{
// Success
append(timeValue, file);
}
}
if (warnings)
{
Info<< ")" << nl << nl;
}
// Don't trust the order. Sort by time and name instead.
this->sort();
return size();
}
bool Foam::vtk::seriesWriter::removeNewer(const scalar timeValue)
{
// Rebuild hash as side-effect
existing_.clear();
label dsti = 0;
const label nElem = entries_.size();
for (label elemi=0; elemi < nElem; ++elemi)
{
fileNameInstant& src = entries_[elemi];
if (!src.name().empty() && lessThan(src.value(), timeValue))
{
if (dsti != elemi)
{
entries_[dsti] = std::move(src);
existing_.insert(entries_[dsti].name());
}
++dsti;
}
}
entries_.resize(dsti);
return (nElem != entries_.size());
}
void Foam::vtk::seriesWriter::sort()
{
Foam::sort(entries_, seriesLess());
}
// ************************************************************************* //

View File

@ -0,0 +1,276 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2018 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::vtk::seriesWriter
Description
Provides a means of accumulating and generating VTK file series.
The VTK file series format is a simple JSON format with the following
type of content:
\verbatim
{
"file-series-version" : "1.0",
"files": [
{ "name" : "file1.vtk", "time" : 10 },
{ "name" : "file2.vtk", "time" : 20 },
{ "name" : "file3.vtk", "time" : 30 },
]
}
\endverbatim
The append() operations include various sanity checks.
Entries with an empty name are ignored.
If an entry with an identical name already exists, its place
will be overwritten with the new time value.
SourceFiles
foamVtkSeriesWriter.C
\*---------------------------------------------------------------------------*/
#ifndef foamVtkSeriesWriter_H
#define foamVtkSeriesWriter_H
#include <fstream>
#include "foamVtkOutputOptions.H"
#include "instant.H"
#include "fileNameInstant.H"
#include "DynamicList.H"
#include "HashSet.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace vtk
{
/*---------------------------------------------------------------------------*\
Class vtk::seriesWriter Declaration
\*---------------------------------------------------------------------------*/
class seriesWriter
{
// Private Member Data
//- A list of file/time entries
DynamicList<fileNameInstant> entries_;
//- Hash of existing (known) file names
HashSet<fileName> existing_;
//- Append the specified file/time instant.
// Overwrites existing entry that has the same name,
// does not append empty names.
bool appendCheck(fileNameInstant inst);
//- Remove duplicate filename entries. Keeping the last one seen.
bool removeDuplicates();
public:
// Constructors
//- Construct an empty series
seriesWriter() = default;
//- Copy construct
seriesWriter(const seriesWriter&) = default;
//- Move construct
seriesWriter(seriesWriter&&) = default;
//- Copy assignment
seriesWriter& operator=(const seriesWriter&) = default;
//- Move assignment
seriesWriter& operator=(seriesWriter&&) = default;
//- Destructor
~seriesWriter() = default;
// Static Member Functions
//- Extract the base name for a file series
//
// \param outputName The name of the data output file
// Eg, "somefile_0001.vtk" would extract to "somefile.vtk"
// \param sep The separator used between file stem and suffix.
static fileName base(const fileName& outputName, char sep = '_');
//- Extract the time-varying ending of files
//
// \param file The name of the file
// Eg, "somefile_0001.vtk" would extract to "0001"
// \param sep The separator used between file stem and suffix.
static word suffix(const fileName& file, char sep = '_');
//- Print file series (JSON format) for specified time instances
//
// \param os The output stream
// \param base The name for the series (eg, "path/file.vtk")
// \param series The list of suffix/value entries
// \param sep The separator used between file stem and suffix.
static Ostream& print
(
Ostream& os,
const fileName& seriesName,
const UList<instant>& series,
const char sep = '_'
);
//- Write file series (JSON format) to disk, for specified instances
//
// \param base The name for the series (eg, "path/file.vtk")
// \param series The list of suffix/value entries
// \param sep The separator used between file stem and suffix.
static void write
(
const fileName& base,
const UList<instant>& series,
const char sep = '_'
);
//- Print file series (JSON format) for specified time instances.
// Since the VTK file series does not currently (OCT-2018) support
// sub-directories, these will be stripped on output.
//
// \param os The output stream
// \param series The list of filename/value entries
static Ostream& print
(
Ostream& os,
const UList<fileNameInstant>& series
);
//- Write file series (JSON format) to disk, for specified instances
//
// \param seriesName The name for the series (eg, "path/file.vtk")
// \param series The list of filename/value entries
static void write
(
const fileName& seriesName,
const UList<fileNameInstant>& series
);
// Member Functions
//- True if there are no data sets
inline bool empty() const;
//- The number of data sets
inline label size() const;
// Content Management
//- Clear entries
inline void clear();
//- Append the specified file instant
inline bool append(const fileNameInstant& inst);
//- Append the specified file instant
inline bool append(fileNameInstant&& inst);
//- Append the specified file instant.
inline bool append(scalar timeValue, const fileName& file);
//- Append the specified file instant.
inline bool append(scalar timeValue, fileName&& file);
//- Clear contents and reload by parsing the specified file.
//
// \param seriesName the base name of the series to scan, without
// the ".series" ending.
// \param checkFiles verify that the files also exist
// \param restartTime ignore entries with a time greater/equal
// to the specified restart time.
//
// \return the number of entries
label load
(
const fileName& seriesName,
const bool checkFiles = false,
const scalar restartTime = ROOTVGREAT
);
//- Clear contents and scan directory for files.
//
// The expected xml header content is a comment with the following:
// \verbatim
// <!-- ... time='3.14159' ... -->
// \endverbatim
//
// \param seriesName the base name of the series to scan, without
// the ".series" ending.
// \param restartTime ignore entries with a time greater/equal
// to the specified restart time.
//
// \return the number of entries
label scan
(
const fileName& seriesName,
const scalar restartTime = ROOTVGREAT
);
//- Remove entries that are greater_equal the time value.
//
// \return True if the contents changed
bool removeNewer(const scalar timeValue);
//- Sort by time value and by file name
void sort();
// Writing
//- Print file series as (JSON format)
inline void print(Ostream& os) const;
//- Write file series as (JSON format) to disk
inline void write(const fileName& seriesName) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace vtk
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "foamVtkSeriesWriterI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2018 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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::vtk::seriesWriter::empty() const
{
return entries_.empty();
}
inline Foam::label Foam::vtk::seriesWriter::size() const
{
return entries_.size();
}
inline void Foam::vtk::seriesWriter::clear()
{
entries_.clear();
existing_.clear();
}
inline bool Foam::vtk::seriesWriter::append(const fileNameInstant& inst)
{
// Strip out path before saving
return appendCheck(fileNameInstant(inst.value(), inst.name().name()));
}
inline bool Foam::vtk::seriesWriter::append(fileNameInstant&& inst)
{
// Strip out path before saving
inst.name().removePath();
return appendCheck(inst);
}
inline bool Foam::vtk::seriesWriter::append
(
scalar timeValue,
const fileName& file
)
{
// Strip out path before saving
return appendCheck(fileNameInstant(timeValue, file.name()));
}
inline bool Foam::vtk::seriesWriter::append
(
scalar timeValue,
fileName&& file
)
{
// Strip out path before saving
file.removePath();
return appendCheck(fileNameInstant(timeValue, std::move(file)));
}
inline void Foam::vtk::seriesWriter::print(Ostream& os) const
{
seriesWriter::print(os, entries_);
}
inline void Foam::vtk::seriesWriter::write(const fileName& seriesName) const
{
seriesWriter::write(seriesName, entries_);
}
// ************************************************************************* //