diff --git a/src/amdis/CMakeLists.txt b/src/amdis/CMakeLists.txt index 1237bbc906cd4a0c5806d782675d552daeb8afd2..261e70afb1eef1d35fafe0711383ee9a23d00686 100644 --- a/src/amdis/CMakeLists.txt +++ b/src/amdis/CMakeLists.txt @@ -71,6 +71,7 @@ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis) add_subdirectory("common") add_subdirectory("functions") add_subdirectory("gridfunctions") +add_subdirectory("io") add_subdirectory("linearalgebra") add_subdirectory("localoperators") add_subdirectory("operations") diff --git a/src/amdis/FileWriter.hpp b/src/amdis/FileWriter.hpp index d45a086e64dcd7c8ca619adc9649c578327c55f3..50ee4bb53cd8c730ceaf9cb25fe8e9034c963998 100644 --- a/src/amdis/FileWriter.hpp +++ b/src/amdis/FileWriter.hpp @@ -5,8 +5,7 @@ #include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/grid/io/file/vtk/vtkwriter.hh> -#include <dune/grid/io/file/vtk/vtksequencewriter.hh> -//#include <dune/geometry/referenceelements.hh> +#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh> #include <dune/typetree/childextraction.hh> #include <amdis/FileWriterInterface.hpp> @@ -15,6 +14,7 @@ #include <amdis/common/StaticSize.hpp> #include <amdis/common/ValueCategory.hpp> #include <amdis/gridfunctions/DiscreteFunction.hpp> +#include <amdis/io/VTKSequenceWriter.hpp> namespace AMDiS { @@ -86,7 +86,7 @@ namespace AMDiS vtkWriter_ = std::make_shared<Dune::VTKWriter<GridView>>(gridView()); if (animation_) - vtkSeqWriter_ = std::make_shared<Dune::VTKSequenceWriter<GridView>>(vtkWriter_, filename_, dir_, ""); + vtkSeqWriter_ = std::make_shared<VTKSequenceWriter<GridView>>(vtkWriter_); vtkWriter_->addVertexData(discreteFct_, Dune::VTK::FieldInfo(name_, VTKFieldType<Range>, VTKFieldSize<Range>)); } @@ -97,11 +97,12 @@ namespace AMDiS void writeFiles(AdaptInfo& adaptInfo, bool force) override { test_exit(dir_ == "." || filesystem::exists(dir_), "Output directory '{}' does not exist!",dir_); + filesystem::create_directories(dir_ + "/_piecefiles"); if (vtkSeqWriter_) - vtkSeqWriter_->write(adaptInfo.time(), mode_); + vtkSeqWriter_->pwrite(adaptInfo.time(), filename_, dir_, "_piecefiles", mode_); else if (vtkWriter_) - vtkWriter_->write(filesystem::path({dir_, filename_}).string(), mode_); + vtkWriter_->pwrite(filename_, dir_, "_piecefiles", mode_); } protected: @@ -114,7 +115,7 @@ namespace AMDiS DiscreteFunction<GB,VT,TP> discreteFct_; std::shared_ptr<Dune::VTKWriter<GridView>> vtkWriter_; - std::shared_ptr<Dune::VTKSequenceWriter<GridView>> vtkSeqWriter_; + std::shared_ptr<VTKSequenceWriter<GridView>> vtkSeqWriter_; // write .pvd if animation=true, otherwise write only .vtu bool animation_; diff --git a/src/amdis/io/CMakeLists.txt b/src/amdis/io/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..09203370907abcd7c9fccb825b7d1ec644362816 --- /dev/null +++ b/src/amdis/io/CMakeLists.txt @@ -0,0 +1,3 @@ +install(FILES + VtkSequenceWriter.hpp +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/io) diff --git a/src/amdis/io/VTKSequenceWriter.hpp b/src/amdis/io/VTKSequenceWriter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e8be67ceb1563306e61b908c35c89a352e7b1d03 --- /dev/null +++ b/src/amdis/io/VTKSequenceWriter.hpp @@ -0,0 +1,154 @@ +#pragma once + +#include <vector> +#include <iostream> +#include <sstream> +#include <fstream> +#include <iomanip> +#include <memory> + +#include <dune/grid/io/file/vtk/common.hh> +#include <dune/common/path.hh> + +#include <dune/grid/io/file/vtk/vtkwriter.hh> + +namespace AMDiS +{ + /// \brief class to write pvd-files which contains a list of all collected vtk-files + /** + * Write pvd-file suitable for easy visualization with + * <a href="http://www.vtk.org/">The Visualization Toolkit (VTK)</a>. + * + * \tparam GridView Grid view of the grid we are writing + */ + template <class GridView> + class VTKSequenceWriter + { + using VTKWriter = Dune::VTKWriter<GridView>; + + public: + /// \brief Set up the VTKSequenceWriter class + /** + * \param vtkWriter Writer object used to write the individual time step data files + */ + VTKSequenceWriter(std::shared_ptr<VTKWriter> vtkWriter) + : vtkWriter_(std::move(vtkWriter)) + {} + + /// \brief Set up the VTKSequenceWriter class by creating a timestep writer of type \ref VTKWriter + /** + * \param gridView GridView object passed to the constructor of the VTKWriter + * \param args... Additional arguments forwarded to the VTKWriter constructor. + */ + template <class... Args> + VTKSequenceWriter(GridView const& gridView, Args&&... args) + : VTKSequenceWriter<GridView>(std::make_shared<VTKWriter>(gridView, FWD(args)...)) + {} + + + /// accessor for the underlying VTKWriter instance + std::shared_ptr<VTKWriter> const& vtkWriter() const + { + return vtkWriter_; + } + + /// \brief Adds a field of cell data to the VTK file + template <class... Args> + void addCellData(Args&&... args) + { + vtkWriter_->addCellData(FWD(args)...); + } + + /// \brief Adds a field of vertex data to the VTK file + template <class... Args> + void addVertexData (Args&&... args) + { + vtkWriter_->addVertexData(FWD(args)...); + } + + /// \brief Writes VTK data for the given time, + /** + * \param time The time(step) for the data to be written. + * \param name The basename of the .pvd file (without file extension) + * \param type VTK output type. + */ + virtual void write(double time, std::string const& name, Dune::VTK::OutputType type = Dune::VTK::ascii) + { + pwrite(time, name, ".", "", type); + } + + /// \brief Writes VTK data for the given time, + /** + * \param time The time(step) for the data to be written. + * \param name The basename of the .pvd file (without file extension) + * \param path The directory where to put the .pvd file + * \param extendpath The (relative) subdirectory to path, where to put the timestep files + * \param type VTK output type. + */ + virtual void pwrite(double time, std::string const& name, std::string const& path, std::string const& extendpath, + Dune::VTK::OutputType type = Dune::VTK::ascii) + { + // remember current time step + unsigned int count = timesteps_.size(); + timesteps_.push_back(time); + + // write VTK file + vtkWriter_->pwrite(seqName(name, count), Dune::concatPaths(path, extendpath), "", type); + + // write pvd file ... only on rank 0 + if (Environment::mpiRank() == 0) { + std::ofstream pvdFile; + pvdFile.exceptions(std::ios_base::badbit | std::ios_base::failbit | + std::ios_base::eofbit); + std::string pvdname = path + "/" + name + ".pvd"; + pvdFile.open(pvdname.c_str()); + pvdFile << "<?xml version=\"1.0\"?>\n" + << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"" << Dune::VTK::getEndiannessString() << "\">\n" + << "<Collection>\n"; + for (unsigned int i = 0; i <= count; ++i) { + std::string piecepath = extendpath; + std::string fullname = getParallelHeaderName(seqName(name,i), piecepath, Environment::mpiSize()); + pvdFile << "<DataSet timestep=\"" << timesteps_[i] + << "\" part=\"0\" file=\"" + << fullname << "\"/>\n"; + } + pvdFile << "</Collection>\n" + << "</VTKFile>\n" << std::flush; + pvdFile.close(); + } + } + + protected: + // create sequence name + static std::string seqName(std::string const& name, unsigned int count) + { + std::stringstream n; + n.fill('0'); + n << name << "-" << std::setw(5) << count; + return n.str(); + } + + static std::string getParallelHeaderName(std::string const& name, std::string const& path, int commSize) + { + std::ostringstream s; + if (path.size() > 0) { + s << path; + if (path[path.size()-1] != '/') + s << '/'; + } + s << 's' << std::setw(4) << std::setfill('0') << commSize << '-'; + s << name; + if (GridView::dimension > 1) + s << ".pvtu"; + else + s << ".pvtp"; + return s.str(); + } + + private: + std::shared_ptr<VTKWriter> vtkWriter_; + std::vector<double> timesteps_; + }; + +} // end namespace AMDiS +