diff --git a/dune/vtk/filewriter.hh b/dune/vtk/filewriter.hh index 217c79488900051f03aeda8967bed3792d9b4990..8873e75644fffecabdb1fc4b20026d8943c7e4ae 100644 --- a/dune/vtk/filewriter.hh +++ b/dune/vtk/filewriter.hh @@ -1,6 +1,7 @@ #pragma once #include <string> +#include <dune/common/std/optional.hh> namespace Dune { @@ -10,8 +11,8 @@ namespace Dune /// Virtual destructor virtual ~FileWriter () = default; - /// Write to file given by `filename` - virtual void write (std::string const& filename) const = 0; + /// Write to file given by `filename` and (optionally) store additional data in `dataDir` + virtual void write (std::string const& filename, Std::optional<std::string> dataDir = {}) const = 0; }; } // end namespace Dune diff --git a/dune/vtk/pvdwriter.hh b/dune/vtk/pvdwriter.hh index 919cab9b54d417a392cf197dcef053f336a5bb69..46343bd01d10381c5b30da2379958de38f8f6ac8 100644 --- a/dune/vtk/pvdwriter.hh +++ b/dune/vtk/pvdwriter.hh @@ -34,14 +34,23 @@ namespace Dune * Create timestep files for the data associated to the current timestep `time`. * * \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 **/ - 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. // 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 template <class Function, class... Args> diff --git a/dune/vtk/pvdwriter.impl.hh b/dune/vtk/pvdwriter.impl.hh index ddafacc260e2757b4c022f8c17374767ae1da2af..8841309fe1fab4cf32b65e6768d139f5873f141d 100644 --- a/dune/vtk/pvdwriter.impl.hh +++ b/dune/vtk/pvdwriter.impl.hh @@ -9,30 +9,32 @@ namespace Dune { template <class 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 name = p.stem(); 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 filename = p.string() + "_t" + std::to_string(timesteps_.size()); - - int rank = 0; - int num_ranks = 1; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); - if (num_ranks > 1) + + int rank = vtkWriter_.rank_; + int numRanks = vtkWriter_.numRanks_; + if (numRanks > 1) ext = ".p" + vtkWriter_.getFileExtension(); -#endif - timesteps_.emplace_back(time, filename + ext); - vtkWriter_.write(filename + ext); + timesteps_.emplace_back(time, rel_fn + ext); + vtkWriter_.write(seq_fn + ext); 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()); out.imbue(std::locale::classic()); @@ -47,20 +49,14 @@ void PvdWriter<W> template <class 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 name = p.stem(); p.remove_filename(); p /= name.string(); - int rank = 0; - int num_ranks = 1; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); -#endif - + int rank = vtkWriter_.rank_; if (rank == 0) { std::ofstream out(p.string() + ".pvd", std::ios_base::ate | std::ios::binary); assert(out.is_open()); diff --git a/dune/vtk/vtktimeserieswriter.hh b/dune/vtk/vtktimeserieswriter.hh index a329f528cfdf0e0659fae069acf960df1f41124f..587467731857c948eeb8b2b9c69ee83c15b38402 100644 --- a/dune/vtk/vtktimeserieswriter.hh +++ b/dune/vtk/vtktimeserieswriter.hh @@ -58,16 +58,22 @@ namespace Dune * \param fn Filename of the file to write to. Only the base part * (without dir and extentsion) is used to write the intermediate * 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 **/ - 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. // NOTE: requires an aforging call to \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 template <class Function, class... Args> diff --git a/dune/vtk/vtktimeserieswriter.impl.hh b/dune/vtk/vtktimeserieswriter.impl.hh index b51ad6368c026b7db6f1f49bb451a2c69324750f..fb7d76266c457867023c462286358845b9b0ce57 100644 --- a/dune/vtk/vtktimeserieswriter.impl.hh +++ b/dune/vtk/vtktimeserieswriter.impl.hh @@ -9,7 +9,7 @@ #include <sstream> #include <string> -#ifdef HAVE_ZLIB +#if HAVE_ZLIB #include <zlib.h> #endif @@ -39,24 +39,20 @@ VtkTimeseriesWriter<W>::~VtkTimeseriesWriter () template <class 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 tmp = tmpDir_; + auto tmp = tmpDir ? filesystem::path(*tmpDir) : tmpDir_; tmp /= name.string(); vtkWriter_.dataCollector_.update(); std::string filenameBase = tmp.string(); - int rank = 0; - int num_ranks = 1; - #ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); - if (num_ranks > 1) - filenameBase = tmp.string() + "_p" + std::to_string(rank); - #endif + int rank = vtkWriter_.rank_; + int numRanks = vtkWriter_.numRanks_; + if (numRanks > 1) + filenameBase = tmp.string() + "_p" + std::to_string(rank); if (!initialized_) { // write points and cells only once @@ -78,28 +74,29 @@ void VtkTimeseriesWriter<W> template <class W> void VtkTimeseriesWriter<W> - ::write (std::string const& fn) const + ::write (std::string const& fn, Std::optional<std::string> dir) const { assert( initialized_ ); auto p = filesystem::path(fn); auto name = p.stem(); 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; - int num_ranks = 1; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); - if (num_ranks > 1) - filename = p.string() + "_ts_p" + std::to_string(rank); -#endif + std::string serial_fn = fn_dir.string() + '/' + name.string() + "_ts"; + std::string parallel_fn = data_dir.string() + '/' + name.string() + "_ts"; + std::string rel_fn = rel_dir.string() + '/' + name.string() + "_ts"; + + int rank = vtkWriter_.rank_; + int numRanks = vtkWriter_.numRanks_; + if (numRanks > 1) + serial_fn += "_p" + std::to_string(rank); { // 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); assert(serial_out.is_open()); @@ -111,10 +108,9 @@ void VtkTimeseriesWriter<W> vtkWriter_.writeTimeseriesSerialFile(serial_out, filenameMesh_, timesteps_, blocks_); } -#ifdef HAVE_MPI - if (num_ranks > 1 && rank == 0) { + if (numRanks > 1 && rank == 0) { // 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); assert(parallel_out.is_open()); @@ -123,9 +119,8 @@ void VtkTimeseriesWriter<W> ? std::numeric_limits<float>::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 diff --git a/dune/vtk/vtkwriterinterface.hh b/dune/vtk/vtkwriterinterface.hh index 9f1b3866704c1e025c414b4e9e29629ad91511b1..ca63534bdd6f7986541af6f50fa1383ba816a0e5 100644 --- a/dune/vtk/vtkwriterinterface.hh +++ b/dune/vtk/vtkwriterinterface.hh @@ -44,10 +44,12 @@ namespace Dune Vtk::FormatTypes format = Vtk::BINARY, Vtk::DataTypes datatype = Vtk::FLOAT32) : dataCollector_(gridView) + , rank_(gridView.comm().rank()) + , numRanks_(gridView.comm().size()) , format_(format) , datatype_(datatype) { -#ifndef HAVE_ZLIB +#if !HAVE_ZLIB if (format_ == Vtk::COMPRESSED) { std::cout << "Dune is compiled without compression. Falling back to BINARY VTK output!\n"; format_ = Vtk::BINARY; @@ -56,7 +58,11 @@ namespace Dune } /// 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 template <class Function, class... Args> @@ -151,6 +157,10 @@ namespace Dune protected: mutable DataCollector dataCollector_; + // the rank and size of the gridView collective communication + int rank_ = 0; + int numRanks_ = 1; + Vtk::FormatTypes format_; Vtk::DataTypes datatype_; diff --git a/dune/vtk/vtkwriterinterface.impl.hh b/dune/vtk/vtkwriterinterface.impl.hh index e5ed55f6ab56628cf23bf85a72c3adcb072d4f5c..ce08aa8af8a746451569b3511350d0dfecb07aa2 100644 --- a/dune/vtk/vtkwriterinterface.impl.hh +++ b/dune/vtk/vtkwriterinterface.impl.hh @@ -8,7 +8,7 @@ #include <sstream> #include <string> -#ifdef HAVE_ZLIB +#if HAVE_ZLIB #include <zlib.h> #endif @@ -23,29 +23,27 @@ namespace Dune { template <class GV, class DC> void VtkWriterInterface<GV,DC> - ::write (std::string const& fn) const + ::write (std::string const& fn, Std::optional<std::string> dir) const { dataCollector_.update(); auto p = filesystem::path(fn); auto name = p.stem(); 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; - int num_ranks = 1; + std::string serial_fn = fn_dir.string() + '/' + name.string(); + std::string parallel_fn = data_dir.string() + '/' + name.string(); + std::string rel_fn = rel_dir.string() + '/' + name.string(); -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); - if (num_ranks > 1) - filename = p.string() + "_p" + std::to_string(rank); -#endif + if (numRanks_ > 1) + serial_fn += "_p" + std::to_string(rank_); { // 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()); serial_out.imbue(std::locale::classic()); @@ -56,10 +54,9 @@ void VtkWriterInterface<GV,DC> writeSerialFile(serial_out); } -#ifdef HAVE_MPI - if (num_ranks > 1 && rank == 0) { + if (numRanks_ > 1 && rank_ == 0) { // 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()); parallel_out.imbue(std::locale::classic()); @@ -67,9 +64,8 @@ void VtkWriterInterface<GV,DC> ? std::numeric_limits<float>::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> std::uint64_t writeCompressed (unsigned char const* buffer, unsigned char* buffer_out, std::uint64_t bs, std::uint64_t cbs, int level, OStream& outb) { -#ifdef HAVE_ZLIB +#if HAVE_ZLIB uLongf uncompressed_space = uLongf(bs); uLongf compressed_space = uLongf(cbs); diff --git a/src/timeserieswriter.cc b/src/timeserieswriter.cc index 73282db04c076fcf683e7e75da894a4b743416ae..e8ac785add8f210d0f31b5847aee33f6e70662c5 100644 --- a/src/timeserieswriter.cc +++ b/src/timeserieswriter.cc @@ -34,7 +34,7 @@ void write (std::string prefix, GridView const& gridView) seriesWriter.addCellData(p1Analytic, "q0"); std::string filename = prefix + "_" + std::to_string(GridView::dimensionworld) + "d_binary32.vtu"; for (double t = 0.0; t < 5; t += 0.5) { - seriesWriter.writeTimestep(t, filename, false); + seriesWriter.writeTimestep(t, filename, {}, false); shift += 0.25; } seriesWriter.write(filename);