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