From 6f03bd17118370e4cbc803039fef842da78dc6df Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Sun, 26 Aug 2018 17:35:43 +0200
Subject: [PATCH] cleanup of source code

---
 dune/vtk/gridcreator.hh                    |   8 +-
 dune/vtk/utility/string.hh                 |  19 ++-
 dune/vtk/vtkfunction.hh                    |  35 ++++-
 dune/vtk/vtkimagedatawriter.impl.hh        | 163 +++++++++------------
 dune/vtk/vtkstructuredgridwriter.impl.hh   | 144 ++++++++----------
 dune/vtk/vtktypes.cc                       |  72 ++++++---
 dune/vtk/vtktypes.hh                       |  22 ++-
 dune/vtk/vtkunstructuredgridwriter.impl.hh | 119 +++++++--------
 dune/vtk/vtkwriter.hh                      |  31 ++++
 dune/vtk/vtkwriter.impl.hh                 |   4 +-
 10 files changed, 346 insertions(+), 271 deletions(-)

diff --git a/dune/vtk/gridcreator.hh b/dune/vtk/gridcreator.hh
index 7399bdc..ec44cad 100644
--- a/dune/vtk/gridcreator.hh
+++ b/dune/vtk/gridcreator.hh
@@ -28,9 +28,7 @@ namespace Dune { namespace experimental
 
       std::size_t idx = 0;
       for (std::size_t i = 0; i < types.size(); ++i) {
-        if (Vtk::Map::from_type.count(types[i]) == 0)
-          DUNE_THROW(Exception, "Unknown ElementType: " << types[i]);
-        auto type = Vtk::Map::from_type[types[i]];
+        auto type = Vtk::to_geometry(types[i]);
         Vtk::CellType cellType{type};
         auto refElem = referenceElement<double,Grid::dimension>(type);
 
@@ -92,9 +90,7 @@ namespace Dune { namespace experimental
 
       idx = 0;
       for (std::size_t i = 0; i < types.size(); ++i) {
-        if (Vtk::Map::from_type.count(types[i]) == 0)
-          DUNE_THROW(Exception, "Unknown ElementType: " << types[i]);
-        auto type = Vtk::Map::from_type[types[i]];
+        auto type = Vtk::to_geometry(types[i]);
         Vtk::CellType cellType{type};
 
         std::size_t nNodes = offsets[i] - (i == 0 ? 0 : offsets[i-1]);
diff --git a/dune/vtk/utility/string.hh b/dune/vtk/utility/string.hh
index d0640a8..7724911 100644
--- a/dune/vtk/utility/string.hh
+++ b/dune/vtk/utility/string.hh
@@ -3,6 +3,7 @@
 #include <algorithm>
 #include <cctype>
 #include <locale>
+#include <sstream>
 #include <string>
 
 namespace Dune
@@ -74,8 +75,8 @@ namespace Dune
     }
   }
 
-  template <class InputIter, class SeparaterIter, class Func>
-  void split(InputIter first, InputIter end, SeparaterIter s_first, SeparaterIter s_end, Func f)
+  template <class InputIter, class SeparatorIter, class Func>
+  void split(InputIter first, InputIter end, SeparatorIter s_first, SeparatorIter s_end, Func f)
   {
     if (first == end)
       return;
@@ -102,4 +103,18 @@ namespace Dune
     }
   }
 
+
+  template <class InputIter>
+  std::string join (InputIter first, InputIter end, std::string sep = " ")
+  {
+    if (first == end)
+      return "";
+
+    std::ostringstream os;
+    os << *first++;
+    while (first != end)
+      os << sep << *first++;
+    return os.str();
+  }
+
 } // end namspace Dune
diff --git a/dune/vtk/vtkfunction.hh b/dune/vtk/vtkfunction.hh
index 3220e0d..11a61ec 100644
--- a/dune/vtk/vtkfunction.hh
+++ b/dune/vtk/vtkfunction.hh
@@ -3,6 +3,7 @@
 #include <type_traits>
 
 #include <dune/common/std/type_traits.hh>
+#include <dune/functions/common/signature.hh>
 #include <dune/functions/common/typeerasure.hh>
 
 namespace Dune { namespace experimental
@@ -162,14 +163,32 @@ namespace Dune { namespace experimental
     template <class F>
     using HasLocalFunction = decltype(localFunction(std::declval<F>()));
 
-  public:
     template <class F>
-    VTKFunction (F&& f, std::string name, int ncomps = 1)
+    using Signature = typename std::decay_t<F>::Signature;
+
+  public:
+    template <class F,
+      class Range = typename Functions::SignatureTraits<Signature<F>>::Range>
+    VTKFunction (F&& f, std::string name, int ncomps = 1,
+                 Vtk::DataTypes type = Vtk::Map::type<Range>)
+      : Super(std::forward<F>(f))
+      , name_(std::move(name))
+      , ncomps_(ncomps > 3 ? 9 : ncomps > 1 ? 3 : 1) // tensor, vector, or scalar
+      , type_(type)
+    {
+      static_assert(Std::is_detected<HasLocalFunction,F>::value,
+        "Requires A GridFunction to be passed to the VTKFunction.");
+    }
+
+    template <class F,
+      std::enable_if_t<not Std::is_detected<Signature,F>::value,int> = 0>
+    VTKFunction (F&& f, std::string name, int ncomps = 1,
+                 Vtk::DataTypes type = Vtk::FLOAT32)
       : Super(std::forward<F>(f))
       , name_(std::move(name))
-      , ncomps_(ncomps > 1 ? 3 : 1)
+      , ncomps_(ncomps > 3 ? 9 : ncomps > 1 ? 3 : 1) // tensor, vector, or scalar
+      , type_(type)
     {
-      assert(1 <= ncomps && ncomps <= 3);
       static_assert(Std::is_detected<HasLocalFunction,F>::value,
         "Requires A GridFunction to be passed to the VTKFunction.");
     }
@@ -194,10 +213,16 @@ namespace Dune { namespace experimental
       return ncomps_;
     }
 
+    /// Return the VTK Datatype associated with the functions range type
+    Vtk::DataTypes type () const
+    {
+      return type_;
+    }
+
   private:
     std::string name_;
-
     int ncomps_ = 1;
+    Vtk::DataTypes type_;
   };
 
 }} // end namespace Dune::experimental
diff --git a/dune/vtk/vtkimagedatawriter.impl.hh b/dune/vtk/vtkimagedatawriter.impl.hh
index b392047..6ae03f0 100644
--- a/dune/vtk/vtkimagedatawriter.impl.hh
+++ b/dune/vtk/vtkimagedatawriter.impl.hh
@@ -29,56 +29,39 @@ void VtkImageDataWriter<GV,DC>
   }
 
   std::vector<pos_type> offsets; // pos => offset
-  out << "<VTKFile type=\"ImageData\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
-  out << "<ImageData WholeExtent=\"";
+  out << "<VTKFile"
+      << " type=\"StructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
   auto const& wholeExtent = dataCollector_.wholeExtent();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
-  }
-  out << "\" Origin=\"";
   auto const& origin = dataCollector_.origin();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << origin[i];
-  }
-  out << "\" Spacing=\"";
   auto const& spacing = dataCollector_.spacing();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << spacing[i];
-  }
-  out << "\">\n";
-
-  dataCollector_.writeLocalPiece([&out](std::array<int,6> const& extent)
-  {
-    out << "<Piece Extent=\"";
-    for (int i = 0; i < 3; ++i) {
-      out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
-    }
-    out << "\">\n";
+  out << "<ImageData"
+      << " WholeExtent=\"" << join(wholeExtent.begin(), wholeExtent.end()) << "\""
+      << " Origin=\"" << join(origin.begin(), origin.end()) << "\""
+      << " Spacing=\"" << join(spacing.begin(), spacing.end()) << "\""
+      << ">\n";
+
+  dataCollector_.writeLocalPiece([&out](auto const& extent) {
+    out << "<Piece Extent=\"" << join(extent.begin(), extent.end()) << "\">\n";
   });
 
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : pointData_)
-      this->writeData(out, offsets, v, Super::POINT_DATA);
-    out << "</PointData>\n";
-  }
+  // Write data associated with grid points
+  out << "<PointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_)
+    this->writeData(out, offsets, v, Super::POINT_DATA);
+  out << "</PointData>\n";
+
+  // Write data associated with grid cells
+  out << "<CellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_)
+    this->writeData(out, offsets, v, Super::CELL_DATA);
+  out << "</CellData>\n";
 
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<CellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                       << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                       << ">\n";
-    for (auto const& v : cellData_)
-      this->writeData(out, offsets, v, Super::CELL_DATA);
-    out << "</CellData>\n";
-  }
   out << "</Piece>\n";
   out << "</ImageData>\n";
 
@@ -88,13 +71,13 @@ void VtkImageDataWriter<GV,DC>
     out << "<AppendedData encoding=\"raw\">\n_";
     appended_pos = out.tellp();
     for (auto const& v : pointData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::POINT_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::POINT_DATA) );
     }
     for (auto const& v : cellData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::CELL_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::CELL_DATA) );
@@ -123,63 +106,53 @@ void VtkImageDataWriter<GV,DC>
   std::string filename = pfilename + ".p" + this->fileExtension();
   std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
 
-  out << "<VTKFile type=\"PImageData\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
-  out << "<PImageData GhostLevel=\"0\" WholeExtent=\"";
+  out << "<VTKFile"
+      << " type=\"StructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
   auto const& wholeExtent = dataCollector_.wholeExtent();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
-  }
-  out << "\" Origin=\"";
   auto const& origin = dataCollector_.origin();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << origin[i];
-  }
-  out << "\" Spacing=\"";
   auto const& spacing = dataCollector_.spacing();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << spacing[i];
+  out << "<PImageData"
+      << " GhostLevel=\"0\""
+      << " WholeExtent=\"" << join(wholeExtent.begin(), wholeExtent.end()) << "\""
+      << " Origin=\"" << join(origin.begin(), origin.end()) << "\""
+      << " Spacing=\"" << join(spacing.begin(), spacing.end()) << "\""
+      << ">\n";
+
+  // Write data associated with grid points
+  out << "<PPointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" << to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
-  out << "\">\n";
-
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PPointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                         << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                         << ">\n";
-    for (auto const& v : pointData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PPointData>\n";
-  }
-
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PCellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : cellData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PCellData>\n";
+  out << "</PPointData>\n";
+
+  // Write data associated with grid cells
+  out << "<PCellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" <<  to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
+  out << "</PCellData>\n";
 
   // Write piece file references
-  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, std::array<int,6> const& extent, bool write_extent)
+  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, auto const& extent, bool write_extent)
   {
-    out << "<Piece Source=\"" << pfilename << "_p" << std::to_string(p) << "." << ext << "\"";
-    if (write_extent) {
-      out << " Extent=\"";
-      for (int i = 0; i < 3; ++i) {
-        out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
-      }
-      out << "\"";
-     }
+    std::string piece_source = pfilename + "_p" + std::to_string(p) + "." + ext;
+    out << "<Piece Source=\"" << piece_source << "\"";
+    if (write_extent)
+      out << " Extent=\"" << join(extent.begin(), extent.end()) << "\"";
      out << " />\n";
   });
 
diff --git a/dune/vtk/vtkstructuredgridwriter.impl.hh b/dune/vtk/vtkstructuredgridwriter.impl.hh
index d7f6294..60a9c98 100644
--- a/dune/vtk/vtkstructuredgridwriter.impl.hh
+++ b/dune/vtk/vtkstructuredgridwriter.impl.hh
@@ -29,46 +29,32 @@ void VtkStructuredGridWriter<GV,DC>
   }
 
   std::vector<pos_type> offsets; // pos => offset
-  out << "<VTKFile type=\"StructuredGrid\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
-  out << "<StructuredGrid WholeExtent=\"";
+  out << "<VTKFile"
+      << " type=\"StructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
   auto const& wholeExtent = dataCollector_.wholeExtent();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
-  }
-  out << "\">\n";
+  out << "<StructuredGrid WholeExtent=\"" << join(wholeExtent.begin(), wholeExtent.end()) << "\">\n";
 
-  dataCollector_.writeLocalPiece([&out](std::array<int,6> const& extent)
-  {
-    out << "<Piece Extent=\"";
-    for (int i = 0; i < 3; ++i) {
-      out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
-    }
-    out << "\">\n";
+  dataCollector_.writeLocalPiece([&out](auto const& extent) {
+    out << "<Piece Extent=\"" << join(extent.begin(), extent.end()) << "\">\n";
   });
 
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : pointData_)
-      this->writeData(out, offsets, v, Super::POINT_DATA);
-    out << "</PointData>\n";
-  }
+  // Write data associated with grid points
+  out << "<PointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_)
+    this->writeData(out, offsets, v, Super::POINT_DATA);
+  out << "</PointData>\n";
 
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<CellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                       << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                       << ">\n";
-    for (auto const& v : cellData_)
-      this->writeData(out, offsets, v, Super::CELL_DATA);
-    out << "</CellData>\n";
-  }
+  // Write data associated with grid cells
+  out << "<CellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_)
+    this->writeData(out, offsets, v, Super::CELL_DATA);
+  out << "</CellData>\n";
 
   // Write point coordinates
   out << "<Points>\n";
@@ -84,17 +70,18 @@ void VtkStructuredGridWriter<GV,DC>
     out << "<AppendedData encoding=\"raw\">\n_";
     appended_pos = out.tellp();
     for (auto const& v : pointData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::POINT_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::POINT_DATA) );
     }
     for (auto const& v : cellData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::CELL_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::CELL_DATA) );
     }
+
     if (datatype_ == Vtk::FLOAT32)
       blocks.push_back( this->template writePointsAppended<float>(out) );
     else
@@ -123,58 +110,57 @@ void VtkStructuredGridWriter<GV,DC>
   std::string filename = pfilename + ".p" + this->fileExtension();
   std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
 
-  out << "<VTKFile type=\"PStructuredGrid\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
-  out << "<PStructuredGrid GhostLevel=\"0\" WholeExtent=\"";
+  out << "<VTKFile"
+      << " type=\"PStructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
   auto const& wholeExtent = dataCollector_.wholeExtent();
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
+  out << "<PStructuredGrid"
+      << " GhostLevel=\"0\""
+      << " WholeExtent=\"" << join(wholeExtent.begin(), wholeExtent.end()) << "\""
+      << ">\n";
+
+  // Write data associated with grid points
+  out << "<PPointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" << to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
-  out << "\">\n";
-
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PPointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                         << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                         << ">\n";
-    for (auto const& v : pointData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PPointData>\n";
-  }
-
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PCellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : cellData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PCellData>\n";
+  out << "</PPointData>\n";
+
+  // Write data associated with grid cells
+  out << "<PCellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" << to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
+  out << "</PCellData>\n";
 
   // Write points
   out << "<PPoints>\n";
-  out << "<PDataArray type=\"" << Vtk::Map::from_datatype[datatype_] << "\" NumberOfComponents=\"3\" />\n";
+  out << "<PDataArray"
+      << " type=\"" << to_string(datatype_) << "\""
+      << " NumberOfComponents=\"3\""
+      << " />\n";
   out << "</PPoints>\n";
 
   // Write piece file references
-  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, std::array<int,6> const& extent, bool write_extent)
+  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, auto const& extent, bool write_extent)
   {
-    out << "<Piece Source=\"" << pfilename << "_p" << std::to_string(p) << "." << ext << "\"";
-    if (write_extent) {
-      out << " Extent=\"";
-      for (int i = 0; i < 3; ++i) {
-        out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
-      }
-      out << "\"";
-    }
+    std::string piece_source = pfilename + "_p" + std::to_string(p) + "." + ext;
+    out << "<Piece Source=\"" << piece_source << "\"";
+    if (write_extent)
+      out << " Extent=\"" << join(extent.begin(), extent.end()) << "\"";
     out << " />\n";
   });
 
diff --git a/dune/vtk/vtktypes.cc b/dune/vtk/vtktypes.cc
index feae227..f14ffc5 100644
--- a/dune/vtk/vtktypes.cc
+++ b/dune/vtk/vtktypes.cc
@@ -5,16 +5,55 @@
 namespace Dune { namespace experimental {
 namespace Vtk {
 
-std::map<std::uint8_t, GeometryType> Map::from_type = {
-  {VERTEX,     GeometryTypes::vertex },
-  {LINE,       GeometryTypes::line },
-  {TRIANGLE,   GeometryTypes::triangle },
-  {QUAD,       GeometryTypes::quadrilateral },
-  {TETRA,      GeometryTypes::tetrahedron },
-  {HEXAHEDRON, GeometryTypes::hexahedron },
-  {WEDGE,      GeometryTypes::prism },
-  {PYRAMID,    GeometryTypes::pyramid },
-};
+std::string to_string (FormatTypes type)
+{
+  switch (type) {
+    case ASCII:      return "ascii";
+    case BINARY:     return "binary";
+    case COMPRESSED: return "compressed";
+    case APPENDED:   return "appended";
+    default:
+      DUNE_THROW(RangeError, "FormatType not found.");
+      std::abort();
+  }
+}
+
+std::string to_string (DataTypes type)
+{
+  switch (type) {
+    case INT8: return "Int8";
+    case UINT8: return "UInt8";
+    case INT16: return "Int16";
+    case UINT16: return "UInt16";
+    case INT32: return "Int32";
+    case UINT32: return "UInt32";
+    case INT64: return "Int64";
+    case UINT64: return "UInt64";
+    case FLOAT32: return "Float32";
+    case FLOAT64: return "Float64";
+    default:
+      DUNE_THROW(RangeError, "DataType not found.");
+      std::abort();
+  }
+}
+
+GeometryType to_geometry (std::uint8_t cell)
+{
+  switch (cell) {
+    case VERTEX:     return GeometryTypes::vertex;
+    case LINE:       return GeometryTypes::line;
+    case TRIANGLE:   return GeometryTypes::triangle;
+    case QUAD:       return GeometryTypes::quadrilateral;
+    case TETRA:      return GeometryTypes::tetrahedron;
+    case HEXAHEDRON: return GeometryTypes::hexahedron;
+    case WEDGE:      return GeometryTypes::prism;
+    case PYRAMID:    return GeometryTypes::pyramid;
+    default:
+      DUNE_THROW(RangeError, "CellType does not map to GeometryType.");
+      std::abort();
+  }
+}
+
 
 std::map<std::string, DataTypes> Map::to_datatype = {
   {"Int8",    INT8},
@@ -29,18 +68,7 @@ std::map<std::string, DataTypes> Map::to_datatype = {
   {"Float64", FLOAT64}
 };
 
-std::map<DataTypes, std::string> Map::from_datatype = {
-  {INT8,    "Int8"},
-  {UINT8,   "UInt8"},
-  {INT16,   "Int16"},
-  {UINT16,  "UInt16"},
-  {INT32,   "Int32"},
-  {UINT32,  "UInt32"},
-  {INT64,   "Int64"},
-  {UINT64,  "UInt64"},
-  {FLOAT32, "Float32"},
-  {FLOAT64, "Float64"}
-};
+
 
 CellType::CellType (GeometryType const& t, CellParametrization parametrization)
   : noPermutation_(true)
diff --git a/dune/vtk/vtktypes.hh b/dune/vtk/vtktypes.hh
index 68342ce..0415be7 100644
--- a/dune/vtk/vtktypes.hh
+++ b/dune/vtk/vtktypes.hh
@@ -17,6 +17,7 @@ namespace Dune { namespace experimental
       COMPRESSED = 1<<2,
       APPENDED = BINARY | COMPRESSED
     };
+    std::string to_string (FormatTypes);
 
     enum DataTypes {
       UNKNOWN = 0,
@@ -27,6 +28,7 @@ namespace Dune { namespace experimental
       FLOAT32 = 32,
       FLOAT64 = 64
     };
+    std::string to_string (DataTypes);
 
     enum CellParametrization {
       LINEAR,
@@ -56,12 +58,28 @@ namespace Dune { namespace experimental
       QUADRATIC_TETRA      = 24,
       QUADRATIC_HEXAHEDRON = 25
     };
+    GeometryType to_geometry (std::uint8_t);
 
     struct Map
     {
-      static std::map<std::uint8_t, GeometryType> from_type; // VTK Cell type -> Dune::GeometryType
       static std::map<std::string, DataTypes> to_datatype; // String -> DataTypes
-      static std::map<DataTypes, std::string> from_datatype; // DataTypes -> String
+
+      template <class T> struct Type {};
+
+      static constexpr DataTypes typeImpl (Type<std::int8_t>)   { return INT8; }
+      static constexpr DataTypes typeImpl (Type<std::uint8_t>)  { return UINT8; }
+      static constexpr DataTypes typeImpl (Type<std::int16_t>)  { return INT16; }
+      static constexpr DataTypes typeImpl (Type<std::uint16_t>) { return UINT16; }
+      static constexpr DataTypes typeImpl (Type<std::int32_t>)  { return INT32; }
+      static constexpr DataTypes typeImpl (Type<std::uint32_t>) { return UINT32; }
+      static constexpr DataTypes typeImpl (Type<std::int64_t>)  { return INT64; }
+      static constexpr DataTypes typeImpl (Type<std::uint64_t>) { return UINT64; }
+      static constexpr DataTypes typeImpl (Type<float>)       { return FLOAT32; }
+      static constexpr DataTypes typeImpl (Type<double>)      { return FLOAT64; }
+      static constexpr DataTypes typeImpl (Type<long double>) { return FLOAT64; }
+
+      template <class T>
+      static constexpr DataTypes type = typeImpl(Type<T>{});
     };
 
 
diff --git a/dune/vtk/vtkunstructuredgridwriter.impl.hh b/dune/vtk/vtkunstructuredgridwriter.impl.hh
index 226f004..41c602c 100644
--- a/dune/vtk/vtkunstructuredgridwriter.impl.hh
+++ b/dune/vtk/vtkunstructuredgridwriter.impl.hh
@@ -29,34 +29,31 @@ void VtkUnstructuredGridWriter<GV,DC>
   }
 
   std::vector<pos_type> offsets; // pos => offset
-  out << "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
-  out << "<UnstructuredGrid>\n";
-  out << "<Piece NumberOfPoints=\"" << dataCollector_.numPoints() << "\" "
-      << "NumberOfCells=\"" << dataCollector_.numCells() << "\">\n";
-
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : pointData_)
-      this->writeData(out, offsets, v, Super::POINT_DATA);
-    out << "</PointData>\n";
-  }
+  out << "<VTKFile"
+      << " type=\"UnstructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
 
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<CellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                       << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                       << ">\n";
-    for (auto const& v : cellData_)
-      this->writeData(out, offsets, v, Super::CELL_DATA);
-    out << "</CellData>\n";
-  }
+  out << "<UnstructuredGrid>\n";
+  out << "<Piece"
+      << " NumberOfPoints=\"" << dataCollector_.numPoints() << "\""
+      << " NumberOfCells=\"" << dataCollector_.numCells() << "\""
+      << ">\n";
+
+  // Write data associated with grid points
+  out << "<PointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_)
+    this->writeData(out, offsets, v, Super::POINT_DATA);
+  out << "</PointData>\n";
+
+  // Write data associated with grid cells
+  out << "<CellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_)
+    this->writeData(out, offsets, v, Super::CELL_DATA);
+  out << "</CellData>\n";
 
   // Write point coordinates
   out << "<Points>\n";
@@ -77,17 +74,18 @@ void VtkUnstructuredGridWriter<GV,DC>
     out << "<AppendedData encoding=\"raw\">\n_";
     appended_pos = out.tellp();
     for (auto const& v : pointData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::POINT_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::POINT_DATA) );
     }
     for (auto const& v : cellData_) {
-      if (datatype_ == Vtk::FLOAT32)
+      if (v.type() == Vtk::FLOAT32)
         blocks.push_back( this->template writeDataAppended<float>(out, v, Super::CELL_DATA) );
       else
         blocks.push_back( this->template writeDataAppended<double>(out, v, Super::CELL_DATA) );
     }
+
     if (datatype_ == Vtk::FLOAT32)
       blocks.push_back( this->template writePointsAppended<float>(out) );
     else
@@ -118,45 +116,50 @@ void VtkUnstructuredGridWriter<GV,DC>
   std::string filename = pfilename + ".pvtu";
   std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
 
-  out << "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" "
-      << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
+  out << "<VTKFile"
+      << " type=\"PUnstructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
   out << "<PUnstructuredGrid GhostLevel=\"0\">\n";
 
-  { // Write data associated with grid points
-    auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PPointData" << (scalar != pointData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                         << (vector != pointData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                         << ">\n";
-    for (auto const& v : pointData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PPointData>\n";
+  // Write data associated with grid points
+  out << "<PPointData" << this->getNames(pointData_) << ">\n";
+  for (auto const& v : pointData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" << to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
-
-  { // Write data associated with grid cells
-    auto scalar = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() == 1; });
-    auto vector = std::find_if(cellData_.begin(), cellData_.end(), [](auto const& v) { return v.ncomps() > 1; });
-    out << "<PCellData" << (scalar != cellData_.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
-                        << (vector != cellData_.end() ? " Vectors=\"" + vector->name() + "\"" : "")
-                        << ">\n";
-    for (auto const& v : cellData_) {
-      out << "<PDataArray Name=\"" << v.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
-          << " NumberOfComponents=\"" << v.ncomps() << "\" />\n";
-    }
-    out << "</PCellData>\n";
+  out << "</PPointData>\n";
+
+  // Write data associated with grid cells
+  out << "<PCellData" << this->getNames(cellData_) << ">\n";
+  for (auto const& v : cellData_) {
+    out << "<PDataArray"
+        << " Name=\"" << v.name() << "\""
+        << " type=\"" << to_string(v.type()) << "\""
+        << " NumberOfComponents=\"" << v.ncomps() << "\""
+        << " />\n";
   }
+  out << "</PCellData>\n";
 
   // Write points
   out << "<PPoints>\n";
-  out << "<PDataArray type=\"" << Vtk::Map::from_datatype[datatype_] << "\" NumberOfComponents=\"3\" />\n";
+  out << "<PDataArray"
+      << " type=\"" << to_string(datatype_) << "\""
+      << " NumberOfComponents=\"3\""
+      << " />\n";
   out << "</PPoints>\n";
 
   // Write piece file references
-  for (int i = 0; i < size; ++i) {
-    out << "<Piece Source=\"" << pfilename << "_p" << std::to_string(i) << "." << this->fileExtension() << "\" />\n";
+  for (int p = 0; p < size; ++p) {
+    std::string piece_source = pfilename + "_p" + std::to_string(p) + "." + this->fileExtension();
+    out << "<Piece Source=\"" << piece_source << "\" />\n";
   }
 
   out << "</PUnstructuredGrid>\n";
diff --git a/dune/vtk/vtkwriter.hh b/dune/vtk/vtkwriter.hh
index 769cb9b..9e08181 100644
--- a/dune/vtk/vtkwriter.hh
+++ b/dune/vtk/vtkwriter.hh
@@ -4,6 +4,8 @@
 #include <iosfwd>
 #include <map>
 
+#include <dune/common/std/optional.hh>
+
 #include "datacollector.hh"
 #include "filewriter.hh"
 #include "vtkfunction.hh"
@@ -117,6 +119,35 @@ namespace Dune { namespace experimental
     template <class T>
     std::uint64_t writeAppended (std::ofstream& out, std::vector<T> const& values) const;
 
+
+    Std::optional<std::string> getScalarName (std::vector<GlobalFunction> const& data) const
+    {
+      auto scalar = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.ncomps() == 1; });
+      return scalar != data.end() ? Std::optional<std::string>{scalar->name()} : Std::optional<std::string>{};
+    }
+
+    Std::optional<std::string> getVectorName (std::vector<GlobalFunction> const& data) const
+    {
+      auto vector = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.ncomps() == 3; });
+      return vector != data.end() ? Std::optional<std::string>{vector->name()} : Std::optional<std::string>{};
+    }
+
+    Std::optional<std::string> getTensorName (std::vector<GlobalFunction> const& data) const
+    {
+      auto tensor = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.ncomps() == 9; });
+      return tensor != data.end() ? Std::optional<std::string>{tensor->name()} : Std::optional<std::string>{};
+    }
+
+    std::string getNames (std::vector<GlobalFunction> const& data) const
+    {
+      auto n1 = getScalarName(data);
+      auto n2 = getVectorName(data);
+      auto n3 = getScalarName(data);
+      return (n1 ? " Scalars=\"" + *n1 + "\"" : "")
+           + (n2 ? " Vectors=\"" + *n2 + "\"" : "")
+           + (n3 ? " Tensors=\"" + *n3 + "\"" : "");
+    }
+
     // Returns endianness
     std::string getEndian () const
     {
diff --git a/dune/vtk/vtkwriter.impl.hh b/dune/vtk/vtkwriter.impl.hh
index 184e477..7cb7f49 100644
--- a/dune/vtk/vtkwriter.impl.hh
+++ b/dune/vtk/vtkwriter.impl.hh
@@ -65,7 +65,7 @@ void VtkWriter<GV,DC>
   ::writeData (std::ofstream& out, std::vector<pos_type>& offsets,
                GlobalFunction const& fct, PositionTypes type) const
 {
-  out << "<DataArray Name=\"" << fct.name() << "\" type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
+  out << "<DataArray Name=\"" << fct.name() << "\" type=\"" << to_string(fct.type()) << "\""
       << " NumberOfComponents=\"" << fct.ncomps() << "\" format=\"" << (format_ == Vtk::ASCII ? "ascii\">\n" : "appended\"");
 
   if (format_ == Vtk::ASCII) {
@@ -93,7 +93,7 @@ template <class GV, class DC>
 void VtkWriter<GV,DC>
   ::writePoints (std::ofstream& out, std::vector<pos_type>& offsets) const
 {
-  out << "<DataArray type=\"" << Vtk::Map::from_datatype[datatype_] << "\""
+  out << "<DataArray type=\"" << to_string(datatype_) << "\""
       << " NumberOfComponents=\"3\" format=\"" << (format_ == Vtk::ASCII ? "ascii\">\n" : "appended\"");
 
   if (format_ == Vtk::ASCII) {
-- 
GitLab