Commit df5edefd authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

added optional directory argument to file writer

parent ba7a8410
#pragma once #pragma once
#include <string> #include <string>
#include <dune/common/std/optional.hh>
namespace Dune namespace Dune
{ {
...@@ -10,8 +11,8 @@ namespace Dune ...@@ -10,8 +11,8 @@ namespace Dune
/// Virtual destructor /// Virtual destructor
virtual ~FileWriter () = default; virtual ~FileWriter () = default;
/// Write to file given by `filename` /// Write to file given by `filename` and (optionally) store additional data in `dataDir`
virtual void write (std::string const& filename) const = 0; virtual void write (std::string const& filename, Std::optional<std::string> dataDir = {}) const = 0;
}; };
} // end namespace Dune } // end namespace Dune
...@@ -34,14 +34,23 @@ namespace Dune ...@@ -34,14 +34,23 @@ namespace Dune
* Create timestep files for the data associated to the current timestep `time`. * Create timestep files for the data associated to the current timestep `time`.
* *
* \param time The time value of the written data * \param time The time value of the written data
* \param fn Filename of the file to write to. Is stored in \ref timesteps_. * \param fn Filename of the PVD file to write to. The base part is used to
* create filenames for the timestep files that are stored in \ref timesteps_.
* May contain directory and any filename extension.
* \param dir Specifies where to write the timestep files.
* \param writeCollection Create a collection .pvd file directly * \param writeCollection Create a collection .pvd file directly
**/ **/
void writeTimestep (double time, std::string const& fn, bool writeCollection = true) const; void writeTimestep (double time, std::string const& fn, Std::optional<std::string> dir = {},
bool writeCollection = true) const;
/// Writes collection of timesteps to .pvd file. /// Writes collection of timesteps to .pvd file.
// NOTE: requires an aforging call to \ref writeTimestep // NOTE: requires an aforging call to \ref writeTimestep
virtual void write (std::string const& fn) const override; /**
* \param fn The filename of the PVD file. May contain directory and any filename extension.
* \param dir (Ignored) Timestep files are already written and their filenames are
* stored in \ref timesteps_.
**/
virtual void write (std::string const& fn, Std::optional<std::string> dir = {}) const override;
/// Attach point data to the writer, \see VtkFunction for possible arguments /// Attach point data to the writer, \see VtkFunction for possible arguments
template <class Function, class... Args> template <class Function, class... Args>
......
...@@ -9,30 +9,32 @@ namespace Dune { ...@@ -9,30 +9,32 @@ namespace Dune {
template <class W> template <class W>
void PvdWriter<W> void PvdWriter<W>
::writeTimestep (double time, std::string const& fn, bool writeCollection) const ::writeTimestep (double time, std::string const& fn, Std::optional<std::string> dir, bool writeCollection) const
{ {
auto p = filesystem::path(fn); auto p = filesystem::path(fn);
auto name = p.stem(); auto name = p.stem();
p.remove_filename(); p.remove_filename();
p /= name.string();
filesystem::path fn_dir = p;
filesystem::path data_dir = dir ? filesystem::path(*dir) : fn_dir;
filesystem::path rel_dir = filesystem::relative(data_dir, fn_dir);
std::string pvd_fn = fn_dir.string() + '/' + name.string();
std::string seq_fn = data_dir.string() + '/' + name.string() + "_t" + std::to_string(timesteps_.size());
std::string rel_fn = rel_dir.string() + '/' + name.string() + "_t" + std::to_string(timesteps_.size());
std::string ext = "." + vtkWriter_.getFileExtension(); std::string ext = "." + vtkWriter_.getFileExtension();
std::string filename = p.string() + "_t" + std::to_string(timesteps_.size());
int rank = vtkWriter_.rank_;
int rank = 0; int numRanks = vtkWriter_.numRanks_;
int num_ranks = 1; if (numRanks > 1)
#ifdef HAVE_MPI
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
if (num_ranks > 1)
ext = ".p" + vtkWriter_.getFileExtension(); ext = ".p" + vtkWriter_.getFileExtension();
#endif
timesteps_.emplace_back(time, filename + ext); timesteps_.emplace_back(time, rel_fn + ext);
vtkWriter_.write(filename + ext); vtkWriter_.write(seq_fn + ext);
if (rank == 0 && writeCollection) { if (rank == 0 && writeCollection) {
std::ofstream out(p.string() + ".pvd", std::ios_base::ate | std::ios::binary); std::ofstream out(pvd_fn + ".pvd", std::ios_base::ate | std::ios::binary);
assert(out.is_open()); assert(out.is_open());
out.imbue(std::locale::classic()); out.imbue(std::locale::classic());
...@@ -47,20 +49,14 @@ void PvdWriter<W> ...@@ -47,20 +49,14 @@ void PvdWriter<W>
template <class W> template <class W>
void PvdWriter<W> void PvdWriter<W>
::write (std::string const& fn) const ::write (std::string const& fn, Std::optional<std::string> /*dir*/) const
{ {
auto p = filesystem::path(fn); auto p = filesystem::path(fn);
auto name = p.stem(); auto name = p.stem();
p.remove_filename(); p.remove_filename();
p /= name.string(); p /= name.string();
int rank = 0; int rank = vtkWriter_.rank_;
int num_ranks = 1;
#ifdef HAVE_MPI
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
#endif
if (rank == 0) { if (rank == 0) {
std::ofstream out(p.string() + ".pvd", std::ios_base::ate | std::ios::binary); std::ofstream out(p.string() + ".pvd", std::ios_base::ate | std::ios::binary);
assert(out.is_open()); assert(out.is_open());
......
...@@ -58,16 +58,22 @@ namespace Dune ...@@ -58,16 +58,22 @@ namespace Dune
* \param fn Filename of the file to write to. Only the base part * \param fn Filename of the file to write to. Only the base part
* (without dir and extentsion) is used to write the intermediate * (without dir and extentsion) is used to write the intermediate
* file into a tmp directory. * file into a tmp directory.
* \param tmpDir If the directory is given, it is used as tmp dir, otherwise /tmp.
* \param writeCollection Create a timeseries file directly * \param writeCollection Create a timeseries file directly
**/ **/
void writeTimestep (double time, std::string const& fn, bool writeCollection = true) const; void writeTimestep (double time, std::string const& fn,
Std::optional<std::string> tmpDir = {},
bool writeCollection = true) const;
/// Writes all timesteps to single timeseries file. /// Writes all timesteps to single timeseries file.
// NOTE: requires an aforging call to \ref writeTimestep // NOTE: requires an aforging call to \ref writeTimestep
/** /**
* Create a timeseries file with all timesteps written by \ref writeTimestep. * Create a timeseries file with all timesteps written by \ref writeTimestep.
*
* \param fn Filename of the Timeseries file. May contain a directory and any file extension.
* \param dir The optional parameter specifies the directory of the partition files.
**/ **/
virtual void write (std::string const& fn) const override; virtual void write (std::string const& fn, Std::optional<std::string> dir = {}) const override;
/// Attach point data to the writer, \see VtkFunction for possible arguments /// Attach point data to the writer, \see VtkFunction for possible arguments
template <class Function, class... Args> template <class Function, class... Args>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#ifdef HAVE_ZLIB #if HAVE_ZLIB
#include <zlib.h> #include <zlib.h>
#endif #endif
...@@ -39,24 +39,20 @@ VtkTimeseriesWriter<W>::~VtkTimeseriesWriter () ...@@ -39,24 +39,20 @@ VtkTimeseriesWriter<W>::~VtkTimeseriesWriter ()
template <class W> template <class W>
void VtkTimeseriesWriter<W> void VtkTimeseriesWriter<W>
::writeTimestep (double time, std::string const& fn, bool writeCollection) const ::writeTimestep (double time, std::string const& fn, Std::optional<std::string> tmpDir, bool writeCollection) const
{ {
auto name = filesystem::path(fn).stem(); auto name = filesystem::path(fn).stem();
auto tmp = tmpDir_; auto tmp = tmpDir ? filesystem::path(*tmpDir) : tmpDir_;
tmp /= name.string(); tmp /= name.string();
vtkWriter_.dataCollector_.update(); vtkWriter_.dataCollector_.update();
std::string filenameBase = tmp.string(); std::string filenameBase = tmp.string();
int rank = 0; int rank = vtkWriter_.rank_;
int num_ranks = 1; int numRanks = vtkWriter_.numRanks_;
#ifdef HAVE_MPI if (numRanks > 1)
MPI_Comm_rank(MPI_COMM_WORLD, &rank); filenameBase = tmp.string() + "_p" + std::to_string(rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
if (num_ranks > 1)
filenameBase = tmp.string() + "_p" + std::to_string(rank);
#endif
if (!initialized_) { if (!initialized_) {
// write points and cells only once // write points and cells only once
...@@ -78,28 +74,29 @@ void VtkTimeseriesWriter<W> ...@@ -78,28 +74,29 @@ void VtkTimeseriesWriter<W>
template <class W> template <class W>
void VtkTimeseriesWriter<W> void VtkTimeseriesWriter<W>
::write (std::string const& fn) const ::write (std::string const& fn, Std::optional<std::string> dir) const
{ {
assert( initialized_ ); assert( initialized_ );
auto p = filesystem::path(fn); auto p = filesystem::path(fn);
auto name = p.stem(); auto name = p.stem();
p.remove_filename(); p.remove_filename();
p /= name.string();
std::string filename = p.string() + "_ts"; filesystem::path fn_dir = p;
filesystem::path data_dir = dir ? filesystem::path(*dir) : fn_dir;
filesystem::path rel_dir = filesystem::relative(data_dir, fn_dir);
int rank = 0; std::string serial_fn = fn_dir.string() + '/' + name.string() + "_ts";
int num_ranks = 1; std::string parallel_fn = data_dir.string() + '/' + name.string() + "_ts";
#ifdef HAVE_MPI std::string rel_fn = rel_dir.string() + '/' + name.string() + "_ts";
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); int rank = vtkWriter_.rank_;
if (num_ranks > 1) int numRanks = vtkWriter_.numRanks_;
filename = p.string() + "_ts_p" + std::to_string(rank); if (numRanks > 1)
#endif serial_fn += "_p" + std::to_string(rank);
{ // write serial file { // write serial file
std::ofstream serial_out(filename + "." + vtkWriter_.getFileExtension(), std::ofstream serial_out(serial_fn + "." + vtkWriter_.getFileExtension(),
std::ios_base::ate | std::ios::binary); std::ios_base::ate | std::ios::binary);
assert(serial_out.is_open()); assert(serial_out.is_open());
...@@ -111,10 +108,9 @@ void VtkTimeseriesWriter<W> ...@@ -111,10 +108,9 @@ void VtkTimeseriesWriter<W>
vtkWriter_.writeTimeseriesSerialFile(serial_out, filenameMesh_, timesteps_, blocks_); vtkWriter_.writeTimeseriesSerialFile(serial_out, filenameMesh_, timesteps_, blocks_);
} }
#ifdef HAVE_MPI if (numRanks > 1 && rank == 0) {
if (num_ranks > 1 && rank == 0) {
// write parallel file // write parallel file
std::ofstream parallel_out(p.string() + "_ts.p" + vtkWriter_.getFileExtension(), std::ofstream parallel_out(parallel_fn + ".p" + vtkWriter_.getFileExtension(),
std::ios_base::ate | std::ios::binary); std::ios_base::ate | std::ios::binary);
assert(parallel_out.is_open()); assert(parallel_out.is_open());
...@@ -123,9 +119,8 @@ void VtkTimeseriesWriter<W> ...@@ -123,9 +119,8 @@ void VtkTimeseriesWriter<W>
? std::numeric_limits<float>::digits10+2 ? std::numeric_limits<float>::digits10+2
: std::numeric_limits<double>::digits10+2); : std::numeric_limits<double>::digits10+2);
vtkWriter_.writeTimeseriesParallelFile(parallel_out, p.string() + "_ts", num_ranks, timesteps_); vtkWriter_.writeTimeseriesParallelFile(parallel_out, rel_fn, numRanks, timesteps_);
} }
#endif
} }
} // end namespace Dune } // end namespace Dune
...@@ -44,10 +44,12 @@ namespace Dune ...@@ -44,10 +44,12 @@ namespace Dune
Vtk::FormatTypes format = Vtk::BINARY, Vtk::FormatTypes format = Vtk::BINARY,
Vtk::DataTypes datatype = Vtk::FLOAT32) Vtk::DataTypes datatype = Vtk::FLOAT32)
: dataCollector_(gridView) : dataCollector_(gridView)
, rank_(gridView.comm().rank())
, numRanks_(gridView.comm().size())
, format_(format) , format_(format)
, datatype_(datatype) , datatype_(datatype)
{ {
#ifndef HAVE_ZLIB #if !HAVE_ZLIB
if (format_ == Vtk::COMPRESSED) { if (format_ == Vtk::COMPRESSED) {
std::cout << "Dune is compiled without compression. Falling back to BINARY VTK output!\n"; std::cout << "Dune is compiled without compression. Falling back to BINARY VTK output!\n";
format_ = Vtk::BINARY; format_ = Vtk::BINARY;
...@@ -56,7 +58,11 @@ namespace Dune ...@@ -56,7 +58,11 @@ namespace Dune
} }
/// Write the attached data to the file /// Write the attached data to the file
virtual void write (std::string const& fn) const override; /**
* \param fn Filename of the VTK file. May contain a directory and any file extension.
* \param dir The optional parameter specifies the directory of the partition files.
**/
virtual void write (std::string const& fn, Std::optional<std::string> dir = {}) const override;
/// Attach point data to the writer, \see VtkFunction for possible arguments /// Attach point data to the writer, \see VtkFunction for possible arguments
template <class Function, class... Args> template <class Function, class... Args>
...@@ -151,6 +157,10 @@ namespace Dune ...@@ -151,6 +157,10 @@ namespace Dune
protected: protected:
mutable DataCollector dataCollector_; mutable DataCollector dataCollector_;
// the rank and size of the gridView collective communication
int rank_ = 0;
int numRanks_ = 1;
Vtk::FormatTypes format_; Vtk::FormatTypes format_;
Vtk::DataTypes datatype_; Vtk::DataTypes datatype_;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#ifdef HAVE_ZLIB #if HAVE_ZLIB
#include <zlib.h> #include <zlib.h>
#endif #endif
...@@ -23,29 +23,27 @@ namespace Dune { ...@@ -23,29 +23,27 @@ namespace Dune {
template <class GV, class DC> template <class GV, class DC>
void VtkWriterInterface<GV,DC> void VtkWriterInterface<GV,DC>
::write (std::string const& fn) const ::write (std::string const& fn, Std::optional<std::string> dir) const
{ {
dataCollector_.update(); dataCollector_.update();
auto p = filesystem::path(fn); auto p = filesystem::path(fn);
auto name = p.stem(); auto name = p.stem();
p.remove_filename(); p.remove_filename();
p /= name.string();
std::string filename = p.string(); filesystem::path fn_dir = p;
filesystem::path data_dir = dir ? filesystem::path(*dir) : fn_dir;
filesystem::path rel_dir = filesystem::relative(data_dir, fn_dir);
int rank = 0; std::string serial_fn = fn_dir.string() + '/' + name.string();
int num_ranks = 1; std::string parallel_fn = data_dir.string() + '/' + name.string();
std::string rel_fn = rel_dir.string() + '/' + name.string();
#ifdef HAVE_MPI if (numRanks_ > 1)
MPI_Comm_rank(MPI_COMM_WORLD, &rank); serial_fn += "_p" + std::to_string(rank_);
MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
if (num_ranks > 1)
filename = p.string() + "_p" + std::to_string(rank);
#endif
{ // write serial file { // write serial file
std::ofstream serial_out(filename + "." + fileExtension(), std::ios_base::ate | std::ios::binary); std::ofstream serial_out(serial_fn + "." + fileExtension(), std::ios_base::ate | std::ios::binary);
assert(serial_out.is_open()); assert(serial_out.is_open());
serial_out.imbue(std::locale::classic()); serial_out.imbue(std::locale::classic());
...@@ -56,10 +54,9 @@ void VtkWriterInterface<GV,DC> ...@@ -56,10 +54,9 @@ void VtkWriterInterface<GV,DC>
writeSerialFile(serial_out); writeSerialFile(serial_out);
} }
#ifdef HAVE_MPI if (numRanks_ > 1 && rank_ == 0) {
if (num_ranks > 1 && rank == 0) {
// write parallel file // write parallel file
std::ofstream parallel_out(p.string() + ".p" + fileExtension(), std::ios_base::ate | std::ios::binary); std::ofstream parallel_out(parallel_fn + ".p" + fileExtension(), std::ios_base::ate | std::ios::binary);
assert(parallel_out.is_open()); assert(parallel_out.is_open());
parallel_out.imbue(std::locale::classic()); parallel_out.imbue(std::locale::classic());
...@@ -67,9 +64,8 @@ void VtkWriterInterface<GV,DC> ...@@ -67,9 +64,8 @@ void VtkWriterInterface<GV,DC>
? std::numeric_limits<float>::digits10+2 ? std::numeric_limits<float>::digits10+2
: std::numeric_limits<double>::digits10+2); : std::numeric_limits<double>::digits10+2);
writeParallelFile(parallel_out, p.string(), num_ranks); writeParallelFile(parallel_out, rel_fn, numRanks_);
} }
#endif
} }
...@@ -220,7 +216,7 @@ template <class OStream> ...@@ -220,7 +216,7 @@ template <class OStream>
std::uint64_t writeCompressed (unsigned char const* buffer, unsigned char* buffer_out, std::uint64_t writeCompressed (unsigned char const* buffer, unsigned char* buffer_out,
std::uint64_t bs, std::uint64_t cbs, int level, OStream& outb) std::uint64_t bs, std::uint64_t cbs, int level, OStream& outb)
{ {
#ifdef HAVE_ZLIB #if HAVE_ZLIB
uLongf uncompressed_space = uLongf(bs); uLongf uncompressed_space = uLongf(bs);
uLongf compressed_space = uLongf(cbs); uLongf compressed_space = uLongf(cbs);
......
...@@ -34,7 +34,7 @@ void write (std::string prefix, GridView const& gridView) ...@@ -34,7 +34,7 @@ void write (std::string prefix, GridView const& gridView)
seriesWriter.addCellData(p1Analytic, "q0"); seriesWriter.addCellData(p1Analytic, "q0");
std::string filename = prefix + "_" + std::to_string(GridView::dimensionworld) + "d_binary32.vtu"; std::string filename = prefix + "_" + std::to_string(GridView::dimensionworld) + "d_binary32.vtu";
for (double t = 0.0; t < 5; t += 0.5) { for (double t = 0.0; t < 5; t += 0.5) {
seriesWriter.writeTimestep(t, filename, false); seriesWriter.writeTimestep(t, filename, {}, false);
shift += 0.25; shift += 0.25;
} }
seriesWriter.write(filename); seriesWriter.write(filename);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment