OGS
CreateDeactivatedSubdomain.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <Eigen/Core>
7#include <range/v3/algorithm/all_of.hpp>
8#include <range/v3/algorithm/copy_if.hpp>
9#include <range/v3/algorithm/partition_copy.hpp>
10#include <range/v3/range/conversion.hpp>
11
12#include "BaseLib/ConfigTree.h"
13#include "BaseLib/Error.h"
16#include "MeshLib/Mesh.h"
17#include "MeshLib/Node.h"
21#include "ParameterLib/Utils.h"
22
23namespace ProcessLib
24{
25template <typename IsActive>
26static std::pair<std::vector<std::size_t>, std::vector<std::size_t>>
28 MeshLib::Mesh const& sub_mesh,
29 IsActive is_active)
30{
31 auto* const bulk_node_ids = MeshLib::bulkNodeIDs(sub_mesh);
32 if (bulk_node_ids == nullptr)
33 {
35 "Bulk node ids map is not available in the deactivate subdomain "
36 "mesh.");
37 }
38
39 std::vector<std::size_t> inner_nodes;
40 // Reserve for more than needed, but not much, because almost all nodes will
41 // be the inner nodes.
42 inner_nodes.reserve(sub_mesh.getNumberOfNodes());
43
44 std::vector<std::size_t> outer_nodes;
45
46 ranges::partition_copy(
47 sub_mesh.getNodes() | MeshLib::views::ids,
48 back_inserter(inner_nodes),
49 back_inserter(outer_nodes),
50 [&](std::size_t const n)
51 {
52 auto const bulk_node = mesh.getNode((*bulk_node_ids)[n]);
53 const auto& connected_elements =
54 mesh.getElementsConnectedToNode(*bulk_node);
55 // Check whether this node is connected only to an active
56 // elements. Then it is an inner node, and outer otherwise.
57 return ranges::all_of(connected_elements | MeshLib::views::ids,
58 is_active);
59 });
60
61 return {std::move(inner_nodes), std::move(outer_nodes)};
62}
63
64static std::vector<std::vector<std::size_t>> extractElementsAlongOuterNodes(
65 MeshLib::Mesh const& mesh, MeshLib::Mesh const& sub_mesh,
66 std::vector<std::size_t> const& outer_nodes)
67{
68 auto const& bulk_node_ids =
69 *sub_mesh.getProperties().template getPropertyVector<std::size_t>(
72
73 auto to_bulk_node_id =
74 ranges::views::transform([&bulk_node_ids](std::size_t const node_id)
75 { return bulk_node_ids[node_id]; });
76 auto connected_elements = ranges::views::transform(
77 [&mesh](std::size_t const node_id)
78 {
79 return mesh.getElementsConnectedToNode(node_id) |
80 MeshLib::views::ids | ranges::to<std::vector>;
81 });
82
83 return outer_nodes | to_bulk_node_id | connected_elements |
84 ranges::to<std::vector>;
85}
86
88 MeshLib::Mesh const& mesh,
89 std::unordered_set<int> const& deactivated_subdomain_material_ids)
90{
91 // An element is active if its material id matches one of the deactivated
92 // subdomain material ids.
93 auto is_active =
94 [&deactivated_subdomain_material_ids,
95 &material_ids = *materialIDs(mesh)](std::size_t element_id)
96 {
97 return deactivated_subdomain_material_ids.contains(
98 material_ids[element_id]);
99 };
100
101 auto const& elements = mesh.getElements();
102 std::vector<MeshLib::Element*> deactivated_elements;
103 ranges::copy_if(elements, back_inserter(deactivated_elements), is_active,
104 [](auto const e) { return e->getID(); });
105
106 auto bulk_element_ids = deactivated_elements | MeshLib::views::ids |
107 ranges::to<std::unordered_set>;
108
109 static int mesh_number = 0;
110 // Subdomain mesh consisting of deactivated elements.
112 "deactivate_subdomain_" + std::to_string(mesh_number++),
113 MeshLib::cloneElements(deactivated_elements));
114
115 auto [inner_nodes, outer_nodes] =
116 extractInnerAndOuterNodes(mesh, *sub_mesh, is_active);
117
118 auto outer_nodes_elements =
119 extractElementsAlongOuterNodes(mesh, *sub_mesh, outer_nodes);
120
121 return {std::move(*sub_mesh), std::move(bulk_element_ids),
122 std::move(inner_nodes), std::move(outer_nodes),
123 std::move(outer_nodes_elements)};
124}
125
127 std::optional<BaseLib::ConfigTree> const& time_interval_config,
128 std::optional<std::string> const& curve_name,
129 std::map<std::string,
130 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
131 curves)
132{
133 // Check for the error case first: only one of the configs must be used.
134 if (time_interval_config && curve_name)
135 {
136 OGS_FATAL(
137 "In the deactivate subdomain either a time interval or a curve "
138 "must be given, not both.");
139 }
140
141 // Parse time interval and return a curve
142 if (time_interval_config)
143 {
144 DBUG("Constructing time interval");
145 auto const start_time =
147 time_interval_config->getConfigParameter<double>("start");
148
149 auto const end_time =
151 time_interval_config->getConfigParameter<double>("end");
152
153 // Using very large value for the curve's value, s.t. for any time from
154 // start to end the whole subdomain is deactivated at once.
155 return {std::vector<double>({start_time, end_time}),
156 std::vector<double>({std::numeric_limits<double>::max(),
157 std::numeric_limits<double>::max()}),
158 false};
159 }
160
161 // Try to find the curve.
162 if (curve_name)
163 {
164 DBUG("Using curve '{:s}'", *curve_name);
165 // Return a copy of the curve because the time interval in the other
166 // branch returns a temporary.
167 return *BaseLib::getOrError(curves, *curve_name,
168 "Could not find curve.");
169 }
170
171 // If we got so far, there is an error: one of the configs must be
172 // available.
173 OGS_FATAL(
174 "In the deactivate subdomain neither a time interval nor a curve are "
175 "given. One of them must be specified.");
176}
177
179static std::pair<Eigen::Vector3d, Eigen::Vector3d> parseLineSegment(
180 BaseLib::ConfigTree const& config)
181{
182 DBUG("Constructing line segment");
183 auto const start =
185 config.getConfigParameter<std::vector<double>>("start");
186 if (start.size() != 3)
187 {
188 OGS_FATAL(
189 "For construction of a line segment the start point must be a 3D "
190 "point. Got a vector of size {}.",
191 start.size());
192 }
193
194 auto const end =
196 config.getConfigParameter<std::vector<double>>("end");
197
198 if (end.size() != 3)
199 {
200 OGS_FATAL(
201 "For construction of a line segment the end point must be a 3D "
202 "point. Got a vector of size {}.",
203 end.size());
204 }
205 return {Eigen::Vector3d{start[0], start[1], start[2]},
206 Eigen::Vector3d{end[0], end[1], end[2]}};
207}
208
211{
212 DBUG("Constructing a ball");
213 auto const center =
215 config.getConfigParameter<std::vector<double>>("center");
216 if (center.size() != 3)
217 {
218 OGS_FATAL(
219 "For construction of the center of a ball must be a 3D point. Got "
220 "a vector of size {}.",
221 center.size());
222 }
223
224 auto const radius =
226 config.getConfigParameter<double>("radius");
227
228 return {Eigen::Vector3d{center[0], center[1], center[2]}, radius};
229}
230
232 BaseLib::ConfigTree const& config, MeshLib::Mesh const& mesh,
233 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
234 std::map<std::string,
235 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
236 curves)
237{
238 auto const& time_interval_config =
240 config.getConfigSubtreeOptional("time_interval");
241
242 auto const& curve_name =
244 config.getConfigParameterOptional<std::string>("time_curve");
245 auto time_interval =
246 parseTimeIntervalOrCurve(time_interval_config, curve_name, curves);
247
248 auto const line_segment_config =
250 config.getConfigSubtreeOptional("line_segment");
251
252 auto const ball_config =
254 config.getConfigSubtreeOptional("ball");
255
256 if (line_segment_config && ball_config)
257 {
258 OGS_FATAL(
259 "line_segment and ball can not be defined "
260 "simultaneously.");
261 }
262
263 if (time_interval_config && (line_segment_config || ball_config))
264 {
265 OGS_FATAL(
266 "When using time interval for subdomain deactivation a line "
267 "segment or a ball must not be specified.");
268 }
269
270 if (curve_name && !(line_segment_config || ball_config))
271 {
272 OGS_FATAL(
273 "When using curve for subdomain deactivation a line segment or a "
274 "ball must be specified.");
275 }
276
277 // If time interval was specified then an empty optional line segment is
278 // used *internally* because the whole selected material ids subdomain will
279 // be deactivated.
280 std::optional<std::pair<Eigen::Vector3d, Eigen::Vector3d>> line_segment;
281 if (line_segment_config)
282 {
283 line_segment = parseLineSegment(*line_segment_config);
284 }
285
286 std::optional<detail::Ball> ball;
287 if (ball_config)
288 {
289 ball = parseBall(*ball_config);
290 }
291
292 ParameterLib::Parameter<double>* boundary_value_parameter = nullptr;
293 auto boundary_value_parameter_name =
295 config.getConfigParameterOptional<std::string>("boundary_parameter");
296 if (boundary_value_parameter_name)
297 {
298 DBUG("Using parameter {:s}", *boundary_value_parameter_name);
299 boundary_value_parameter = &ParameterLib::findParameter<double>(
300 *boundary_value_parameter_name, parameters, 1, &mesh);
301 }
302
303 auto deactivated_subdomain_material_ids =
305 config.getConfigParameter("material_ids", std::vector<int>{}) |
306 ranges::to<std::unordered_set>();
307
308 if (deactivated_subdomain_material_ids.empty())
309 {
310 OGS_FATAL(
311 "The material IDs of the deactivated subdomains are not given. The "
312 "program terminates now.");
313 }
314
315 if (materialIDs(mesh) == nullptr)
316 {
317 OGS_FATAL(
318 "The mesh doesn't contain materialIDs for subdomain deactivation. "
319 "The program terminates now.");
320 }
321
322 auto deactivated_subdomain_mesh = createDeactivatedSubdomainMesh(
323 mesh, deactivated_subdomain_material_ids);
324
325 return {std::move(time_interval), line_segment, ball,
326 std::move(deactivated_subdomain_mesh), boundary_value_parameter};
327}
328
329std::vector<DeactivatedSubdomain> createDeactivatedSubdomains(
330 BaseLib::ConfigTree const& config,
331 MeshLib::Mesh const& mesh,
332 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
333 std::map<std::string,
334 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
335 curves)
336{
337 std::vector<DeactivatedSubdomain> deactivated_subdomains;
338 // Deactivated subdomains
339 if (auto subdomains_config =
341 config.getConfigSubtreeOptional("deactivated_subdomains"))
342 {
343 INFO("There are subdomains being deactivated.");
344
345 auto const deactivated_subdomain_configs =
347 subdomains_config->getConfigSubtreeList("deactivated_subdomain");
348 std::transform(std::begin(deactivated_subdomain_configs),
349 std::end(deactivated_subdomain_configs),
350 std::back_inserter(deactivated_subdomains),
351 [&](auto const& config) {
353 config, mesh, parameters, curves);
354 });
355 }
356 return deactivated_subdomains;
357}
358
359} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
std::optional< T > getConfigParameterOptional(std::string const &param) const
T getConfigParameter(std::string const &param) const
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:97
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100
const Node * getNode(std::size_t idx) const
Get the node with the given index.
Definition Mesh.h:82
Properties & getProperties()
Definition Mesh.h:125
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:91
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:246
OGS_NO_DANGLING Map::mapped_type & getOrError(Map &map, Key const &key, std::string const &error_message)
Definition Algorithm.h:111
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:216
std::unique_ptr< MeshLib::Mesh > createMeshFromElementSelection(std::string mesh_name, std::vector< MeshLib::Element * > const &elements)
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
std::vector< Element * > cloneElements(std::vector< Element * > const &elements)
Clones a vector of elements using the Element::clone() function.
PropertyVector< std::size_t > const * bulkNodeIDs(Mesh const &mesh)
Definition Mesh.cpp:282
OGS_NO_DANGLING Parameter< ParameterDataType > & findParameter(std::string const &parameter_name, std::vector< std::unique_ptr< ParameterBase > > const &parameters, int const num_components, MeshLib::Mesh const *const mesh=nullptr)
static DeactivatedSubdomainMesh createDeactivatedSubdomainMesh(MeshLib::Mesh const &mesh, std::unordered_set< int > const &deactivated_subdomain_material_ids)
static detail::Ball parseBall(BaseLib::ConfigTree const &config)
Returns a ball represented by its center and its radius.
static std::pair< std::vector< std::size_t >, std::vector< std::size_t > > extractInnerAndOuterNodes(MeshLib::Mesh const &mesh, MeshLib::Mesh const &sub_mesh, IsActive is_active)
DeactivatedSubdomain createDeactivatedSubdomain(BaseLib::ConfigTree const &config, MeshLib::Mesh const &mesh, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)
std::vector< DeactivatedSubdomain > createDeactivatedSubdomains(BaseLib::ConfigTree const &config, MeshLib::Mesh const &mesh, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)
static std::pair< Eigen::Vector3d, Eigen::Vector3d > parseLineSegment(BaseLib::ConfigTree const &config)
Returns a line segment represented by its begin and end points.
static std::vector< std::vector< std::size_t > > extractElementsAlongOuterNodes(MeshLib::Mesh const &mesh, MeshLib::Mesh const &sub_mesh, std::vector< std::size_t > const &outer_nodes)
static MathLib::PiecewiseLinearInterpolation parseTimeIntervalOrCurve(std::optional< BaseLib::ConfigTree > const &time_interval_config, std::optional< std::string > const &curve_name, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)