diff --git a/dune/vtk/utility/uid.hh b/dune/vtk/utility/uid.hh
new file mode 100644
index 0000000000000000000000000000000000000000..22c2bb7e7bf4eb72c4aa2062cea325b39c428825
--- /dev/null
+++ b/dune/vtk/utility/uid.hh
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <string>
+
+namespace Dune
+{
+  inline std::string uid (std::size_t len = 8)
+  {
+    static const auto digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    static const int N = std::strlen(digits);
+
+    std::string id(len,' ');
+    for (std::size_t i = 0; i < len; ++i)
+      id[i] = digits[std::rand()%N];
+
+    return id;
+  }
+
+} // end namespace Dune
diff --git a/dune/vtk/vtktimeserieswriter.hh b/dune/vtk/vtktimeserieswriter.hh
index 32a3e467308fe4a4059e1ad5655e7c59f4d77d8f..bb4d646942fa7dbe1af1908ee6d97970934c3daf 100644
--- a/dune/vtk/vtktimeserieswriter.hh
+++ b/dune/vtk/vtktimeserieswriter.hh
@@ -6,10 +6,17 @@
 
 #include <dune/vtk/filewriter.hh>
 #include <dune/vtk/vtktypes.hh>
+#include <dune/vtk/utility/filesystem.hh>
+#include <dune/vtk/utility/uid.hh>
 
 namespace Dune
 {
-  /// File-Writer for Vtk .vtu files
+  /// File-Writer for Vtk timeseries .vtu files
+  /**
+   * \tparam VtkWriter  Type of a FileWriter derived from \ref VtkWriterInterface that
+   *                    additionally supports writeTimeseriesSerialFile() and writeTimeseriesParallelFile(),
+   *                    e.g. \ref VtkUnstructuredGridWriter.
+   **/
   template <class VtkWriter>
   class VtkTimeseriesWriter
       : public FileWriter
@@ -18,6 +25,14 @@ namespace Dune
     using Self = VtkTimeseriesWriter;
     using pos_type = typename std::ostream::pos_type;
 
+    template <class W>
+    using HasWriteTimeseriesSerialFile = decltype(&W::writeTimeseriesSerialFile);
+    static_assert(Std::is_detected<HasWriteTimeseriesSerialFile, VtkWriter>::value, "");
+
+    template <class W>
+    using HasWriteTimeseriesParallelFile = decltype(&W::writeTimeseriesParallelFile);
+    static_assert(Std::is_detected<HasWriteTimeseriesParallelFile, VtkWriter>::value, "");
+
   public:
     /// Constructor, stores the gridView
     template <class... Args, disableCopyMove<Self, Args...> = 0>
@@ -25,6 +40,16 @@ namespace Dune
       : vtkWriter_{std::forward<Args>(args)...}
     {
       assert(vtkWriter_.format_ != Vtk::ASCII && "Timeseries writer requires APPENDED mode");
+      std::srand(std::time(nullptr));
+      // put temporary file to /tmp directory
+      tmpDir_ = filesystem::path("/tmp/vtktimeserieswriter_" + uid(10) + "/");
+      assert( filesystem::exists("/tmp") );
+      filesystem::create_directories(tmpDir_);
+    }
+
+    ~VtkTimeseriesWriter ()
+    {
+      std::remove(tmpDir_.string().c_str());
     }
 
     /// Write the attached data to the file with \ref Vtk::FormatTypes and \ref Vtk::DataTypes
@@ -52,6 +77,7 @@ namespace Dune
 
   protected:
     VtkWriter vtkWriter_;
+    filesystem::path tmpDir_;
 
     bool initialized_ = false;
 
diff --git a/dune/vtk/vtktimeserieswriter.impl.hh b/dune/vtk/vtktimeserieswriter.impl.hh
index 015f65bd1be1be10c6443d5af0ec336c2ff5b5b2..37b35527c9b6d9df66ed7171667470925e8b9a18 100644
--- a/dune/vtk/vtktimeserieswriter.impl.hh
+++ b/dune/vtk/vtktimeserieswriter.impl.hh
@@ -26,22 +26,32 @@ template <class W>
 void VtkTimeseriesWriter<W>
   ::writeTimestep (double time, std::string const& fn)
 {
-  auto p = filesystem::path(fn);
-  auto name = p.stem();
-  p.remove_filename();
-  p /= name.string();
+  auto name = filesystem::path(fn).stem();
+  auto tmp = tmpDir_;
+  tmp /= name.string();
 
   vtkWriter_.dataCollector_.update();
 
+  std::string filenameBase = tmp.string();
+
+  int rank = 0;
+  int num_ranks = 1;
+  #ifdef HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
+    if (num_ranks > 1)
+      filenameBase = tmp.string() + "_p" + std::to_string(rank);
+  #endif
+
   if (!initialized_) {
     // write points and cells only once
-    filenameMesh_ = p.string() + ".mesh.vtkdata";
+    filenameMesh_ = filenameBase + ".mesh.vtkdata";
     std::ofstream out(filenameMesh_, std::ios_base::ate | std::ios::binary);
     vtkWriter_.writeGridAppended(out, blocks_);
     initialized_ = true;
   }
 
-  std::string filenameData = p.string() + "_t" + std::to_string(timesteps_.size()) + ".vtkdata";
+  std::string filenameData = filenameBase + "_t" + std::to_string(timesteps_.size()) + ".vtkdata";
   std::ofstream out(filenameData, std::ios_base::ate | std::ios::binary);
   vtkWriter_.writeDataAppended(out, blocks_);
   timesteps_.emplace_back(time, filenameData);
@@ -59,8 +69,25 @@ void VtkTimeseriesWriter<W>
   auto name = p.stem();
   p.remove_filename();
   p /= name.string();
-  std::string filename = p.string() + ".ts." + vtkWriter_.getFileExtension();
-  vtkWriter_.writeTimeseriesFile(filename, filenameMesh_, timesteps_, blocks_);
+
+  std::string filenameBase = p.string() + "_ts";
+
+  int rank = 0;
+  int num_ranks = 1;
+#ifdef HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
+    if (num_ranks > 1)
+      filenameBase = p.string() + "_ts_p" + std::to_string(rank);
+#endif
+
+  std::string filename = filenameBase + "." + vtkWriter_.getFileExtension();
+  vtkWriter_.writeTimeseriesSerialFile(filename, filenameMesh_, timesteps_, blocks_);
+
+#ifdef HAVE_MPI
+  if (num_ranks > 1 && rank == 0)
+    vtkWriter_.writeTimeseriesParallelFile(p.string() + "_ts", num_ranks, timesteps_);
+#endif
 
   // remove all temporary data files
   int ec = std::remove(filenameMesh_.c_str());
diff --git a/dune/vtk/vtkwriterinterface.impl.hh b/dune/vtk/vtkwriterinterface.impl.hh
index c5d4eccb6879bfd1cc46a09704841d2e94491dfa..945dc4bbcd2ce56da815ed354ec4ccfa74ac5dcd 100644
--- a/dune/vtk/vtkwriterinterface.impl.hh
+++ b/dune/vtk/vtkwriterinterface.impl.hh
@@ -30,21 +30,21 @@ void VtkWriterInterface<GV,DC>
 
   std::string filename = p.string() + "." + fileExtension();
 
+  int rank = 0;
+  int num_ranks = 1;
+
 #ifdef HAVE_MPI
-  int rank = -1;
-  int num_ranks = -1;
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);
   MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
-  if (num_ranks > 1) {
+  if (num_ranks > 1)
     filename = p.string() + "_p" + std::to_string(rank) + "." + fileExtension();
+#endif
 
-    writeSerialFile(filename);
-    if (rank == 0) {
-      writeParallelFile(p.string(), num_ranks);
-    }
-  } else {
-    writeSerialFile(filename);
-  }
+  writeSerialFile(filename);
+
+#ifdef HAVE_MPI
+  if (num_ranks > 1 && rank == 0)
+    writeParallelFile(p.string(), num_ranks);
 #endif
 }
 
diff --git a/dune/vtk/writers/vtkunstructuredgridwriter.hh b/dune/vtk/writers/vtkunstructuredgridwriter.hh
index f5d557c45ab1ab78d3a4cf8b55f953a176dc7d6d..2429214253eda0c0986ad2b935426e39a697a504 100644
--- a/dune/vtk/writers/vtkunstructuredgridwriter.hh
+++ b/dune/vtk/writers/vtkunstructuredgridwriter.hh
@@ -47,10 +47,22 @@ namespace Dune
     virtual void writeParallelFile (std::string const& pfilename, int size) const override;
 
     /// Write a series of timesteps in one file
-    void writeTimeseriesFile (std::string const& filename,
-                              std::string const& filenameMesh,
-                              std::vector<std::pair<double, std::string>> const& timesteps,
-                              std::vector<std::uint64_t> const& blocksize) const;
+    /**
+     * \param filename      The name of the output file
+     * \param filenameMesh  The name of a file where the mesh is stored. Must exist.
+     * \param timesteps     A vector of pairs (timestep, filename) where the filename indicates
+     *                      a file where the data of the timestep is stored.
+     * \param blocks        A list of block sizes of the binary data stored in the files.
+     *                      Order: (points, cells, pointdata[0], celldata[0], pointdata[1], celldata[1],...)
+     **/
+    void writeTimeseriesSerialFile (std::string const& filename,
+                                    std::string const& filenameMesh,
+                                    std::vector<std::pair<double, std::string>> const& timesteps,
+                                    std::vector<std::uint64_t> const& blocks) const;
+
+    /// Write parallel VTK file for series of timesteps
+    void writeTimeseriesParallelFile (std::string const& pfilename, int size,
+                                      std::vector<std::pair<double, std::string>> const& timesteps) const;
 
     virtual std::string fileExtension () const override
     {
diff --git a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
index 752e3b5bf42172dc80b6b5c1d6b8225d9cf080b9..9bc44820d8741cb2729ab202fce3a3a6146d911b 100644
--- a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
+++ b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
@@ -136,10 +136,10 @@ void VtkUnstructuredGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
-  ::writeTimeseriesFile (std::string const& filename,
-                         std::string const& filenameMesh,
-                         std::vector<std::pair<double, std::string>> const& timesteps,
-                         std::vector<std::uint64_t> const& blocks) const
+  ::writeTimeseriesSerialFile (std::string const& filename,
+                               std::string const& filenameMesh,
+                               std::vector<std::pair<double, std::string>> const& timesteps,
+                               std::vector<std::uint64_t> const& blocks) const
 {
   std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
   assert(out.is_open());
@@ -206,15 +206,16 @@ void VtkUnstructuredGridWriter<GV,DC>
   out << "</Piece>\n";
   out << "</UnstructuredGrid>\n";
 
-  pos_type appended_pos = 0;
   out << "<AppendedData encoding=\"raw\">\n_";
-  appended_pos = out.tellp();
+  pos_type appended_pos = out.tellp();
 
-  std::ifstream file_mesh(filenameMesh, std::ios_base::in | std::ios_base::binary);
-  out << file_mesh.rdbuf();
-  file_mesh.close();
-  assert( std::uint64_t(out.tellp()) == std::accumulate(blocks.begin(), std::next(blocks.begin(),shift), std::uint64_t(appended_pos)) );
+  { // write grid (points, cells)
+    std::ifstream file_mesh(filenameMesh, std::ios_base::in | std::ios_base::binary);
+    out << file_mesh.rdbuf();
+    assert( std::uint64_t(out.tellp()) == std::accumulate(blocks.begin(), std::next(blocks.begin(),shift), std::uint64_t(appended_pos)) );
+  }
 
+  // write point-data and cell-data
   for (auto const& timestep : timesteps) {
     std::ifstream file(timestep.second, std::ios_base::in | std::ios_base::binary);
     out << file.rdbuf();
@@ -250,6 +251,78 @@ void VtkUnstructuredGridWriter<GV,DC>
 }
 
 
+template <class GV, class DC>
+void VtkUnstructuredGridWriter<GV,DC>
+  ::writeTimeseriesParallelFile (std::string const& pfilename, int size, std::vector<std::pair<double, std::string>> const& timesteps) const
+{
+  std::string filename = pfilename + ".pvtu";
+  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
+  assert(out.is_open());
+
+  out << "<VTKFile"
+      << " type=\"PUnstructuredGrid\""
+      << " version=\"1.0\""
+      << " byte_order=\"" << this->getEndian() << "\""
+      << " header_type=\"UInt64\""
+      << (format_ == Vtk::COMPRESSED ? " compressor=\"vtkZLibDataCompressor\"" : "")
+      << ">\n";
+
+  out << "<PUnstructuredGrid GhostLevel=\"0\""
+      << " TimeValues=\"";
+  {
+    std::size_t i = 0;
+    for (auto const& timestep : timesteps)
+      out << timestep.first << (++i % 6 != 0 ? ' ' : '\n');
+  }
+  out << "\">\n";
+
+  // Write points
+  out << "<PPoints>\n";
+  out << "<PDataArray"
+      << " type=\"" << to_string(datatype_) << "\""
+      << " NumberOfComponents=\"3\""
+      << " />\n";
+  out << "</PPoints>\n";
+
+  // Write data associated with grid points
+  out << "<PPointData" << this->getNames(pointData_) << ">\n";
+  for (std::size_t i = 0; i < timesteps.size(); ++i) {
+    for (auto const& v : pointData_) {
+      out << "<PDataArray"
+          << " Name=\"" << v.name() << "\""
+          << " type=\"" << to_string(v.type()) << "\""
+          << " NumberOfComponents=\"" << v.ncomps() << "\""
+          << " TimeStep=\"" << i << "\""
+          << " />\n";
+    }
+  }
+  out << "</PPointData>\n";
+
+  // Write data associated with grid cells
+  out << "<PCellData" << this->getNames(cellData_) << ">\n";
+  for (std::size_t i = 0; i < timesteps.size(); ++i) {
+    for (auto const& v : cellData_) {
+      out << "<PDataArray"
+          << " Name=\"" << v.name() << "\""
+          << " type=\"" << to_string(v.type()) << "\""
+          << " NumberOfComponents=\"" << v.ncomps() << "\""
+          << " TimeStep=\"" << i << "\""
+          << " />\n";
+    }
+  }
+  out << "</PCellData>\n";
+
+  // Write piece file references
+  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";
+  out << "</VTKFile>";
+}
+
+
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
   ::writeCells (std::ofstream& out, std::vector<pos_type>& offsets,
diff --git a/src/timeserieswriter.cc b/src/timeserieswriter.cc
index 2b5f693412e7b529a0bfe57c234cf242522b7dd2..e999b222e2923bb777405f2965b235c5df93ceba 100644
--- a/src/timeserieswriter.cc
+++ b/src/timeserieswriter.cc
@@ -49,7 +49,7 @@ int main (int argc, char** argv)
 
   using GridType = YaspGrid<3>;
   FieldVector<double,3> upperRight; upperRight = 1.0;
-  auto numElements = filledArray<3,int>(4);
+  auto numElements = filledArray<3,int>(8);
   GridType grid(upperRight, numElements);
   write("yasp", grid.leafGridView());
 }
\ No newline at end of file