diff --git a/dune.module b/dune.module
index d2413eb1270fedd9f74b692ea38242ad60fabbf7..0016381c19b9851567aaa40ebc49735de58cc361 100644
--- a/dune.module
+++ b/dune.module
@@ -8,3 +8,4 @@ Version: 0.1
 Maintainer: simon.praetorius@tu-dresden.de
 #depending on
 Depends: dune-grid dune-functions
+Suggests: dune-spgrid
diff --git a/dune/vtk/datacollector.hh b/dune/vtk/datacollector.hh
index bfbae79bb613e4ebe118360ad5dac999d73f7acb..a5bd9fcc23e45fa868c1636c40ac64d27cb80763 100644
--- a/dune/vtk/datacollector.hh
+++ b/dune/vtk/datacollector.hh
@@ -113,7 +113,7 @@ protected: // default implementations
     std::vector<T> data(numCells() * fct.ncomps());
     auto const& indexSet = gridView_.indexSet();
     auto localFct = localFunction(fct);
-    for (auto const& e : elements(gridView_)) {
+    for (auto const& e : elements(gridView_, Partitions::all)) {
       localFct.bind(e);
       auto geometry = e.geometry();
       std::size_t idx = fct.ncomps() * indexSet.index(e);
diff --git a/dune/vtk/datacollectors/continuousdatacollector.hh b/dune/vtk/datacollectors/continuousdatacollector.hh
index dea7840685df4ab24ea58f9105dcd518677ed410..340f558a545a39d926eea9ff4762dd5e8e566fb1 100644
--- a/dune/vtk/datacollectors/continuousdatacollector.hh
+++ b/dune/vtk/datacollectors/continuousdatacollector.hh
@@ -33,7 +33,7 @@ public:
   {
     std::vector<T> data(this->numPoints() * 3);
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& vertex : vertices(gridView_)) {
+    for (auto const& vertex : vertices(gridView_, Partitions::all)) {
       std::size_t idx = 3 * indexSet.index(vertex);
       auto v = vertex.geometry().center();
       for (std::size_t j = 0; j < v.size(); ++j)
@@ -61,7 +61,7 @@ public:
     cells.types.reserve(this->numCells());
 
     std::int64_t old_o = 0;
-    for (auto const& c : elements(gridView_)) {
+    for (auto const& c : elements(gridView_, Partitions::all)) {
       Vtk::CellType cellType(c.type());
       for (int j = 0; j < c.subEntities(dim); ++j)
         cells.connectivity.push_back( std::int64_t(indexSet.subIndex(c,cellType.permutation(j),dim)) );
@@ -79,7 +79,7 @@ public:
     std::vector<T> data(this->numPoints() * fct.ncomps());
     auto const& indexSet = gridView_.indexSet();
     auto localFct = localFunction(fct);
-    for (auto const& e : elements(gridView_)) {
+    for (auto const& e : elements(gridView_, Partitions::all)) {
       localFct.bind(e);
       Vtk::CellType cellType{e.type()};
       auto refElem = referenceElement(e.geometry());
diff --git a/dune/vtk/datacollectors/discontinuousdatacollector.hh b/dune/vtk/datacollectors/discontinuousdatacollector.hh
index 80ecfe0276c64f2eadf846369eab456669af0616..88d60a3b5aca50bff8d484e67289feec8d843bc3 100644
--- a/dune/vtk/datacollectors/discontinuousdatacollector.hh
+++ b/dune/vtk/datacollectors/discontinuousdatacollector.hh
@@ -30,7 +30,7 @@ public:
     indexMap_.resize(gridView_.size(dim));
     std::int64_t vertex_idx = 0;
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& c : elements(gridView_)) {
+    for (auto const& c : elements(gridView_, Partitions::interior)) {
       numPoints_ += c.subEntities(dim);
       for (int i = 0; i < c.subEntities(dim); ++i)
         indexMap_[indexSet.subIndex(c, i, dim)] = vertex_idx++;
@@ -49,7 +49,7 @@ public:
   {
     std::vector<T> data(this->numPoints() * 3);
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& element : elements(gridView_)) {
+    for (auto const& element : elements(gridView_, Partitions::interior)) {
       for (int i = 0; i < element.subEntities(dim); ++i) {
         std::size_t idx = 3 * indexMap_[indexSet.subIndex(element, i, dim)];
         auto v = element.geometry().corner(i);
@@ -72,7 +72,7 @@ public:
 
     std::int64_t old_o = 0;
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& c : elements(gridView_)) {
+    for (auto const& c : elements(gridView_, Partitions::interior)) {
       Vtk::CellType cellType(c.type());
       for (int j = 0; j < c.subEntities(dim); ++j) {
         std::int64_t vertex_idx = indexMap_[indexSet.subIndex(c,cellType.permutation(j),dim)];
@@ -92,7 +92,7 @@ public:
     std::vector<T> data(this->numPoints() * fct.ncomps());
     auto const& indexSet = gridView_.indexSet();
     auto localFct = localFunction(fct);
-    for (auto const& e : elements(gridView_)) {
+    for (auto const& e : elements(gridView_, Partitions::interior)) {
       localFct.bind(e);
       Vtk::CellType cellType{e.type()};
       auto refElem = referenceElement(e.geometry());
diff --git a/dune/vtk/datacollectors/quadraticdatacollector.hh b/dune/vtk/datacollectors/quadraticdatacollector.hh
index 7308158041ca34b5a5d1b3a8da12f3255109d3f0..df3aeb3db0bd2aeeb7f17057919284a6dae4e3a8 100644
--- a/dune/vtk/datacollectors/quadraticdatacollector.hh
+++ b/dune/vtk/datacollectors/quadraticdatacollector.hh
@@ -37,7 +37,7 @@ public:
   {
     std::vector<T> data(this->numPoints() * 3);
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& element : elements(gridView_)) {
+    for (auto const& element : elements(gridView_, Partitions::interior)) {
       auto geometry = element.geometry();
       auto refElem = referenceElement<T,dim>(element.type());
 
@@ -77,7 +77,7 @@ public:
 
     std::int64_t old_o = 0;
     auto const& indexSet = gridView_.indexSet();
-    for (auto const& c : elements(gridView_)) {
+    for (auto const& c : elements(gridView_, Partitions::interior)) {
       Vtk::CellType cellType(c.type(), Vtk::QUADRATIC);
       for (int j = 0; j < c.subEntities(dim); ++j) {
         int k = cellType.permutation(j);
@@ -103,7 +103,7 @@ public:
     std::vector<T> data(this->numPoints() * fct.ncomps());
     auto const& indexSet = gridView_.indexSet();
     auto localFct = localFunction(fct);
-    for (auto const& e : elements(gridView_)) {
+    for (auto const& e : elements(gridView_, Partitions::interior)) {
       localFct.bind(e);
       Vtk::CellType cellType{e.type(), Vtk::QUADRATIC};
       auto refElem = referenceElement(e.geometry());
diff --git a/dune/vtk/datacollectors/spdatacollector.hh b/dune/vtk/datacollectors/spdatacollector.hh
new file mode 100644
index 0000000000000000000000000000000000000000..5ec8d538326662f341ec51e891fc95fb7dce54b8
--- /dev/null
+++ b/dune/vtk/datacollectors/spdatacollector.hh
@@ -0,0 +1,102 @@
+#pragma once
+
+#ifdef HAVE_DUNE_SPGRID
+#include <dune/grid/spgrid.hh>
+#endif
+#include <dune/vtk/datacollectors/structureddatacollector.hh>
+
+namespace Dune { namespace experimental
+{
+#ifdef HAVE_DUNE_SPGRID
+
+// Specialization for SPGrid
+template <class GridView>
+class SPDataCollector
+    : public StructuredDataCollectorInterface<GridView, SPDataCollector<GridView>>
+{
+  enum { dim = GridView::dimension };
+
+  using Self = SPDataCollector;
+  using Super = StructuredDataCollectorInterface<GridView, Self>;
+  using Super::gridView_;
+  using ctype = typename GridView::ctype;
+
+public:
+  SPDataCollector (GridView const& gridView)
+    : Super(gridView)
+    , wholeExtent_(filledArray<6,int>(0))
+    , origin_(0.0)
+    , spacing_(0.0)
+  {}
+
+  std::array<int, 6> const& wholeExtentImpl () const
+  {
+    return wholeExtent_;
+  }
+
+  auto const& originImpl () const
+  {
+    return origin_;
+  }
+
+  auto const& spacingImpl () const
+  {
+    return spacing_;
+  }
+
+  void updateImpl ()
+  {
+    Super::updateImpl();
+
+    auto const& begin = gridView_.impl().gridLevel().globalMesh().begin();
+    auto const& end = gridView_.impl().gridLevel().globalMesh().end();
+    auto const& cube = gridView_.grid().domain().cube();
+
+    for (int i = 0; i < dim; ++i) {
+      wholeExtent_[2*i] = begin[i];
+      wholeExtent_[2*i+1] = end[i];
+      spacing_[i] = cube.width()[i] / (end[i] - begin[i]);
+      origin_[i] = cube.origin()[i];
+    }
+  }
+
+  template <class Writer>
+  void writeLocalPieceImpl (Writer const& writer) const
+  {
+    auto extent = filledArray<6,int>(0);
+    auto const& localMesh = gridView_.impl().gridLevel().localMesh();
+    for (int i = 0; i < dim; ++i) {
+      extent[2*i] = localMesh.begin()[i];
+      extent[2*i+1] = localMesh.end()[i];
+    }
+    writer(extent);
+  }
+
+  template <class Writer>
+  void writePiecesImpl (Writer const& writer) const
+  {
+    auto extent = filledArray<6,int>(0);
+    auto const& partitionList = gridView_.impl().gridLevel().decomposition_;
+    // for (auto const& part : partitionList)
+    for (std::size_t p = 0; p < partitionList.size(); ++p)
+    {
+      auto const& part = partitionList[p];
+      for (int i = 0; i < dim; ++i) {
+        extent[2*i] = part.begin()[i];
+        extent[2*i+1] = part.begin()[i] + part.width(i);
+      }
+      writer(p, extent, true);
+    }
+  }
+
+private:
+  std::array<int, 6> wholeExtent_;
+  std::array<int, 6> extent_;
+  FieldVector<ctype,3> spacing_;
+  FieldVector<ctype,3> origin_;
+  std::vector<std::size_t> indexMap_;
+};
+
+#endif
+
+}} // end namespace Dune::experimental
diff --git a/dune/vtk/datacollectors/structureddatacollector.hh b/dune/vtk/datacollectors/structureddatacollector.hh
index 80b54dd457a76d0c2b1d4c94a9a934e4826a44e4..667696f8f103275edda9fd28f13d6cc6bc249461 100644
--- a/dune/vtk/datacollectors/structureddatacollector.hh
+++ b/dune/vtk/datacollectors/structureddatacollector.hh
@@ -1,156 +1,78 @@
 #pragma once
 
-#include <dune/vtk/datacollector.hh>
+#include <dune/vtk/datacollectors/continuousdatacollector.hh>
 
 namespace Dune { namespace experimental
 {
-
-/// Implementation of \ref DataCollector for linear cells, with continuous data.
-template <class GridView>
-class StructuredDataCollector
-    : public DataCollectorInterface<GridView, StructuredDataCollector<GridView>>
+template <class GridView, class Derived>
+class StructuredDataCollectorInterface
+    : public DataCollectorInterface<GridView, Derived>
 {
-  enum { dim = GridView::dimension };
-
-  using Self = StructuredDataCollector;
-  using Super = DataCollectorInterface<GridView, Self>;
+protected:
+  using Super = DataCollectorInterface<GridView, Derived>;
   using Super::gridView_;
   using ctype = typename GridView::ctype;
 
-  struct CoordLess
-  {
-    template <class T, int N>
-    bool operator() (FieldVector<T,N> const& lhs, FieldVector<T,N> const& rhs) const
-    {
-      for (int i = N-1; i >= 0; --i) {
-        if (std::abs(lhs[i] - rhs[i]) < std::numeric_limits<T>::epsilon())
-          continue;
-        return lhs[i] < rhs[i];
-      }
-      return false;
-    }
-  };
-
 public:
-  StructuredDataCollector (GridView const& gridView)
+  StructuredDataCollectorInterface (GridView const& gridView)
     : Super(gridView)
+    , defaultDataCollector_(gridView)
   {}
 
   /// Return number of grid vertices
   std::uint64_t numPointsImpl () const
   {
-    return gridView_.size(dim);
+    return gridView_.size(GridView::dimension);
   }
 
-  std::array<int, 6> const& extent () const
+  void updateImpl ()
   {
-    return extent_;
+    defaultDataCollector_.update();
   }
 
-  auto const& origin () const
+  std::array<int, 6> const& wholeExtent () const
   {
-    return origin_;
+    return this->asDerived().wholeExtentImpl();
   }
 
-  auto const& spacing () const
+  FieldVector<ctype, 3> const& origin () const
   {
-    return spacing_;
+    return this->asDerived().originImpl();
   }
 
-  void updateImpl ()
+  FieldVector<ctype, 3> const& spacing () const
   {
-    // TODO: extract this information from the grid
-    int extent = GridView::dimension == 1 ? gridView_.size(dim) :
-                 GridView::dimension == 2 ? isqrt(gridView_.size(dim)) :
-                 GridView::dimension == 3 ? icbrt(gridView_.size(dim)) : 0;
-    for (int i = 0; i < 3; ++i) {
-      if (GridView::dimension > i) {
-        extent_[2*i] = 0;
-        extent_[2*i+1] = extent-1;
-        spacing_[i] = gridView_.grid().domainSize()[i] / (extent-1);
-      } else {
-        extent_[2*i] = extent_[2*i+1] = 0;
-        spacing_[i] = 0;
-      }
+    return this->asDerived().spacingImpl();
+  }
 
-      origin_[i] = 0;
-    }
+  template <class Writer>
+  void writeLocalPiece (Writer const& writer) const
+  {
+    this->asDerived().writeLocalPieceImpl(writer);
+  }
+
+  template <class Writer>
+  void writePieces (Writer const& writer) const
+  {
+    this->asDerived().writePiecesImpl(writer);
   }
 
   /// Return the coordinates of all grid vertices in the order given by the indexSet
   template <class T>
   std::vector<T> pointsImpl () const
   {
-    std::vector<T> data(this->numPoints() * 3);
-    auto const& indexSet = gridView_.indexSet();
-    for (auto const& vertex : vertices(gridView_)) {
-      std::size_t idx = 3 * indexSet.index(vertex);
-      auto v = vertex.geometry().center();
-      for (std::size_t j = 0; j < v.size(); ++j)
-        data[idx + j] = T(v[j]);
-      for (std::size_t j = v.size(); j < 3u; ++j)
-        data[idx + j] = T(0);
-    }
-    return data;
+    return defaultDataCollector_.template points<T>();
   }
 
   /// Evaluate the `fct` at the corners of the elements
   template <class T, class GlobalFunction>
   std::vector<T> pointDataImpl (GlobalFunction const& fct) const
   {
-    std::vector<T> data(this->numPoints() * fct.ncomps());
-    auto const& indexSet = gridView_.indexSet();
-    auto localFct = localFunction(fct);
-    for (auto const& e : elements(gridView_)) {
-      localFct.bind(e);
-      Vtk::CellType cellType{e.type()};
-      auto refElem = referenceElement(e.geometry());
-      for (int j = 0; j < e.subEntities(dim); ++j) {
-        int k = cellType.permutation(j);
-        std::size_t idx = fct.ncomps() * indexSet.subIndex(e,k,dim);
-        for (int comp = 0; comp < fct.ncomps(); ++comp)
-          data[idx + comp] = T(localFct.evaluate(comp, refElem.position(k,dim)));
-      }
-      localFct.unbind();
-    }
-    return data;
-  }
-
-private:
-  static constexpr std::uint32_t isqrt (std::uint64_t x)
-  {
-    std::uint32_t c = 0x8000;
-    std::uint32_t g = 0x8000;
-
-    while (true) {
-      if (g*g > x)
-        g ^= c;
-      c >>= 1;
-      if (c == 0)
-        return g;
-      g |= c;
-    }
-  }
-
-  static constexpr std::uint32_t icbrt (std::uint64_t x)
-  {
-    std::uint32_t y = 0;
-    for (int s = 63; s >= 0; s -= 3) {
-      y += y;
-      std::uint64_t b = 3*y*(std::uint64_t(y) + 1) + 1;
-      if ((x >> s) >= b) {
-        x -= b << s;
-        y++;
-      }
-    }
-    return y;
+    return defaultDataCollector_.template pointData<T>(fct);
   }
 
 private:
-  std::array<int, 6> extent_;
-  FieldVector<ctype,3> spacing_;
-  FieldVector<ctype,3> origin_;
-  std::vector<std::size_t> indexMap_;
+  DefaultDataCollector<GridView> defaultDataCollector_;
 };
 
 }} // end namespace Dune::experimental
diff --git a/dune/vtk/datacollectors/yaspdatacollector.hh b/dune/vtk/datacollectors/yaspdatacollector.hh
new file mode 100644
index 0000000000000000000000000000000000000000..e557941a123417e10fd19f5e35be818e0f6266fe
--- /dev/null
+++ b/dune/vtk/datacollectors/yaspdatacollector.hh
@@ -0,0 +1,124 @@
+#pragma once
+
+#include <dune/grid/yaspgrid.hh>
+#include <dune/vtk/datacollectors/structureddatacollector.hh>
+
+namespace Dune { namespace experimental
+{
+// Specialization for YaspGrid
+template <class GridView>
+class YaspDataCollector
+    : public StructuredDataCollectorInterface<GridView, YaspDataCollector<GridView>>
+{
+  enum { dim = GridView::dimension };
+
+  using Self = YaspDataCollector;
+  using Super = StructuredDataCollectorInterface<GridView, Self>;
+  using Super::gridView_;
+  using ctype = typename GridView::ctype;
+
+public:
+  YaspDataCollector (GridView const& gridView)
+    : Super(gridView)
+    , wholeExtent_(filledArray<6,int>(0))
+    , origin_(0.0)
+    , spacing_(0.0)
+    , level_(gridView.template begin<0,Interior_Partition>()->level())
+  {}
+
+  std::array<int, 6> const& wholeExtentImpl () const
+  {
+    return wholeExtent_;
+  }
+
+  auto const& originImpl () const
+  {
+    return origin_;
+  }
+
+  auto const& spacingImpl () const
+  {
+    return spacing_;
+  }
+
+  void updateImpl ()
+  {
+    Super::updateImpl();
+
+    for (int i = 0; i < dim; ++i) {
+      wholeExtent_[2*i] = 0;
+      wholeExtent_[2*i+1] = gridView_.grid().levelSize(level_,i);
+    }
+
+    auto it = gridView_.grid().begin(level_);
+    initGeometry(it->coords);
+  }
+
+  template <class Coords>
+  void initGeometry (Coords const& coords) { DUNE_THROW(NotImplemented, "Coordinate-Type not implemented!"); }
+
+  void initGeometry (EquidistantCoordinates<ctype,dim> const& coords)
+  {
+    for (int i = 0; i < dim; ++i) {
+      spacing_[i] = coords.meshsize(i,0);
+      origin_[i] = 0;
+    }
+  }
+
+  void initGeometry (EquidistantOffsetCoordinates<ctype,dim> const& coords)
+  {
+    for (int i = 0; i < dim; ++i) {
+      spacing_[i] = coords.meshsize(i,0);
+      origin_[i] = coords.origin(i);
+    }
+  }
+
+  void initGeometry (TensorProductCoordinates<ctype,dim> const& coords)
+  {
+    for (int i = 0; i < dim; ++i) {
+      spacing_[i] = coords.meshsize(i,0); // is not constant, but also not used.
+      origin_[i] = coords.coordinate(i,0);
+    }
+  }
+
+  template <class Writer>
+  void writeLocalPieceImpl (Writer const& writer) const
+  {
+    auto const& gl = *gridView_.grid().begin(level_);
+    auto const& g = gl.interior[0];
+    auto extent = filledArray<6,int>(0);
+    auto const& gc = *g.dataBegin();
+    for (int i = 0; i < dim; ++i) {
+      extent[2*i] = gc.min(i);
+      extent[2*i+1] = gc.max(i)+1;
+    }
+    writer(extent);
+  }
+
+  template <class Writer>
+  void writePiecesImpl (Writer const& writer) const
+  {
+    auto extent = filledArray<6,int>(0);
+    // for (auto const& part : gridView_.gridLevel().template partition<InteriorEntity>())
+    // {
+    //   for (int i = 0; i < dim; ++i) {
+    //     extent[2*i] = part.begin()[i];
+    //     extent[2*i+1] = part.end()[i]-1;
+    //   }
+
+    int num_ranks = -1;
+    MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
+    for (int p = 0; p < num_ranks; ++p) {
+      writer(p, extent, false);
+    }
+  }
+
+private:
+  std::array<int, 6> wholeExtent_;
+  FieldVector<ctype,3> spacing_;
+  FieldVector<ctype,3> origin_;
+  std::vector<std::size_t> indexMap_;
+  int level_;
+};
+
+}} // end namespace Dune::experimental
diff --git a/dune/vtk/vtkimagedatawriter.hh b/dune/vtk/vtkimagedatawriter.hh
index b1e43457aaefbd2c4d160f8df30f54a8e7f0a14c..55a1df5eae36f2065ae739b5f64a6fdc229329d4 100644
--- a/dune/vtk/vtkimagedatawriter.hh
+++ b/dune/vtk/vtkimagedatawriter.hh
@@ -14,7 +14,7 @@
 namespace Dune { namespace experimental
 {
   /// File-Writer for VTK .vtu files
-  template <class GridView, class DataCollector = StructuredDataCollector<GridView>>
+  template <class GridView, class DataCollector>
   class VtkImageDataWriter
       : public VtkWriter<GridView, DataCollector>
   {
diff --git a/dune/vtk/vtkimagedatawriter.impl.hh b/dune/vtk/vtkimagedatawriter.impl.hh
index 0f0ac77740d2b4ce74f9b4c86c1335047b805662..b392047719f51071303a38a262ad2530cf6e3424 100644
--- a/dune/vtk/vtkimagedatawriter.impl.hh
+++ b/dune/vtk/vtkimagedatawriter.impl.hh
@@ -28,16 +28,14 @@ void VtkImageDataWriter<GV,DC>
       out << std::setprecision(std::numeric_limits<double>::digits10+2);
   }
 
-  dataCollector_.update();
-
   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=\"";
-  auto const& extent = dataCollector_.extent();
+  auto const& wholeExtent = dataCollector_.wholeExtent();
   for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
+    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
   }
   out << "\" Origin=\"";
   auto const& origin = dataCollector_.origin();
@@ -50,11 +48,15 @@ void VtkImageDataWriter<GV,DC>
     out << (i == 0 ? "" : " ") << spacing[i];
   }
   out << "\">\n";
-  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](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";
+  });
 
   { // Write data associated with grid points
     auto scalar = std::find_if(pointData_.begin(), pointData_.end(), [](auto const& v) { return v.ncomps() == 1; });
@@ -125,9 +127,9 @@ void VtkImageDataWriter<GV,DC>
       << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
       << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
   out << "<PImageData GhostLevel=\"0\" WholeExtent=\"";
-  auto const& extent = dataCollector_.extent();
+  auto const& wholeExtent = dataCollector_.wholeExtent();
   for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
+    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
   }
   out << "\" Origin=\"";
   auto const& origin = dataCollector_.origin();
@@ -168,15 +170,20 @@ void VtkImageDataWriter<GV,DC>
   }
 
   // Write piece file references
-  for (int i = 0; i < size; ++i) {
-    out << "<Piece Source=\"" << pfilename << "_p" << std::to_string(i) << "." << this->fileExtension() << "\" Extent=\"";
-    for (int i = 0; i < 3; ++i) {
-      out << (i == 0 ? "" : " ") << extent[2*i] << " " << extent[2*i+1];
-    }
-    out << "\" />\n";
-  }
-
-  out << "</PUnstructuredGrid>\n";
+  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, std::array<int,6> 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 << "\"";
+     }
+     out << " />\n";
+  });
+
+  out << "</PImageData>\n";
   out << "</VTKFile>";
 }
 
diff --git a/dune/vtk/vtkstructuredgridwriter.hh b/dune/vtk/vtkstructuredgridwriter.hh
index 8c3aaa23ff4dd54b92901105392f1ce80b2f5443..a3c3b68b20f63eb2d6c33279fd9874648f447bbc 100644
--- a/dune/vtk/vtkstructuredgridwriter.hh
+++ b/dune/vtk/vtkstructuredgridwriter.hh
@@ -9,12 +9,11 @@
 #include "vtkfunction.hh"
 #include "vtktypes.hh"
 #include "vtkwriter.hh"
-#include "datacollectors/structureddatacollector.hh"
 
 namespace Dune { namespace experimental
 {
   /// File-Writer for VTK .vtu files
-  template <class GridView, class DataCollector = StructuredDataCollector<GridView>>
+  template <class GridView, class DataCollector>
   class VtkStructuredGridWriter
       : public VtkWriter<GridView, DataCollector>
   {
diff --git a/dune/vtk/vtkstructuredgridwriter.impl.hh b/dune/vtk/vtkstructuredgridwriter.impl.hh
index 7900e33942b1391cc697a95d97ea3180637578d5..d7f62943a4bd753578eb4a3d0592c8678508c451 100644
--- a/dune/vtk/vtkstructuredgridwriter.impl.hh
+++ b/dune/vtk/vtkstructuredgridwriter.impl.hh
@@ -28,26 +28,26 @@ void VtkStructuredGridWriter<GV,DC>
       out << std::setprecision(std::numeric_limits<double>::digits10+2);
   }
 
-  dataCollector_.update();
-
   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=\"";
+  auto const& wholeExtent = dataCollector_.wholeExtent();
   for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << dataCollector_.extent()[2*i];
-    out << " " << dataCollector_.extent()[2*i+1];
-  }
-  out << "\">\n";
-  out << "<Piece NumberOfPoints=\"" << dataCollector_.numPoints() << "\" "
-      << "NumberOfCells=\"" << dataCollector_.numCells() << "\" Extent=\"";
-  for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << dataCollector_.extent()[2*i];
-    out << " " << dataCollector_.extent()[2*i+1];
+    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
   }
   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";
+  });
+
   { // 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; });
@@ -127,10 +127,10 @@ void VtkStructuredGridWriter<GV,DC>
       << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
       << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\">\n" : ">\n");
   out << "<PStructuredGrid GhostLevel=\"0\" WholeExtent=\"";
+  auto const& wholeExtent = dataCollector_.wholeExtent();
   for (int i = 0; i < 3; ++i) {
-    out << (i == 0 ? "" : " ") << dataCollector_.extent()[2*i];
-    out << " " << dataCollector_.extent()[2*i+1];
-  } // TODO: WholeExtent is probably a global information. needs synchronization
+    out << (i == 0 ? "" : " ") << wholeExtent[2*i] << " " << wholeExtent[2*i+1];
+  }
   out << "\">\n";
 
   { // Write data associated with grid points
@@ -165,16 +165,20 @@ void VtkStructuredGridWriter<GV,DC>
   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() << "\" Extent=\"";
-    for (int i = 0; i < 3; ++i) {
-      out << (i == 0 ? "" : " ") << dataCollector_.extent()[2*i];
-      out << " " << dataCollector_.extent()[2*i+1];
-    } // TODO: need extent of piece
-    out << "\" />\n";
-  }
+  dataCollector_.writePieces([&out,pfilename,ext=this->fileExtension()](int p, std::array<int,6> 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 << "\"";
+    }
+    out << " />\n";
+  });
 
-  out << "</PUnstructuredGrid>\n";
+  out << "</PStructuredGrid>\n";
   out << "</VTKFile>";
 }
 
diff --git a/dune/vtk/vtkunstructuredgridwriter.impl.hh b/dune/vtk/vtkunstructuredgridwriter.impl.hh
index 4b619c30cc44838737a482bae824f8f08d7716d2..226f004e2b6dcc51d384e21135edce1bab3bbcad 100644
--- a/dune/vtk/vtkunstructuredgridwriter.impl.hh
+++ b/dune/vtk/vtkunstructuredgridwriter.impl.hh
@@ -28,8 +28,6 @@ void VtkUnstructuredGridWriter<GV,DC>
       out << std::setprecision(std::numeric_limits<double>::digits10+2);
   }
 
-  dataCollector_.update();
-
   std::vector<pos_type> offsets; // pos => offset
   out << "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" "
       << "byte_order=\"" << this->getEndian() << "\" header_type=\"UInt64\""
diff --git a/dune/vtk/vtkwriter.impl.hh b/dune/vtk/vtkwriter.impl.hh
index f70936a8386401a6f5f13b5bb5b73c4322bfe781..184e477e00c773f5be589cd80d248762be0271f5 100644
--- a/dune/vtk/vtkwriter.impl.hh
+++ b/dune/vtk/vtkwriter.impl.hh
@@ -34,6 +34,8 @@ void VtkWriter<GV,DC>
   }
 #endif
 
+  dataCollector_.update();
+
   auto p = filesystem::path(fn);
   auto name = p.stem();
   p.remove_filename();
diff --git a/src/structuredgridwriter.cc b/src/structuredgridwriter.cc
index 8d08855f8325ef818a9173c4c3d2ef81475b5264..5fbcb7d73f503c6ec30dc2319eb1e9e2865b7e61 100644
--- a/src/structuredgridwriter.cc
+++ b/src/structuredgridwriter.cc
@@ -22,78 +22,106 @@
 
 #include <dune/vtk/vtkstructuredgridwriter.hh>
 #include <dune/vtk/vtkimagedatawriter.hh>
+#include <dune/vtk/datacollectors/yaspdatacollector.hh>
+#include <dune/vtk/datacollectors/spdatacollector.hh>
 
 using namespace Dune;
 using namespace Dune::experimental;
 using namespace Dune::Functions;
 
-#define GRID_TYPE 1
-
-int main(int argc, char** argv)
+namespace Impl_
 {
-  Dune::MPIHelper::instance(argc, argv);
+  template <class GridView, class Grid>
+  struct StructuredDataCollector;
 
-  const int dim = 3;
+#ifdef HAVE_DUNE_SPGRID
+  template<class GridView, class ct, int dim, template< int > class Ref, class Comm>
+  struct StructuredDataCollector<GridView, SPGrid<ct,dim,Ref,Comm>>
+  {
+    using type = SPDataCollector<GridView>;
+  };
+#endif
+
+  template<class GridView, int dim, class Coordinates>
+  struct StructuredDataCollector<GridView, YaspGrid<dim,Coordinates>>
+  {
+    using type = YaspDataCollector<GridView>;
+  };
+}
+
+template <class GridView>
+using StructuredDataCollector = typename Impl_::StructuredDataCollector<GridView, typename GridView::Grid>::type;
 
-  using GridType = YaspGrid<dim>;
-  FieldVector<double,dim> upperRight; upperRight = 1.0;
-  auto numElements = filledArray<dim,int>(8);
-  GridType grid(upperRight,numElements);
 
-  using GridView = typename GridType::LeafGridView;
-  GridView gridView = grid.leafGridView();
+template <int dim>
+using int_ = std::integral_constant<int,dim>;
 
+template <class GridView>
+void write(std::string prefix, GridView const& gridView)
+{
   using namespace BasisFactory;
   auto basis = makeBasis(gridView, lagrange<1>());
 
   std::vector<double> p1function(basis.dimension());
-
   interpolate(basis, p1function, [](auto const& x) {
     return 100*x[0] + 10*x[1] + 1*x[2];
   });
 
-  // write discrete global-basis function
-  auto p1FctWrapped = makeDiscreteGlobalBasisFunction<double>(basis, p1function);
+  auto fct1 = makeDiscreteGlobalBasisFunction<double>(basis, p1function);
+  auto fct2 = makeAnalyticGridViewFunction([](auto const& x) {
+    return std::sin(10*x[0])*std::cos(10*x[1])+std::sin(10*x[2]);
+  }, gridView);
 
   {
-    using Writer = VtkStructuredGridWriter<GridView>;
+    using Writer = VtkStructuredGridWriter<GridView, StructuredDataCollector<GridView>>;
     Writer vtkWriter(gridView);
-    vtkWriter.addPointData(p1FctWrapped, "p1");
-    vtkWriter.addCellData(p1FctWrapped, "p0");
-
-    // write analytic function
-    auto p1Analytic = makeAnalyticGridViewFunction([](auto const& x) {
-      return std::sin(10*x[0])*std::cos(10*x[1])+std::sin(10*x[2]);
-    }, gridView);
-
-    vtkWriter.addPointData(p1Analytic, "analytic");
-
-    vtkWriter.write("sg_ascii_float32.vts", Vtk::ASCII);
-    vtkWriter.write("sg_binary_float32.vts", Vtk::BINARY);
-    vtkWriter.write("sg_compressed_float32.vts", Vtk::COMPRESSED);
-    vtkWriter.write("sg_ascii_float64.vts", Vtk::ASCII, Vtk::FLOAT64);
-    vtkWriter.write("sg_binary_float64.vts", Vtk::BINARY, Vtk::FLOAT64);
-    vtkWriter.write("sg_compressed_float64.vts", Vtk::COMPRESSED, Vtk::FLOAT64);
+    vtkWriter.addPointData(fct1, "p1");
+    vtkWriter.addCellData(fct1, "p0");
+    vtkWriter.addPointData(fct2, "analytic");
+    vtkWriter.write(prefix + "sg_ascii_float32.vts", Vtk::ASCII);
   }
 
   {
-    using Writer = VtkImageDataWriter<GridView>;
+    using Writer = VtkImageDataWriter<GridView, StructuredDataCollector<GridView>>;
     Writer vtkWriter(gridView);
-    vtkWriter.addPointData(p1FctWrapped, "p1");
-    vtkWriter.addCellData(p1FctWrapped, "p0");
-
-    // write analytic function
-    auto p1Analytic = makeAnalyticGridViewFunction([](auto const& x) {
-      return std::sin(10*x[0])*std::cos(10*x[1])+std::sin(10*x[2]);
-    }, gridView);
-
-    vtkWriter.addPointData(p1Analytic, "analytic");
-
-    vtkWriter.write("id_ascii_float32.vti", Vtk::ASCII);
-    vtkWriter.write("id_binary_float32.vti", Vtk::BINARY);
-    vtkWriter.write("id_compressed_float32.vti", Vtk::COMPRESSED);
-    vtkWriter.write("id_ascii_float64.vti", Vtk::ASCII, Vtk::FLOAT64);
-    vtkWriter.write("id_binary_float64.vti", Vtk::BINARY, Vtk::FLOAT64);
-    vtkWriter.write("id_compressed_float64.vti", Vtk::COMPRESSED, Vtk::FLOAT64);
+    vtkWriter.addPointData(fct1, "p1");
+    vtkWriter.addCellData(fct1, "p0");
+    vtkWriter.addPointData(fct2, "analytic");
+    vtkWriter.write(prefix + "id_ascii_float32.vti", Vtk::ASCII);
   }
 }
+
+template <int dim>
+void write_yaspgrid(std::integral_constant<int,dim>)
+{
+  using GridType = YaspGrid<dim>;
+  FieldVector<double,dim> upperRight; upperRight = 1.0;
+  auto numElements = filledArray<dim,int>(8);
+  GridType grid(upperRight,numElements,0,0);
+
+  write("yasp_" + std::to_string(dim) + "d_", grid.leafGridView());
+}
+
+template <int dim>
+void write_spgrid(std::integral_constant<int,dim>)
+{
+#ifdef HAVE_DUNE_SPGRID
+  using GridType = SPGrid<double,dim, SPIsotropicRefinement>;
+  FieldVector<double,dim> upperRight; upperRight = 1.0;
+  auto numElements = filledArray<dim,int>(8);
+  GridType grid(SPDomain<double,dim>::unitCube(),numElements);
+
+  write("sp_" + std::to_string(dim) + "d_", grid.leafGridView());
+#endif
+}
+
+int main(int argc, char** argv)
+{
+  Dune::MPIHelper::instance(argc, argv);
+
+  Hybrid::forEach(std::make_tuple(int_<1>{}, int_<2>{}, int_<3>{}), [](auto const dim)
+  {
+    write_yaspgrid(dim);
+    write_spgrid(dim);
+  });
+}