From f7ec35e15d7fb960b29d4ddd2a66664b6462aee9 Mon Sep 17 00:00:00 2001
From: Dmitri Naumov <github@naumov.de>
Date: Thu, 7 Jan 2021 20:36:58 +0100
Subject: [PATCH] Add iteration number output to file names.

Especially useful when all nonlinear iterations should
be output. See <output_iteration_results> tag.
---
 BaseLib/FileTools.cpp                         |  6 ++--
 BaseLib/FileTools.h                           |  3 +-
 ProcessLib/Output/Output.cpp                  | 35 +++++++++++--------
 ProcessLib/Output/Output.h                    | 10 +++---
 ProcessLib/TimeLoop.cpp                       | 14 +++++---
 .../TestConstructFormattedFileName.cpp        | 27 ++++++++------
 6 files changed, 57 insertions(+), 38 deletions(-)

diff --git a/BaseLib/FileTools.cpp b/BaseLib/FileTools.cpp
index b0876d860e5..a70cd564db3 100644
--- a/BaseLib/FileTools.cpp
+++ b/BaseLib/FileTools.cpp
@@ -111,7 +111,8 @@ bool substituteKeyword(std::string& result, std::string& parenthesized_string,
 std::string constructFormattedFileName(std::string const& format_specification,
                                        std::string const& mesh_name,
                                        int const timestep,
-                                       double const t)
+                                       double const t,
+                                       int const iteration)
 {
     char const open_char = '{';
     char const close_char = '}';
@@ -127,7 +128,8 @@ std::string constructFormattedFileName(std::string const& format_specification,
         std::tie(str, begin, end) =
             getParenthesizedString(result, open_char, close_char, begin);
         if (!substituteKeyword(result, str, begin, end, "timestep", timestep) &&
-            !substituteKeyword(result, str, begin, end, "time", t))
+            !substituteKeyword(result, str, begin, end, "time", t) &&
+            !substituteKeyword(result, str, begin, end, "iteration", iteration))
         {
             substituteKeyword(result, str, begin, end, "meshname", mesh_name);
         }
diff --git a/BaseLib/FileTools.h b/BaseLib/FileTools.h
index 74d4fbaf3a0..acbdf546fb1 100644
--- a/BaseLib/FileTools.h
+++ b/BaseLib/FileTools.h
@@ -44,7 +44,8 @@ getParenthesizedString(std::string const& in,
 std::string constructFormattedFileName(std::string const& format_specification,
                                        std::string const& mesh_name,
                                        int const timestep,
-                                       double const t);
+                                       double const t,
+                                       int const iteration);
 
 /**
  * \brief write value as binary into the given output stream
diff --git a/ProcessLib/Output/Output.cpp b/ProcessLib/Output/Output.cpp
index 76b52c5c6b5..82719102170 100644
--- a/ProcessLib/Output/Output.cpp
+++ b/ProcessLib/Output/Output.cpp
@@ -51,7 +51,7 @@ std::string constructPVDName(std::string const& output_directory,
 {
     return BaseLib::joinPaths(output_directory,
                               BaseLib::constructFormattedFileName(
-                                  output_file_prefix, mesh_name, 0, 0) +
+                                  output_file_prefix, mesh_name, 0, 0, 0) +
                                   ".pvd");
 }
 }  // namespace
@@ -178,8 +178,10 @@ struct Output::OutputFile
     OutputFile(std::string const& directory, OutputType const type,
                std::string const& prefix, std::string const& suffix,
                std::string const& mesh_name, int const timestep, double const t,
-               int const data_mode_, bool const compression_)
-        : name(constructFilename(type, prefix, suffix, mesh_name, timestep, t)),
+               int const iteration, int const data_mode_,
+               bool const compression_)
+        : name(constructFilename(type, prefix, suffix, mesh_name, timestep, t,
+                                 iteration)),
           path(BaseLib::joinPaths(directory, name)),
           type(type),
           data_mode(data_mode_),
@@ -202,7 +204,8 @@ struct Output::OutputFile
     static std::string constructFilename(OutputType const type,
                                          std::string prefix, std::string suffix,
                                          std::string mesh_name,
-                                         int const timestep, double const t)
+                                         int const timestep, double const t,
+                                         int const iteration)
     {
         std::map<OutputType, std::string> filetype_to_extension = {
             {OutputType::vtk, "vtu"}, {OutputType::xdmf, "xdmf"}};
@@ -211,9 +214,9 @@ struct Output::OutputFile
         {
             std::string extension = filetype_to_extension.at(type);
             return BaseLib::constructFormattedFileName(prefix, mesh_name,
-                                                       timestep, t) +
+                                                       timestep, t, iteration) +
                    BaseLib::constructFormattedFileName(suffix, mesh_name,
-                                                       timestep, t) +
+                                                       timestep, t, iteration) +
                    "." + extension;
         }
         catch (std::out_of_range& e)
@@ -266,6 +269,7 @@ void Output::doOutputAlways(Process const& process,
                             const int process_id,
                             int const timestep,
                             const double t,
+                            int const iteration,
                             std::vector<GlobalVector*> const& x)
 {
     BaseLib::RunTime time_output;
@@ -304,7 +308,7 @@ void Output::doOutputAlways(Process const& process,
         {
             OutputFile const file(
                 _output_directory, _output_file_type, _output_file_prefix,
-                _output_file_suffix, mesh.getName(), timestep, t,
+                _output_file_suffix, mesh.getName(), timestep, t, iteration,
                 _output_file_data_mode, _output_file_compression);
 
             pvd_file = findPVDFile(process, process_id, mesh.getName());
@@ -315,7 +319,7 @@ void Output::doOutputAlways(Process const& process,
 #ifdef OGS_USE_XDMF
             OutputFile const file(_output_directory, _output_file_type,
                                   _output_file_prefix, "", mesh.getName(),
-                                  timestep, t, _output_file_data_mode,
+                                  timestep, t, iteration, _output_file_data_mode,
                                   _output_file_compression);
 
             outputMeshXdmf(file, mesh, timestep, t);
@@ -388,11 +392,12 @@ void Output::doOutput(Process const& process,
                       const int process_id,
                       int const timestep,
                       const double t,
+                      int const iteration,
                       std::vector<GlobalVector*> const& x)
 {
     if (shallDoOutput(timestep, t))
     {
-        doOutputAlways(process, process_id, timestep, t, x);
+        doOutputAlways(process, process_id, timestep, t, iteration, x);
     }
 #ifdef USE_INSITU
     // Note: last time step may be output twice: here and in
@@ -406,11 +411,12 @@ void Output::doOutputLastTimestep(Process const& process,
                                   const int process_id,
                                   int const timestep,
                                   const double t,
+                                  int const iteration,
                                   std::vector<GlobalVector*> const& x)
 {
     if (!shallDoOutput(timestep, t))
     {
-        doOutputAlways(process, process_id, timestep, t, x);
+        doOutputAlways(process, process_id, timestep, t, iteration, x);
     }
 #ifdef USE_INSITU
     InSituLib::CoProcess(process.getMesh(), t, timestep, true,
@@ -421,8 +427,8 @@ void Output::doOutputLastTimestep(Process const& process,
 void Output::doOutputNonlinearIteration(Process const& process,
                                         const int process_id,
                                         int const timestep, const double t,
-                                        std::vector<GlobalVector*> const& x,
-                                        const int iteration)
+                                        int const iteration,
+                                        std::vector<GlobalVector*> const& x)
 {
     if (!_output_nonlinear_iteration_results)
     {
@@ -459,9 +465,8 @@ void Output::doOutputNonlinearIteration(Process const& process,
     findPVDFile(process, process_id, process.getMesh().getName());
 
     std::string const output_file_name = OutputFile::constructFilename(
-        _output_file_type, _output_file_prefix,
-        "_ts_{:timestep}_nliter_{:time}", process.getMesh().getName(), timestep,
-        iteration);
+        _output_file_type, _output_file_prefix, _output_file_suffix,
+        process.getMesh().getName(), timestep, t, iteration);
 
     std::string const output_file_path =
         BaseLib::joinPaths(_output_directory, output_file_name);
diff --git a/ProcessLib/Output/Output.h b/ProcessLib/Output/Output.h
index 1c38f1729d3..8aa7ca35aa8 100644
--- a/ProcessLib/Output/Output.h
+++ b/ProcessLib/Output/Output.h
@@ -56,7 +56,7 @@ public:
     //! Writes output for the given \c process if it should be written in the
     //! given \c timestep.
     void doOutput(Process const& process, const int process_id,
-                  int const timestep, const double t,
+                  int const timestep, const double t, int const iteration,
                   std::vector<GlobalVector*> const& x);
 
     //! Writes output for the given \c process if it has not been written yet.
@@ -64,22 +64,22 @@ public:
     //! order to make sure that its results are written.
     void doOutputLastTimestep(Process const& process, const int process_id,
                               int const timestep, const double t,
+                              int const iteration,
                               std::vector<GlobalVector*> const& x);
 
     //! Writes output for the given \c process.
     //! This method will always write.
     //! It is intended to write output in error handling routines.
     void doOutputAlways(Process const& process, const int process_id,
-                        int const timestep, const double t,
+                        int const timestep, const double t, int const iteration,
                         std::vector<GlobalVector*> const& x);
 
     //! Writes output for the given \c process.
     //! To be used for debug output after an iteration of the nonlinear solver.
     void doOutputNonlinearIteration(Process const& process,
                                     const int process_id, int const timestep,
-                                    const double t,
-                                    std::vector<GlobalVector*> const& x,
-                                    const int iteration);
+                                    const double t, const int iteration,
+                                    std::vector<GlobalVector*> const& x);
 
     std::vector<double> getFixedOutputTimes() const
     {
diff --git a/ProcessLib/TimeLoop.cpp b/ProcessLib/TimeLoop.cpp
index 0c01b849b8f..8e619d254c0 100644
--- a/ProcessLib/TimeLoop.cpp
+++ b/ProcessLib/TimeLoop.cpp
@@ -296,7 +296,7 @@ NumLib::NonlinearSolverStatus solveOneTimeStepOneProcess(
     auto const post_iteration_callback =
         [&](int iteration, std::vector<GlobalVector*> const& x) {
             output_control.doOutputNonlinearIteration(
-                process, process_id, timestep, t, x, iteration);
+                process, process_id, timestep, t, iteration, x);
         };
 
     auto const nonlinear_solver_status =
@@ -705,8 +705,10 @@ NumLib::NonlinearSolverStatus TimeLoop::solveUncoupledEquationSystems(
             if (!process_data->timestepper->canReduceTimestepSize())
             {
                 // save unsuccessful solution
-                _output->doOutputAlways(process_data->process, process_id,
-                                        timestep_id, t, _process_solutions);
+                _output->doOutputAlways(
+                    process_data->process, process_id, timestep_id, t,
+                    process_data->nonlinear_solver_status.number_iterations,
+                    _process_solutions);
                 OGS_FATAL(timestepper_cannot_reduce_dt.data());
             }
 
@@ -902,8 +904,10 @@ void TimeLoop::outputSolutions(bool const output_initial_condition,
 
             NumLib::GlobalVectorProvider::provider.releaseVector(x_dot);
         }
-        (output_object.*output_class_member)(pcs, process_id, timestep, t,
-                                             _process_solutions);
+        (output_object.*output_class_member)(
+            pcs, process_id, timestep, t,
+            process_data->nonlinear_solver_status.number_iterations,
+            _process_solutions);
     }
 }
 
diff --git a/Tests/BaseLib/TestConstructFormattedFileName.cpp b/Tests/BaseLib/TestConstructFormattedFileName.cpp
index 64a31f86d7f..2c6120dc84b 100644
--- a/Tests/BaseLib/TestConstructFormattedFileName.cpp
+++ b/Tests/BaseLib/TestConstructFormattedFileName.cpp
@@ -23,50 +23,57 @@ TEST(BaseLib, constructFormattedFileName)
 {
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "test_{:timestep}", "mesh_name", 2, 0.2);
+            "test_{:timestep}", "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("test_2", formatted_filename);
     }
     {
         auto const formatted_filename_time =
             BaseLib::constructFormattedFileName("test_{:0.5time}", "mesh_name",
-                                                2, 0.2);
+                                                2, 0.2, 3);
         ASSERT_EQ("test_0.20000", formatted_filename_time);
     }
+    {
+        auto const formatted_filename =
+            BaseLib::constructFormattedFileName("test_{:iteration}", "mesh_name",
+                                                2, 0.2, 3);
+        ASSERT_EQ("test_3", formatted_filename);
+    }
     {
         auto const formatted_filename_timestep_time =
             BaseLib::constructFormattedFileName("test_{:timestep}_{:0.5time}",
-                                                "mesh_name", 2, 0.2);
+                                                "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("test_2_0.20000", formatted_filename_timestep_time);
     }
     {
         auto const formatted_filename_time_timestep =
             BaseLib::constructFormattedFileName("test_{:.4time}_{:timestep}",
-                                                "mesh_name", 2, 0.2);
+                                                "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("test_0.2000_2", formatted_filename_time_timestep);
     }
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "test_{:.4time}_{:timestep}", "mesh_name", 2, 0.2);
+            "test_{:.4time}_{:timestep}", "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("test_0.2000_2", formatted_filename);
     }
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "_ts_{:timestep}_t_{:.4time}", "mesh_name", 2, 0.2);
+            "_ts_{:timestep}_t_{:.4time}", "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("_ts_2_t_0.2000", formatted_filename);
     }
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "_ts_{:0>3timestep}_t_{:.4time}", "mesh_name", 2, 0.2);
+            "_ts_{:0>3timestep}_t_{:.4time}", "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("_ts_002_t_0.2000", formatted_filename);
     }
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "_ts_{:0>3timestep}_t_{:.4etime}", "mesh_name", 2, 0.2);
+            "_ts_{:0>3timestep}_t_{:.4etime}", "mesh_name", 2, 0.2, 3);
         ASSERT_EQ("_ts_002_t_2.0000e-01", formatted_filename);
     }
     {
         auto const formatted_filename = BaseLib::constructFormattedFileName(
-            "{:meshname}_ts_{:0>3timestep}_t_{:.4etime}", "mesh_name", 2, 0.2);
-        ASSERT_EQ("mesh_name_ts_002_t_2.0000e-01", formatted_filename);
+            "{:meshname}_ts_{:0>3timestep}_t_{:.4etime}_iter_{:0>2iteration}",
+            "mesh_name", 2, 0.2, 3);
+        ASSERT_EQ("mesh_name_ts_002_t_2.0000e-01_iter_03", formatted_filename);
     }
 }
-- 
GitLab