From 5408049536bd88773d6a26b5b6e5335aca031cce Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Sun, 2 Sep 2018 20:30:23 +0200
Subject: [PATCH] corrected writer of vector/tensor values data

---
 dune/vtk/defaultvtkfunction.hh                | 32 +++++--
 dune/vtk/vtkfunction.hh                       | 58 ++++++++-----
 dune/vtk/vtktypes.hh                          |  3 +-
 dune/vtk/vtkwriterinterface.hh                |  9 +-
 dune/vtk/vtkwriterinterface.impl.hh           | 67 +++++++++++----
 dune/vtk/writers/vtkimagedatawriter.impl.hh   | 16 +---
 .../writers/vtkrectilineargridwriter.impl.hh  | 22 +----
 .../writers/vtkstructuredgridwriter.impl.hh   | 26 ++----
 .../writers/vtkunstructuredgridwriter.impl.hh | 65 +++-----------
 src/CMakeLists.txt                            |  4 +
 src/vectorwriter.cc                           | 85 +++++++++++++++++++
 src/vtkreader.cc                              |  2 +-
 12 files changed, 234 insertions(+), 155 deletions(-)
 create mode 100644 src/vectorwriter.cc

diff --git a/dune/vtk/defaultvtkfunction.hh b/dune/vtk/defaultvtkfunction.hh
index d32f8a4..796144f 100644
--- a/dune/vtk/defaultvtkfunction.hh
+++ b/dune/vtk/defaultvtkfunction.hh
@@ -4,6 +4,13 @@
 
 namespace Dune
 {
+  template <class T, int N>
+  class FieldVector;
+
+  template <class T, int N, int M>
+  class FieldMatrix;
+
+
   /// Type erasure for dune-functions LocalFunction interface
   template <class GridView, class LocalFunction>
   class LocalFunctionWrapper final
@@ -17,9 +24,6 @@ namespace Dune
     template <class F, class D>
     using Range = std::decay_t<decltype(std::declval<F>()(std::declval<D>()))>;
 
-    template <class F, class D>
-    using VectorValued = decltype(std::declval<Range<F,D>>()[0u]);
-
   public:
     template <class LocalFct, disableCopyMove<Self, LocalFct> = 0>
     LocalFunctionWrapper (LocalFct&& localFct)
@@ -38,22 +42,32 @@ namespace Dune
 
     virtual double evaluate (int comp, LocalCoordinate const& xi) const override
     {
-      return evaluateImpl(comp, xi, Std::is_detected<VectorValued,LocalFunction,LocalCoordinate>{});
+      return evaluateImpl(comp, localFct_(xi));
     }
 
   private:
     // Evaluate a component of a vector valued data
-    double evaluateImpl (int comp, LocalCoordinate const& xi, std::true_type) const
+    template <class T, int N, int M>
+    double evaluateImpl (int comp, FieldMatrix<T,N,M> const& mat) const
+    {
+      int r = comp / 3;
+      int c = comp % 3;
+      return r < N && c < M ? mat[r][c] : 0.0;
+    }
+
+    // Evaluate a component of a vector valued data
+    template <class T, int N>
+    double evaluateImpl (int comp, FieldVector<T,N> const& vec) const
     {
-      auto y = localFct_(xi);
-      return comp < y.size() ? y[comp] : 0.0;
+      return comp < N ? vec[comp] : 0.0;
     }
 
     // Return the scalar values
-    double evaluateImpl (int comp, LocalCoordinate const& xi, std::false_type) const
+    template <class T>
+    double evaluateImpl (int comp, T const& value) const
     {
       assert(comp == 0);
-      return localFct_(xi);
+      return value;
     }
 
   private:
diff --git a/dune/vtk/vtkfunction.hh b/dune/vtk/vtkfunction.hh
index 8fa14a7..148a065 100644
--- a/dune/vtk/vtkfunction.hh
+++ b/dune/vtk/vtkfunction.hh
@@ -2,6 +2,7 @@
 
 #include <type_traits>
 
+#include <dune/common/std/optional.hh>
 #include <dune/common/std/type_traits.hh>
 
 #include "vtklocalfunction.hh"
@@ -9,17 +10,41 @@
 
 namespace Dune
 {
+  template <class T, int N>
+  class FieldVector;
+
+  template <class T, int N, int M>
+  class FieldMatrix;
+
+  namespace Impl
+  {
+    template <class T, class = void>
+    struct SizeImpl
+        : std::integral_constant<int, 1> {};
+
+    template <class T, int N>
+    struct SizeImpl<FieldVector<T,N>>
+        : std::integral_constant<int, N> {};
+
+    template <class T, int N, int M>
+    struct SizeImpl<FieldMatrix<T,N,M>>
+        : std::integral_constant<int, N*M> {};
+  }
+
+  template <class T>
+  constexpr int Size = Impl::SizeImpl<std::decay_t<T>>::value;
+
+
   template <class GridView>
   class VtkFunction
   {
     template <class F>
     using HasLocalFunction = decltype(localFunction(std::declval<F>()));
 
-    template <class F>
-    using Domain = typename std::decay_t<F>::EntitySet::GlobalCoordinate;
+    using Domain = typename GridView::template Codim<0>::Entity::Geometry::LocalCoordinate;
 
     template <class F>
-    using Range = std::decay_t<decltype(std::declval<F>()(std::declval<Domain<F>>()))>;
+    using Range = std::decay_t<decltype(std::declval<F>()(std::declval<Domain>()))>;
 
   public:
     /// Constructor VtkFunction from legacy VTKFunction
@@ -32,25 +57,18 @@ namespace Dune
 
     /// Construct VtkFunction from dune-functions GridFunction with Signature
     template <class F,
-      std::enable_if_t<Std::is_detected<HasLocalFunction,F>::value, int> = 0,
-      std::enable_if_t<Std::is_detected<Range,F>::value,int> = 0>
-    VtkFunction (F&& fct, std::string name, int ncomps = 1, Vtk::DataTypes type = Vtk::Map::type<Range<F>>)
+      std::enable_if_t<Std::is_detected<HasLocalFunction,F>::value, int> = 0>
+    VtkFunction (F&& fct, std::string name,
+                 Std::optional<int> ncomps = {},
+                 Std::optional<Vtk::DataTypes> type = {})
       : localFct_(localFunction(std::forward<F>(fct)))
       , name_(std::move(name))
-      , ncomps_(ncomps)
-      , type_(type)
-    {}
+    {
+      using R = Range<decltype(localFunction(std::forward<F>(fct)))>;
 
-    /// Construct VtkFunction from dune-functions GridFunction without Signature
-    template <class F,
-      std::enable_if_t<Std::is_detected<HasLocalFunction,F>::value, int> = 0,
-      std::enable_if_t<not Std::is_detected<Range,F>::value,int> = 0>
-    VtkFunction (F const& fct, std::string name, int ncomps = 1, Vtk::DataTypes type = Vtk::FLOAT32)
-      : localFct_(localFunction(std::forward<F>(fct)))
-      , name_(std::move(name))
-      , ncomps_(ncomps)
-      , type_(type)
-    {}
+      ncomps_ = ncomps ? *ncomps : Size<R>;
+      type_ = type ? *type : Vtk::Map::type<R>;
+    }
 
     VtkFunction () = default;
 
@@ -69,7 +87,7 @@ namespace Dune
     /// Return the number of components of the Range
     int ncomps () const
     {
-      return ncomps_;
+      return ncomps_ > 3 ? 9 : ncomps_ > 1 ? 3 : 1; // tensor, vector, scalar
     }
 
     /// Return the VTK Datatype associated with the functions range type
diff --git a/dune/vtk/vtktypes.hh b/dune/vtk/vtktypes.hh
index 250d5a8..5e50c6a 100644
--- a/dune/vtk/vtktypes.hh
+++ b/dune/vtk/vtktypes.hh
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include <dune/common/ftraits.hh>
 #include <dune/geometry/type.hh>
 
 namespace Dune
@@ -79,7 +80,7 @@ namespace Dune
       static constexpr DataTypes typeImpl (Type<long double>) { return FLOAT64; }
 
       template <class T>
-      static constexpr DataTypes type = typeImpl(Type<T>{});
+      static constexpr DataTypes type = typeImpl(Type<typename FieldTraits<T>::field_type>{});
     };
 
 
diff --git a/dune/vtk/vtkwriterinterface.hh b/dune/vtk/vtkwriterinterface.hh
index c32a062..9f1b386 100644
--- a/dune/vtk/vtkwriterinterface.hh
+++ b/dune/vtk/vtkwriterinterface.hh
@@ -5,10 +5,6 @@
 #include <string>
 #include <vector>
 
-#ifdef HAVE_ZLIB
-#include <zlib.h>
-#endif
-
 #include <dune/common/std/optional.hh>
 #include <dune/vtk/filewriter.hh>
 #include <dune/vtk/vtkfunction.hh>
@@ -121,6 +117,11 @@ namespace Dune
     template <class T>
     std::uint64_t writeValuesAppended (std::ofstream& out, std::vector<T> const& values) const;
 
+    template <class T>
+    void writeValuesAscii (std::ofstream& out, std::vector<T> const& values) const;
+
+    void writeHeader (std::ofstream& out, std::string const& type) const;
+
     /// Return PointData/CellData attributes for the name of the first scalar/vector/tensor DataArray
     std::string getNames (std::vector<VtkFunction> const& data) const;
 
diff --git a/dune/vtk/vtkwriterinterface.impl.hh b/dune/vtk/vtkwriterinterface.impl.hh
index 4242cf6..8a6b9fa 100644
--- a/dune/vtk/vtkwriterinterface.impl.hh
+++ b/dune/vtk/vtkwriterinterface.impl.hh
@@ -8,6 +8,10 @@
 #include <sstream>
 #include <string>
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
 #include <dune/geometry/referenceelements.hh>
 #include <dune/geometry/type.hh>
 
@@ -82,17 +86,11 @@ void VtkWriterInterface<GV,DC>
 
   if (format_ == Vtk::ASCII) {
     out << ">\n";
-    std::size_t i = 0;
-    if (type == POINT_DATA) {
-      auto data = dataCollector_.template pointData<double>(fct);
-      for (auto const& v : data)
-        out << v << (++i % 6 != 0 ? ' ' : '\n');
-    } else {
-      auto data = dataCollector_.template cellData<double>(fct);
-      for (auto const& v : data)
-        out << v << (++i % 6 != 0 ? ' ' : '\n');
-    }
-    out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+    if (type == POINT_DATA)
+      writeValuesAscii(out, dataCollector_.template pointData<double>(fct));
+    else
+      writeValuesAscii(out, dataCollector_.template cellData<double>(fct));
+    out << "</DataArray>\n";
   } else {
     out << " offset=";
     offsets.push_back(out.tellp());
@@ -114,11 +112,8 @@ void VtkWriterInterface<GV,DC>
 
   if (format_ == Vtk::ASCII) {
     out << ">\n";
-    auto points = dataCollector_.template points<double>();
-    std::size_t i = 0;
-    for (auto const& v : points)
-      out << v << (++i % 6 != 0 ? ' ' : '\n');
-    out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+    writeValuesAscii(out, dataCollector_.template points<double>());
+    out << "</DataArray>\n";
   } else {
     out << " offset=";
     offsets.push_back(out.tellp());
@@ -168,6 +163,46 @@ void VtkWriterInterface<GV,DC>
 }
 
 
+namespace Impl {
+
+  template <class T, std::enable_if_t<(sizeof(T)>1), int> = 0>
+  T const& printable (T const& t) { return t; }
+
+  std::int16_t printable (std::int8_t c) { return std::int16_t(c); }
+  std::uint16_t printable (std::uint8_t c) { return std::uint16_t(c); }
+
+} // end namespace Impl
+
+
+template <class GV, class DC>
+  template <class T>
+void VtkWriterInterface<GV,DC>
+  ::writeValuesAscii (std::ofstream& out, std::vector<T> const& values) const
+{
+  assert(is_a(format_, Vtk::ASCII) && "Function should by called only in ascii mode!\n");
+  std::size_t i = 0;
+  for (auto const& v : values)
+    out << Impl::printable(v) << (++i % 6 != 0 ? ' ' : '\n');
+  if (i % 6 != 0)
+    out << '\n';
+}
+
+template <class GV, class DC>
+void VtkWriterInterface<GV,DC>
+  ::writeHeader (std::ofstream& out, std::string const& type) const
+{
+  out << "<VTKFile"
+      << " type=\"" << type << "\""
+      << " version=\"1.0\""
+      << " header_type=\"UInt64\"";
+  if (format_ != Vtk::ASCII)
+    out << " byte_order=\"" << getEndian() << "\"";
+  if (format_ == Vtk::COMPRESSED)
+    out << " compressor=\"vtkZLibDataCompressor\"";
+  out << ">\n";
+}
+
+
 namespace Impl {
 
 template <class T>
diff --git a/dune/vtk/writers/vtkimagedatawriter.impl.hh b/dune/vtk/writers/vtkimagedatawriter.impl.hh
index f37691c..0eb3c38 100644
--- a/dune/vtk/writers/vtkimagedatawriter.impl.hh
+++ b/dune/vtk/writers/vtkimagedatawriter.impl.hh
@@ -21,13 +21,7 @@ void VtkImageDataWriter<GV,DC>
   ::writeSerialFile (std::ofstream& out) const
 {
   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";
+  this->writeHeader(out, "ImageData");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   auto const& origin = dataCollector_.origin();
@@ -66,13 +60,7 @@ template <class GV, class DC>
 void VtkImageDataWriter<GV,DC>
   ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  out << "<VTKFile"
-      << " type=\"PImageData\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
+  this->writeHeader(out, "PImageData");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   auto const& origin = dataCollector_.origin();
diff --git a/dune/vtk/writers/vtkrectilineargridwriter.impl.hh b/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
index 3ac7235..8bad8f4 100644
--- a/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
+++ b/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
@@ -21,13 +21,7 @@ void VtkRectilinearGridWriter<GV,DC>
   ::writeSerialFile (std::ofstream& out) const
 {
   std::vector<pos_type> offsets; // pos => offset
-  out << "<VTKFile"
-      << " type=\"RectilinearGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
+  this->writeHeader(out, "RectilinearGrid");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   out << "<RectilinearGrid"
@@ -67,13 +61,7 @@ template <class GV, class DC>
 void VtkRectilinearGridWriter<GV,DC>
   ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  out << "<VTKFile"
-      << " type=\"PRectilinearGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
+  this->writeHeader(out, "PRectilinearGrid");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   out << "<PRectilinearGrid"
@@ -138,10 +126,8 @@ void VtkRectilinearGridWriter<GV,DC>
       if (timestep)
         out << " TimeStep=\"" << *timestep << "\"";
       out << ">\n";
-      std::size_t i = 0;
-      for (auto const& c : coordinates[d])
-        out << c << (++i % 6 != 0 ? ' ' : '\n');
-      out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+      this->writeValuesAscii(out, coordinates[d]);
+      out << "</DataArray>\n";
     }
   }
   else { // Vtk::APPENDED format
diff --git a/dune/vtk/writers/vtkstructuredgridwriter.impl.hh b/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
index 30e6323..baf7d7e 100644
--- a/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
+++ b/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
@@ -21,13 +21,7 @@ void VtkStructuredGridWriter<GV,DC>
   ::writeSerialFile (std::ofstream& out) const
 {
   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";
+  this->writeHeader(out, "StructuredGrid");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   out << "<StructuredGrid WholeExtent=\"" << join(wholeExtent.begin(), wholeExtent.end()) << "\">\n";
@@ -65,13 +59,7 @@ template <class GV, class DC>
 void VtkStructuredGridWriter<GV,DC>
   ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  out << "<VTKFile"
-      << " type=\"PStructuredGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
+  this->writeHeader(out, "PStructuredGrid");
 
   auto const& wholeExtent = dataCollector_.wholeExtent();
   out << "<PStructuredGrid"
@@ -131,13 +119,9 @@ void VtkStructuredGridWriter<GV,DC>
   assert(is_a(format_, Vtk::APPENDED) && "Function should by called only in appended mode!\n");
 
   // write points
-  if (datatype_ == Vtk::FLOAT32) {
-    auto points = dataCollector_.template points<float>();
-    blocks.push_back(this->writeValuesAppended(out, points));
-  } else {
-    auto points = dataCollector_.template points<double>();
-    blocks.push_back(this->writeValuesAppended(out, points));
-  }
+  blocks.push_back( datatype_ == Vtk::FLOAT32
+    ? this->writeValuesAppended(out, dataCollector_.template points<float>())
+    : this->writeValuesAppended(out, dataCollector_.template points<double>()) );
 }
 
 } // end namespace Dune
diff --git a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
index 0a4e8b7..d915751 100644
--- a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
+++ b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
@@ -21,15 +21,9 @@ void VtkUnstructuredGridWriter<GV,DC>
   ::writeSerialFile (std::ofstream& out) const
 {
   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";
-
+  this->writeHeader(out, "UnstructuredGrid");
   out << "<UnstructuredGrid>\n";
+
   out << "<Piece"
       << " NumberOfPoints=\"" << dataCollector_.numPoints() << "\""
       << " NumberOfCells=\"" << dataCollector_.numCells() << "\""
@@ -69,14 +63,7 @@ template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
   ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const
 {
-  out << "<VTKFile"
-      << " type=\"PUnstructuredGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
-
+  this->writeHeader(out, "PUnstructuredGrid");
   out << "<PUnstructuredGrid GhostLevel=\"0\">\n";
 
   // Write points
@@ -130,14 +117,7 @@ void VtkUnstructuredGridWriter<GV,DC>
   assert(is_a(format_, Vtk::APPENDED));
 
   std::vector<std::vector<pos_type>> offsets(timesteps.size()); // pos => offset
-  out << "<VTKFile"
-      << " type=\"UnstructuredGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
-
+  this->writeHeader(out, "UnstructuredGrid");
   out << "<UnstructuredGrid"
       << " TimeValues=\"";
   {
@@ -237,14 +217,7 @@ void VtkUnstructuredGridWriter<GV,DC>
                                  int size,
                                  std::vector<std::pair<double, std::string>> const& timesteps) const
 {
-  out << "<VTKFile"
-      << " type=\"PUnstructuredGrid\""
-      << " version=\"1.0\""
-      << " byte_order=\"" << this->getEndian() << "\""
-      << " header_type=\"UInt64\""
-      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
-      << ">\n";
-
+  this->writeHeader(out, "PUnstructuredGrid");
   out << "<PUnstructuredGrid GhostLevel=\"0\""
       << " TimeValues=\"";
   {
@@ -312,28 +285,22 @@ void VtkUnstructuredGridWriter<GV,DC>
     if (timestep)
       out << " TimeStep=\"" << *timestep << "\"";
     out << ">\n";
-    std::size_t i = 0;
-    for (auto const& c : cells.connectivity)
-      out << c << (++i % 6 != 0 ? ' ' : '\n');
-    out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+    this->writeValuesAscii(out, cells.connectivity);
+    out << "</DataArray>\n";
 
     out << "<DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\"";
     if (timestep)
       out << " TimeStep=\"" << *timestep << "\"";
     out << ">\n";
-    i = 0;
-    for (auto const& o : cells.offsets)
-      out << o << (++i % 6 != 0 ? ' ' : '\n');
-    out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+    this->writeValuesAscii(out, cells.offsets);
+    out << "</DataArray>\n";
 
     out << "<DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\"";
     if (timestep)
       out << " TimeStep=\"" << *timestep << "\"";
     out << ">\n";
-    i = 0;
-    for (auto const& t : cells.types)
-      out << int(t) << (++i % 6 != 0 ? ' ' : '\n');
-    out << (i % 6 != 0 ? "\n" : "") << "</DataArray>\n";
+    this->writeValuesAscii(out, cells.types);
+    out << "</DataArray>\n";
   }
   else { // Vtk::APPENDED format
     out << "<DataArray type=\"Int64\" Name=\"connectivity\" format=\"appended\"";
@@ -370,13 +337,9 @@ void VtkUnstructuredGridWriter<GV,DC>
   assert(is_a(format_, Vtk::APPENDED) && "Function should by called only in appended mode!\n");
 
   // write points
-  if (datatype_ == Vtk::FLOAT32) {
-    auto points = dataCollector_.template points<float>();
-    blocks.push_back(this->writeValuesAppended(out, points));
-  } else {
-    auto points = dataCollector_.template points<double>();
-    blocks.push_back(this->writeValuesAppended(out, points));
-  }
+  blocks.push_back( datatype_ == Vtk::FLOAT32
+    ? this->writeValuesAppended(out, dataCollector_.template points<float>())
+    : this->writeValuesAppended(out, dataCollector_.template points<double>()) );
 
   // write conncetivity, offsets, and types
   auto cells = dataCollector_.cells();
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 82056a0..dcab3e6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,6 +35,10 @@ if (dune-functions_FOUND)
   add_executable("pvdwriter" pvdwriter.cc)
   target_link_dune_default_libraries("pvdwriter")
   target_link_libraries("pvdwriter" dunevtk)
+
+  add_executable("vectorwriter" vectorwriter.cc)
+  target_link_dune_default_libraries("vectorwriter")
+  target_link_libraries("vectorwriter" dunevtk)
 endif ()
 
 if (dune-polygongrid_FOUND)
diff --git a/src/vectorwriter.cc b/src/vectorwriter.cc
new file mode 100644
index 0000000..c7eac50
--- /dev/null
+++ b/src/vectorwriter.cc
@@ -0,0 +1,85 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <iostream>
+#include <set>
+#include <vector>
+
+#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI
+#include <dune/common/exceptions.hh> // We use exceptions
+
+#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+#include <dune/functions/functionspacebases/interpolate.hh>
+#include <dune/functions/gridfunctions/analyticgridviewfunction.hh>
+#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
+#include <dune/grid/yaspgrid.hh>
+
+#include <dune/vtk/vtkwriter.hh>
+
+using namespace Dune;
+using namespace Dune::Functions;
+
+using TestCases = std::set<std::tuple<std::string,Vtk::FormatTypes,Vtk::DataTypes>>;
+static TestCases test_cases = {
+  {"ascii32", Vtk::ASCII, Vtk::FLOAT32},
+  {"bin32", Vtk::BINARY, Vtk::FLOAT32},
+  {"zlib32", Vtk::COMPRESSED, Vtk::FLOAT32},
+  {"ascii64", Vtk::ASCII, Vtk::FLOAT64},
+  {"bin64", Vtk::BINARY, Vtk::FLOAT64},
+  {"zlib64", Vtk::COMPRESSED, Vtk::FLOAT64},
+};
+
+template <class GridView>
+void write (std::string prefix, GridView const& gridView)
+{
+  using namespace BasisFactory;
+  auto basis = makeBasis(gridView, lagrange<1>());
+
+  FieldVector<double,GridView::dimensionworld> c;
+  if (GridView::dimensionworld > 0) c[0] = 11.0;
+  if (GridView::dimensionworld > 1) c[1] = 7.0;
+  if (GridView::dimensionworld > 2) c[2] = 3.0;
+
+  auto vec = [&c](auto const& x) {
+    FieldVector<double,GridView::dimensionworld> result; result = c.dot(x);
+    return result;
+  };
+  auto mat = [&c](auto const& x) {
+    FieldMatrix<double,GridView::dimensionworld,GridView::dimensionworld> result;
+    for (int i = 0; i < GridView::dimensionworld; ++i)
+      result[i][i] = c.dot(x);
+    return result;
+  };
+  auto vec_fct = makeAnalyticGridViewFunction(vec, gridView);
+  auto mat_fct = makeAnalyticGridViewFunction(mat, gridView);
+
+  for (auto const& test_case : test_cases) {
+    VtkWriter<GridView> vtkWriter(gridView, std::get<1>(test_case), std::get<2>(test_case));
+    vtkWriter.addPointData(vec_fct, "vec");
+    vtkWriter.addPointData(mat_fct, "mat");
+    vtkWriter.write(prefix + "_" + std::to_string(GridView::dimensionworld) + "d_" + std::get<0>(test_case) + ".vtu");
+  }
+}
+
+template <int I>
+using int_ = std::integral_constant<int,I>;
+
+int main (int argc, char** argv)
+{
+  Dune::MPIHelper::instance(argc, argv);
+
+  // Test VtkWriter for YaspGrid
+  Hybrid::forEach(std::make_tuple(int_<2>{}, int_<3>{}), [](auto dim)
+  {
+    using GridType = YaspGrid<dim.value>;
+    FieldVector<double,dim.value> upperRight; upperRight = 1.0;
+    auto numElements = filledArray<dim.value,int>(8);
+    GridType grid(upperRight, numElements, 0, 0);
+    write("yasp_vec", grid.leafGridView());
+  });
+}
\ No newline at end of file
diff --git a/src/vtkreader.cc b/src/vtkreader.cc
index 8453d99..d82e96b 100644
--- a/src/vtkreader.cc
+++ b/src/vtkreader.cc
@@ -31,7 +31,7 @@ int main(int argc, char** argv)
   {
     FieldVector<double,dim> lowerLeft; lowerLeft = 0.0;
     FieldVector<double,dim> upperRight; upperRight = 1.0;
-    auto numElements = filledArray<dim,unsigned int>(8);
+    auto numElements = filledArray<dim,unsigned int>(4);
     auto gridPtr = StructuredGridFactory<GridType>::createSimplexGrid(lowerLeft, upperRight, numElements);
     auto& grid = *gridPtr;
 
-- 
GitLab