mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: vtk::vtmWriter for generating vtkMultiBlockDataSet (.vtm) (issue #926)
- Provides a means of accumulating file entries for generating vtm by accumulate blocks, datasets and writing them later. Only a single block depth is currently supported and the methods are kept fairly simple.
This commit is contained in:
3
applications/test/vtmWriter/Make/files
Normal file
3
applications/test/vtmWriter/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-vtmWriter.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/Test-vtmWriter
|
||||
5
applications/test/vtmWriter/Make/options
Normal file
5
applications/test/vtmWriter/Make/options
Normal file
@ -0,0 +1,5 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lfileFormats
|
||||
159
applications/test/vtmWriter/Test-vtmWriter.C
Normal file
159
applications/test/vtmWriter/Test-vtmWriter.C
Normal file
@ -0,0 +1,159 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / 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-vtmWriter
|
||||
|
||||
Description
|
||||
Basic functionality tests for vtk::vtmWriter
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "foamVtmWriter.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
vtk::vtmWriter writer1;
|
||||
{
|
||||
fileName base = "region1_0001";
|
||||
|
||||
writer1.beginBlock("internal");
|
||||
writer1.append_vtu
|
||||
(
|
||||
base/"internal"
|
||||
);
|
||||
writer1.endBlock("internal");
|
||||
|
||||
{
|
||||
writer1.beginBlock("boundary");
|
||||
writer1.append_vtp
|
||||
(
|
||||
base/"patch0"
|
||||
);
|
||||
writer1.append(""); // bad entry
|
||||
writer1.append_vtp
|
||||
(
|
||||
base/"patch1"
|
||||
);
|
||||
writer1.append_vtp
|
||||
(
|
||||
base/"patch2"
|
||||
);
|
||||
}
|
||||
|
||||
writer1.endBlock("boundary");
|
||||
|
||||
{
|
||||
writer1.beginBlock("empty");
|
||||
writer1.endBlock("empty");
|
||||
}
|
||||
{
|
||||
writer1.beginBlock("dangling1");
|
||||
writer1.beginBlock("dangling2");
|
||||
}
|
||||
}
|
||||
|
||||
Info<< nl << "vtm information" << nl;
|
||||
writer1.dump(Info),
|
||||
Info<< nl;
|
||||
|
||||
// writer1.repair();
|
||||
//
|
||||
// Info<< nl << "vtm information - after repair" << nl;
|
||||
// writer1.dump(Info),
|
||||
// Info<< nl;
|
||||
|
||||
writer1.repair(true);
|
||||
|
||||
// Info<< nl << "vtm information - after repair(collapse)" << nl;
|
||||
// writer1.dump(Info),
|
||||
// Info<< nl;
|
||||
//
|
||||
// Info<< nl << "vtm information - after repair(collapse)" << nl;
|
||||
// writer1.dump(Info),
|
||||
// Info<< nl;
|
||||
|
||||
Info<< nl << "Write to file" << nl;
|
||||
writer1.write("vtmWriter1.vtm");
|
||||
|
||||
|
||||
vtk::vtmWriter writer2;
|
||||
{
|
||||
fileName base = "region2_0001";
|
||||
|
||||
writer2.beginBlock("internal");
|
||||
writer2.append_vtu
|
||||
(
|
||||
base/"internal"
|
||||
);
|
||||
writer2.endBlock("internal");
|
||||
|
||||
{
|
||||
writer2.beginBlock("boundary");
|
||||
writer2.append_vtp
|
||||
(
|
||||
base/"patch0"
|
||||
);
|
||||
writer2.append(""); // bad entry
|
||||
writer2.append_vtp
|
||||
(
|
||||
base/"patch1"
|
||||
);
|
||||
writer2.append_vtp
|
||||
(
|
||||
base/"patch2"
|
||||
);
|
||||
}
|
||||
|
||||
writer2.endBlock("boundary");
|
||||
|
||||
// These should be automatically skiped
|
||||
writer2.endBlock();
|
||||
writer2.endBlock();
|
||||
writer2.endBlock();
|
||||
writer2.endBlock();
|
||||
}
|
||||
|
||||
Info<< nl << "vtm information" << nl;
|
||||
writer2.dump(Info);
|
||||
|
||||
writer2.repair(true);
|
||||
|
||||
|
||||
vtk::vtmWriter writer3;
|
||||
|
||||
writer3.add("some-region1", writer1);
|
||||
writer3.add("some-region2", writer2);
|
||||
|
||||
Info<< nl << "Combined:" << nl;
|
||||
writer3.dump(Info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -17,6 +17,7 @@ stl/STLAsciiParseManual.C
|
||||
stl/STLAsciiParseRagel.C
|
||||
|
||||
vtk/file/foamVtkFileWriter.C
|
||||
vtk/file/foamVtmWriter.C
|
||||
vtk/core/foamVtkCore.C
|
||||
vtk/core/foamVtkPTraits.C
|
||||
|
||||
|
||||
694
src/fileFormats/vtk/file/foamVtmWriter.C
Normal file
694
src/fileFormats/vtk/file/foamVtmWriter.C
Normal file
@ -0,0 +1,694 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / 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 <fstream>
|
||||
#include "foamVtmWriter.H"
|
||||
#include "Time.H"
|
||||
#include "OSspecific.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * Local Class * * * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::vtk::vtmWriter::vtmEntry::clear()
|
||||
{
|
||||
type_ = NONE;
|
||||
name_.clear();
|
||||
file_.clear();
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::vtmEntry::good() const
|
||||
{
|
||||
return
|
||||
(
|
||||
type_ == vtmEntry::BEGIN_BLOCK
|
||||
|| type_ == vtmEntry::END_BLOCK
|
||||
|| (type_ == vtmEntry::DATA && file_.size())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::vtmEntry::write(vtk::formatter& format) const
|
||||
{
|
||||
if (type_ == vtmEntry::BEGIN_BLOCK)
|
||||
{
|
||||
format.openTag(vtk::fileTag::BLOCK);
|
||||
if (name_.size())
|
||||
{
|
||||
format.xmlAttr("name", name_);
|
||||
}
|
||||
format.closeTag();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (type_ == vtmEntry::END_BLOCK)
|
||||
{
|
||||
format.endBlock();
|
||||
return true;
|
||||
}
|
||||
else if (type_ == vtmEntry::DATA && file_.size())
|
||||
{
|
||||
format.openTag(vtk::fileTag::DATA_SET);
|
||||
|
||||
if (name_.size())
|
||||
{
|
||||
format.xmlAttr("name", name_);
|
||||
}
|
||||
|
||||
format.xmlAttr("file", file_);
|
||||
|
||||
format.closeTag(true); // Empty tag. ie, <DataSet ... />
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::vtk::vtmWriter::pruneEmpty()
|
||||
{
|
||||
const label nEntries = entries_.size();
|
||||
|
||||
label dst=0;
|
||||
|
||||
for (label src=0; src < nEntries; ++src)
|
||||
{
|
||||
if (entries_[src].good())
|
||||
{
|
||||
if (dst != src)
|
||||
{
|
||||
entries_[dst] = std::move(entries_[src]);
|
||||
}
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
const bool changed = (dst != nEntries);
|
||||
entries_.resize(dst);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::pruneEmptyBlocks()
|
||||
{
|
||||
bool pruned = false;
|
||||
|
||||
const label nEntries = entries_.size();
|
||||
|
||||
while (true)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
for (label i=0; i < nEntries; ++i)
|
||||
{
|
||||
vtmEntry& e = entries_[i];
|
||||
|
||||
if (e.isType(vtmEntry::BEGIN_BLOCK))
|
||||
{
|
||||
for (label j=i+1; j < nEntries; ++j)
|
||||
{
|
||||
if (entries_[j].isType(vtmEntry::END_BLOCK))
|
||||
{
|
||||
e.clear();
|
||||
entries_[j].clear();
|
||||
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
else if (!entries_[j].isType(vtmEntry::NONE))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
pruned = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse single-entry blocks when the names allow it
|
||||
|
||||
// Transcribe, removing NONE entries
|
||||
pruneEmpty();
|
||||
|
||||
return pruned;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::collapseBlocks()
|
||||
{
|
||||
bool collapsed = false;
|
||||
|
||||
const label nEntries = entries_.size();
|
||||
|
||||
for (label i=0; i < nEntries-2; ++i)
|
||||
{
|
||||
vtmEntry& b = entries_[i]; // begin
|
||||
vtmEntry& d = entries_[i+1]; // data
|
||||
vtmEntry& e = entries_[i+2]; // end
|
||||
|
||||
if
|
||||
(
|
||||
b.isType(vtmEntry::BEGIN_BLOCK)
|
||||
&& e.isType(vtmEntry::END_BLOCK)
|
||||
&& d.isType(vtmEntry::DATA)
|
||||
&& (d.name_.empty() || d.name_ == b.name_)
|
||||
)
|
||||
{
|
||||
d.name_ = std::move(b.name_);
|
||||
|
||||
b.clear();
|
||||
e.clear();
|
||||
|
||||
collapsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
pruneEmpty();
|
||||
|
||||
return collapsed;
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::repair(bool collapse)
|
||||
{
|
||||
// Add or remove END_BLOCK
|
||||
|
||||
label depth = 0;
|
||||
label nEntries = 0;
|
||||
|
||||
for (vtmEntry& e : entries_)
|
||||
{
|
||||
if (e.isType(vtmEntry::BEGIN_BLOCK))
|
||||
{
|
||||
++depth;
|
||||
}
|
||||
else if (e.isType(vtmEntry::END_BLOCK))
|
||||
{
|
||||
--depth;
|
||||
|
||||
if (depth < 0)
|
||||
{
|
||||
// Truncate now and exit
|
||||
entries_.resize(nEntries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (e.isType(vtmEntry::DATA))
|
||||
{
|
||||
if (e.file_.empty())
|
||||
{
|
||||
// Bad entry - reset to NONE
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
|
||||
++nEntries;
|
||||
}
|
||||
|
||||
// Close any dangling blocks
|
||||
while (depth--)
|
||||
{
|
||||
entries_.append(vtmEntry::endblock());
|
||||
}
|
||||
|
||||
blocks_.clear();
|
||||
pruneEmpty();
|
||||
|
||||
if (collapse)
|
||||
{
|
||||
pruneEmptyBlocks();
|
||||
collapseBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::dump(Ostream& os) const
|
||||
{
|
||||
label depth = 0;
|
||||
|
||||
// Output format is a mix of dictionary and JSON
|
||||
// the only purpose being for diagnostics
|
||||
|
||||
for (const vtmEntry& e : entries_)
|
||||
{
|
||||
switch (e.type_)
|
||||
{
|
||||
case vtmEntry::NONE:
|
||||
{
|
||||
os.indent();
|
||||
os << "none" << nl;
|
||||
break;
|
||||
}
|
||||
case vtmEntry::DATA:
|
||||
{
|
||||
os.indent();
|
||||
os << "{ \"name\" : " << e.name_
|
||||
<< ", \"file\" : " << e.file_ << " }" << nl;
|
||||
break;
|
||||
}
|
||||
case vtmEntry::BEGIN_BLOCK:
|
||||
{
|
||||
++depth;
|
||||
os.beginBlock(e.name_);
|
||||
break;
|
||||
}
|
||||
case vtmEntry::END_BLOCK:
|
||||
{
|
||||
--depth;
|
||||
os.endBlock();
|
||||
os << nl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (label i=0; i < depth; ++i)
|
||||
{
|
||||
os.decrIndent();
|
||||
}
|
||||
|
||||
if (depth > 0)
|
||||
{
|
||||
os << "# Had " << depth << " unclosed blocks" << nl;
|
||||
}
|
||||
if (depth < 0)
|
||||
{
|
||||
os << "# Had " << (-depth) << " too many end blocks" << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::vtk::vtmWriter::vtmWriter()
|
||||
:
|
||||
vtmWriter(true, false)
|
||||
{}
|
||||
|
||||
|
||||
Foam::vtk::vtmWriter::vtmWriter(bool autoName)
|
||||
:
|
||||
vtmWriter(autoName, false)
|
||||
{}
|
||||
|
||||
|
||||
Foam::vtk::vtmWriter::vtmWriter(bool autoName, bool autoCollapse)
|
||||
:
|
||||
autoName_(autoName),
|
||||
autoCollapse_(autoCollapse),
|
||||
hasTime_(false),
|
||||
entries_(),
|
||||
blocks_(),
|
||||
timeValue_(Zero)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::vtk::vtmWriter::clear()
|
||||
{
|
||||
entries_.clear();
|
||||
blocks_.clear();
|
||||
|
||||
timeValue_ = Zero;
|
||||
hasTime_ = false;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::empty() const
|
||||
{
|
||||
for (const auto& e : entries_)
|
||||
{
|
||||
if (e.isType(vtmEntry::DATA) && e.name_.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::vtk::vtmWriter::size() const
|
||||
{
|
||||
label ndata = 0;
|
||||
|
||||
for (const auto& e : entries_)
|
||||
{
|
||||
if (e.isType(vtmEntry::DATA) && e.file_.size())
|
||||
{
|
||||
++ndata;
|
||||
}
|
||||
}
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::setTime(scalar timeValue)
|
||||
{
|
||||
timeValue_ = timeValue;
|
||||
hasTime_ = true;
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::setTime(const Time& t)
|
||||
{
|
||||
timeValue_ = t.value();
|
||||
hasTime_ = true;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::vtk::vtmWriter::beginBlock(const word& blockName)
|
||||
{
|
||||
entries_.append(vtmEntry::block(blockName));
|
||||
blocks_.append(blockName);
|
||||
|
||||
return blocks_.size();
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::vtk::vtmWriter::endBlock(const word& blockName)
|
||||
{
|
||||
label nblock = blocks_.size();
|
||||
|
||||
if (nblock)
|
||||
{
|
||||
const word curr(blocks_.remove());
|
||||
|
||||
// Verify expected end tag
|
||||
if (!blockName.empty() && blockName != curr)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "expecting to end block '" << blockName
|
||||
<< "' but found '" << curr << "' instead"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
entries_.append(vtmEntry::endblock());
|
||||
}
|
||||
|
||||
return blocks_.size();
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::append(const fileName& file)
|
||||
{
|
||||
if (autoName_)
|
||||
{
|
||||
return append(fileName::nameLessExt(file), file);
|
||||
}
|
||||
else
|
||||
{
|
||||
return append(word::null, file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::append
|
||||
(
|
||||
const fileName& file,
|
||||
vtk::fileTag contentType
|
||||
)
|
||||
{
|
||||
if (autoName_)
|
||||
{
|
||||
return append(fileName::nameLessExt(file), file, contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return append(word::null, file, contentType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::append
|
||||
(
|
||||
const word& name,
|
||||
const fileName& file
|
||||
)
|
||||
{
|
||||
if (file.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
entries_.append(vtmEntry::entry(name, file));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::vtk::vtmWriter::append
|
||||
(
|
||||
const word& name,
|
||||
const fileName& file,
|
||||
vtk::fileTag contentType
|
||||
)
|
||||
{
|
||||
if (file.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.hasExt(vtk::fileExtension[contentType]))
|
||||
{
|
||||
entries_.append(vtmEntry::entry(name, file));
|
||||
}
|
||||
else
|
||||
{
|
||||
entries_.append
|
||||
(
|
||||
vtmEntry::entry
|
||||
(
|
||||
name,
|
||||
file + "." + vtk::fileExtension[contentType]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::add
|
||||
(
|
||||
const word& blockName,
|
||||
const fileName& prefix,
|
||||
const vtmWriter& other
|
||||
)
|
||||
{
|
||||
// Standard sanity repair (block ending), prune empty entries
|
||||
repair();
|
||||
|
||||
beginBlock(blockName);
|
||||
|
||||
label depth = 0;
|
||||
bool good = true;
|
||||
|
||||
for (const vtmEntry& e : other.entries_)
|
||||
{
|
||||
switch (e.type_)
|
||||
{
|
||||
case vtmEntry::NONE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case vtmEntry::DATA:
|
||||
{
|
||||
if (e.good())
|
||||
{
|
||||
entries_.append(e);
|
||||
|
||||
if (prefix.size())
|
||||
{
|
||||
fileName& f = entries_.last().file_;
|
||||
|
||||
f = prefix/f;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case vtmEntry::BEGIN_BLOCK:
|
||||
{
|
||||
++depth;
|
||||
entries_.append(e);
|
||||
break;
|
||||
}
|
||||
case vtmEntry::END_BLOCK:
|
||||
{
|
||||
good = (depth > 0);
|
||||
--depth;
|
||||
if (good)
|
||||
{
|
||||
entries_.append(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!good) break;
|
||||
}
|
||||
|
||||
while (depth--)
|
||||
{
|
||||
entries_.append(vtmEntry::endblock());
|
||||
}
|
||||
|
||||
entries_.append(vtmEntry::endblock());
|
||||
|
||||
if (!hasTime_ && other.hasTime_)
|
||||
{
|
||||
hasTime_ = true;
|
||||
timeValue_ = other.timeValue_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::vtk::vtmWriter::add
|
||||
(
|
||||
const word& blockName,
|
||||
const vtmWriter& other
|
||||
)
|
||||
{
|
||||
add(blockName, fileName::null, other);
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::vtk::vtmWriter::write(const fileName& file)
|
||||
{
|
||||
std::ofstream os_;
|
||||
|
||||
mkDir(file.path());
|
||||
|
||||
if (file.hasExt(ext()))
|
||||
{
|
||||
os_.open(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
os_.open(file + "." + ext());
|
||||
}
|
||||
|
||||
auto format = vtk::newFormatter(os_, formatType::INLINE_ASCII);
|
||||
|
||||
|
||||
// Contents Header
|
||||
{
|
||||
format().xmlHeader();
|
||||
|
||||
if (hasTime_)
|
||||
{
|
||||
format().xmlComment
|
||||
(
|
||||
"time='" + Foam::name(timeValue_) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
format().beginVTKFile<vtk::fileTag::MULTI_BLOCK>();
|
||||
}
|
||||
|
||||
|
||||
// Walk the block and dataset contents
|
||||
|
||||
label depth = 0;
|
||||
label ndata = 0;
|
||||
|
||||
for (const vtmEntry& e : entries_)
|
||||
{
|
||||
switch (e.type_)
|
||||
{
|
||||
case vtmEntry::DATA:
|
||||
{
|
||||
if (e.file_.empty())
|
||||
{
|
||||
continue; // Empty dataset is junk - skip
|
||||
}
|
||||
++ndata;
|
||||
break;
|
||||
}
|
||||
case vtmEntry::BEGIN_BLOCK:
|
||||
{
|
||||
++depth;
|
||||
break;
|
||||
}
|
||||
case vtmEntry::END_BLOCK:
|
||||
{
|
||||
--depth;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth < 0)
|
||||
{
|
||||
// Too many end blocks - stop output now. Should we warn?
|
||||
break;
|
||||
}
|
||||
e.write(format());
|
||||
}
|
||||
|
||||
// Close any dangling blocks
|
||||
while (depth--)
|
||||
{
|
||||
format().endBlock();
|
||||
}
|
||||
|
||||
format().endTag(vtk::fileTag::MULTI_BLOCK);
|
||||
|
||||
|
||||
// FieldData for TimeValue
|
||||
if (hasTime_)
|
||||
{
|
||||
format()
|
||||
.beginFieldData()
|
||||
.writeTimeValue(timeValue_)
|
||||
.endFieldData();
|
||||
}
|
||||
|
||||
format().endVTKFile();
|
||||
|
||||
format.clear();
|
||||
os_.close();
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
342
src/fileFormats/vtk/file/foamVtmWriter.H
Normal file
342
src/fileFormats/vtk/file/foamVtmWriter.H
Normal file
@ -0,0 +1,342 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / 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::vtmWriter
|
||||
|
||||
Description
|
||||
Provides a means of accumulating file entries for generating
|
||||
a vtkMultiBlockDataSet (.vtm) file.
|
||||
|
||||
For example, to generate the following content:
|
||||
\verbatim
|
||||
<?xml version='1.0'?>
|
||||
<VTKFile type='vtkMultiBlockDataSet' ...>
|
||||
<vtkMultiBlockDataSet>
|
||||
<DataSet name='internal' file='internal.vtu' />
|
||||
<Block name='boundary'>
|
||||
<DataSet name='inlet' file='boundary/inlet.vtp' />
|
||||
<DataSet name='outlet' file='boundary/outlet.vtp' />
|
||||
</Block>
|
||||
</vtkMultiBlockDataSet>
|
||||
<FieldData>
|
||||
<DataArray type='Float32' Name='TimeValue' ...>
|
||||
12.345
|
||||
</DataArray>
|
||||
</FieldData>
|
||||
</VTKFile>
|
||||
\endverbatim
|
||||
|
||||
The following code would be used:
|
||||
\code
|
||||
vtm.clear();
|
||||
vtm.setTime(12.345);
|
||||
|
||||
vtm.append("internal", "internal.vtu");
|
||||
|
||||
vtm.beginBlock("boundary");
|
||||
vtm.append("boundary/inlet.vtp");
|
||||
vtm.append("boundary/outlet.vtp");
|
||||
|
||||
vtm.write("outputName");
|
||||
\endcode
|
||||
|
||||
SourceFiles
|
||||
foamVtmWriter.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef foamVtmWriter_H
|
||||
#define foamVtmWriter_H
|
||||
|
||||
#include "foamVtkOutputOptions.H"
|
||||
#include "DynamicList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
class Time;
|
||||
|
||||
namespace vtk
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class vtk::vtmWriter Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class vtmWriter
|
||||
{
|
||||
//- Simple structure for containing entries
|
||||
struct vtmEntry
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
NONE = 0,
|
||||
DATA = 'D',
|
||||
BEGIN_BLOCK = '{',
|
||||
END_BLOCK = '}'
|
||||
};
|
||||
|
||||
//- The entry type
|
||||
int type_;
|
||||
|
||||
//- The 'name' entry (to describe block or data)
|
||||
string name_;
|
||||
|
||||
//- The 'file' entry (data only)
|
||||
fileName file_;
|
||||
|
||||
// Constructors
|
||||
|
||||
vtmEntry(const vtmEntry&) = default;
|
||||
vtmEntry(vtmEntry&&) = default;
|
||||
vtmEntry& operator=(const vtmEntry&) = default;
|
||||
vtmEntry& operator=(vtmEntry&&) = default;
|
||||
|
||||
//- Construct null
|
||||
vtmEntry()
|
||||
:
|
||||
type_(NONE)
|
||||
{}
|
||||
|
||||
//- Construct from components
|
||||
vtmEntry(int what, const string& name, const fileName& file)
|
||||
:
|
||||
type_(what), name_(name), file_(file)
|
||||
{}
|
||||
|
||||
|
||||
// Factory Methods
|
||||
|
||||
static vtmEntry block(const string& name)
|
||||
{
|
||||
return vtmEntry(BEGIN_BLOCK, name, "");
|
||||
}
|
||||
|
||||
static vtmEntry endblock()
|
||||
{
|
||||
return vtmEntry(END_BLOCK, "", "");
|
||||
}
|
||||
|
||||
static vtmEntry entry(const fileName& file)
|
||||
{
|
||||
return vtmEntry(DATA, "", file);
|
||||
}
|
||||
|
||||
static vtmEntry entry(const string& name, const fileName& file)
|
||||
{
|
||||
return vtmEntry(DATA, name, file);
|
||||
}
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Test the type
|
||||
bool isType(Type what) const
|
||||
{
|
||||
return type_ == what;
|
||||
}
|
||||
|
||||
//- Reset to NONE
|
||||
void clear();
|
||||
|
||||
//- True if the entry is good.
|
||||
bool good() const;
|
||||
|
||||
//- Output valid entry as XML
|
||||
bool write(vtk::formatter& format) const;
|
||||
};
|
||||
|
||||
|
||||
// Private Member Data
|
||||
|
||||
//- Auto-generate names from 'file' entry?
|
||||
bool autoName_;
|
||||
|
||||
//- Collapse empty blocks and combine block/dataset etc.
|
||||
bool autoCollapse_;
|
||||
|
||||
//- Has a TimeValue for FieldData?
|
||||
bool hasTime_;
|
||||
|
||||
//- A vtm file entry: begin/end block, dataset
|
||||
DynamicList<vtmEntry> entries_;
|
||||
|
||||
//- LIFO stack of current block names
|
||||
DynamicList<word> blocks_;
|
||||
|
||||
//- TimeValue for FieldData
|
||||
scalar timeValue_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Remove NONE entries
|
||||
bool pruneEmpty();
|
||||
|
||||
//- Remove empty blocks
|
||||
bool pruneEmptyBlocks();
|
||||
|
||||
//- Collapse block if it has a single dataset and the names allow it
|
||||
bool collapseBlocks();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null, with autoName on
|
||||
vtmWriter();
|
||||
|
||||
//- Construct with specified behaviour for autoName
|
||||
explicit vtmWriter(bool autoName);
|
||||
|
||||
//- Construct with specified behaviour for autoName, autoCollapse
|
||||
vtmWriter(bool autoName, bool autoCollapse);
|
||||
|
||||
|
||||
//- Destructor
|
||||
~vtmWriter() = default;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- File extension (always "vtm")
|
||||
inline static word ext();
|
||||
|
||||
//- If there are no data sets
|
||||
bool empty() const;
|
||||
|
||||
//- The number of data sets
|
||||
label size() const;
|
||||
|
||||
|
||||
// Content Management
|
||||
|
||||
//- Clear all entries and reset output
|
||||
void clear();
|
||||
|
||||
//- Define "TimeValue" for FieldData (name as per Catalyst output)
|
||||
void setTime(scalar timeValue);
|
||||
|
||||
//- Define "TimeValue" for FieldData (name as per Catalyst output)
|
||||
void setTime(const Time& t);
|
||||
|
||||
|
||||
//- Start a new block, optionally with a name
|
||||
// \return block depth
|
||||
label beginBlock(const word& blockName = word::null);
|
||||
|
||||
//- End the previous block, optionally with name checking
|
||||
// \return block depth
|
||||
label endBlock(const word& blockName = word::null);
|
||||
|
||||
|
||||
//- Add a file. The name is either empty or created with autoName
|
||||
// \return True if file is non-empty
|
||||
bool append(const fileName& file);
|
||||
|
||||
//- Add a file with name
|
||||
// \return True if file is non-empty
|
||||
bool append(const word& name, const fileName& file);
|
||||
|
||||
//- Add a file with given contentType extension
|
||||
//- The name is either empty or created with autoName
|
||||
// \return True if file is non-empty
|
||||
bool append(const fileName& file, vtk::fileTag contentType);
|
||||
|
||||
//- Add a file with name, with given contentType extension
|
||||
// \return True if file is non-empty
|
||||
bool append
|
||||
(
|
||||
const word& name,
|
||||
const fileName& file,
|
||||
vtk::fileTag contentType
|
||||
);
|
||||
|
||||
//- Add a (.vtp) file
|
||||
// \return True if file is non-empty
|
||||
inline bool append_vtp(const fileName& file);
|
||||
|
||||
//- Add a (.vtp) file with name
|
||||
// \return True if file is non-empty
|
||||
inline bool append_vtp(const word& name, const fileName& file);
|
||||
|
||||
//- Add a (.vtu) file
|
||||
// \return True if file is non-empty
|
||||
inline bool append_vtu(const fileName& file);
|
||||
|
||||
//- Add a (.vtu) file with name
|
||||
// \return True if file is non-empty
|
||||
inline bool append_vtu(const word& name, const fileName& file);
|
||||
|
||||
|
||||
// Content Management
|
||||
|
||||
//- Sanity fixes on the data
|
||||
void repair(bool collapse=false);
|
||||
|
||||
//- Add in content from another vtm and place under the given block
|
||||
//- name.
|
||||
void add(const word& blockName, const vtmWriter& other);
|
||||
|
||||
//- Add in content from another vtm and place under the given block
|
||||
//- name. Adjust the added 'file' entries to include the given prefix.
|
||||
void add
|
||||
(
|
||||
const word& blockName,
|
||||
const fileName& prefix,
|
||||
const vtmWriter& other
|
||||
);
|
||||
|
||||
// Writing
|
||||
|
||||
//- Open file for writing (creates parent directory) and write the
|
||||
//- blocks and TimeValue.
|
||||
// The file name is with/without an extension.
|
||||
// \return number of data sets
|
||||
label write(const fileName& file);
|
||||
|
||||
//- Print debug view of block and dataset contents
|
||||
void dump(Ostream& os) const;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace vtk
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "foamVtmWriterI.H"
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
66
src/fileFormats/vtk/file/foamVtmWriterI.H
Normal file
66
src/fileFormats/vtk/file/foamVtmWriterI.H
Normal file
@ -0,0 +1,66 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / 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 Foam::word Foam::vtk::vtmWriter::ext()
|
||||
{
|
||||
return vtk::fileExtension[vtk::fileTag::MULTI_BLOCK];
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::vtk::vtmWriter::append_vtp(const fileName& file)
|
||||
{
|
||||
return append(file, vtk::fileTag::POLY_DATA);
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::vtk::vtmWriter::append_vtp
|
||||
(
|
||||
const word& name,
|
||||
const fileName& file
|
||||
)
|
||||
{
|
||||
return append(name, file, vtk::fileTag::POLY_DATA);
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::vtk::vtmWriter::append_vtu(const fileName& file)
|
||||
{
|
||||
return append(file, vtk::fileTag::UNSTRUCTURED_GRID);
|
||||
}
|
||||
|
||||
|
||||
inline bool Foam::vtk::vtmWriter::append_vtu
|
||||
(
|
||||
const word& name,
|
||||
const fileName& file
|
||||
)
|
||||
{
|
||||
return append(name, file, vtk::fileTag::UNSTRUCTURED_GRID);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user