From c28e4ec4c991a98e72683468e2347f9b76f88ffb Mon Sep 17 00:00:00 2001
From: Wenqing Wang <wenqing.wang@ufz.de>
Date: Thu, 14 Dec 2017 16:44:31 +0100
Subject: [PATCH] [Coupling] Enabled each individual process having its own
 convergence criterion

 in the coupling loop.
---
 .../i_convergence_criteria.md}                |  0
 .../t_convergence_criterion.md                |  2 +
 .../i_global_process_coupling.md              |  2 +-
 ProcessLib/UncoupledProcessesTimeLoop.cpp     | 86 ++++++++++++-------
 ProcessLib/UncoupledProcessesTimeLoop.h       |  5 +-
 .../ConstViscosity/square_5500x5500.vtu       |  2 +-
 .../square_5500x5500_staggered_scheme.prj     | 19 ++--
 7 files changed, 76 insertions(+), 40 deletions(-)
 rename Documentation/ProjectFile/prj/time_loop/global_process_coupling/{t_convergence_criterion.md => convergence_criteria/i_convergence_criteria.md} (100%)
 create mode 100644 Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/t_convergence_criterion.md

diff --git a/Documentation/ProjectFile/prj/time_loop/global_process_coupling/t_convergence_criterion.md b/Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/i_convergence_criteria.md
similarity index 100%
rename from Documentation/ProjectFile/prj/time_loop/global_process_coupling/t_convergence_criterion.md
rename to Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/i_convergence_criteria.md
diff --git a/Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/t_convergence_criterion.md b/Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/t_convergence_criterion.md
new file mode 100644
index 00000000000..4e4aa84b97b
--- /dev/null
+++ b/Documentation/ProjectFile/prj/time_loop/global_process_coupling/convergence_criteria/t_convergence_criterion.md
@@ -0,0 +1,2 @@
+Defines the convergence criteria of the global un-coupling loop of the staggered
+ scheme for each individual process.
diff --git a/Documentation/ProjectFile/prj/time_loop/global_process_coupling/i_global_process_coupling.md b/Documentation/ProjectFile/prj/time_loop/global_process_coupling/i_global_process_coupling.md
index 5263a21d1d8..7073b6fc903 100644
--- a/Documentation/ProjectFile/prj/time_loop/global_process_coupling/i_global_process_coupling.md
+++ b/Documentation/ProjectFile/prj/time_loop/global_process_coupling/i_global_process_coupling.md
@@ -1 +1 @@
-Global convergence criteria of the coupling iterations.
\ No newline at end of file
+Defines global convergence controls of the coupling iterations.
\ No newline at end of file
diff --git a/ProcessLib/UncoupledProcessesTimeLoop.cpp b/ProcessLib/UncoupledProcessesTimeLoop.cpp
index 4b4e4ec926d..4df5dbbc22d 100644
--- a/ProcessLib/UncoupledProcessesTimeLoop.cpp
+++ b/ProcessLib/UncoupledProcessesTimeLoop.cpp
@@ -325,16 +325,29 @@ std::unique_ptr<UncoupledProcessesTimeLoop> createUncoupledProcessesTimeLoop(
         //! \ogs_file_param{prj__time_loop__global_process_coupling}
         = config.getConfigSubtreeOptional("global_process_coupling");
 
-    std::unique_ptr<NumLib::ConvergenceCriterion> coupling_conv_crit = nullptr;
+    std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>
+        _global_coupling_conv_criteria;
     unsigned max_coupling_iterations = 1;
     if (coupling_config)
     {
         max_coupling_iterations
             //! \ogs_file_param{prj__time_loop__global_process_coupling__max_iter}
             = coupling_config->getConfigParameter<unsigned>("max_iter");
-        coupling_conv_crit = NumLib::createConvergenceCriterion(
-            //! \ogs_file_param{prj__time_loop__global_process_coupling__convergence_criterion}
-            coupling_config->getConfigSubtree("convergence_criterion"));
+
+        auto const& coupling_convergence_criteria_config =
+            //! \ogs_file_param{prj__time_loop__global_process_coupling__convergence_criteria}
+            coupling_config->getConfigSubtree("convergence_criteria");
+
+        for (
+            auto coupling_convergence_criterion_config :
+            //! \ogs_file_param{prj__time_loop__global_process_coupling__convergence_criteria__convergence_criterion}
+            coupling_convergence_criteria_config.getConfigSubtreeList(
+                "convergence_criterion"))
+        {
+            _global_coupling_conv_criteria.push_back(
+                NumLib::createConvergenceCriterion(
+                    coupling_convergence_criterion_config));
+        }
     }
 
     auto output =
@@ -361,7 +374,7 @@ std::unique_ptr<UncoupledProcessesTimeLoop> createUncoupledProcessesTimeLoop(
 
     return std::make_unique<UncoupledProcessesTimeLoop>(
         std::move(output), std::move(per_process_data), max_coupling_iterations,
-        std::move(coupling_conv_crit), start_time, end_time);
+        std::move(_global_coupling_conv_criteria), start_time, end_time);
 }
 
 std::vector<GlobalVector*> setInitialConditions(
@@ -409,9 +422,9 @@ std::vector<GlobalVector*> setInitialConditions(
     return process_solutions;
 }
 
-bool solveOneTimeStepOneProcess(const unsigned process_index,
-                                GlobalVector& x, std::size_t const timestep,
-                                double const t, double const delta_t,
+bool solveOneTimeStepOneProcess(const unsigned process_index, GlobalVector& x,
+                                std::size_t const timestep, double const t,
+                                double const delta_t,
                                 SingleProcessData const& process_data,
                                 Output& output_control)
 {
@@ -435,9 +448,9 @@ bool solveOneTimeStepOneProcess(const unsigned process_index,
 
     auto const post_iteration_callback = [&](unsigned iteration,
                                              GlobalVector const& x) {
-        output_control.doOutputNonlinearIteration(
-            process, process_index, process_data.process_output, timestep, t,
-            x, iteration);
+        output_control.doOutputNonlinearIteration(process, process_index,
+                                                  process_data.process_output,
+                                                  timestep, t, x, iteration);
     };
 
     bool nonlinear_solver_succeeded =
@@ -450,7 +463,8 @@ UncoupledProcessesTimeLoop::UncoupledProcessesTimeLoop(
     std::unique_ptr<Output>&& output,
     std::vector<std::unique_ptr<SingleProcessData>>&& per_process_data,
     const unsigned global_coupling_max_iterations,
-    std::unique_ptr<NumLib::ConvergenceCriterion>&& global_coupling_conv_crit,
+    std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&&
+        global_coupling_conv_crit,
     const double start_time, const double end_time)
     : _output(std::move(output)),
       _per_process_data(std::move(per_process_data)),
@@ -800,8 +814,8 @@ bool UncoupledProcessesTimeLoop::solveUncoupledEquationSystems(
         auto& pcs = spd->process;
         pcs.preTimestep(x, t, dt, pcs_idx);
 
-        const auto nonlinear_solver_succeeded =
-            solveOneTimeStepOneProcess(pcs_idx, x, timestep_id, t, dt, *spd, *_output);
+        const auto nonlinear_solver_succeeded = solveOneTimeStepOneProcess(
+            pcs_idx, x, timestep_id, t, dt, *spd, *_output);
         spd->nonlinear_solver_converged = nonlinear_solver_succeeded;
         pcs.postTimestep(x, pcs_idx);
         pcs.computeSecondaryVariable(t, x);
@@ -816,8 +830,8 @@ bool UncoupledProcessesTimeLoop::solveUncoupledEquationSystems(
                 timestep_id, t, pcs_idx);
 
             // save unsuccessful solution
-            _output->doOutputAlways(pcs, pcs_idx, spd->process_output, timestep_id, t,
-                                    x);
+            _output->doOutputAlways(pcs, pcs_idx, spd->process_output,
+                                    timestep_id, t, x);
 
             if (!spd->timestepper->isSolutionErrorComputationNeeded())
             {
@@ -842,12 +856,22 @@ bool UncoupledProcessesTimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
     if (_global_coupling_max_iterations != 0)
     {
         // Set the flag of the first iteration be true.
-        _global_coupling_conv_crit->preFirstIteration();
+        for (auto& conv_crit : _global_coupling_conv_crit)
+        {
+            conv_crit->preFirstIteration();
+        }
     }
+    auto resetCouplingConvergenceCtiteria = [&]() {
+        for (auto& conv_crit : _global_coupling_conv_crit)
+        {
+            conv_crit->reset();
+        }
+    };
+
     bool coupling_iteration_converged = true;
     for (unsigned global_coupling_iteration = 0;
          global_coupling_iteration < _global_coupling_max_iterations;
-         global_coupling_iteration++, _global_coupling_conv_crit->reset())
+         global_coupling_iteration++, resetCouplingConvergenceCtiteria())
     {
         // TODO(wenqing): use process name
         bool nonlinear_solver_succeeded = true;
@@ -900,8 +924,7 @@ bool UncoupledProcessesTimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
 
                 // save unsuccessful solution
                 _output->doOutputAlways(spd->process, pcs_idx,
-                                        spd->process_output,
-                                        timestep_id, t, x);
+                                        spd->process_output, timestep_id, t, x);
 
                 if (!spd->timestepper->isSolutionErrorComputationNeeded())
                 {
@@ -913,15 +936,17 @@ bool UncoupledProcessesTimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
 
             // Check the convergence of the coupling iteration
             auto& x_old = *_solutions_of_last_cpl_iteration[pcs_idx];
-            MathLib::LinAlg::axpy(x_old, -1.0, x);
-            _global_coupling_conv_crit->checkResidual(x_old);
-            coupling_iteration_converged =
-                coupling_iteration_converged &&
-                _global_coupling_conv_crit->isSatisfied();
-
+            if (global_coupling_iteration > 0)
+            {
+                MathLib::LinAlg::axpy(x_old, -1.0, x); // save dx to x_old
+                _global_coupling_conv_crit[pcs_idx]->checkDeltaX(x_old, x);
+                coupling_iteration_converged =
+                    coupling_iteration_converged &&
+                    _global_coupling_conv_crit[pcs_idx]->isSatisfied();
+            }
             MathLib::LinAlg::copy(x, x_old);
 
-            if (coupling_iteration_converged)
+            if (coupling_iteration_converged && global_coupling_iteration > 0)
             {
                 break;
             }
@@ -929,7 +954,7 @@ bool UncoupledProcessesTimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
             ++pcs_idx;
         }  // end of for (auto& spd : _per_process_data)
 
-        if (coupling_iteration_converged)
+        if (coupling_iteration_converged && global_coupling_iteration > 0)
         {
             break;
         }
@@ -1007,9 +1032,8 @@ void UncoupledProcessesTimeLoop::outputSolutions(
             spd->process.setCoupledSolutionsForStaggeredScheme(
                 &coupled_solutions);
             spd->process.setCoupledTermForTheStaggeredSchemeToLocalAssemblers();
-            (output_object.*output_class_member)(pcs, pcs_idx,
-                                                 spd->process_output,
-                                                 timestep, t, x);
+            (output_object.*output_class_member)(
+                pcs, pcs_idx, spd->process_output, timestep, t, x);
         }
         else
         {
diff --git a/ProcessLib/UncoupledProcessesTimeLoop.h b/ProcessLib/UncoupledProcessesTimeLoop.h
index e26ea2d986f..b62cf9c3df0 100644
--- a/ProcessLib/UncoupledProcessesTimeLoop.h
+++ b/ProcessLib/UncoupledProcessesTimeLoop.h
@@ -39,7 +39,7 @@ public:
         std::unique_ptr<Output>&& output,
         std::vector<std::unique_ptr<SingleProcessData>>&& per_process_data,
         const unsigned global_coupling_max_iterations,
-        std::unique_ptr<NumLib::ConvergenceCriterion>&&
+        std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&&
             global_coupling_conv_crit,
         const double start_time, const double end_time);
 
@@ -72,7 +72,8 @@ private:
     /// Maximum iterations of the global coupling.
     const unsigned _global_coupling_max_iterations;
     /// Convergence criteria of the global coupling iterations.
-    std::unique_ptr<NumLib::ConvergenceCriterion> _global_coupling_conv_crit;
+    std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>
+        _global_coupling_conv_crit;
 
     /**
      *  Vector of solutions of the coupled processes.
diff --git a/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500.vtu b/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500.vtu
index 3df5c5201c9..daa22a7fd61 100644
--- a/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500.vtu
+++ b/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500.vtu
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:6f5d32a50ce7d3eddd0f4f4b1f33de2230d2e49a24aa1b55511222e3cf038f68
+oid sha256:5938bdfce5fdd7675654514a0e2c26ff1b8fbdf419e02cef8ffc48da15f13aa2
 size 138816
diff --git a/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500_staggered_scheme.prj b/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500_staggered_scheme.prj
index fe303865d28..eee8f7a9319 100644
--- a/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500_staggered_scheme.prj
+++ b/Tests/Data/Parabolic/HT/StaggeredCoupling/ConstViscosity/square_5500x5500_staggered_scheme.prj
@@ -57,11 +57,20 @@
     <time_loop>
         <global_process_coupling>
             <max_iter> 6 </max_iter>
-            <convergence_criterion>
-                <type>Residual</type>
-                <norm_type>NORM2</norm_type>
-                <reltol>1.e-10</reltol>
-            </convergence_criterion>
+            <convergence_criteria>
+                <!-- convergence criterion for the first process -->
+                <convergence_criterion>
+                    <type>DeltaX</type>
+                    <norm_type>NORM2</norm_type>
+                    <reltol>1.e-14</reltol>
+                </convergence_criterion>
+                <!-- convergence criterion for the second process -->
+                <convergence_criterion>
+                    <type>DeltaX</type>
+                    <norm_type>NORM2</norm_type>
+                    <reltol>1.e-14</reltol>
+                </convergence_criterion>
+            </convergence_criteria>
         </global_process_coupling>
 
         <processes>
-- 
GitLab