From 61cc252b6668cdf013abb5f49f319c9993d78463 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Sat, 16 Jul 2022 16:20:10 +0200
Subject: [PATCH] Allow output without time specifier

Related to #27

Now one can set two types of writers. Writers with a specified output
time period (the was the previous behavior) and writers without time
info.

The output filenames are simpler in the second case since they do not
include the output step number in their names.

To these writers are now associated two `write` functions. The first
one (legacy one) specifies the time of the output. The second one (new
one) does not expect time value.
---
 src/language/modules/WriterModule.cpp | 36 +++++++++++++++
 src/output/GnuplotWriter.cpp          | 50 ++++++++++++++------
 src/output/GnuplotWriter.hpp          | 16 +++++--
 src/output/GnuplotWriter1D.cpp        | 37 ++++++++++++---
 src/output/GnuplotWriter1D.hpp        | 16 +++++--
 src/output/IWriter.hpp                |  3 ++
 src/output/VTKWriter.cpp              | 66 +++++++++++++++++++--------
 src/output/VTKWriter.hpp              | 16 ++++---
 src/output/WriterBase.cpp             | 24 +++++++++-
 src/output/WriterBase.hpp             |  9 ++++
 10 files changed, 216 insertions(+), 57 deletions(-)

diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp
index fcb3beb61..a1eebb3ed 100644
--- a/src/language/modules/WriterModule.cpp
+++ b/src/language/modules/WriterModule.cpp
@@ -20,6 +20,14 @@ WriterModule::WriterModule()
 
   this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IWriter>>);
 
+  this
+    ->_addBuiltinFunction("vtk_writer",
+                          std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>(
+
+                            [](const std::string& filename) { return std::make_shared<VTKWriter>(filename); }
+
+                            ));
+
   this->_addBuiltinFunction("vtk_writer",
                             std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&,
                                                                                                     const double&)>>(
@@ -30,6 +38,14 @@ WriterModule::WriterModule()
 
                               ));
 
+  this
+    ->_addBuiltinFunction("gnuplot_writer",
+                          std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>(
+
+                            [](const std::string& filename) { return std::make_shared<GnuplotWriter>(filename); }
+
+                            ));
+
   this->_addBuiltinFunction("gnuplot_writer",
                             std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&,
                                                                                                     const double&)>>(
@@ -40,6 +56,14 @@ WriterModule::WriterModule()
 
                               ));
 
+  this
+    ->_addBuiltinFunction("gnuplot_1d_writer",
+                          std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>(
+
+                            [](const std::string& filename) { return std::make_shared<GnuplotWriter1D>(filename); }
+
+                            ));
+
   this->_addBuiltinFunction("gnuplot_1d_writer",
                             std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&,
                                                                                                     const double&)>>(
@@ -72,6 +96,18 @@ WriterModule::WriterModule()
 
                               ));
 
+  this->_addBuiltinFunction("write", std::make_shared<BuiltinFunctionEmbedder<
+                                       void(std::shared_ptr<const IWriter>,
+                                            const std::vector<std::shared_ptr<const NamedDiscreteFunction>>&)>>(
+
+                                       [](std::shared_ptr<const IWriter> writer,
+                                          const std::vector<std::shared_ptr<const NamedDiscreteFunction>>&
+                                            named_discrete_function_list) -> void {
+                                         writer->write(named_discrete_function_list);
+                                       }
+
+                                       ));
+
   this->_addBuiltinFunction("write",
                             std::make_shared<BuiltinFunctionEmbedder<
                               void(std::shared_ptr<const IWriter>,
diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp
index 4f98d0f23..ae0ba69af 100644
--- a/src/output/GnuplotWriter.cpp
+++ b/src/output/GnuplotWriter.cpp
@@ -239,9 +239,9 @@ GnuplotWriter::_writeNodeData(const NodeArray<DataType>& node_array, NodeId node
 
 template <typename MeshType>
 void
-GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                            const OutputNamedItemDataSet& output_named_item_data_set,
-                            double time) const
+GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh,
+                      const OutputNamedItemDataSet& output_named_item_data_set,
+                      std::optional<double> time) const
 {
   if (parallel::rank() == 0) {
     std::ofstream fout{_getFilename()};
@@ -249,8 +249,9 @@ GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
     fout.setf(std::ios_base::scientific);
 
     fout << this->_getDateAndVersionComment();
-    fout << "# time = " << time << "\n\n";
-
+    if (time.has_value()) {
+      fout << "# time = " << *time << "\n\n";
+    }
     this->_writePreamble<MeshType::Dimension>(output_named_item_data_set, fout);
   }
 
@@ -267,17 +268,41 @@ GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
 }
 
 void
-GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) 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);
+
+  OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list);
+
+  switch (mesh->dimension()) {
+  case 1: {
+    this->_write(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);
+    break;
+  }
+  default: {
+    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh->dimension()));
+  }
+  }
+}
+
+void
+GnuplotWriter::_writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const
 {
   OutputNamedItemDataSet output_named_item_data_set{};
 
   switch (p_mesh->dimension()) {
   case 1: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, 0);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, {});
     break;
   }
   case 2: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, 0);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, {});
     break;
   }
   default: {
@@ -287,9 +312,8 @@ GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const
 }
 
 void
-GnuplotWriter::_writeAtTime(
-  const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
-  double time) const
+GnuplotWriter::_write(
+  const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const
 {
   std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
 
@@ -297,11 +321,11 @@ GnuplotWriter::_writeAtTime(
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {});
     break;
   }
   case 2: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {});
     break;
   }
   default: {
diff --git a/src/output/GnuplotWriter.hpp b/src/output/GnuplotWriter.hpp
index 312e4886c..112b46062 100644
--- a/src/output/GnuplotWriter.hpp
+++ b/src/output/GnuplotWriter.hpp
@@ -9,9 +9,10 @@
 
 class IMesh;
 
+#include <optional>
 #include <string>
 
-class GnuplotWriter : public WriterBase
+class GnuplotWriter final : public WriterBase
 {
  private:
   std::string _getDateAndVersionComment() const;
@@ -45,15 +46,20 @@ class GnuplotWriter : public WriterBase
                          std::ostream& fout) const;
 
   template <typename MeshType>
-  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                    const OutputNamedItemDataSet& output_named_item_data_set,
-                    double time) const;
+  void _write(const std::shared_ptr<const MeshType>& mesh,
+              const OutputNamedItemDataSet& output_named_item_data_set,
+              std::optional<double> time) const;
 
   void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                     double time) const final;
 
+  void _write(
+    const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final;
+
+  void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
+
  public:
-  void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
+  GnuplotWriter(const std::string& base_filename) : WriterBase(base_filename) {}
 
   GnuplotWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {}
 
diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp
index 7fbd6612a..73e5a4e64 100644
--- a/src/output/GnuplotWriter1D.cpp
+++ b/src/output/GnuplotWriter1D.cpp
@@ -260,9 +260,9 @@ GnuplotWriter1D::_writeItemDatas(const std::shared_ptr<const MeshType>& mesh,
 
 template <typename MeshType>
 void
-GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                              const OutputNamedItemDataSet& output_named_item_data_set,
-                              double time) const
+GnuplotWriter1D::_write(const std::shared_ptr<const MeshType>& mesh,
+                        const OutputNamedItemDataSet& output_named_item_data_set,
+                        std::optional<double> time) const
 {
   bool has_cell_data = false;
   for (const auto& [name, item_data_variant] : output_named_item_data_set) {
@@ -286,7 +286,9 @@ GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
     fout.setf(std::ios_base::scientific);
     fout << _getDateAndVersionComment();
 
-    fout << "# time = " << time << "\n\n";
+    if (time.has_value()) {
+      fout << "# time = " << *time << "\n\n";
+    }
 
     _writePreamble(output_named_item_data_set, fout);
   }
@@ -299,7 +301,7 @@ GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
 }
 
 void
-GnuplotWriter1D::writeMesh(const std::shared_ptr<const IMesh>&) const
+GnuplotWriter1D::_writeMesh(const std::shared_ptr<const IMesh>&) const
 {
   std::ostringstream errorMsg;
   errorMsg << "gnuplot_1d_writer does not write meshes\n"
@@ -319,7 +321,7 @@ GnuplotWriter1D::_writeAtTime(
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
     break;
   }
   case 2: {
@@ -334,3 +336,26 @@ GnuplotWriter1D::_writeAtTime(
   }
   }
 }
+
+void
+GnuplotWriter1D::_write(
+  const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const
+{
+  std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
+
+  OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list);
+
+  switch (mesh->dimension()) {
+  case 1: {
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {});
+    break;
+  }
+  case 2: {
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {});
+    break;
+  }
+  default: {
+    throw NormalError("gnuplot format is not available in dimension " + stringify(mesh->dimension()));
+  }
+  }
+}
diff --git a/src/output/GnuplotWriter1D.hpp b/src/output/GnuplotWriter1D.hpp
index f1e7b23c8..fad94c136 100644
--- a/src/output/GnuplotWriter1D.hpp
+++ b/src/output/GnuplotWriter1D.hpp
@@ -9,9 +9,10 @@
 
 class IMesh;
 
+#include <optional>
 #include <string>
 
-class GnuplotWriter1D : public WriterBase
+class GnuplotWriter1D final : public WriterBase
 {
  private:
   std::string _getDateAndVersionComment() const;
@@ -38,15 +39,20 @@ class GnuplotWriter1D : public WriterBase
   void _writePreamble(const OutputNamedItemDataSet& output_named_item_value_set, std::ostream& fout) const;
 
   template <typename MeshType>
-  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                    const OutputNamedItemDataSet& output_named_item_value_set,
-                    double time) const;
+  void _write(const std::shared_ptr<const MeshType>& mesh,
+              const OutputNamedItemDataSet& output_named_item_value_set,
+              std::optional<double> time) const;
 
   void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                     double time) const final;
 
+  void _write(
+    const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final;
+
+  void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
+
  public:
-  void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
+  GnuplotWriter1D(const std::string& base_filename) : WriterBase(base_filename) {}
 
   GnuplotWriter1D(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period)
   {}
diff --git a/src/output/IWriter.hpp b/src/output/IWriter.hpp
index 02317ad98..dab629604 100644
--- a/src/output/IWriter.hpp
+++ b/src/output/IWriter.hpp
@@ -13,6 +13,9 @@ class IWriter
  public:
   virtual void writeMesh(const std::shared_ptr<const IMesh>& mesh) const = 0;
 
+  virtual void write(
+    const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const = 0;
+
   virtual void writeIfNeeded(
     const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
     double time) const = 0;
diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp
index 55a2e90d9..8295c351f 100644
--- a/src/output/VTKWriter.cpp
+++ b/src/output/VTKWriter.cpp
@@ -355,14 +355,10 @@ VTKWriter::_write_node_data(std::ofstream& os,
 
 template <typename MeshType>
 void
-VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                        const OutputNamedItemDataSet& given_output_named_item_data_set,
-                        double time) const
+VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh,
+                  const OutputNamedItemDataSet& given_output_named_item_data_set,
+                  std::optional<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()});
@@ -622,14 +618,18 @@ VTKWriter::_writeAtTime(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_period_manager->nbSavedTimes(); ++i_time) {
-      std::ostringstream sout;
-      sout << m_base_filename;
-      sout << '.' << std::setfill('0') << std::setw(4) << i_time << ".pvtu";
+    if (time.has_value()) {
+      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_period_manager->savedTime(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";
+    } else {
+      fout << "<DataSet file=\"" << _getFilenamePVTU() << "\"/>\n";
     }
-    fout << "<DataSet timestep=\"" << time << "\" file=\"" << _getFilenamePVTU() << "\"/>\n";
 
     fout << "</Collection>\n";
     fout << "</VTKFile>\n";
@@ -637,21 +637,21 @@ VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh,
 }
 
 void
-VTKWriter::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
+VTKWriter::_writeMesh(const std::shared_ptr<const IMesh>& mesh) const
 {
   OutputNamedItemDataSet output_named_item_data_set;
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, 0);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {});
     break;
   }
   case 2: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, 0);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {});
     break;
   }
   case 3: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, 0);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, {});
     break;
   }
   default: {
@@ -670,15 +670,41 @@ VTKWriter::_writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFun
 
   switch (mesh->dimension()) {
   case 1: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time);
+    this->_write(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);
+    break;
+  }
+  case 3: {
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time);
+    break;
+  }
+  default: {
+    throw UnexpectedError("invalid mesh dimension");
+  }
+  }
+}
+
+void
+VTKWriter::_write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const
+{
+  std::shared_ptr mesh = this->_getMesh(named_discrete_function_list);
+
+  OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list);
+
+  switch (mesh->dimension()) {
+  case 1: {
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {});
     break;
   }
   case 2: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {});
     break;
   }
   case 3: {
-    this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time);
+    this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, {});
     break;
   }
   default: {
diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp
index eb0f70d92..c0adbd6c4 100644
--- a/src/output/VTKWriter.hpp
+++ b/src/output/VTKWriter.hpp
@@ -9,9 +9,10 @@
 
 class IMesh;
 
+#include <optional>
 #include <string>
 
-class VTKWriter : public WriterBase
+class VTKWriter final : public WriterBase
 {
  private:
   class SerializedDataList;
@@ -95,16 +96,19 @@ class VTKWriter : public WriterBase
                         SerializedDataList& serialized_data_list) const;
 
   template <typename MeshType>
-  void _writeAtTime(const std::shared_ptr<const MeshType>& mesh,
-                    const OutputNamedItemDataSet& output_named_item_data_set,
-                    double time) const;
+  void _write(const std::shared_ptr<const MeshType>& mesh,
+              const OutputNamedItemDataSet& output_named_item_data_set,
+              std::optional<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) const final;
+
+  void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
 
+ public:
   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 7ae28e9e8..2fe733d54 100644
--- a/src/output/WriterBase.cpp
+++ b/src/output/WriterBase.cpp
@@ -214,7 +214,7 @@ WriterBase::writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteF
       m_period_manager->setSaveTime(time);
     }
   } else {
-    throw NormalError("Writer has no period defined");
+    throw NormalError("this writer does not allow time value");
   }
 }
 
@@ -229,6 +229,26 @@ WriterBase::writeForced(const std::vector<std::shared_ptr<const NamedDiscreteFun
     this->_writeAtTime(named_discrete_function_list, time);
     m_period_manager->setSaveTime(time);
   } else {
-    throw NormalError("Writer has no period defined");
+    throw NormalError("this writer does not allow time value");
+  }
+}
+
+void
+WriterBase::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const
+{
+  if (m_period_manager.has_value()) {
+    throw NormalError("this writer requires time value");
+  } else {
+    this->_write(named_discrete_function_list);
+  }
+}
+
+void
+WriterBase::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
+{
+  if (m_period_manager.has_value()) {
+    throw NormalError("write_mesh requires a writer without time period");
+  } else {
+    this->_writeMesh(mesh);
   }
 }
diff --git a/src/output/WriterBase.hpp b/src/output/WriterBase.hpp
index 6d96ee410..2f29120b5 100644
--- a/src/output/WriterBase.hpp
+++ b/src/output/WriterBase.hpp
@@ -105,13 +105,22 @@ class WriterBase : public IWriter
     const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
     double time) const = 0;
 
+  virtual void _write(
+    const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const = 0;
+
+  virtual void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const = 0;
+
  public:
+  void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final;
+
   void writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                      double time) const final;
 
   void writeForced(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list,
                    double time) const final;
 
+  void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final;
+
   WriterBase() = delete;
 
   WriterBase(const std::string& base_filename, const double& time_period);
-- 
GitLab