From 24b9b2991600cdd39651bacfc39efc090583c723 Mon Sep 17 00:00:00 2001
From: "Praetorius, Simon" <simon.praetorius@tu-dresden.de>
Date: Mon, 30 Sep 2019 10:47:52 +0200
Subject: [PATCH] Filewriter abstraction

---
 dune.module                        |   2 +-
 examples/boundary.cc               |   2 +-
 examples/convection_diffusion.cc   |   2 +-
 examples/ellipt.cc                 |   9 +-
 examples/init/boundary.dat.2d      |   1 +
 examples/init/cahn_hilliard.dat.2d |  12 +-
 examples/init/ellipt.dat.2d        |   1 +
 examples/init/ellipt.dat.3d        |   1 +
 examples/init/heat.dat.2d          |   6 +-
 examples/init/stokes.dat.2d        |   8 +-
 examples/init/surface.dat.2d       |   1 +
 examples/neumann.cc                |   2 +-
 examples/vecellipt.cc              |   2 +-
 src/amdis/AdaptInfo.hpp            |   4 +-
 src/amdis/BoundaryManager.hpp      |   5 +
 src/amdis/CMakeLists.txt           |   2 -
 src/amdis/FileWriter.hpp           | 141 ------------------------
 src/amdis/FileWriterInterface.hpp  |  68 ------------
 src/amdis/ProblemStat.hpp          |  31 +++---
 src/amdis/ProblemStat.inc.hpp      | 170 ++++++++++-------------------
 src/amdis/ProblemStatBase.hpp      |   6 -
 src/amdis/io/BackupWriter.hpp      |  78 +++++++++++++
 src/amdis/io/CMakeLists.txt        |  10 ++
 src/amdis/io/DuneVtkWriter.hpp     |  89 +++++++++++++++
 src/amdis/io/FileWriterBase.cpp    |  36 ++++++
 src/amdis/io/FileWriterBase.hpp    |  84 ++++++++++++++
 src/amdis/io/FileWriterCreator.hpp | 114 +++++++++++++++++++
 src/amdis/io/GmshWriter.hpp        |  72 ++++++++++++
 src/amdis/io/VTKSequenceWriter.hpp |   2 +
 src/amdis/io/VTKWriter.hpp         | 117 ++++++++++++++++++++
 test/BackupRestoreTest.cpp         |   7 +-
 31 files changed, 712 insertions(+), 373 deletions(-)
 delete mode 100644 src/amdis/FileWriter.hpp
 delete mode 100644 src/amdis/FileWriterInterface.hpp
 create mode 100644 src/amdis/io/BackupWriter.hpp
 create mode 100644 src/amdis/io/DuneVtkWriter.hpp
 create mode 100644 src/amdis/io/FileWriterBase.cpp
 create mode 100644 src/amdis/io/FileWriterBase.hpp
 create mode 100644 src/amdis/io/FileWriterCreator.hpp
 create mode 100644 src/amdis/io/GmshWriter.hpp
 create mode 100644 src/amdis/io/VTKWriter.hpp

diff --git a/dune.module b/dune.module
index fecc6271..d1774028 100644
--- a/dune.module
+++ b/dune.module
@@ -6,4 +6,4 @@ Module: amdis
 Version: 0.2
 Maintainer: simon.praetorius@tu-dresden.de
 Depends: dune-common (>= 2.6) dune-geometry (>= 2.6) dune-localfunctions (>= 2.6) dune-typetree (>= 2.6) dune-grid (>= 2.6) dune-functions (>= 2.6)
-Suggests: dune-uggrid dune-alugrid dune-foamgrid dune-spgrid dune-istl
+Suggests: dune-uggrid dune-alugrid dune-foamgrid dune-spgrid dune-istl dune-vtk
diff --git a/examples/boundary.cc b/examples/boundary.cc
index 91ef916e..d08280c7 100644
--- a/examples/boundary.cc
+++ b/examples/boundary.cc
@@ -89,7 +89,7 @@ void run_periodic()
 
   prob.assemble(adaptInfo);
   prob.solve(adaptInfo);
-  prob.writeFiles(adaptInfo, true);
+  prob.writeFiles(adaptInfo);
 }
 
 
diff --git a/examples/convection_diffusion.cc b/examples/convection_diffusion.cc
index b0af5d22..0ba82e9a 100644
--- a/examples/convection_diffusion.cc
+++ b/examples/convection_diffusion.cc
@@ -37,7 +37,7 @@ int main(int argc, char** argv)
   AdaptInfo adaptInfo("adapt");
   prob.assemble(adaptInfo);
   prob.solve(adaptInfo);
-  prob.writeFiles(adaptInfo, true);
+  prob.writeFiles(adaptInfo);
 
   return 0;
 }
diff --git a/examples/ellipt.cc b/examples/ellipt.cc
index e032165b..147f6d2e 100644
--- a/examples/ellipt.cc
+++ b/examples/ellipt.cc
@@ -69,14 +69,11 @@ int main(int argc, char** argv)
     errL2.push_back(std::sqrt(errorL2));
     double errorH1 = errorL2 + integrate(unary_dot(grad_g - gradientAtQP(prob.solution(0))), prob.gridView(), 6);
     errH1.push_back(std::sqrt(errorH1));
-
-#if WRITE_FILES
-    Dune::VTKWriter<typename ElliptProblem::GridView> vtkWriter(gridView);
-    vtkWriter.addVertexData(prob.solution(0), Dune::VTK::FieldInfo("u", Dune::VTK::FieldInfo::Type::scalar, 1));
-    vtkWriter.write("u_" + std::to_string(l));
-#endif
   }
 
+  // write last solution to file
+  prob.writeFiles(adaptInfo);
+
   msg("");
   msg("{:5} | {:12} | {:12} | {:12} | {:12} | {:12}",
       "level", "h", "|u - u*|_L2","|u - u*|_H1","eoc_L2","eoc_H1");
diff --git a/examples/init/boundary.dat.2d b/examples/init/boundary.dat.2d
index 23f56aeb..d4e033a7 100644
--- a/examples/init/boundary.dat.2d
+++ b/examples/init/boundary.dat.2d
@@ -8,6 +8,7 @@ ellipt->solver->relative tolerance: 1.e-10
 ellipt->solver->info:           1
 ellipt->solver->precon:         ilu
 
+ellipt->output[0]->format:      vtk
 ellipt->output[0]->filename:    boundary.2d
 ellipt->output[0]->name:        u
 ellipt->output[0]->output directory: ./output
diff --git a/examples/init/cahn_hilliard.dat.2d b/examples/init/cahn_hilliard.dat.2d
index 56ef77a4..7af9db93 100644
--- a/examples/init/cahn_hilliard.dat.2d
+++ b/examples/init/cahn_hilliard.dat.2d
@@ -18,19 +18,19 @@ ch->solver->relative tolerance: 1e-6
 ch->solver->break if tolerance not reached: 1
 ch->solver->info: 2
 
+ch->output[0]->format:             vtk
 ch->output[0]->filename:           phi.2d
 ch->output[0]->output directory:   output
 ch->output[0]->name:               phi
-ch->output[0]->ParaView format:    1
-ch->output[0]->ParaView mode:      1
-ch->output[0]->ParaView animation: 1
+ch->output[0]->mode:               1
+ch->output[0]->animation:          1
 
+ch->output[1]->format:             vtk
 ch->output[1]->filename:           mu.2d
 ch->output[1]->output directory:   output
 ch->output[1]->name:               mu
-ch->output[1]->ParaView format:    1
-ch->output[1]->ParaView mode:      1
-ch->output[1]->ParaView animation: 1
+ch->output[1]->mode:               1
+ch->output[1]->animation:          1
 
 adapt->timestep:    0.001
 adapt->start time:  0.0
diff --git a/examples/init/ellipt.dat.2d b/examples/init/ellipt.dat.2d
index bc4dcc23..0ef31af1 100644
--- a/examples/init/ellipt.dat.2d
+++ b/examples/init/ellipt.dat.2d
@@ -13,6 +13,7 @@ ellipt->solver->max iteration: 10000
 ellipt->solver->relative tolerance: 1.e-10
 ellipt->solver->precon: ilu
 
+ellipt->output[0]->format: vtk backup
 ellipt->output[0]->filename: ellipt.2d
 ellipt->output[0]->name: u
 ellipt->output[0]->output directory: ./output
diff --git a/examples/init/ellipt.dat.3d b/examples/init/ellipt.dat.3d
index ad5cbc12..baef5567 100644
--- a/examples/init/ellipt.dat.3d
+++ b/examples/init/ellipt.dat.3d
@@ -13,6 +13,7 @@ ellipt->solver->max iteration: 10000
 ellipt->solver->relative tolerance: 1.e-10
 ellipt->solver->precon: ilu
 
+ellipt->output[0]->format: vtk
 ellipt->output[0]->filename: ellipt.3d
 ellipt->output[0]->name: u
 ellipt->output[0]->output directory: ./output
diff --git a/examples/init/heat.dat.2d b/examples/init/heat.dat.2d
index 4db5cd5e..c23a811c 100644
--- a/examples/init/heat.dat.2d
+++ b/examples/init/heat.dat.2d
@@ -12,10 +12,12 @@ heat->solver->absolute tolerance: 1e-6
 heat->solver->info: 1
 heat->solver->precon: ilu
 
+heat->output[0]->format: vtk backup
+heat->output[0]->name: u
 heat->output[0]->filename: heat.2d
 heat->output[0]->output directory: output
-heat->output[0]->ParaView mode: 1
-heat->output[0]->ParaView animation: 1
+heat->output[0]->mode: 1
+heat->output[0]->animation: 1
 
 adapt->timestep:    0.1
 adapt->start time:  0.0
diff --git a/examples/init/stokes.dat.2d b/examples/init/stokes.dat.2d
index c4ac8b2f..2f3b32cb 100644
--- a/examples/init/stokes.dat.2d
+++ b/examples/init/stokes.dat.2d
@@ -10,18 +10,18 @@ stokes->solver->relative tolerance: 1e-8
 stokes->solver->precon: ilu
 stokes->solver->info:	2
 
+stokes->output[0]->format: vtk
 stokes->output[0]->filename: stokes_u.2d
 stokes->output[0]->name: u
 stokes->output[0]->subsampling: 2
 stokes->output[0]->output directory: ./output
-stokes->output[0]->ParaView format: 1
-stokes->output[0]->ParaView mode: 1
+stokes->output[0]->mode: 1
 
+stokes->output[1]->format: vtk
 stokes->output[1]->filename: stokes_p.2d
 stokes->output[1]->name: p
 stokes->output[1]->output directory: ./output
-stokes->output[1]->ParaView format: 1
-stokes->output[1]->ParaView mode: 1
+stokes->output[1]->mode: 1
 
 stokes->viscosity: 1.0
 stokes->density: 1.0
diff --git a/examples/init/surface.dat.2d b/examples/init/surface.dat.2d
index 7fad6f50..282ea4d0 100644
--- a/examples/init/surface.dat.2d
+++ b/examples/init/surface.dat.2d
@@ -9,6 +9,7 @@ surface->solver->relative tolerance: 1.e-6
 surface->solver->info:           1
 surface->solver->precon:         ilu
 
+surface->output[0]->format:      vtk
 surface->output[0]->filename:    surface.2d
 surface->output[0]->name:        u
 surface->output[0]->output directory: ./output
diff --git a/examples/neumann.cc b/examples/neumann.cc
index 20f07106..1037b813 100644
--- a/examples/neumann.cc
+++ b/examples/neumann.cc
@@ -45,7 +45,7 @@ void run(Grid& grid)
 
   prob.assemble(adaptInfo);
   prob.solve(adaptInfo);
-  prob.writeFiles(adaptInfo, true);
+  prob.writeFiles(adaptInfo);
 }
 
 
diff --git a/examples/vecellipt.cc b/examples/vecellipt.cc
index 2cb3a414..7f183562 100644
--- a/examples/vecellipt.cc
+++ b/examples/vecellipt.cc
@@ -51,7 +51,7 @@ int main(int argc, char** argv)
 #endif
 
   prob.solve(adaptInfo);
-  prob.writeFiles(adaptInfo, true);
+  prob.writeFiles(adaptInfo);
 
   return 0;
 }
diff --git a/src/amdis/AdaptInfo.hpp b/src/amdis/AdaptInfo.hpp
index d233e0b3..f03a4ecc 100644
--- a/src/amdis/AdaptInfo.hpp
+++ b/src/amdis/AdaptInfo.hpp
@@ -733,10 +733,10 @@ namespace AMDiS
     double lastProcessedTimestep_ = 0.0;
 
     /// Minimal step size
-    double minTimestep_ = 0.0;
+    double minTimestep_ = std::sqrt(std::numeric_limits<double>::epsilon());
 
     /// Maximal step size
-    double maxTimestep_ = 1.0;
+    double maxTimestep_ = std::sqrt(std::numeric_limits<double>::max());
 
     /// Number of current time step
     int timestepNumber_ = 0;
diff --git a/src/amdis/BoundaryManager.hpp b/src/amdis/BoundaryManager.hpp
index 1b435839..856e92f6 100644
--- a/src/amdis/BoundaryManager.hpp
+++ b/src/amdis/BoundaryManager.hpp
@@ -25,6 +25,11 @@ namespace AMDiS
       return boundaryIds_[intersection.boundarySegmentIndex()];
     }
 
+    std::vector<BoundaryType> const boundaryIds() const
+    {
+      return boundaryIds_;
+    }
+
   protected:
     std::vector<BoundaryType> boundaryIds_; // maps a boundarySegementIndex to an ID
   };
diff --git a/src/amdis/CMakeLists.txt b/src/amdis/CMakeLists.txt
index 316e348e..25ca9c6c 100644
--- a/src/amdis/CMakeLists.txt
+++ b/src/amdis/CMakeLists.txt
@@ -39,8 +39,6 @@ install(FILES
     DOFVector.inc.hpp
     DOFVectorInterface.hpp
     Environment.hpp
-    FileWriter.hpp
-    FileWriterInterface.hpp
     Flag.hpp
     GridFunctionOperator.hpp
     GridFunctions.hpp
diff --git a/src/amdis/FileWriter.hpp b/src/amdis/FileWriter.hpp
deleted file mode 100644
index 22ed7404..00000000
--- a/src/amdis/FileWriter.hpp
+++ /dev/null
@@ -1,141 +0,0 @@
-#pragma once
-
-#include <string>
-#include <memory>
-
-#include <dune/functions/functionspacebases/lagrangebasis.hh>
-#include <dune/grid/io/file/vtk/vtkwriter.hh>
-#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh>
-#include <dune/typetree/childextraction.hh>
-
-#include <amdis/FileWriterInterface.hpp>
-#include <amdis/Initfile.hpp>
-#include <amdis/common/Filesystem.hpp>
-#include <amdis/common/StaticSize.hpp>
-#include <amdis/common/ValueCategory.hpp>
-#include <amdis/gridfunctions/DiscreteFunction.hpp>
-#include <amdis/io/VTKSequenceWriter.hpp>
-
-namespace AMDiS
-{
-  namespace Impl
-  {
-    template <class Tag> struct VTKFieldTypeImpl;
-    template <>
-    struct VTKFieldTypeImpl<tag::scalar> {
-      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::scalar;
-    };
-    template <>
-    struct VTKFieldTypeImpl<tag::vector> {
-      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::vector;
-    };
-    template <>
-    struct VTKFieldTypeImpl<tag::matrix> {
-      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::tensor;
-    };
-
-  } // end namespace Impl
-
-  template <class Range>
-  constexpr Dune::VTK::FieldInfo::Type VTKFieldType = Impl::VTKFieldTypeImpl<ValueCategory_t<Range>>::value;
-
-  template <class Range>
-  constexpr std::size_t VTKFieldSize = Size_v<Range>;
-
-
-  template <class GB, class VT, class TP>
-  class FileWriter
-      : public FileWriterInterface
-  {
-    using GlobalBasis = GB;
-    using ValueType = VT;
-    using TreePath = TP;
-
-  private:
-    using GridView = typename GlobalBasis::GridView;
-    using Range = typename DiscreteFunction<GB,VT,TP>::Range;
-
-    /// Dimension of the mesh
-    static constexpr int dim = GridView::dimension;
-
-    /// Dimension of the world
-    static constexpr int dow = GridView::dimensionworld;
-
-  public:
-    /// Constructor.
-    FileWriter(std::string const& name, DiscreteFunction<GB,VT,TP> const& discreteFct)
-      : FileWriterInterface(name)
-      , discreteFct_(discreteFct)
-      , animation_(false)
-    {
-      Parameters::get(name + "->ParaView animation", animation_);
-
-      int m = Parameters::get<int>(name + "->ParaView mode").value_or(0);
-      mode_ = (m == 0 ? Dune::VTK::ascii : Dune::VTK::appendedraw);
-
-      init(name, ValueCategory_t<Range>{});
-    }
-
-    template <class ValueCat>
-    void init(std::string const& baseName, ValueCat)
-    {
-      auto subSampling = Parameters::get<int>(baseName + "->subsampling");
-      if (subSampling)
-        vtkWriter_ = std::make_shared<Dune::SubsamplingVTKWriter<GridView>>(gridView(), subSampling.value());
-      else
-        vtkWriter_ = std::make_shared<Dune::VTKWriter<GridView>>(gridView());
-
-      if (animation_)
-        vtkSeqWriter_ = std::make_shared<VTKSequenceWriter<GridView>>(vtkWriter_);
-
-      vtkWriter_->addVertexData(discreteFct_, Dune::VTK::FieldInfo(name_, VTKFieldType<Range>, VTKFieldSize<Range>));
-
-      test_exit(dir_ == "." || filesystem::exists(dir_), "Output directory '{}' does not exist!",dir_);
-    }
-
-    void init(std::string const&, tag::unknown) {}
-
-    /// Implements \ref FileWriterInterface::writeFiles
-    void writeFiles(AdaptInfo& adaptInfo, bool force) override
-    {
-      filesystem::create_directories(dir_ + "/_piecefiles");
-      if (vtkSeqWriter_)
-        vtkSeqWriter_->pwrite(adaptInfo.time(), filename_, dir_, "_piecefiles", mode_);
-      else if (vtkWriter_)
-        vtkWriter_->pwrite(filename_, dir_, "_piecefiles", mode_);
-    }
-
-  protected:
-    GridView const& gridView() const
-    {
-      return discreteFct_.basis()->gridView();
-    }
-
-  private:
-    DiscreteFunction<GB,VT,TP> discreteFct_;
-
-    std::shared_ptr<Dune::VTKWriter<GridView>> vtkWriter_;
-    std::shared_ptr<VTKSequenceWriter<GridView>> vtkSeqWriter_;
-
-    // write .pvd if animation=true, otherwise write only .vtu
-    bool animation_;
-
-    // represents VTK::OutputType: ascii, appendedraw
-    Dune::VTK::OutputType mode_;
-  };
-
-  template <class GlobalBasis, class ValueType, class TreePath>
-  auto makeFileWriter(std::string const& name,
-      DiscreteFunction<GlobalBasis,ValueType,TreePath> const& discreteFct)
-  {
-    return FileWriter<GlobalBasis,ValueType,TreePath>{name, discreteFct};
-  }
-
-  template <class GlobalBasis, class ValueType, class TreePath>
-  auto makeFileWriterPtr(std::string const& name,
-      DiscreteFunction<GlobalBasis,ValueType,TreePath> const& discreteFct)
-  {
-    return std::make_unique<FileWriter<GlobalBasis,ValueType,TreePath>>(name, discreteFct);
-  }
-
-} // end namespace AMDiS
diff --git a/src/amdis/FileWriterInterface.hpp b/src/amdis/FileWriterInterface.hpp
deleted file mode 100644
index f8f656de..00000000
--- a/src/amdis/FileWriterInterface.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#pragma once
-
-#include <string>
-
-#include <amdis/Initfile.hpp>
-#include <amdis/Output.hpp>
-#include <amdis/common/Filesystem.hpp>
-
-namespace AMDiS
-{
-  // forward declaration
-  class AdaptInfo;
-
-  class FileWriterInterface
-  {
-  public:
-    explicit FileWriterInterface(std::string const& base)
-    {
-      Parameters::get(base + "->filename", filename_);
-      Parameters::get(base + "->output directory", dir_);
-      Parameters::get(base + "->name", name_);
-    }
-
-    virtual ~FileWriterInterface() = default;
-
-
-    // pure virtual method to be implemented by derived classes
-    virtual void writeFiles(AdaptInfo& adaptInfo, bool force) = 0;
-
-  public: // getter and setter
-
-    std::string const& filename() const
-    {
-      return filename_;
-    }
-
-    std::string const& dir() const
-    {
-      return dir_;
-    }
-
-    std::string const& name() const
-    {
-      return name_;
-    }
-
-    void setFilename(std::string const& filename)
-    {
-      filename_ = filename;
-    }
-
-    void setDir(std::string const& dir)
-    {
-      dir_ = dir;
-    }
-
-    void setName(std::string const& name)
-    {
-      name_ = name;
-    }
-
-  protected:
-    std::string filename_ = "solution";
-    std::string dir_ = ".";
-    std::string name_ = "solution";
-  };
-
-} // end namespace AMDiS
diff --git a/src/amdis/ProblemStat.hpp b/src/amdis/ProblemStat.hpp
index 710f33af..02796a2d 100644
--- a/src/amdis/ProblemStat.hpp
+++ b/src/amdis/ProblemStat.hpp
@@ -37,7 +37,7 @@
 #include <amdis/gridfunctions/DiscreteFunction.hpp>
 #include <amdis/gridfunctions/DOFVectorView.hpp>
 
-#include <amdis/FileWriterInterface.hpp>
+#include <amdis/io/FileWriterBase.hpp>
 
 #include <amdis/typetree/TreeData.hpp>
 #include <amdis/typetree/TreePath.hpp>
@@ -106,14 +106,21 @@ namespace AMDiS
     }
 
 
+    /// \brief Initialisation of the problem.
     /**
-     * \brief Initialisation of the problem.
-     *
-     * Parameters read in initialize() for problem with name 'PROB'
-     *   MESH[0]->global refinements:  nr of initial global refinements
+     * Parameters read in initialize()
+     *   - `[GRID_NAME]->global refinements`:  nr of initial global refinements
      **/
     void initialize(Flag initFlag, Self* adoptProblem = nullptr, Flag adoptFlag = INIT_NOTHING);
 
+    /// \brief Read the grid and solution from backup files and initialize the problem
+    /**
+     * Parameters read in restore() for problem with name 'PROB'
+     *   - `[PROB]->restore->grid`:      name of the grid backup file
+     *   - `[PROB]->restore->solution`:  name of the solution backup file
+     **/
+    void restore(Flag initFlag);
+
 
     /// Add an operator to \ref A.
     /** @{ */
@@ -296,21 +303,9 @@ namespace AMDiS
     /// Uniform global refinement by n level
     Flag globalRefine(int n) override;
 
-    /// Writes output files.
+    /// Writes output files. If force=true write even if timestep out of write rhythm.
     void writeFiles(AdaptInfo& adaptInfo, bool force = false);
 
-    /// Backup the grid
-    void backup(std::string const& filename) const;
-
-    /// Implements \ref ProblemStatBase::backup
-    void backup(AdaptInfo& adaptInfo) override;
-
-    /// Retore the grid
-    auto restore(std::string const& filename);
-
-    /// Implements \ref ProblemStatBase::restore
-    void restore(Flag initFlag) override;
-
 
   public: // get-methods
 
diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp
index 71775277..c6e7fe9f 100644
--- a/src/amdis/ProblemStat.inc.hpp
+++ b/src/amdis/ProblemStat.inc.hpp
@@ -12,10 +12,10 @@
 
 #include <amdis/AdaptInfo.hpp>
 #include <amdis/BackupRestore.hpp>
-#include <amdis/FileWriter.hpp>
 #include <amdis/Assembler.hpp>
 #include <amdis/GridFunctionOperator.hpp>
 #include <amdis/GridTransferManager.hpp>
+#include <amdis/io/FileWriterCreator.hpp>
 #include <amdis/linearalgebra/SymmetryStructure.hpp>
 
 namespace AMDiS {
@@ -131,6 +131,48 @@ void ProblemStat<Traits>::initialize(
 }
 
 
+template <class Traits>
+void ProblemStat<Traits>::
+restore(Flag initFlag)
+{
+  std::string grid_filename = Parameters::get<std::string>(name_ + "->restore->grid").value();
+  std::string solution_filename = Parameters::get<std::string>(name_ + "->restore->solution").value();
+  test_exit(filesystem::exists(grid_filename), "Restore file '{}' not found.", grid_filename);
+  test_exit(filesystem::exists(solution_filename), "Restore file '{}' not found.", solution_filename);
+
+  // restore grid from file
+  if (Dune::Capabilities::hasBackupRestoreFacilities<Grid>::v)
+    adoptGrid(std::unique_ptr<Grid>(Dune::BackupRestoreFacility<Grid>::restore(grid_filename)));
+  else
+    adoptGrid(std::unique_ptr<Grid>(BackupRestoreByGridFactory<Grid>::restore(grid_filename)));
+
+  // create fespace
+  if (initFlag.isSet(INIT_FE_SPACE) || initFlag.isSet(INIT_SYSTEM))
+    createGlobalBasis();
+
+  // create system
+  if (initFlag.isSet(INIT_SYSTEM))
+    createMatricesAndVectors();
+
+  // create solver
+  if (linearSolver_)
+    warning("solver already created\n");
+  else if (initFlag.isSet(INIT_SOLVER))
+    createSolver();
+
+  // create marker
+  if (initFlag.isSet(INIT_MARKER))
+    createMarker();
+
+  // create file writer
+  if (initFlag.isSet(INIT_FILEWRITER))
+    createFileWriter();
+
+  solution_->resize();
+  solution_->restore(solution_filename);
+}
+
+
 template <class Traits>
 void ProblemStat<Traits>::createGrid()
 {
@@ -256,17 +298,29 @@ void ProblemStat<Traits>::createMarker()
 template <class Traits>
 void ProblemStat<Traits>::createFileWriter()
 {
+  FileWriterCreator<CoefficientVector> creator(solution_, boundaryManager_);
+
   filewriter_.clear();
   auto localView = globalBasis_->localView();
-  for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) -> void
+  for_each_node(localView.tree(), [&](auto const& /*node*/, auto treePath) -> void
   {
     std::string componentName = name_ + "->output[" + to_string(treePath) + "]";
+    auto format = Parameters::get<std::vector<std::string>>(componentName + "->format");
+
+    if (!format && to_string(treePath).empty()) {
+      // alternative for root treepath
+      componentName = name_ + "->output";
+      format = Parameters::get<std::vector<std::string>>(componentName + "->format");
+    }
 
-    if (!Parameters::get<std::string>(componentName + "->filename"))
+    if (!format)
       return;
 
-    auto writer = makeFileWriterPtr(componentName, this->solution(treePath));
-    filewriter_.push_back(std::move(writer));
+    for (std::string const& type : format.value()) {
+      auto writer = creator.create(type, componentName, treePath);
+      if (writer)
+        filewriter_.push_back(std::move(writer));
+    }
   });
 }
 
@@ -518,112 +572,8 @@ writeFiles(AdaptInfo& adaptInfo, bool force)
 {
   Dune::Timer t;
   for (auto writer : filewriter_)
-    writer->writeFiles(adaptInfo, force);
+    writer->write(adaptInfo, force);
   msg("writeFiles needed {} seconds", t.elapsed());
 }
 
-
-template <class Grid, class GridView,
-  class = decltype(Dune::BackupRestoreFacility<Grid>::backup(std::declval<Grid>(), std::string("")))>
-void backup_impl(Grid const& grid, GridView const& gv, std::string filename, std::true_type)
-{
-  Dune::BackupRestoreFacility<Grid>::backup(grid, filename);
-}
-
-template <class Grid, class GridView, bool B,
-  class = decltype(BackupRestoreByGridFactory<Grid>::backup(std::declval<GridView>(), std::string("")))>
-void backup_impl(Grid const& grid, GridView const& gv, std::string filename, bool_t<B>)
-{
-  warning("Falling back to backup of gridview.");
-  BackupRestoreByGridFactory<Grid>::backup(gv, filename);
-}
-
-template <class Traits>
-void ProblemStat<Traits>::
-backup(std::string const& filename) const
-{
-  backup_impl(*grid_, gridView(), filename, bool_t<Dune::Capabilities::hasBackupRestoreFacilities<Grid>::v>{});
-}
-
-
-template <class Traits>
-void ProblemStat<Traits>::
-backup(AdaptInfo& adaptInfo)
-{
-  auto param = Parameters::get<std::string>(name_ + "->backup->grid");
-  std::string grid_filename = param ? *param :
-    name_ + "_" + std::to_string(adaptInfo.timestepNumber()) + ".grid";
-
-  auto param2 = Parameters::get<std::string>(name_ + "->backup->solution");
-  std::string solution_filename = param2 ? *param2 :
-    name_ + "_" + std::to_string(adaptInfo.timestepNumber()) + ".solution";
-
-  backup(grid_filename);
-  solution_->backup(solution_filename);
-  msg("Problem backuped to files '{}' and '{}'.", grid_filename, solution_filename);
-}
-
-
-template <class Grid,
-  class = decltype(Dune::BackupRestoreFacility<Grid>::restore(std::string("")))>
-auto restore_impl(std::string filename, std::true_type)
-{
-  return Dune::BackupRestoreFacility<Grid>::restore(filename);
-}
-
-template <class Grid, bool B,
-  class = decltype(BackupRestoreByGridFactory<Grid>::restore(std::string("")))>
-auto restore_impl(std::string filename, bool_t<B>)
-{
-  return BackupRestoreByGridFactory<Grid>::restore(filename);
-}
-
-template <class Traits>
-auto ProblemStat<Traits>::
-restore(std::string const& filename)
-{
-  // restore grid from file
-  std::unique_ptr<Grid> grid(restore_impl<Grid>(filename, bool_t<Dune::Capabilities::hasBackupRestoreFacilities<Grid>::v>{}));
-  return std::move(grid);
-}
-
-
-template <class Traits>
-void ProblemStat<Traits>::
-restore(Flag initFlag)
-{
-  std::string grid_filename = Parameters::get<std::string>(name_ + "->restore->grid").value();
-  std::string solution_filename = Parameters::get<std::string>(name_ + "->restore->solution").value();
-  test_exit(filesystem::exists(grid_filename), "Restore file '{}' not found.", grid_filename);
-  test_exit(filesystem::exists(solution_filename), "Restore file '{}' not found.", solution_filename);
-
-  // restore grid from file
-  adoptGrid(restore(grid_filename));
-
-  // create fespace
-  if (initFlag.isSet(INIT_FE_SPACE) || initFlag.isSet(INIT_SYSTEM))
-    createGlobalBasis();
-
-  // create system
-  if (initFlag.isSet(INIT_SYSTEM))
-    createMatricesAndVectors();
-
-  // create solver
-  if (linearSolver_)
-    warning("solver already created\n");
-  else if (initFlag.isSet(INIT_SOLVER))
-    createSolver();
-
-  // create marker
-  if (initFlag.isSet(INIT_MARKER))
-    createMarker();
-
-  // create file writer
-  if (initFlag.isSet(INIT_FILEWRITER))
-    createFileWriter();
-
-  solution_->resizeZero();
-  solution_->restore(solution_filename);
-}
-
 } // end namespace AMDiS
diff --git a/src/amdis/ProblemStatBase.hpp b/src/amdis/ProblemStatBase.hpp
index df333cff..81f4a7cf 100644
--- a/src/amdis/ProblemStatBase.hpp
+++ b/src/amdis/ProblemStatBase.hpp
@@ -111,12 +111,6 @@ namespace AMDiS
      */
     virtual void estimate(AdaptInfo& adaptInfo) = 0;
 
-    /// \brief backup the grid and the solution to a file
-    virtual void backup(AdaptInfo& adaptInfo) = 0;
-
-    /// \brief restore the grid and the solution from a file
-    virtual void restore(Flag initFlag) = 0;
-
     /// Returns the name of the problem.
     virtual std::string const& name() const = 0;
   };
diff --git a/src/amdis/io/BackupWriter.hpp b/src/amdis/io/BackupWriter.hpp
new file mode 100644
index 00000000..45aa4497
--- /dev/null
+++ b/src/amdis/io/BackupWriter.hpp
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <string>
+#include <memory>
+#include <utility>
+
+#include <dune/grid/common/backuprestore.hh>
+#include <dune/grid/common/capabilities.hh>
+
+#include <amdis/BackupRestore.hpp>
+#include <amdis/Initfile.hpp>
+#include <amdis/Output.hpp>
+#include <amdis/common/Filesystem.hpp>
+#include <amdis/io/FileWriterBase.hpp>
+
+namespace AMDiS
+{
+  template <class SystemVector>
+  class BackupWriter
+      : public FileWriterBase
+  {
+    using GlobalBasis  = typename SystemVector::GlobalBasis;
+    using GridView     = typename GlobalBasis::GridView;
+    using Grid         = typename GridView::Grid;
+
+  public:
+    /// Constructor.
+    BackupWriter(std::string const& name, std::shared_ptr<SystemVector> systemVector)
+      : FileWriterBase(name)
+      , systemVector_(std::move(systemVector))
+    {
+      Parameters::get(name + "->animation", animation_);
+    }
+
+    /// Implements \ref FileWriterBase::write
+    void write(AdaptInfo& adaptInfo, bool force) override
+    {
+      std::string filename = filesystem::path({this->dir(), this->filename()}).string();
+
+      if (animation_)
+        filename += "_" + std::to_string(adaptInfo.timestepNumber());
+
+      if (force || this->doWrite(adaptInfo)) {
+        GridView const& gridView = systemVector_->basis()->gridView();
+        backupGrid(gridView, filename + ".grid",
+          bool_t<Dune::Capabilities::hasBackupRestoreFacilities<Grid>::v>{});
+        systemVector_->backup(filename + ".solution");
+
+        msg("Backup written to files '{}' and '{}'.", filename + ".grid", filename + ".solution");
+      }
+    }
+
+
+  private:
+
+    template <class G = Grid,
+      class = decltype(Dune::BackupRestoreFacility<G>::backup(std::declval<G>(), std::string("")))>
+    void backupGrid(GridView const& gv, std::string filename, std::true_type)
+    {
+      Dune::BackupRestoreFacility<Grid>::backup(gv.grid(), filename);
+    }
+
+    template <bool B, class G = Grid, class GV = GridView,
+      class = decltype(BackupRestoreByGridFactory<G>::backup(std::declval<GV>(), std::string("")))>
+    void backupGrid(GridView const& gv, std::string filename, bool_t<B>)
+    {
+      warning("Falling back to backup of gridview.");
+      BackupRestoreByGridFactory<Grid>::backup(gv, filename);
+    }
+
+  private:
+    std::shared_ptr<SystemVector> systemVector_;
+
+    /// append timestepnumber if animation=true, otherwise always override
+    bool animation_ = false;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/CMakeLists.txt b/src/amdis/io/CMakeLists.txt
index d367155d..2f1f42aa 100644
--- a/src/amdis/io/CMakeLists.txt
+++ b/src/amdis/io/CMakeLists.txt
@@ -1,3 +1,13 @@
+dune_library_add_sources(amdis SOURCES
+    FileWriterBase.cpp
+)
+
 install(FILES
+    BackupWriter.hpp
+    DuneVtkWriter.hpp
+    FileWriterBase.hpp
+    FileWriterCreator.hpp
+    GmshWriter.hpp
     VTKSequenceWriter.hpp
+    VTKWriter.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/io)
diff --git a/src/amdis/io/DuneVtkWriter.hpp b/src/amdis/io/DuneVtkWriter.hpp
new file mode 100644
index 00000000..60b9fd8a
--- /dev/null
+++ b/src/amdis/io/DuneVtkWriter.hpp
@@ -0,0 +1,89 @@
+#pragma once
+
+#include <string>
+#include <memory>
+
+#if HAVE_DUNE_VTK
+
+#include <dune/vtk/pvdwriter.hh>
+#include <dune/vtk/vtkwriter.hh>
+
+#include <amdis/Initfile.hpp>
+#include <amdis/common/Filesystem.hpp>
+#include <amdis/io/FileWriterBase.hpp>
+
+namespace AMDiS
+{
+  /// Adapter for the dune-vtk writer
+  template <class GB, class VT, class TP>
+  class DuneVtkWriter
+      : public FileWriterBase
+  {
+    using GridView = typename GB::GridView;
+    using Writer = Dune::VtkWriter<GridView>;
+    using SeqWriter = Dune::PvdWriter<Writer>;
+
+  public:
+    /// Constructor.
+    DuneVtkWriter(std::string const& name, DiscreteFunction<GB,VT,TP> const& discreteFct)
+      : FileWriterBase(name)
+      , discreteFct_(discreteFct)
+    {
+      int m = 0, p = 0;
+      Parameters::get(name + "->animation", animation_);
+      Parameters::get(name + "->mode", m);
+      Parameters::get(name + "->precision", p);
+
+      Dune::Vtk::FormatTypes mode =
+        m == 0 ? Dune::Vtk::ASCII :
+        m == 1 ? Dune::Vtk::BINARY :
+                 Dune::Vtk::COMPRESSED;
+
+      Dune::Vtk::DataTypes precision =
+        p == 0 ? Dune::Vtk::FLOAT32 :
+                 Dune::Vtk::FLOAT64;
+
+      if (animation_) {
+        vtkSeqWriter_ = std::make_shared<SeqWriter>(gridView(), mode, precision);
+        vtkSeqWriter_->addPointData(discreteFct_, this->name());
+      } else {
+        vtkWriter_ = std::make_shared<Writer>(gridView(), mode, precision);
+        vtkWriter_->addPointData(discreteFct_, this->name());
+      }
+    }
+
+    /// Implements \ref FileWriterBase::write
+    void write(AdaptInfo& adaptInfo, bool force) override
+    {
+      std::string data_dir = this->dir() + "/_piecefiles";
+      filesystem::create_directories(data_dir);
+
+      std::string filename = filesystem::path({this->dir(), this->filename() + ".vtk"}).string();
+      if (force || this->doWrite(adaptInfo)) {
+        if (animation_)
+          vtkSeqWriter_->writeTimestep(adaptInfo.time(), filename, data_dir, true);
+        else
+          vtkWriter_->write(filename, data_dir);
+      }
+    }
+
+  private:
+    /// The Gridview this writer lives on. Given by the discrete function.
+    GridView const& gridView() const
+    {
+      return discreteFct_.basis()->gridView();
+    }
+
+  private:
+    DiscreteFunction<GB,VT,TP> discreteFct_;
+
+    std::shared_ptr<Writer> vtkWriter_;
+    std::shared_ptr<SeqWriter> vtkSeqWriter_;
+
+    /// write .pvd if animation=true, otherwise write only .vtu
+    bool animation_ = false;
+  };
+
+} // end namespace AMDiS
+
+#endif // HAVE_DUNE_VTK
diff --git a/src/amdis/io/FileWriterBase.cpp b/src/amdis/io/FileWriterBase.cpp
new file mode 100644
index 00000000..009bf000
--- /dev/null
+++ b/src/amdis/io/FileWriterBase.cpp
@@ -0,0 +1,36 @@
+#include "FileWriterBase.hpp"
+
+#include <amdis/AdaptInfo.hpp>
+#include <amdis/Initfile.hpp>
+#include <amdis/common/Filesystem.hpp>
+
+namespace AMDiS
+{
+
+FileWriterBase::FileWriterBase(std::string const& base)
+{
+  Parameters::get(base + "->filename", filename_);
+  Parameters::get(base + "->output directory", dir_);
+  Parameters::get(base + "->name", name_);
+  Parameters::get(base + "->write every i-th timestep", tsModulo_);
+  Parameters::get(base + "->write after timestep", timeModulo_);
+
+  test_exit(dir_ == "." || filesystem::exists(dir_), "Output directory '{}' does not exist!", dir_);
+}
+
+
+bool FileWriterBase::doWrite(AdaptInfo& adaptInfo) const
+{
+  if (timeModulo_ > 0.0 &&
+      lastWriteTime_ > adaptInfo.startTime() &&
+      lastWriteTime_ + timeModulo_ > adaptInfo.time() + 0.5*adaptInfo.minTimestep())
+    return false;
+
+  else if (tsModulo_ > 0 && adaptInfo.timestepNumber() % tsModulo_ != 0)
+    return false;
+
+  lastWriteTime_ = adaptInfo.time();
+  return true;
+}
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/FileWriterBase.hpp b/src/amdis/io/FileWriterBase.hpp
new file mode 100644
index 00000000..81065825
--- /dev/null
+++ b/src/amdis/io/FileWriterBase.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <limits>
+#include <string>
+
+namespace AMDiS
+{
+  // forward declaration
+  class AdaptInfo;
+
+  /// Interface class for filewriters
+  class FileWriterInterface
+  {
+  public:
+    /// Virtual destructor
+    virtual ~FileWriterInterface() = default;
+
+    /// Pure virtual method to be implemented by derived classes
+    virtual void write(AdaptInfo& adaptInfo, bool force) = 0;
+  };
+
+  /// \brief Base class for filewriters
+  /**
+   * Read parameters common for all filewriters, where `BASE` is given by the
+   * constructor parameter `base`:
+   * - `[BASE]->filename`:  Base name of the filename, not including the file extension
+   * - `[BASE]->output directory`: Directory where to put the files
+   * - `[BASE]->name`:  Name of the data vector in the output file
+   * - `[BASE]->write every i-th timestep`:  Timestep number interval.
+   * - `[BASE]->write after timestep`:  Time interval.
+   *
+   * Some other parameters found in some filewriter implementations:
+   * - `[BASE]->mode`:  File mode, either ASCII=0, BINARY=1, or COMPRESSED=2
+   * - `[BASE]->precision`:  Output precision, either FLOAT=0, DOUBLE=1
+   * - `[BASE]->animation`:  Write animation files, or append the timestep to the filename.
+   **/
+  class FileWriterBase
+      : public FileWriterInterface
+  {
+  public:
+    /// Constructor. Reads common parameters.
+    FileWriterBase(std::string const& base);
+
+    /// Return whether to write the current timestep or not
+    bool doWrite(AdaptInfo& adaptInfo) const;
+
+  public:
+    std::string const& filename() const
+    {
+      return filename_;
+    }
+
+    std::string const& dir() const
+    {
+      return dir_;
+    }
+
+    std::string const& name() const
+    {
+      return name_;
+    }
+
+  protected:
+    /// Base part of output filename
+    std::string filename_ = "solution";
+
+    /// Output directory
+    std::string dir_ = ".";
+
+    /// Name of the data
+    std::string name_ = "solution";
+
+    /// Write every i'th timestep
+    int tsModulo_ = 0;
+
+    /// Write after every time interval
+    double timeModulo_ = 0.0;
+
+  private:
+    // time counter for the interval output
+    mutable double lastWriteTime_ = std::numeric_limits<double>::lowest();
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/FileWriterCreator.hpp b/src/amdis/io/FileWriterCreator.hpp
new file mode 100644
index 00000000..1193f19b
--- /dev/null
+++ b/src/amdis/io/FileWriterCreator.hpp
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <amdis/BoundaryManager.hpp>
+#include <amdis/LinearAlgebra.hpp>
+#include <amdis/Output.hpp>
+#include <amdis/gridfunctions/DiscreteFunction.hpp>
+#include <amdis/io/BackupWriter.hpp>
+#include <amdis/io/DuneVtkWriter.hpp>
+#include <amdis/io/FileWriterBase.hpp>
+#include <amdis/io/GmshWriter.hpp>
+#include <amdis/io/VTKWriter.hpp>
+
+namespace AMDiS
+{
+  /// \brief Creator class for filewriters depending on a given type name
+  /**
+   * \tparam SystemVector  Type of the DOFVector to write with the filewriter
+   **/
+  template <class SystemVector>
+  class FileWriterCreator
+  {
+    using GlobalBasis  = typename SystemVector::GlobalBasis;
+    using GridView     = typename GlobalBasis::GridView;
+    using Grid         = typename GridView::Grid;
+
+  public:
+    /// Constructor. Stores the pointer to the systemVector and to the (optional) boundaryManager.
+    FileWriterCreator(std::shared_ptr<SystemVector> systemVector,
+                      std::shared_ptr<BoundaryManager<Grid>> boundaryManager = nullptr)
+      : systemVector_(std::move(systemVector))
+      , boundaryManager_(std::move(boundaryManager))
+    {}
+
+    /// Create a new FileWriter of type `type`
+    /**
+     * \param type      String representing the type of the writer. One of {vtk, dune-vtk, gmsh, backup}
+     * \param prefix    The initfile prefix tp configure the filewriter
+     * \param treePath  Treepath to the component of the systemVector to be handled by the fileWriter.
+     **/
+    template <class TreePath = RootTreePath>
+    std::unique_ptr<FileWriterInterface>
+    create(std::string type, std::string prefix, TreePath treePath = {}) const
+    {
+      auto data = makeDiscreteFunction(*systemVector_, treePath);
+      using Range = typename TYPEOF(data)::Range;
+
+      return create_impl(std::move(type), std::move(prefix), data, ValueCategory_t<Range>{});
+    }
+
+  private:
+    template <class GB, class VT, class TP, class ValCat>
+    std::unique_ptr<FileWriterInterface>
+    create_impl(std::string type, std::string prefix, DiscreteFunction<GB,VT,TP> const& data, ValCat) const
+    {
+      // ParaView VTK format, writer from dune-grid
+      if (type == "vtk")
+      {
+        return std::make_unique<VTKWriter<GB,VT,TP>>(prefix, data);
+      }
+#if HAVE_DUNE_VTK
+      // ParaView VTK format, writer from dune-vtk
+      else if (type == "dune-vtk")
+      {
+        return std::make_unique<DuneVtkWriter<GB,VT,TP>>(prefix, data);
+      }
+#endif
+      // GMsh file format, writing just the grid and optionally boundary ids
+      else if (type == "gmsh")
+      {
+        GridView const& gridView = systemVector_->basis()->gridView();
+        if (!!boundaryManager_)
+          return std::make_unique<GmshWriter<typename GB::GridView>>(prefix, gridView,
+            std::vector<int>{}, boundaryManager_->boundaryIds());
+        else
+          return std::make_unique<GmshWriter<typename GB::GridView>>(prefix, gridView);
+      }
+      // Backup writer, writing the grid and the solution vector
+      else if (type == "backup")
+      {
+        return std::make_unique<BackupWriter<SystemVector>>(prefix, systemVector_);
+      }
+
+      error_exit("Unknown filewriter type '{}' given for '{}'. Use one of "
+                 "(vtk, gmsh, backup, [dune-vtk]), where the last one is only available "
+                 "if the dune module dune-vtk is found.", type, prefix);
+      return {};
+    }
+
+    // The value-category is unknown, like a composite/hierarchic vector or any unknown type.
+    template <class GB, class VT, class TP>
+    std::unique_ptr<FileWriterInterface>
+    create_impl(std::string type, std::string prefix, DiscreteFunction<GB,VT,TP> const& /*data*/, tag::unknown) const
+    {
+      // Backup writer, writing the grid and the solution vector
+      if (type == "backup")
+      {
+        return std::make_unique<BackupWriter<SystemVector>>(prefix, systemVector_);
+      }
+
+      error_exit("Filewriter '{}' cannot be applied to this component in the tree. "
+                 "Either use the writer 'backup' to write the whole tree, or add a treepath "
+                 "to the output prefix '{}'.", type, prefix);
+      return {};
+    }
+
+  private:
+    std::shared_ptr<SystemVector> systemVector_;
+    std::shared_ptr<BoundaryManager<Grid>> boundaryManager_ = nullptr;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/GmshWriter.hpp b/src/amdis/io/GmshWriter.hpp
new file mode 100644
index 00000000..0082680c
--- /dev/null
+++ b/src/amdis/io/GmshWriter.hpp
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <string>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include <dune/grid/io/file/gmshwriter.hh>
+
+#include <amdis/Initfile.hpp>
+#include <amdis/Output.hpp>
+#include <amdis/common/Filesystem.hpp>
+#include <amdis/io/FileWriterBase.hpp>
+
+namespace AMDiS
+{
+  /// The GmshWriter just writes the grid of a given gridView to a gmsh compatible .msh file
+  template <class GV>
+  class GmshWriter
+      : public FileWriterBase
+  {
+    using GridView = GV;
+    using Writer = Dune::GmshWriter<GridView>;
+
+  public:
+    /// Constructor.
+    GmshWriter(std::string const& name, GridView const& gridView,
+               std::vector<int> const& physicalEntities = std::vector<int>(),
+               std::vector<int> const& physicalBoundaries = std::vector<int>())
+      : FileWriterBase(name)
+      , gridView_(gridView)
+      , physicalEntities_(physicalEntities)
+      , physicalBoundaries_(physicalBoundaries)
+    {
+      int p = 0;
+      Parameters::get(name + "->animation", animation_);
+      Parameters::get(name + "->precision", p);
+
+      int precision = (p == 0)
+        ? std::numeric_limits<float>::max_digits10
+        : std::numeric_limits<double>::max_digits10;
+
+      writer_ = std::make_shared<Writer>(gridView_, precision);
+    }
+
+    /// Implements \ref FileWriterBase::write
+    void write(AdaptInfo& adaptInfo, bool force) override
+    {
+      std::string filename = this->filename();
+      if (animation_)
+        filename += "_" + std::to_string(adaptInfo.time());
+
+      if (force || this->doWrite(adaptInfo)) {
+        writer_->write(filesystem::path({this->dir(), filename + ".msh"}).string(),
+          physicalEntities_, physicalBoundaries_);
+
+        msg("Grid written to file '{}'.", filesystem::path({this->dir(), filename + ".msh"}).string());
+      }
+    }
+
+  private:
+    GridView gridView_;
+    std::vector<int> const& physicalEntities_;
+    std::vector<int> const& physicalBoundaries_;
+
+    std::shared_ptr<Writer> writer_;
+
+    /// write .pvd if animation=true, otherwise write only .vtu
+    bool animation_ = false;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/VTKSequenceWriter.hpp b/src/amdis/io/VTKSequenceWriter.hpp
index 3311ecda..bbb17a49 100644
--- a/src/amdis/io/VTKSequenceWriter.hpp
+++ b/src/amdis/io/VTKSequenceWriter.hpp
@@ -12,6 +12,8 @@
 
 #include <dune/grid/io/file/vtk/vtkwriter.hh>
 
+#include <amdis/Environment.hpp>
+
 namespace AMDiS
 {
   /// \brief class to write pvd-files which contains a list of all collected vtk-files
diff --git a/src/amdis/io/VTKWriter.hpp b/src/amdis/io/VTKWriter.hpp
new file mode 100644
index 00000000..d487ed56
--- /dev/null
+++ b/src/amdis/io/VTKWriter.hpp
@@ -0,0 +1,117 @@
+#pragma once
+
+#include <string>
+#include <memory>
+
+#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh>
+#include <dune/grid/io/file/vtk/vtkwriter.hh>
+
+#include <amdis/Initfile.hpp>
+#include <amdis/common/Filesystem.hpp>
+#include <amdis/common/StaticSize.hpp>
+#include <amdis/common/ValueCategory.hpp>
+#include <amdis/io/FileWriterBase.hpp>
+#include <amdis/io/VTKSequenceWriter.hpp>
+
+namespace AMDiS
+{
+  namespace Impl
+  {
+    template <class Tag> struct VTKFieldTypeImpl;
+    template <>
+    struct VTKFieldTypeImpl<tag::scalar> {
+      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::scalar;
+    };
+    template <>
+    struct VTKFieldTypeImpl<tag::vector> {
+      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::vector;
+    };
+    template <>
+    struct VTKFieldTypeImpl<tag::matrix> {
+      static const Dune::VTK::FieldInfo::Type value = Dune::VTK::FieldInfo::Type::tensor;
+    };
+
+  } // end namespace Impl
+
+
+  /// Adapter for the dune-grid VTKWriter
+  template <class GB, class VT, class TP>
+  class VTKWriter
+      : public FileWriterBase
+  {
+    using GridView = typename GB::GridView;
+    using Writer = Dune::VTKWriter<GridView>;
+    using SeqWriter = VTKSequenceWriter<GridView>;
+    using Range = typename DiscreteFunction<GB,VT,TP>::Range;
+
+    template <class R>
+    static constexpr Dune::VTK::FieldInfo::Type VTKFieldType() {
+      return Impl::VTKFieldTypeImpl<ValueCategory_t<R>>::value;
+    }
+
+    template <class R>
+    static constexpr std::size_t VTKFieldSize() {
+      return Size_v<R>;
+    }
+
+  public:
+    /// Constructor.
+    VTKWriter(std::string const& name, DiscreteFunction<GB,VT,TP> const& discreteFct)
+      : FileWriterBase(name)
+      , discreteFct_(discreteFct)
+    {
+      int m = 0;
+      Parameters::get(name + "->animation", animation_);
+      Parameters::get(name + "->mode", m);
+
+      mode_ = (m == 0)
+        ? Dune::VTK::ascii
+        : Dune::VTK::appendedraw;
+
+      auto subSampling = Parameters::get<int>(name + "->subsampling");
+      if (subSampling) {
+        using SubsamplingWriter = Dune::SubsamplingVTKWriter<GridView>;
+        vtkWriter_ = std::make_shared<SubsamplingWriter>(gridView(), subSampling.value());
+      } else {
+        vtkWriter_ = std::make_shared<Writer>(gridView());
+      }
+
+      if (animation_)
+        vtkSeqWriter_ = std::make_shared<SeqWriter>(vtkWriter_);
+
+      vtkWriter_->addVertexData(discreteFct_,
+        Dune::VTK::FieldInfo(name_, VTKFieldType<Range>(), VTKFieldSize<Range>()));
+    }
+
+    /// Implements \ref FileWriterInterface::write
+    void write(AdaptInfo& adaptInfo, bool force) override
+    {
+      filesystem::create_directories(this->dir() + "/_piecefiles");
+      if (force || this->doWrite(adaptInfo)) {
+        if (animation_)
+          vtkSeqWriter_->pwrite(adaptInfo.time(), this->filename(), this->dir(), "_piecefiles", mode_);
+        else
+          vtkWriter_->pwrite(this->filename(), this->dir(), "_piecefiles", mode_);
+      }
+    }
+
+  private:
+    /// The Gridview this writer lives on. Given by the discrete function.
+    GridView const& gridView() const
+    {
+      return discreteFct_.basis()->gridView();
+    }
+
+  private:
+    DiscreteFunction<GB,VT,TP> discreteFct_;
+    std::shared_ptr<Writer> vtkWriter_;
+    std::shared_ptr<SeqWriter> vtkSeqWriter_;
+
+    // write .pvd if animation=true, otherwise write only .vtu
+    bool animation_ = false;
+
+    // represents VTK::OutputType: ascii, appendedraw
+    Dune::VTK::OutputType mode_ = Dune::VTK::ascii;
+  };
+
+} // end namespace AMDiS
diff --git a/test/BackupRestoreTest.cpp b/test/BackupRestoreTest.cpp
index f00d1c15..4f6cc20f 100644
--- a/test/BackupRestoreTest.cpp
+++ b/test/BackupRestoreTest.cpp
@@ -47,7 +47,7 @@ void test(Factory factory)
     num_vertices = prob.grid()->size(Grid::dimension);
 
     AdaptInfo adaptInfo("adapt");
-    prob.backup(adaptInfo);
+    prob.writeFiles(adaptInfo, true);
   }
 
   // restore
@@ -97,11 +97,12 @@ int main(int argc, char** argv)
   Environment env(argc, argv);
 
   std::string filename = "test";
-  Parameters::set("test->backup->grid", filename + "_" + std::to_string(GRID_ID) + ".grid");
   Parameters::set("test->restore->grid", filename + "_" + std::to_string(GRID_ID) + ".grid");
-  Parameters::set("test->backup->solution", filename + "_" + std::to_string(GRID_ID) + ".solution");
   Parameters::set("test->restore->solution", filename + "_" + std::to_string(GRID_ID) + ".solution");
 
+  Parameters::set("test->output->format", "backup");
+  Parameters::set("test->output->filename", filename + "_" + std::to_string(GRID_ID));
+
 #if GRID_ID == 0
   test_cube<Dune::YaspGrid<2>>();
   test_cube<Dune::YaspGrid<3>>();
-- 
GitLab