diff --git a/dune/vtk/pvdwriter.hh b/dune/vtk/pvdwriter.hh new file mode 100644 index 0000000000000000000000000000000000000000..2d0b5d8e46ec487f147bfaab88272a9461281d74 --- /dev/null +++ b/dune/vtk/pvdwriter.hh @@ -0,0 +1,69 @@ +#pragma once + +#include <iosfwd> +#include <string> +#include <vector> +#include <tuple> + +#include <dune/vtk/vtktypes.hh> +#include <dune/vtk/vtkwriterinterface.hh> + +namespace Dune +{ + /// File-Writer for ParaView .pvd files + template <class VtkWriter> + class PvdWriter + { + using Self = PvdWriter; + + static_assert(IsVtkWriter<VtkWriter>::value, "Writer must implement the VtkWriterInterface."); + + public: + /// Constructor, creates a VtkWriter with constructor arguments forwarded + template <class... Args, disableCopyMove<Self,Args...> = 0> + explicit PvdWriter (Args&&... args) + : vtkWriter_{std::forward<Args>(args)...} + {} + + /// Write the attached data to the file + void write (double time, std::string const& fn) + { + write(time, fn, Vtk::BINARY); + } + + /// Write the attached data to the file with \ref Vtk::FormatTypes and \ref Vtk::DataTypes + void write (double time, + std::string const& fn, + Vtk::FormatTypes format, + Vtk::DataTypes datatype = Vtk::FLOAT32); + + /// Attach point data to the writer, \see VtkFunction for possible arguments + template <class Function, class... Args> + PvdWriter& addPointData (Function const& fct, Args&&... args) + { + vtkWriter_.addPointData(fct, std::forward<Args>(args)...); + return *this; + } + + /// Attach cell data to the writer, \see VtkFunction for possible arguments + template <class Function, class... Args> + PvdWriter& addCellData (Function const& fct, Args&&... args) + { + vtkWriter_.addCellData(fct, std::forward<Args>(args)...); + return *this; + } + + protected: + /// Write a series of vtk files in a .pvd ParaView Data file + void writeFile (double time, std::string const& filename) const; + + protected: + VtkWriter vtkWriter_; + std::vector<std::pair<double, std::string>> timeSeries_; + Vtk::FormatTypes format_; + Vtk::DataTypes datatype_; + }; + +} // end namespace Dune + +#include "pvdwriter.impl.hh" diff --git a/dune/vtk/pvdwriter.impl.hh b/dune/vtk/pvdwriter.impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..5c1a528cdb6a0c01fe64e3d502c000a44eb05496 --- /dev/null +++ b/dune/vtk/pvdwriter.impl.hh @@ -0,0 +1,82 @@ +#pragma once + +#include <iomanip> + +#include <dune/vtk/utility/filesystem.hh> +#include <dune/vtk/utility/string.hh> + +namespace Dune { + +template <class W> +void PvdWriter<W> + ::write (double time, std::string const& fn, Vtk::FormatTypes format, Vtk::DataTypes datatype) +{ + format_ = format; + datatype_ = datatype; + +#ifndef HAVE_ZLIB + if (format_ == Vtk::COMPRESSED) + format_ = Vtk::BINARY; +#endif + + auto p = filesystem::path(fn); + auto name = p.stem(); + p.remove_filename(); + p /= name.string(); + + std::string ext = "." + vtkWriter_.getFileExtension(); + std::string filename = p.string() + "_t" + std::to_string(timeSeries_.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) + ext = ".p" + vtkWriter_.getFileExtension(); +#endif + + timeSeries_.emplace_back(time, filename + ext); + vtkWriter_.write(filename + ext, format_, datatype_); + + if (rank == 0) + writeFile(time, p.string() + ".pvd"); +} + + +template <class W> +void PvdWriter<W> + ::writeFile (double time, std::string const& filename) const +{ + std::ofstream out(filename, std::ios_base::ate | std::ios::binary); + assert(out.is_open()); + + if (datatype_ == Vtk::FLOAT32) + out << std::setprecision(std::numeric_limits<float>::digits10+2); + else + out << std::setprecision(std::numeric_limits<double>::digits10+2); + + out << "<?xml version=\"1.0\"?>\n"; + out << "<VTKFile" + << " type=\"Collection\"" + << " version=\"0.1\"" + << (format_ != Vtk::ASCII ? " byte_order=\"" + vtkWriter_.getEndian() + "\"" : "") + << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "") + << ">\n"; + + out << "<Collection>\n"; + + // Write all timesteps + for (auto const& timestep : timeSeries_) { + out << "<DataSet" + << " timestep=\"" << timestep.first << "\"" + << " part=\"0\"" + << " file=\"" << timestep.second << "\"" + << " />\n"; + } + + out << "</Collection>\n"; + out << "</VTKFile>"; +} + +} // end namespace Dune diff --git a/dune/vtk/vtkwriterinterface.hh b/dune/vtk/vtkwriterinterface.hh index d5ae604fe58169ef75cbb228b2810e880da69bf6..4bd647589a9fabe8212f498a60fd46d9753e598a 100644 --- a/dune/vtk/vtkwriterinterface.hh +++ b/dune/vtk/vtkwriterinterface.hh @@ -5,12 +5,15 @@ #include <string> #include <vector> +<<<<<<< HEAD #ifdef HAVE_ZLIB #include <zlib.h> #endif #include <dune/common/std/optional.hh> +======= +>>>>>>> feature/pvdwriter #include <dune/vtk/filewriter.hh> #include <dune/vtk/vtkfunction.hh> #include <dune/vtk/vtktypes.hh> @@ -21,12 +24,16 @@ namespace Dune template <class VtkWriter> class VtkTimeseriesWriter; - /// File-Writer for Vtk .vtu files + template <class VtkWriter> + class PvdWriter; + + /// Interface for file writers for the Vtk XML file formats template <class GridView, class DataCollector> class VtkWriterInterface : public FileWriter { template <class> friend class VtkTimeseriesWriter; + template <class> friend class PvdWriter; protected: static constexpr int dimension = GridView::dimension; @@ -75,7 +82,7 @@ namespace Dune return *this; } - protected: + private: /// Write a serial VTK file in Unstructured format virtual void writeSerialFile (std::string const& filename) const = 0; @@ -90,6 +97,7 @@ namespace Dune /// Write points and cells in raw/compressed format to output stream virtual void writeGridAppended (std::ofstream& out, std::vector<std::uint64_t>& blocks) const = 0; + protected: // Write the point or cell values given by the grid function `fct` to the // output stream `out`. In case of binary format, stores the streampos of XML // attributes "offset" in the vector `offsets`. @@ -127,6 +135,7 @@ namespace Dune return (reinterpret_cast<char*>(&i)[1] == 1 ? "BigEndian" : "LittleEndian"); } + // provide accessor to \ref fileExtension virtual method std::string getFileExtension () const { return fileExtension(); @@ -135,7 +144,6 @@ namespace Dune protected: mutable DataCollector dataCollector_; - std::string filename_; Vtk::FormatTypes format_; Vtk::DataTypes datatype_; @@ -147,6 +155,17 @@ namespace Dune int compression_level = -1; // in [0,9], -1 ... use default value }; + + template <class Writer> + struct IsVtkWriter + { + template <class GV, class DC> + static std::uint16_t test(VtkWriterInterface<GV,DC> const&); + static std::uint8_t test(...); // fall-back overload + + static constexpr bool value = sizeof(test(std::declval<Writer>())) > sizeof(std::uint8_t); + }; + } // end namespace Dune #include "vtkwriterinterface.impl.hh" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3b6012ab3b883a66622327ecc4ca254bc37ebe6f..82056a055042697228fd96b8a1e8f2071767856b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,10 @@ if (dune-functions_FOUND) add_executable("timeserieswriter" timeserieswriter.cc) target_link_dune_default_libraries("timeserieswriter") target_link_libraries("timeserieswriter" dunevtk) + + add_executable("pvdwriter" pvdwriter.cc) + target_link_dune_default_libraries("pvdwriter") + target_link_libraries("pvdwriter" dunevtk) endif () if (dune-polygongrid_FOUND) diff --git a/src/pvdwriter.cc b/src/pvdwriter.cc new file mode 100644 index 0000000000000000000000000000000000000000..37207edf5065e1089f41d357e54ce2d881bd5431 --- /dev/null +++ b/src/pvdwriter.cc @@ -0,0 +1,65 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <iostream> +#include <vector> + +#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI +#include <dune/common/exceptions.hh> // We use exceptions +#include <dune/common/filledarray.hh> + +#include <dune/functions/functionspacebases/defaultglobalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> +#include <dune/functions/gridfunctions/analyticgridviewfunction.hh> + +#include <dune/grid/yaspgrid.hh> + +#include <dune/vtk/writers/vtkunstructuredgridwriter.hh> +#include <dune/vtk/pvdwriter.hh> + +using namespace Dune; +using namespace Dune::Functions; + +template <class GridView> +void write (std::string prefix, GridView const& gridView) +{ + using namespace BasisFactory; + auto basis = makeBasis(gridView, lagrange<1>()); + + FieldVector<double,GridView::dimension> c; + if (GridView::dimension > 0) c[0] = 11.0; + if (GridView::dimension > 1) c[1] = 7.0; + if (GridView::dimension > 2) c[2] = 3.0; + + // write analytic function + auto p1Analytic = makeAnalyticGridViewFunction([&c](auto const& x) { return c.dot(x); }, gridView); + + using Writer = VtkUnstructuredGridWriter<GridView>; + PvdWriter<Writer> pvdWriter(gridView); + + pvdWriter.addPointData(p1Analytic, "p1"); + pvdWriter.addCellData(p1Analytic, "p0"); + for (double t = 0.0; t < 10.0; t += 1.0) { + pvdWriter.write(t, prefix + "_" + std::to_string(GridView::dimension) + "d_ascii.vtu", + Vtk::ASCII, Vtk::FLOAT32); + } +} + +template <int I> +using int_ = std::integral_constant<int,I>; + +int main (int argc, char** argv) +{ + Dune::MPIHelper::instance(argc, argv); + + // Test PvdWriter for YaspGrid + using GridType = YaspGrid<2>; + FieldVector<double,2> upperRight; upperRight = 1.0; + auto numElements = filledArray<2,int>(4); + GridType grid(upperRight, numElements); + write("yasp", grid.leafGridView()); +} \ No newline at end of file