OGS
NumLib::StaggeredCoupling Class Reference

Detailed Description

A class designed to manage the solution of coupled equations using the staggered method.

Definition at line 38 of file StaggeredCoupling.h.

#include <StaggeredCoupling.h>

Public Member Functions

 StaggeredCoupling (const int global_coupling_max_iterations, std::vector< CouplingNodeVariant > &&coupling_nodes)
 ~StaggeredCoupling ()
int lastNumberOfCouplingIterations () const
void initializeCoupledSolutions (std::vector< GlobalVector * > const &process_solutions)
template<typename ProcessData, typename Output>
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)

Private Types

template<typename ProcessData, typename Output>
using ProcessSolver
using CouplingNodeVariant = std::variant<CouplingNode, RootCouplingNode>

Private Member Functions

template<typename ProcessData, typename Output>
std::tuple< NumLib::NonlinearSolverStatus, bool, int > 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)
template<typename ProcessData, typename Output>
std::tuple< NumLib::NonlinearSolverStatus, bool, int > 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)
template<typename ProcessData, typename Output>
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)
void setFirstIterationIndicator (std::vector< CouplingNodeVariant > const &coupling_nodes)
 Set the indicator of the first staggered coupling iteration be true.
void resetCouplingConvergenceCriteria (std::vector< CouplingNodeVariant > const &coupling_nodes)
bool checkCouplingConvergence (const bool convergence_of_last_process, CouplingNode const &coupling_node, GlobalVector const &x) const
void updatePreviousSolution (int const process_id, GlobalVector const &x)

Private Attributes

const int global_coupling_max_iterations_
 Maximum iteration number of the coupling loop of the staggered scheme.
int number_of_global_coupling_iterations_ = 0
std::vector< CouplingNodeVariantcoupling_nodes_
std::vector< GlobalVector * > solutions_of_last_cpl_iteration_

Member Typedef Documentation

◆ CouplingNodeVariant

Definition at line 48 of file StaggeredCoupling.h.

◆ ProcessSolver

template<typename ProcessData, typename Output>
using NumLib::StaggeredCoupling::ProcessSolver
private
Initial value:
std::vector<GlobalVector*>& ,
std::vector<GlobalVector*> const& ,
std::size_t const , double const ,
double const , ProcessData const& ,
std::vector<Output> const& )>
Status of the non-linear solver.

Definition at line 41 of file StaggeredCoupling.h.

Constructor & Destructor Documentation

◆ StaggeredCoupling()

NumLib::StaggeredCoupling::StaggeredCoupling ( const int global_coupling_max_iterations,
std::vector< CouplingNodeVariant > && coupling_nodes )
inline

Definition at line 51 of file StaggeredCoupling.h.

53 : global_coupling_max_iterations_(global_coupling_max_iterations),
54 coupling_nodes_(std::move(coupling_nodes))
55 {
56 }
const int global_coupling_max_iterations_
Maximum iteration number of the coupling loop of the staggered scheme.
std::vector< CouplingNodeVariant > coupling_nodes_

References coupling_nodes_, and global_coupling_max_iterations_.

◆ ~StaggeredCoupling()

NumLib::StaggeredCoupling::~StaggeredCoupling ( )

Definition at line 16 of file StaggeredCoupling.cpp.

17{
19 {
21 }
22}
std::vector< GlobalVector * > solutions_of_last_cpl_iteration_
virtual void releaseVector(GlobalVector const &x)=0
static NUMLIB_EXPORT VectorProvider & provider

References NumLib::GlobalVectorProvider::provider, and solutions_of_last_cpl_iteration_.

Member Function Documentation

◆ checkCouplingConvergence()

bool NumLib::StaggeredCoupling::checkCouplingConvergence ( const bool convergence_of_last_process,
CouplingNode const & coupling_node,
GlobalVector const & x ) const
private

Definition at line 65 of file StaggeredCoupling.cpp.

69{
70 bool is_coupling_iteration_converged = convergence_of_last_process;
71
72 auto& x_old = *solutions_of_last_cpl_iteration_[coupling_node.process_id];
73 // Since x_old can be immediately refreshed after computing dx,
74 // it is assigned with dx to save memory usage
75 MathLib::LinAlg::axpy(x_old, -1.0, x); // save dx = x - x_old to x_old.
76 INFO(
77 "------- Checking convergence criterion for coupled "
78 "solution of process {:s} with ID {:d} -------",
79 coupling_node.process_name, coupling_node.process_id);
80 // Note: x_old stores dx
81 coupling_node.convergence_criterion->checkDeltaX(x_old, x);
82
83 is_coupling_iteration_converged =
84 is_coupling_iteration_converged &&
85 coupling_node.convergence_criterion->isSatisfied();
86
87 return is_coupling_iteration_converged;
88}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void axpy(PETScVector &y, PetscScalar const a, PETScVector const &x)
Definition LinAlg.cpp:50

References MathLib::LinAlg::axpy(), NumLib::CouplingNode::convergence_criterion, INFO(), NumLib::CouplingNode::process_id, NumLib::CouplingNode::process_name, and solutions_of_last_cpl_iteration_.

Referenced by executeConcrete().

◆ execute()

template<typename ProcessData, typename Output>
NumLib::NonlinearSolverStatus NumLib::StaggeredCoupling::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 )

It solves the equations of all coupled processes by the staggered method, and it returns nonlinear solver status.

Definition at line 16 of file StaggeredCoupling-impl.h.

23{
24 auto [nonlinear_solver_status, coupling_iteration_converged,
25 number_of_coupling_iterations] =
27 timestep_id, process_solutions, process_solutions_prev,
28 per_process_data, outputs,
29 solve_one_time_step_one_process);
30
31 number_of_global_coupling_iterations_ = number_of_coupling_iterations;
32
33 // A failed per-process nonlinear solver is already reported as such and
34 // leaves the coupling loop early with unmet error norms. Reaching the
35 // iteration limit with all processes converged individually is the
36 // remaining failure mode: the coupling residuum is not converged, hence
37 // the solution must not be accepted.
38 if (!coupling_iteration_converged &&
39 nonlinear_solver_status.error_norms_met)
40 {
41 WARN(
42 "The coupling iterations reached their maximum number {:d} in time "
43 "step #{:d} at t = {:g} s. The time step will be rejected.",
44 global_coupling_max_iterations_, timestep_id, t);
45
46 nonlinear_solver_status.error_norms_met = false;
47 // The time loop decides on the acceptance of the time step by means of
48 // the per-process nonlinear solver states.
49 for (auto const& process_data : per_process_data)
50 {
51 process_data->nonlinear_solver_status.error_norms_met = false;
52 }
53 }
54
55 return nonlinear_solver_status;
56}
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
std::tuple< NumLib::NonlinearSolverStatus, bool, int > 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)

References coupling_nodes_, executeConcrete(), global_coupling_max_iterations_, number_of_global_coupling_iterations_, and WARN().

◆ executeConcrete()

template<typename ProcessData, typename Output>
std::tuple< NumLib::NonlinearSolverStatus, bool, int > NumLib::StaggeredCoupling::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 )
private

It solves the equation of each coupling process (treated as a coupling node) via function recursion, and it returns nonlinear solver status, and an indicator of coupling iteration convergence.

Definition at line 93 of file StaggeredCoupling-impl.h.

101{
102 setFirstIterationIndicator(coupling_nodes);
103
104 NumLib::NonlinearSolverStatus nonlinear_solver_status{true, -1};
105
106 bool coupling_iteration_converged = true;
107 int number_of_coupling_iterations = 0;
108 // Maximum number of coupling iterations over all nested sub-couplings.
109 int number_of_sub_coupling_iterations = 0;
110 for (int global_coupling_iteration = 0;
111 global_coupling_iteration < max_iterations;
112 global_coupling_iteration++,
113 resetCouplingConvergenceCriteria(coupling_nodes))
114 {
115 coupling_iteration_converged = true;
116 number_of_coupling_iterations = global_coupling_iteration + 1;
117
118 INFO("Global coupling iteration #{:d} started.",
119 global_coupling_iteration);
120 BaseLib::RunTime coupling_iteration_timer;
121 coupling_iteration_timer.start();
122
123 for (auto& coupling_node : coupling_nodes)
124 {
125 // For the dummy root node, perform sub-coupling computation.
126 if (std::holds_alternative<RootCouplingNode>(coupling_node))
127 {
128 auto const [local_nonlinear_solver_status,
129 local_coupling_iteration_converged,
130 local_number_of_coupling_iterations] =
132 coupling_node, t, dt, timestep_id, process_solutions,
133 process_solutions_prev, per_process_data, outputs,
134 solve_one_time_step_one_process);
135
136 number_of_sub_coupling_iterations =
137 std::max(number_of_sub_coupling_iterations,
138 local_number_of_coupling_iterations);
139
140 if (!local_nonlinear_solver_status.error_norms_met)
141 {
142 coupling_iteration_converged = false;
143 return {local_nonlinear_solver_status,
144 coupling_iteration_converged,
145 std::max(number_of_coupling_iterations,
146 number_of_sub_coupling_iterations)};
147 }
148
149 coupling_iteration_converged =
150 coupling_iteration_converged &&
151 local_coupling_iteration_converged;
152 continue;
153 }
154
155 CouplingNode const& regular_coupling_node =
156 std::get<CouplingNode>(coupling_node);
157
158 nonlinear_solver_status = executeSingleIteration(
159 global_coupling_iteration, regular_coupling_node, t, dt,
160 timestep_id, process_solutions, process_solutions_prev,
161 per_process_data, outputs, solve_one_time_step_one_process);
162
163 if (!nonlinear_solver_status.error_norms_met)
164 {
165 WARN(
166 "The nonlinear solver failed in time step #{:d} at t = "
167 "{:g} s for process {:s}.",
168 timestep_id, t, regular_coupling_node.process_name);
169 coupling_iteration_converged = false;
170 return {nonlinear_solver_status, coupling_iteration_converged,
171 std::max(number_of_coupling_iterations,
172 number_of_sub_coupling_iterations)};
173 }
174
175 auto const& x =
176 *process_solutions[regular_coupling_node.process_id];
177
178 // It is unnecessary to check convergence for a process at the first
179 // iteration
180 if (global_coupling_iteration > 0)
181 {
182 coupling_iteration_converged = checkCouplingConvergence(
183 coupling_iteration_converged, regular_coupling_node, x);
184 }
185
186 updatePreviousSolution(regular_coupling_node.process_id, x);
187
188 } // end of for (auto& process_data : _per_process_data)
189
190 // At least to run two coupling iterations, meaning that the coupling
191 // has at least two coupling nodes.
192 INFO("Global coupling iteration #{:d} took {:g} s.",
193 global_coupling_iteration, coupling_iteration_timer.elapsed());
194 if (coupling_iteration_converged && global_coupling_iteration > 0)
195 {
196 break;
197 }
198 }
199
200 return {nonlinear_solver_status, coupling_iteration_converged,
201 std::max(number_of_coupling_iterations,
202 number_of_sub_coupling_iterations)};
203}
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)
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::tuple< NumLib::NonlinearSolverStatus, bool, int > 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)
bool checkCouplingConvergence(const bool convergence_of_last_process, CouplingNode const &coupling_node, GlobalVector const &x) const
void updatePreviousSolution(int const process_id, GlobalVector const &x)

References checkCouplingConvergence(), BaseLib::RunTime::elapsed(), NumLib::NonlinearSolverStatus::error_norms_met, executeSingleIteration(), executeSubCoupling(), INFO(), NumLib::CouplingNode::process_id, NumLib::CouplingNode::process_name, resetCouplingConvergenceCriteria(), setFirstIterationIndicator(), BaseLib::RunTime::start(), updatePreviousSolution(), and WARN().

Referenced by execute(), and executeSubCoupling().

◆ executeSingleIteration()

template<typename ProcessData, typename Output>
NumLib::NonlinearSolverStatus NumLib::StaggeredCoupling::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 )
private

Definition at line 59 of file StaggeredCoupling-impl.h.

68{
69 BaseLib::RunTime time_timestep_process;
70 time_timestep_process.start();
71
72 auto const process_id = regular_coupling_node.process_id;
73 auto const& process_name = regular_coupling_node.process_name;
74 INFO("Solve process #{:d} (named as {:s})", process_id, process_name);
75
76 auto& process_data = *(per_process_data[process_id]);
77
78 process_data.nonlinear_solver_status = solve_one_time_step_one_process(
79 process_solutions, process_solutions_prev, timestep_id, t, dt,
80 process_data, outputs);
81
82 INFO(
83 "[time] Solving process #{:d} (named as {:s}) took {:g} s in "
84 "time step #{} coupling iteration #{}.",
85 process_id, process_name, time_timestep_process.elapsed(), timestep_id,
86 global_coupling_iteration);
87
88 return process_data.nonlinear_solver_status;
89}

References BaseLib::RunTime::elapsed(), INFO(), NumLib::CouplingNode::process_id, NumLib::CouplingNode::process_name, and BaseLib::RunTime::start().

Referenced by executeConcrete().

◆ executeSubCoupling()

template<typename ProcessData, typename Output>
std::tuple< NumLib::NonlinearSolverStatus, bool, int > NumLib::StaggeredCoupling::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 )
private

Definition at line 207 of file StaggeredCoupling-impl.h.

215{
216 INFO("--- Execute sub-coupling:");
217 RootCouplingNode& root_coupling_node =
218 std::get<RootCouplingNode>(coupling_node);
219 const int local_max_iterations =
220 std::get<CouplingNode>(root_coupling_node.sub_coupling_nodes.front())
221 .max_iterations;
222
223 auto const [sub_nonlinear_solver_status, sub_coupling_iteration_converged,
224 sub_number_of_coupling_iterations] =
226 root_coupling_node.sub_coupling_nodes, local_max_iterations, t, dt,
227 timestep_id, process_solutions, process_solutions_prev,
228 per_process_data, outputs, solve_one_time_step_one_process);
229
230 INFO("--- End sub-coupling.");
231 return {sub_nonlinear_solver_status, sub_coupling_iteration_converged,
232 sub_number_of_coupling_iterations};
233}

References executeConcrete(), INFO(), and NumLib::RootCouplingNode::sub_coupling_nodes.

Referenced by executeConcrete().

◆ initializeCoupledSolutions()

void NumLib::StaggeredCoupling::initializeCoupledSolutions ( std::vector< GlobalVector * > const & process_solutions)

This function fills the vector of solutions of coupled processes of processes, solutions_of_coupled_processes_, and initializes the vector of solutions of the previous coupling iteration, _solutions_of_last_cpl_iteration.

Definition at line 24 of file StaggeredCoupling.cpp.

26{
27 for (auto const* const x : process_solutions)
28 {
29 // Create a vector to store the solution of the last coupling iteration
32
33 // append a solution vector of suitable size
34 solutions_of_last_cpl_iteration_.emplace_back(&x0);
35 }
36}
virtual GlobalVector & getVector(std::size_t &id)=0
Get an uninitialized vector with the given id.
void copy(PETScVector const &x, PETScVector &y)
Definition LinAlg.cpp:30

References MathLib::LinAlg::copy(), NumLib::GlobalVectorProvider::provider, and solutions_of_last_cpl_iteration_.

◆ lastNumberOfCouplingIterations()

int NumLib::StaggeredCoupling::lastNumberOfCouplingIterations ( ) const
inline

Number of global coupling iterations performed in the last solved time step. Used to drive the time step size control in the staggered scheme.

Definition at line 62 of file StaggeredCoupling.h.

References number_of_global_coupling_iterations_.

◆ resetCouplingConvergenceCriteria()

void NumLib::StaggeredCoupling::resetCouplingConvergenceCriteria ( std::vector< CouplingNodeVariant > const & coupling_nodes)
private

Definition at line 52 of file StaggeredCoupling.cpp.

54{
55 auto is_regular_node = [](const CouplingNodeVariant& node)
56 { return std::holds_alternative<CouplingNode>(node); };
57
58 for (auto& coupling_node :
59 coupling_nodes | ranges::views::filter(is_regular_node))
60 {
61 std::get<CouplingNode>(coupling_node).convergence_criterion->reset();
62 }
63}
std::variant< CouplingNode, RootCouplingNode > CouplingNodeVariant

Referenced by executeConcrete().

◆ setFirstIterationIndicator()

void NumLib::StaggeredCoupling::setFirstIterationIndicator ( std::vector< CouplingNodeVariant > const & coupling_nodes)
private

Set the indicator of the first staggered coupling iteration be true.

Definition at line 38 of file StaggeredCoupling.cpp.

40{
41 auto is_regular_node = [](const CouplingNodeVariant& node)
42 { return std::holds_alternative<CouplingNode>(node); };
43
44 for (auto const& coupling_node :
45 coupling_nodes | ranges::views::filter(is_regular_node))
46 {
47 std::get<CouplingNode>(coupling_node)
48 .convergence_criterion->preFirstIteration();
49 }
50}

Referenced by executeConcrete().

◆ updatePreviousSolution()

void NumLib::StaggeredCoupling::updatePreviousSolution ( int const process_id,
GlobalVector const & x )
private

Definition at line 90 of file StaggeredCoupling.cpp.

92{
93 auto& x_old = *solutions_of_last_cpl_iteration_[process_id];
94 MathLib::LinAlg::copy(x, x_old);
95}

References MathLib::LinAlg::copy(), and solutions_of_last_cpl_iteration_.

Referenced by executeConcrete().

Member Data Documentation

◆ coupling_nodes_

std::vector<CouplingNodeVariant> NumLib::StaggeredCoupling::coupling_nodes_
private

Coupling graph for the staggered scheme. It looks like:

x ... x o o / \ / \ / \ / \ x ... x x ... x

where x represents a coupling node, and o represents a dummy root coupling node.

Definition at line 108 of file StaggeredCoupling.h.

Referenced by StaggeredCoupling(), and execute().

◆ global_coupling_max_iterations_

const int NumLib::StaggeredCoupling::global_coupling_max_iterations_
private

Maximum iteration number of the coupling loop of the staggered scheme.

Definition at line 92 of file StaggeredCoupling.h.

Referenced by StaggeredCoupling(), and execute().

◆ number_of_global_coupling_iterations_

int NumLib::StaggeredCoupling::number_of_global_coupling_iterations_ = 0
private

Number of global coupling iterations performed in the last solved time step.

Definition at line 96 of file StaggeredCoupling.h.

Referenced by execute(), and lastNumberOfCouplingIterations().

◆ solutions_of_last_cpl_iteration_

std::vector<GlobalVector*> NumLib::StaggeredCoupling::solutions_of_last_cpl_iteration_
private

Solutions of the previous coupling iteration for the convergence criteria of the coupling iteration.

Definition at line 153 of file StaggeredCoupling.h.

Referenced by ~StaggeredCoupling(), checkCouplingConvergence(), initializeCoupledSolutions(), and updatePreviousSolution().


The documentation for this class was generated from the following files: