OGS
CreateStaggeredCoupling-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 <numeric>
7
8#include "BaseLib/Error.h"
10#include "StaggeredCoupling.h"
11
12namespace NumLib
13{
14using CouplingNodeVariant = std::variant<CouplingNode, RootCouplingNode>;
15
16template <typename ProcessData>
18 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
19 std::vector<LocalCouplingParameters> const& all_local_coupling_parameters)
20{
21 // Check whether the process names in the sub-coupling definitions exist in
22 // the process data.
23 for (auto const& local_coupling_parameters : all_local_coupling_parameters)
24 {
25 for (auto const& process_name : local_coupling_parameters.process_names)
26 {
27 if (std::none_of(
28 per_process_data.begin(),
29 per_process_data.end(),
30 [&process_name](auto const& process_data)
31 { return process_data->process_name == process_name; }))
32 {
34 "The given process name '{}' for the element "
35 "'time_loop/global_process_coupling/"
36 "local_coupling_processes/process_name' is not found "
37 "in the element 'time_loop/global_process_coupling/"
38 "local_coupling_processes/process_name' in the project "
39 "file.",
40 process_name);
41 }
42 }
43 }
44}
45
47template <typename ProcessData>
48std::vector<CouplingNodeVariant> createRegularCouplingNodes(
49 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
50 std::vector<LocalCouplingParameters> const& all_local_coupling_parameters,
51 int const global_max_coupling_iterations,
52 std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&
53 global_coupling_conv_criteria)
54{
55 std::vector<CouplingNodeVariant> coupling_nodes;
56
57 for (auto const& process_data : per_process_data)
58 {
59 auto const& process_name = process_data->process_name;
60
61 // If process_data->process_name occurs in local_coupling_parameters
62 // do nothing
63 if (std::any_of(
64 all_local_coupling_parameters.begin(),
65 all_local_coupling_parameters.end(),
66 [&process_name](auto const& local_coupling_parameters)
67 {
68 auto const& process_names =
69 local_coupling_parameters.process_names;
70 return std::find(process_names.begin(), process_names.end(),
71 process_name) != process_names.end();
72 }))
73 {
74 continue;
75 }
76
77 std::string const used_process_name =
78 process_name.empty() ? "not given" : process_name;
79 CouplingNode regular_node{
80 used_process_name,
81 std::move(global_coupling_conv_criteria[process_data->process_id]),
82 global_max_coupling_iterations,
83 process_data->process_id,
84 };
85 coupling_nodes.emplace_back(std::move(regular_node));
86 }
87
88 return coupling_nodes;
89}
90
92template <typename ProcessData>
93std::vector<CouplingNodeVariant> createRootCouplingNodes(
94 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
95 std::vector<LocalCouplingParameters> const& all_local_coupling_parameters,
96 int const global_max_coupling_iterations,
97 std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&
98 global_coupling_conv_criteria)
99{
100 std::vector<CouplingNodeVariant> coupling_nodes;
101
102 for (auto const& local_coupling_parameters : all_local_coupling_parameters)
103 {
104 RootCouplingNode root_node = {global_max_coupling_iterations, {}};
105
106 for (auto const& local_process_name :
107 local_coupling_parameters.process_names)
108 {
109 if (auto it = std::find_if(
110 per_process_data.begin(),
111 per_process_data.end(),
112 [&local_process_name](auto const& process_data) {
113 return process_data->process_name == local_process_name;
114 });
115 it != per_process_data.end())
116 {
117 auto const& process_data = *it;
118
119 CouplingNode regular_node{
120 process_data->process_name,
121 std::move(global_coupling_conv_criteria[process_data
122 ->process_id]),
123 local_coupling_parameters.max_iterations,
124 process_data->process_id};
125
126 root_node.sub_coupling_nodes.emplace_back(
127 std::move(regular_node));
128 }
129 }
130 coupling_nodes.emplace_back(std::move(root_node));
131 }
132
133 return coupling_nodes;
134}
135
136template <typename ProcessData>
137std::vector<CouplingNodeVariant> createCouplingNodes(
138 std::vector<std::unique_ptr<ProcessData>> const& per_process_data,
139 std::vector<LocalCouplingParameters> const& all_local_coupling_parameters,
140 int const global_max_coupling_iterations,
141 std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&
142 global_coupling_conv_criteria)
143{
144 checkLocalCouplingParameters(per_process_data,
145 all_local_coupling_parameters);
146
147 // First, get the coupling nodes that do not have local-coupling nodes.
148 std::vector<CouplingNodeVariant> coupling_nodes =
150 per_process_data, all_local_coupling_parameters,
151 global_max_coupling_iterations, global_coupling_conv_criteria);
152
153 // Second, get the coupling nodes that have local-coupling nodes.
154 std::vector<CouplingNodeVariant> root_coupling_nodes =
155 createRootCouplingNodes(per_process_data, all_local_coupling_parameters,
156 global_max_coupling_iterations,
157 global_coupling_conv_criteria);
158
159 std::size_t const num_coupling_nodes =
160 coupling_nodes.size() +
161 std::accumulate(
162 root_coupling_nodes.begin(),
163 root_coupling_nodes.end(),
164 std::size_t{0},
165 [](std::size_t accumulated_sizes, const auto& coupling_node)
166 {
167 return accumulated_sizes +
168 std::get<RootCouplingNode>(coupling_node)
169 .sub_coupling_nodes.size();
170 });
171
172 if (num_coupling_nodes != per_process_data.size())
173 {
174 OGS_FATAL(
175 "The number of all coupling nodes including sub-nodes is not "
176 "identical to the number of the processes! Please check the "
177 "element by tag global_process_coupling in the project file.");
178 }
179
180 if (coupling_nodes.empty())
181 {
182 coupling_nodes = std::move(root_coupling_nodes);
183 }
184 else
185 {
186 coupling_nodes.reserve(coupling_nodes.size() +
187 root_coupling_nodes.size());
188
189 std::move(std::begin(root_coupling_nodes),
190 std::end(root_coupling_nodes),
191 std::back_inserter(coupling_nodes));
192 }
193
194 return coupling_nodes;
195}
196
198template <typename ProcessData>
199std::unique_ptr<StaggeredCoupling> createStaggeredCoupling(
200 BaseLib::ConfigTree const& config,
201 std::vector<std::unique_ptr<ProcessData>> const& per_process_data)
202{
203 auto [global_coupling_conv_criteria, all_local_coupling_parameters,
204 max_coupling_iterations] = parseCoupling(config);
205
206 if (per_process_data.size() != global_coupling_conv_criteria.size())
207 {
208 OGS_FATAL(
209 "The number of convergence criteria of the global "
210 "staggered coupling loop is not identical to the number of the "
211 "processes! Please check the element by tag "
212 "global_process_coupling in the project file.");
213 }
214
215 auto coupling_nodes = createCouplingNodes(
216 per_process_data, all_local_coupling_parameters,
217 max_coupling_iterations, global_coupling_conv_criteria);
218
219 return std::make_unique<StaggeredCoupling>(max_coupling_iterations,
220 std::move(coupling_nodes));
221}
222} // namespace NumLib
#define OGS_FATAL(...)
Definition Error.h:19
void checkLocalCouplingParameters(std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< LocalCouplingParameters > const &all_local_coupling_parameters)
std::unique_ptr< StaggeredCoupling > createStaggeredCoupling(BaseLib::ConfigTree const &config, std::vector< std::unique_ptr< ProcessData > > const &per_process_data)
Create a StaggeredCoupling instance from the given configuration.
std::variant< CouplingNode, RootCouplingNode > CouplingNodeVariant
std::vector< CouplingNodeVariant > createCouplingNodes(std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< LocalCouplingParameters > const &all_local_coupling_parameters, int const global_max_coupling_iterations, std::vector< std::unique_ptr< NumLib::ConvergenceCriterion > > &global_coupling_conv_criteria)
std::tuple< std::vector< std::unique_ptr< NumLib::ConvergenceCriterion > >, std::vector< LocalCouplingParameters >, int > parseCoupling(BaseLib::ConfigTree const &config)
std::vector< CouplingNodeVariant > createRootCouplingNodes(std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< LocalCouplingParameters > const &all_local_coupling_parameters, int const global_max_coupling_iterations, std::vector< std::unique_ptr< NumLib::ConvergenceCriterion > > &global_coupling_conv_criteria)
Create coupling nodes that have local-coupling nodes.
std::vector< CouplingNodeVariant > createRegularCouplingNodes(std::vector< std::unique_ptr< ProcessData > > const &per_process_data, std::vector< LocalCouplingParameters > const &all_local_coupling_parameters, int const global_max_coupling_iterations, std::vector< std::unique_ptr< NumLib::ConvergenceCriterion > > &global_coupling_conv_criteria)
Create coupling nodes that do not have local-coupling nodes.
Information of a coupling node.
std::vector< CouplingNodeVariant > sub_coupling_nodes