OGS
StaggeredCoupling-impl.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include "BaseLib/Error.h"
7#include "BaseLib/RunTime.h"
9#include "StaggeredCoupling.h"
10
11namespace NumLib
12{
13template <typename ProcessData, typename Output>
15 const double t, const double dt, const std::size_t timestep_id,
16 std::vector<GlobalVector*>& process_solutions,
17 std::vector<GlobalVector*> const& process_solutions_prev,
18 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
19 std::vector<Output> const& outputs,
20 ProcessSolver<ProcessData, Output> const& solve_one_time_step_one_process)
21{
22 auto const [nonlinear_solver_status, coupling_iteration_converged] =
24 timestep_id, process_solutions, process_solutions_prev,
25 per_process_data, outputs,
26 solve_one_time_step_one_process);
27
28 if (!coupling_iteration_converged)
29 {
30 WARN(
31 "The coupling iterations reaches its maximum number in time step "
32 "#{:d} at t = {:g}",
33 timestep_id, t);
34 }
35
36 return nonlinear_solver_status;
37}
38
39template <typename ProcessData, typename Output>
41 int const global_coupling_iteration,
42 CouplingNode const& regular_coupling_node, const double t, const double dt,
43 const std::size_t timestep_id,
44 std::vector<GlobalVector*>& process_solutions,
45 std::vector<GlobalVector*> const& process_solutions_prev,
46 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
47 std::vector<Output> const& outputs,
48 ProcessSolver<ProcessData, Output> const& solve_one_time_step_one_process)
49{
50 BaseLib::RunTime time_timestep_process;
51 time_timestep_process.start();
52
53 auto const process_id = regular_coupling_node.process_id;
54 auto const& process_name = regular_coupling_node.process_name;
55 INFO("Solve process #{:d} (named as {:s})", process_id, process_name);
56
57 auto& process_data = *(per_process_data[process_id]);
58
59 process_data.nonlinear_solver_status = solve_one_time_step_one_process(
60 process_solutions, process_solutions_prev, timestep_id, t, dt,
61 process_data, outputs);
62
63 INFO(
64 "[time] Solving process #{:d} (named as {:s}) took {:g} s in "
65 "time step #{} coupling iteration #{}.",
66 process_id, process_name, time_timestep_process.elapsed(), timestep_id,
67 global_coupling_iteration);
68
69 return process_data.nonlinear_solver_status;
70}
71
72template <typename ProcessData, typename Output>
73std::tuple<NumLib::NonlinearSolverStatus, bool>
75 std::vector<CouplingNodeVariant>& coupling_nodes, const int max_iterations,
76 const double t, const double dt, const std::size_t timestep_id,
77 std::vector<GlobalVector*>& process_solutions,
78 std::vector<GlobalVector*> const& process_solutions_prev,
79 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
80 std::vector<Output> const& outputs,
81 ProcessSolver<ProcessData, Output> const& solve_one_time_step_one_process)
82{
83 setFirstIterationIndicator(coupling_nodes);
84
85 NumLib::NonlinearSolverStatus nonlinear_solver_status{true, -1};
86
87 bool coupling_iteration_converged = true;
88 for (int global_coupling_iteration = 0;
89 global_coupling_iteration < max_iterations;
90 global_coupling_iteration++,
92 {
93 coupling_iteration_converged = true;
94
95 INFO("Global coupling iteration #{:d} started.",
96 global_coupling_iteration);
97 BaseLib::RunTime coupling_iteration_timer;
98 coupling_iteration_timer.start();
99
100 for (auto& coupling_node : coupling_nodes)
101 {
102 // For the dummy root node, perform sub-coupling computation.
103 if (std::holds_alternative<RootCouplingNode>(coupling_node))
104 {
105 auto const [local_nonlinear_solver_status,
106 local_coupling_iteration_converged] =
108 coupling_node, t, dt, timestep_id, process_solutions,
109 process_solutions_prev, per_process_data, outputs,
110 solve_one_time_step_one_process);
111
112 if (!local_nonlinear_solver_status.error_norms_met)
113 {
114 coupling_iteration_converged = false;
115 return {local_nonlinear_solver_status,
116 coupling_iteration_converged};
117 }
118
119 coupling_iteration_converged =
120 coupling_iteration_converged &&
121 local_coupling_iteration_converged;
122 continue;
123 }
124
125 CouplingNode const& regular_coupling_node =
126 std::get<CouplingNode>(coupling_node);
127
128 nonlinear_solver_status = executeSingleIteration(
129 global_coupling_iteration, regular_coupling_node, t, dt,
130 timestep_id, process_solutions, process_solutions_prev,
131 per_process_data, outputs, solve_one_time_step_one_process);
132
133 if (!nonlinear_solver_status.error_norms_met)
134 {
135 WARN(
136 "The nonlinear solver failed in time step #{:d} at t = "
137 "{:g} s for process {:s}.",
138 timestep_id, t, regular_coupling_node.process_name);
139 coupling_iteration_converged = false;
140 return {nonlinear_solver_status, coupling_iteration_converged};
141 }
142
143 auto const& x =
144 *process_solutions[regular_coupling_node.process_id];
145
146 // It is unnecessary to check convergence for a process at the first
147 // iteration
148 if (global_coupling_iteration > 0)
149 {
150 coupling_iteration_converged = checkCouplingConvergence(
151 coupling_iteration_converged, regular_coupling_node, x);
152 }
153
154 updatePreviousSolution(regular_coupling_node.process_id, x);
155
156 } // end of for (auto& process_data : _per_process_data)
157
158 // At least to run two coupling iterations, meaning that the coupling
159 // has at least two coupling nodes.
160 INFO("Global coupling iteration #{:d} took {:g} s.",
161 global_coupling_iteration, coupling_iteration_timer.elapsed());
162 if (coupling_iteration_converged && global_coupling_iteration > 0)
163 {
164 break;
165 }
166 }
167
168 return {nonlinear_solver_status, coupling_iteration_converged};
169}
170
171template <typename ProcessData, typename Output>
172std::tuple<NumLib::NonlinearSolverStatus, bool>
174 CouplingNodeVariant& coupling_node, const double t, const double dt,
175 const std::size_t timestep_id,
176 std::vector<GlobalVector*>& process_solutions,
177 std::vector<GlobalVector*> const& process_solutions_prev,
178 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
179 std::vector<Output> const& outputs,
180 ProcessSolver<ProcessData, Output> const& solve_one_time_step_one_process)
181{
182 INFO("--- Execute sub-coupling:");
183 RootCouplingNode& root_coupling_node =
184 std::get<RootCouplingNode>(coupling_node);
185 const int local_max_iterations =
186 std::get<CouplingNode>(root_coupling_node.sub_coupling_nodes.front())
187 .max_iterations;
188
189 auto const [sub_nonlinear_solver_status, sub_coupling_iteration_converged] =
191 root_coupling_node.sub_coupling_nodes, local_max_iterations, t, dt,
192 timestep_id, process_solutions, process_solutions_prev,
193 per_process_data, outputs, solve_one_time_step_one_process);
194
195 INFO("--- End sub-coupling.");
196 return {sub_nonlinear_solver_status, sub_coupling_iteration_converged};
197}
198
199} // namespace NumLib
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
Count the running time.
Definition RunTime.h:18
double elapsed() const
Get the elapsed time in seconds.
Definition RunTime.h:31
void start()
Start the timer.
Definition RunTime.h:21
NumLib::NonlinearSolverStatus executeSingleIteration(int const global_coupling_iteration, CouplingNode const &regular_coupling_node, const double t, const double dt, const std::size_t timestep_id, std::vector< GlobalVector * > &process_solutions, std::vector< GlobalVector * > const &process_solutions_prev, std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< Output > const &outputs, ProcessSolver< ProcessData, Output > const &solve_one_time_step_one_process)
const int global_coupling_max_iterations_
Maximum iteration number of the coupling loop of the staggered scheme.
std::tuple< NumLib::NonlinearSolverStatus, bool > executeConcrete(std::vector< CouplingNodeVariant > &coupling_nodes, const int max_iterations, const double t, const double dt, const std::size_t timestep_id, std::vector< GlobalVector * > &process_solutions, std::vector< GlobalVector * > const &process_solutions_prev, std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< Output > const &outputs, ProcessSolver< ProcessData, Output > const &solve_one_time_step_one_process)
void resetCouplingConvergenceCriteria(std::vector< CouplingNodeVariant > const &coupling_nodes)
void setFirstIterationIndicator(std::vector< CouplingNodeVariant > const &coupling_nodes)
Set the indicator of the first staggered coupling iteration be true.
std::vector< CouplingNodeVariant > coupling_nodes_
std::function< NumLib::NonlinearSolverStatus( std::vector< GlobalVector * > &, std::vector< GlobalVector * > const &, std::size_t const, double const, double const, ProcessData const &, std::vector< Output > const &)> ProcessSolver
NumLib::NonlinearSolverStatus execute(const double t, const double dt, const std::size_t timestep_id, std::vector< GlobalVector * > &process_solutions, std::vector< GlobalVector * > const &process_solutions_prev, std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< Output > const &outputs, ProcessSolver< ProcessData, Output > const &solve_one_time_step_one_process)
bool checkCouplingConvergence(const bool convergence_of_last_process, CouplingNode const &coupling_node, GlobalVector const &x) const
std::tuple< NumLib::NonlinearSolverStatus, bool > executeSubCoupling(CouplingNodeVariant &coupling_node, const double t, const double dt, const std::size_t timestep_id, std::vector< GlobalVector * > &process_solutions, std::vector< GlobalVector * > const &process_solutions_prev, std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< Output > const &outputs, ProcessSolver< ProcessData, Output > const &solve_one_time_step_one_process)
void updatePreviousSolution(int const process_id, GlobalVector const &x)
std::variant< CouplingNode, RootCouplingNode > CouplingNodeVariant
Information of a coupling node.
Status of the non-linear solver.
std::vector< CouplingNodeVariant > sub_coupling_nodes