diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp
index cf85b52eb9e020d165bdc8a30d86609ea1a17a3c..4f98d0f2372323aed61af96c824ed262fcd3ace2 100644
--- a/src/output/GnuplotWriter.cpp
+++ b/src/output/GnuplotWriter.cpp
@@ -36,7 +36,10 @@ GnuplotWriter::_getFilename() const
 {
   std::ostringstream sout;
   sout << m_base_filename;
-  sout << '.' << std::setfill('0') << std::setw(4) << m_saved_times.size() << ".gnu";
+  if (m_period_manager.has_value()) {
+    sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes();
+  }
+  sout << ".gnu";
   return sout.str();
 }
 
@@ -236,9 +239,9 @@ GnuplotWriter::_writeNodeData(const NodeArray<DataType>& node_array, NodeId node
 
 template <typename MeshType>
 void
-GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh,
-                      const OutputNamedItemDataSet& output_named_item_data_set,
-                      double time) const
+GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                            const OutputNamedItemDataSet& output_named_item_data_set,
+                            double time) const
 {
   if (parallel::rank() == 0) {
     std::ofstream fout{_getFilename()};
@@ -270,11 +273,11 @@ GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const
 
   switch (p_mesh->dimension()) {
   case 1: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, 0);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, 0);
     break;
   }
   case 2: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, 0);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, 0);
     break;
   }
   default: {
@@ -284,8 +287,9 @@ GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const
 }
 
 void
-GnuplotWriter::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-                     double time) const
+GnuplotWriter::_writeAtTime(
+  const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+  double time) const
 {
   std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
 
@@ -293,11 +297,11 @@ GnuplotWriter::write(const std::vector<std::shared_ptr<const NamedDiscreteFuncti
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
     break;
   }
   case 2: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
     break;
   }
   default: {
diff --git a/src/output/GnuplotWriter.hpp b/src/output/GnuplotWriter.hpp
index 608d830152cb9c90d6f8b4014bbf2d8054099fe7..312e4886c9d3cb3b19ea2e96bba3d18e611a5eeb 100644
--- a/src/output/GnuplotWriter.hpp
+++ b/src/output/GnuplotWriter.hpp
@@ -45,16 +45,16 @@ class GnuplotWriter : public WriterBase
                          std::ostream& fout) const;
 
   template <typename MeshType>
-  void _write(const std::shared_ptr<const MeshType>& mesh,
-              const OutputNamedItemDataSet& output_named_item_data_set,
-              double time) const;
+  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                    const OutputNamedItemDataSet& output_named_item_data_set,
+                    double time) const;
+
+  void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+                    double time) const final;
 
  public:
   void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
 
-  void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-             double time) const final;
-
   GnuplotWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {}
 
   ~GnuplotWriter() = default;
diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp
index 65bb4039a1c5296bf028a869d3c5d1774b1ddd6c..7fbd6612ada3a1aaed3b95fc1050ac43ffc632ac 100644
--- a/src/output/GnuplotWriter1D.cpp
+++ b/src/output/GnuplotWriter1D.cpp
@@ -36,7 +36,10 @@ GnuplotWriter1D::_getFilename() const
 {
   std::ostringstream sout;
   sout << m_base_filename;
-  sout << '.' << std::setfill('0') << std::setw(4) << m_saved_times.size() << ".gnu";
+  if (m_period_manager.has_value()) {
+    sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes();
+  }
+  sout << ".gnu";
   return sout.str();
 }
 
@@ -257,9 +260,9 @@ GnuplotWriter1D::_writeItemDatas(const std::shared_ptr<const MeshType>& mesh,
 
 template <typename MeshType>
 void
-GnuplotWriter1D::_write(const std::shared_ptr<const MeshType>& mesh,
-                        const OutputNamedItemDataSet& output_named_item_data_set,
-                        double time) const
+GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                              const OutputNamedItemDataSet& output_named_item_data_set,
+                              double time) const
 {
   bool has_cell_data = false;
   for (const auto& [name, item_data_variant] : output_named_item_data_set) {
@@ -298,12 +301,17 @@ GnuplotWriter1D::_write(const std::shared_ptr<const MeshType>& mesh,
 void
 GnuplotWriter1D::writeMesh(const std::shared_ptr<const IMesh>&) const
 {
-  throw UnexpectedError("This function should not be called");
+  std::ostringstream errorMsg;
+  errorMsg << "gnuplot_1d_writer does not write meshes\n"
+           << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue
+           << "gnuplot_writer" << rang::fg::reset << "  instead";
+  throw NormalError(errorMsg.str());
 }
 
 void
-GnuplotWriter1D::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-                       double time) const
+GnuplotWriter1D::_writeAtTime(
+  const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+  double time) const
 {
   std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
 
@@ -311,7 +319,7 @@ GnuplotWriter1D::write(const std::vector<std::shared_ptr<const NamedDiscreteFunc
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
     break;
   }
   case 2: {
diff --git a/src/output/GnuplotWriter1D.hpp b/src/output/GnuplotWriter1D.hpp
index b003d1756f8917dadf7350adada701052494b581..f1e7b23c876aca9aadb93c47154289468e027a85 100644
--- a/src/output/GnuplotWriter1D.hpp
+++ b/src/output/GnuplotWriter1D.hpp
@@ -38,16 +38,16 @@ class GnuplotWriter1D : public WriterBase
   void _writePreamble(const OutputNamedItemDataSet& output_named_item_value_set, std::ostream& fout) const;
 
   template <typename MeshType>
-  void _write(const std::shared_ptr<const MeshType>& mesh,
-              const OutputNamedItemDataSet& output_named_item_value_set,
-              double time) const;
+  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                    const OutputNamedItemDataSet& output_named_item_value_set,
+                    double time) const;
+
+  void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+                    double time) const final;
 
  public:
   void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
 
-  void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-             double time) const final;
-
   GnuplotWriter1D(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period)
   {}
 
diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp
index de7be9f664133bc7de2833893ddc6b19a99e774d..55a2e90d90faeea769a2565df655422f41a983d4 100644
--- a/src/output/VTKWriter.cpp
+++ b/src/output/VTKWriter.cpp
@@ -130,7 +130,10 @@ VTKWriter::_getFilenamePVTU() const
 {
   std::ostringstream sout;
   sout << m_base_filename;
-  sout << '.' << std::setfill('0') << std::setw(4) << m_saved_times.size() << ".pvtu";
+  if (m_period_manager.has_value()) {
+    sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes();
+  }
+  sout << ".pvtu";
   return sout.str();
 }
 
@@ -158,7 +161,10 @@ VTKWriter::_getFilenameVTU(int rank_number) const
   if (parallel::size() > 1) {
     sout << '-' << std::setfill('0') << std::setw(4) << rank_number;
   }
-  sout << '.' << std::setfill('0') << std::setw(4) << m_saved_times.size() << ".vtu";
+  if (m_period_manager.has_value()) {
+    sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes();
+  }
+  sout << ".vtu";
   return sout.str();
 }
 
@@ -349,10 +355,14 @@ VTKWriter::_write_node_data(std::ofstream& os,
 
 template <typename MeshType>
 void
-VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh,
-                  const OutputNamedItemDataSet& given_output_named_item_data_set,
-                  double time) const
+VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                        const OutputNamedItemDataSet& given_output_named_item_data_set,
+                        double time) const
 {
+  if (not m_period_manager.has_value()) {
+    throw NormalError("Writer has no period defined");
+  }
+
   OutputNamedItemDataSet output_named_item_data_set{given_output_named_item_data_set};
   // Adding basic mesh information
   output_named_item_data_set.add(NamedItemData{"cell_number", mesh->connectivity().cellNumber()});
@@ -612,12 +622,12 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh,
     fout << "<VTKFile type=\"Collection\" version=\"0.1\">\n";
 
     fout << "<Collection>\n";
-    for (size_t i_time = 0; i_time < m_saved_times.size(); ++i_time) {
+    for (size_t i_time = 0; i_time < m_period_manager->nbSavedTimes(); ++i_time) {
       std::ostringstream sout;
       sout << m_base_filename;
       sout << '.' << std::setfill('0') << std::setw(4) << i_time << ".pvtu";
 
-      fout << "<DataSet timestep=\"" << m_saved_times[i_time] << "\" file=\"" << sout.str() << "\"/>\n";
+      fout << "<DataSet timestep=\"" << m_period_manager->savedTime(i_time) << "\" file=\"" << sout.str() << "\"/>\n";
     }
     fout << "<DataSet timestep=\"" << time << "\" file=\"" << _getFilenamePVTU() << "\"/>\n";
 
@@ -633,15 +643,15 @@ VTKWriter::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, 0);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, 0);
     break;
   }
   case 2: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, 0);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, 0);
     break;
   }
   case 3: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, 0);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, 0);
     break;
   }
   default: {
@@ -651,8 +661,8 @@ VTKWriter::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
 }
 
 void
-VTKWriter::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-                 double time) const
+VTKWriter::_writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+                        double time) const
 {
   std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
 
@@ -660,15 +670,15 @@ VTKWriter::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
     break;
   }
   case 2: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
     break;
   }
   case 3: {
-    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time);
+    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time);
     break;
   }
   default: {
diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp
index 913a05ef1de358cfe32f9b6faf1a9e6720585238..eb0f70d9253204124123395a531b28c940c28345 100644
--- a/src/output/VTKWriter.hpp
+++ b/src/output/VTKWriter.hpp
@@ -95,15 +95,17 @@ class VTKWriter : public WriterBase
                         SerializedDataList& serialized_data_list) const;
 
   template <typename MeshType>
-  void _write(const std::shared_ptr<const MeshType>& mesh,
-              const OutputNamedItemDataSet& output_named_item_data_set,
-              double time) const;
+  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
+                    const OutputNamedItemDataSet& output_named_item_data_set,
+                    double time) const;
+
+  void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+                    double time) const final;
 
  public:
   void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
 
-  void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-             double time) const final;
+  VTKWriter(const std::string& base_filename) : WriterBase(base_filename) {}
 
   VTKWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {}
 
diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp
index adf3f4a7f38216558602b5e5634c89364ef3cf6e..7ae28e9e800f1a1cea705ab2a1789ad284558e9d 100644
--- a/src/output/WriterBase.cpp
+++ b/src/output/WriterBase.cpp
@@ -194,32 +194,27 @@ WriterBase::_getOutputNamedItemDataSet(
   return named_item_data_set;
 }
 
-double
-WriterBase::getLastTime() const
-{
-  if (m_saved_times.size() > 0) {
-    return m_saved_times[m_saved_times.size() - 1];
-  } else {
-    return -std::numeric_limits<double>::max();
-  }
-}
-
 WriterBase::WriterBase(const std::string& base_filename, const double& time_period)
-  : m_base_filename{base_filename}, m_time_period{time_period}, m_next_time{0}
+  : m_base_filename{base_filename}, m_period_manager(time_period)
 {}
 
+WriterBase::WriterBase(const std::string& base_filename) : m_base_filename{base_filename} {}
+
 void
 WriterBase::writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                           double time) const
 {
-  const double last_time = getLastTime();
-  if (time == last_time)
-    return;   // output already performed
-
-  if (time >= m_next_time) {
-    m_next_time += m_time_period;
-    this->write(named_discrete_function_list, time);
-    m_saved_times.push_back(time);
+  if (m_period_manager.has_value()) {
+    const double last_time = m_period_manager->getLastTime();
+    if (time == last_time)
+      return;   // output already performed
+
+    if (time >= m_period_manager->nextTime()) {
+      this->_writeAtTime(named_discrete_function_list, time);
+      m_period_manager->setSaveTime(time);
+    }
+  } else {
+    throw NormalError("Writer has no period defined");
   }
 }
 
@@ -227,9 +222,13 @@ void
 WriterBase::writeForced(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                         double time) const
 {
-  if (time == getLastTime())
-    return;   // output already performed
+  if (m_period_manager.has_value()) {
+    if (time == m_period_manager->getLastTime())
+      return;   // output already performed
 
-  this->write(named_discrete_function_list, time);
-  m_saved_times.push_back(time);
+    this->_writeAtTime(named_discrete_function_list, time);
+    m_period_manager->setSaveTime(time);
+  } else {
+    throw NormalError("Writer has no period defined");
+  }
 }
diff --git a/src/output/WriterBase.hpp b/src/output/WriterBase.hpp
index 3ba91af2867b50078037a0d699f914e42ed63f3e..6d96ee410d32632ffaf0b5ead86ac4bdbccc88af 100644
--- a/src/output/WriterBase.hpp
+++ b/src/output/WriterBase.hpp
@@ -2,7 +2,10 @@
 #define WRITER_BASE_HPP
 
 #include <output/IWriter.hpp>
+#include <utils/PugsAssert.hpp>
 
+#include <limits>
+#include <optional>
 #include <string>
 
 class IMesh;
@@ -10,12 +13,76 @@ class OutputNamedItemDataSet;
 
 class WriterBase : public IWriter
 {
+ public:
+  class PeriodManager
+  {
+   private:
+    const double m_time_period;
+    mutable double m_next_time;
+
+    mutable std::vector<double> m_saved_times;
+
+   public:
+    double
+    timePeriod() const
+    {
+      return m_time_period;
+    }
+
+    double
+    nextTime() const
+    {
+      return m_next_time;
+    }
+
+    void
+    setNextTime(double next_time)
+    {
+      m_next_time = next_time;
+    }
+
+    size_t
+    nbSavedTimes() const
+    {
+      return m_saved_times.size();
+    }
+
+    double
+    savedTime(size_t i) const
+    {
+      Assert(i < m_saved_times.size());
+      return m_saved_times[i];
+    }
+
+    double
+    getLastTime() const
+    {
+      if (m_saved_times.size() > 0) {
+        return m_saved_times[m_saved_times.size() - 1];
+      } else {
+        return -std::numeric_limits<double>::max();
+      }
+    }
+
+    void
+    setSaveTime(double time) const
+    {
+      if (m_saved_times.size() == 0) {
+        m_next_time = time;
+      }
+      m_next_time += m_time_period;
+      m_saved_times.push_back(time);
+    }
+
+    PeriodManager(const PeriodManager&) = default;
+    PeriodManager(PeriodManager&&)      = default;
+    PeriodManager(double time_period) : m_time_period{time_period}, m_next_time{-std::numeric_limits<double>::max()} {}
+  };
+
  protected:
   const std::string m_base_filename;
-  const double m_time_period;
-  mutable double m_next_time;
 
-  mutable std::vector<double> m_saved_times;
+  std::optional<PeriodManager> m_period_manager;
 
  private:
   template <typename DiscreteFunctionType>
@@ -34,12 +101,11 @@ class WriterBase : public IWriter
   OutputNamedItemDataSet _getOutputNamedItemDataSet(
     const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const;
 
-  virtual void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-                     double time) const = 0;
+  virtual void _writeAtTime(
+    const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
+    double time) const = 0;
 
  public:
-  double getLastTime() const;
-
   void writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                      double time) const final;
 
@@ -50,6 +116,8 @@ class WriterBase : public IWriter
 
   WriterBase(const std::string& base_filename, const double& time_period);
 
+  WriterBase(const std::string& base_filename);
+
   virtual ~WriterBase() = default;
 };