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..22ed7404ba4c274d2090342dec8e810d8441c4ad 100644 --- a/src/amdis/FileWriter.hpp +++ b/src/amdis/FileWriter.hpp @@ -5,8 +5,7 @@ #include #include -#include -//#include +#include #include #include @@ -15,6 +14,7 @@ #include #include #include +#include namespace AMDiS { @@ -86,9 +86,11 @@ namespace AMDiS vtkWriter_ = std::make_shared>(gridView()); if (animation_) - vtkSeqWriter_ = std::make_shared>(vtkWriter_, filename_, dir_, ""); + vtkSeqWriter_ = std::make_shared>(vtkWriter_); vtkWriter_->addVertexData(discreteFct_, Dune::VTK::FieldInfo(name_, VTKFieldType, VTKFieldSize)); + + test_exit(dir_ == "." || filesystem::exists(dir_), "Output directory '{}' does not exist!",dir_); } void init(std::string const&, tag::unknown) {} @@ -96,12 +98,11 @@ namespace AMDiS /// Implements \ref FileWriterInterface::writeFiles 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 discreteFct_; std::shared_ptr> vtkWriter_; - std::shared_ptr> vtkSeqWriter_; + std::shared_ptr> 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..3311ecda8e61beb895e97510d08bb02974958a33 --- /dev/null +++ b/src/amdis/io/VTKSequenceWriter.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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 + * The Visualization Toolkit (VTK). + * + * \tparam GridView Grid view of the grid we are writing + */ + template + class VTKSequenceWriter + { + using VTKWriter = Dune::VTKWriter; + + 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_(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 + VTKSequenceWriter(GridView const& gridView, Args&&... args) + : VTKSequenceWriter(std::make_shared(gridView, FWD(args)...)) + {} + + virtual ~VTKSequenceWriter() = default; + + /// accessor for the underlying VTKWriter instance + std::shared_ptr const& vtkWriter() const + { + return vtkWriter_; + } + + /// \brief Adds a field of cell data to the VTK file + template + void addCellData(Args&&... args) + { + vtkWriter_->addCellData(FWD(args)...); + } + + /// \brief Adds a field of vertex data to the VTK file + template + 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 << "\n" + << "\n" + << "\n"; + for (unsigned int i = 0; i <= count; ++i) { + std::string piecepath = extendpath; + std::string fullname = getParallelHeaderName(seqName(name,i), piecepath, Environment::mpiSize()); + pvdFile << "\n"; + } + pvdFile << "\n" + << "\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_; + std::vector timesteps_; + }; + +} // end namespace AMDiS + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ef3cfe35a22fced0278a86676c4c9b8dc4c0d390..6ef4b43bfc0022f820ae6dc1e186f367577a5a41 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,8 +28,7 @@ dune_add_test(SOURCES DOFVectorTest.cpp LINK_LIBRARIES amdis) dune_add_test(SOURCES DiscreteFunctionTest.cpp - LINK_LIBRARIES amdis - CMD_ARGS "${CMAKE_SOURCE_DIR}/examples/init/ellipt.dat.2d") + LINK_LIBRARIES amdis) dune_add_test(SOURCES ExpressionsTest.cpp LINK_LIBRARIES amdis) @@ -65,8 +64,7 @@ dune_add_test(SOURCES ISTLCommTest.cpp CMAKE_GUARD "MPI_FOUND AND dune-istl_FOUND") dune_add_test(SOURCES IntegrateTest.cpp - LINK_LIBRARIES amdis - CMD_ARGS "${CMAKE_SOURCE_DIR}/examples/init/ellipt.dat.2d") + LINK_LIBRARIES amdis) dune_add_test(SOURCES MarkerTest.cpp LINK_LIBRARIES amdis)