OGS
MeshComponentMap.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
4#include "MeshComponentMap.h"
5
6#include "BaseLib/Error.h"
8#include "MeshLib/Node.h"
9
10#ifdef USE_PETSC
12#endif
13
14namespace NumLib
15{
16using namespace detail;
17
18#ifdef USE_PETSC
20 std::vector<MeshLib::MeshSubset> const& components, ComponentOrder order)
21{
22 // Use PETSc with single thread
23 const MeshLib::NodePartitionedMesh& partitioned_mesh =
24 static_cast<const MeshLib::NodePartitionedMesh&>(
25 components[0].getMesh());
26 if (partitioned_mesh.isForSingleThread())
27 {
28 createSerialMeshComponentMap(components, order);
29 return;
30 }
31 else
32 {
33 createParallelMeshComponentMap(components, order);
34 }
35}
36#else
38 std::vector<MeshLib::MeshSubset> const& components, ComponentOrder order)
39{
40 createSerialMeshComponentMap(components, order);
41}
42#endif // end of USE_PETSC
43
45 std::vector<MeshLib::MeshSubset> const& bulk_mesh_subsets,
46 MeshLib::MeshSubset const& new_mesh_subset) const
47{
48 { // Testing first an assumption met later in the code that the meshes for
49 // all the bulk_mesh_subsets are equal.
50 auto const first_mismatch =
51 std::adjacent_find(begin(bulk_mesh_subsets), end(bulk_mesh_subsets),
52 [](auto const& a, auto const& b)
53 { return a.getMeshID() != b.getMeshID(); });
54 if (first_mismatch != end(bulk_mesh_subsets))
55 {
57 "Assumption in the MeshComponentMap violated. Expecting all of "
58 "mesh ids to be the same, but it is not true for "
59 "the mesh '{:s}' with id {:d}.",
60 first_mismatch->getMesh().getName(),
61 first_mismatch->getMeshID());
62 }
63 }
64
65 // Mapping of the nodes in the new_mesh_subset to the bulk mesh nodes
66 auto bulk_node_ids = [](auto const& mesh)
67 {
68 auto const* bulk_node_ids_ptr = MeshLib::bulkNodeIDs(mesh);
69 if (bulk_node_ids_ptr == nullptr)
70 {
72 "Bulk node ids map expected in the construction of the mesh "
73 "subset.");
74 }
75 return *bulk_node_ids_ptr;
76 };
77 auto const& bulk_node_ids_map = bulk_node_ids(new_mesh_subset.getMesh());
78
79 // New dictionary for the subset.
80 ComponentGlobalIndexDict subset_dict;
81
82 std::size_t const new_mesh_id = new_mesh_subset.getMeshID();
83 // Lookup the locations in the current mesh component map and
84 // insert the full lines into the new subset dictionary.
85 for (auto* const node : new_mesh_subset.getNodes())
86 {
87 auto const node_id = node->getID();
88 bool const is_base_node = MeshLib::isBaseNode(
89 *node,
90 new_mesh_subset.getMesh().getElementsConnectedToNode(node_id));
91
92 MeshLib::Location const new_location{
93 new_mesh_id, MeshLib::MeshItemType::Node, node_id};
94
95 // Assuming the meshes for all the bulk_mesh_subsets are equal.
96 MeshLib::Location const bulk_location{
97 bulk_mesh_subsets.front().getMeshID(), MeshLib::MeshItemType::Node,
98 bulk_node_ids_map[node_id]};
99
100 for (auto component_id : getComponentIDs(bulk_location))
101 {
102 auto const global_index =
103 getGlobalIndex(bulk_location, component_id);
104 if (global_index == nop)
105 {
106 if (is_base_node)
107 {
108 OGS_FATAL(
109 "Could not find a global index for global component "
110 "{:d} for the mesh '{:s}', node {:d}, in the "
111 "corresponding bulk mesh '{:s}' and node {:d}. This "
112 "happens because the boundary mesh is larger than the "
113 "definition region of the bulk component, usually "
114 "because the geometry for the boundary condition is "
115 "too large.",
116 component_id,
117 new_mesh_subset.getMesh().getName(),
118 node_id,
119 bulk_mesh_subsets.front().getMesh().getName(),
120 bulk_node_ids_map[node_id]);
121 }
122 continue;
123 }
124 subset_dict.insert({new_location, component_id, global_index});
125 }
126 }
127
128 return MeshComponentMap(subset_dict);
129}
130
132{
133 GlobalIndexType global_index = offset;
134
135 auto& m = _dict.get<ByLocation>(); // view as sorted by mesh item
136 for (auto itr_mesh_item = m.begin(); itr_mesh_item != m.end();
137 ++itr_mesh_item)
138 {
139 Line pos = *itr_mesh_item;
140 pos.global_index = global_index++;
141 m.replace(itr_mesh_item, pos);
142 }
143}
144
145std::vector<int> MeshComponentMap::getComponentIDs(const Location& l) const
146{
147 auto const& m = _dict.get<ByLocation>();
148 auto const p = m.equal_range(Line(l));
149 std::vector<int> vec_compID;
150 for (auto itr = p.first; itr != p.second; ++itr)
151 {
152 vec_compID.push_back(itr->comp_id);
153 }
154 return vec_compID;
155}
156
158 int const comp_id) const
159{
160 auto const& m = _dict.get<ByLocationAndComponent>();
161 auto const itr = m.find(Line(l, comp_id));
162 return itr != m.end() ? itr->global_index : nop;
163}
164
165std::vector<GlobalIndexType> MeshComponentMap::getGlobalIndices(
166 const Location& l) const
167{
168 auto const& m = _dict.get<ByLocation>();
169 auto const p = m.equal_range(Line(l));
170 std::vector<GlobalIndexType> global_indices;
171 for (auto itr = p.first; itr != p.second; ++itr)
172 {
173 global_indices.push_back(itr->global_index);
174 }
175 return global_indices;
176}
177
179 std::vector<Location> const& ls) const
180{
181 // Create vector of global indices sorted by location containing all
182 // locations given in ls parameter.
183
184 std::vector<GlobalIndexType> global_indices;
185 global_indices.reserve(ls.size());
186
187 auto const& m = _dict.get<ByLocation>();
188 for (const auto& l : ls)
189 {
190 auto const p = m.equal_range(Line(l));
191 for (auto itr = p.first; itr != p.second; ++itr)
192 {
193 global_indices.push_back(itr->global_index);
194 }
195 }
196
197 return global_indices;
198}
199
201 std::vector<Location> const& ls) const
202{
203 // vector of (Component, global Index) pairs.
204 using CIPair = std::pair<int, GlobalIndexType>;
205 std::vector<CIPair> pairs;
206 pairs.reserve(ls.size());
207
208 // Create a sub dictionary containing all lines with location from ls.
209 auto const& m = _dict.get<ByLocation>();
210 for (const auto& l : ls)
211 {
212 auto const p = m.equal_range(Line(l));
213 for (auto itr = p.first; itr != p.second; ++itr)
214 {
215 pairs.emplace_back(itr->comp_id, itr->global_index);
216 }
217 }
218
219 auto CIPairLess = [](CIPair const& a, CIPair const& b)
220 { return a.first < b.first; };
221
222 // Create vector of global indices from sub dictionary sorting by component.
223 if (!std::is_sorted(pairs.begin(), pairs.end(), CIPairLess))
224 {
225 std::stable_sort(pairs.begin(), pairs.end(), CIPairLess);
226 }
227
228 std::vector<GlobalIndexType> global_indices;
229 global_indices.reserve(pairs.size());
230 transform(cbegin(pairs), cend(pairs), back_inserter(global_indices),
231 [&](const auto& pair) { return pair.second; });
232
233 return global_indices;
234}
235
237 Location const& l,
238 int const comp_id,
239 std::size_t const range_begin,
240 std::size_t const range_end) const
241{
242 GlobalIndexType const global_index = getGlobalIndex(l, comp_id);
243 // request for index of linear quantities at higher order nodes
244 // results in returning nop
245 // That index shall not be modified like a usual global index.
246 if (global_index == nop)
247 {
248 return nop;
249 }
250#ifndef USE_PETSC
251 (void)range_begin;
252 (void)range_end;
253 return global_index;
254#else
255 if (global_index >= 0) // non-ghost location.
256 return global_index - range_begin;
257
258 //
259 // For a ghost location look up the global index in ghost indices.
260 //
261
262 // A special case for a ghost location with global index equal to the size
263 // of the local vector:
264 GlobalIndexType const real_global_index =
265 (-global_index == static_cast<GlobalIndexType>(_num_global_dof))
266 ? 0
267 : -global_index;
268
269 // TODO Find in ghost indices is O(n^2/2) for n being the length of
270 // _ghosts_indices. Providing an inverted table would be faster.
271 auto const ghost_index_it = std::find(
272 _ghosts_indices.begin(), _ghosts_indices.end(), real_global_index);
273 if (ghost_index_it == _ghosts_indices.end())
274 {
275 OGS_FATAL("index {:d} not found in ghost_indices", real_global_index);
276 }
277
278 // Using std::distance on a std::vector is O(1). As long as _ghost_indices
279 // remains of std::vector type, this shall be fast.
280 return range_end - range_begin +
281 std::distance(_ghosts_indices.begin(), ghost_index_it);
282
283#endif
284}
285
287 std::vector<MeshLib::MeshSubset> const& components, ComponentOrder order)
288{
289 // construct dict (and here we number global_index by component type)
290 GlobalIndexType global_index = 0;
291 int comp_id = 0;
292 for (auto const& c : components)
293 {
294 std::size_t const mesh_id = c.getMeshID();
295 // mesh items are ordered first by node, cell, ....
296 for (auto const node_id : c.getNodes() | MeshLib::views::ids)
297 {
298 _dict.insert(
299 Line(Location(mesh_id, MeshLib::MeshItemType::Node, node_id),
300 comp_id, global_index++));
301 }
302 comp_id++;
303 }
304 _num_local_dof = _dict.size();
305
306 if (order == ComponentOrder::BY_LOCATION)
307 {
309 }
310}
311
312#ifdef USE_PETSC
313
315 MeshLib::NodePartitionedMesh const& partitioned_mesh,
316 std::size_t const global_node_id,
317 int const number_of_components_at_base_node,
318 int const number_of_components_at_high_order_node,
319 int const component_id_at_base_node,
320 int const component_id_at_high_order_node,
321 bool const is_base_node)
322{
323 int const partition_id = partitioned_mesh.getPartitionID(global_node_id);
324
325 auto const n_total_active_base_nodes_before_this_rank =
326 partitioned_mesh.getNumberOfRegularBaseNodesAtRank(partition_id);
327
328 auto const n_total_active_high_order_nodes_before_this_rank =
329 partitioned_mesh.getNumberOfRegularHighOrderNodesAtRank(partition_id);
330
331 auto const node_id_offset =
332 n_total_active_base_nodes_before_this_rank +
333 n_total_active_high_order_nodes_before_this_rank;
334
335 auto const index_offset = n_total_active_base_nodes_before_this_rank *
336 number_of_components_at_base_node +
337 n_total_active_high_order_nodes_before_this_rank *
338 number_of_components_at_high_order_node;
339
340 if (is_base_node)
341 {
342 return static_cast<GlobalIndexType>(
343 index_offset + (global_node_id - node_id_offset) *
344 number_of_components_at_base_node) +
345 component_id_at_base_node;
346 }
347
348 int const n_active_base_nodes_of_this_partition =
349 partitioned_mesh.getNumberOfRegularBaseNodesAtRank(partition_id + 1) -
350 n_total_active_base_nodes_before_this_rank;
351
352 /*
353 The global indices of components are numbered as what depicted below by
354 assuming that the base node has three components and the high order node
355 has two components:
356
357 Partition | 0 | 1 | ...
358 --------------------------------
359 Regular nodes | Base | higher | Base | higher| ...
360 --------------------------------
361 c0 x x x x ...
362 c1 x x x x ...
363 c2 x x ...
364 */
365 return static_cast<GlobalIndexType>(
366 index_offset +
367 n_active_base_nodes_of_this_partition *
368 number_of_components_at_base_node +
369 (global_node_id - node_id_offset -
370 n_active_base_nodes_of_this_partition) *
371 number_of_components_at_high_order_node) +
372 component_id_at_high_order_node;
373}
374
376 std::vector<MeshLib::MeshSubset> const& components, ComponentOrder order)
377{
378 if (order != ComponentOrder::BY_LOCATION)
379 {
380 // Not allowed in parallel case since this is not suitable to
381 // arrange non ghost entries of a partition within
382 // a rank in the parallel computing.
383 OGS_FATAL(
384 "Global index in the system of equations can only be numbered by "
385 "the order type of ComponentOrder::BY_LOCATION");
386 }
387
388 const MeshLib::NodePartitionedMesh& partitioned_mesh =
389 static_cast<const MeshLib::NodePartitionedMesh&>(
390 components[0].getMesh());
391
392 //
393 // get the number of unknowns and the number of components at extra node
394 //
395 GlobalIndexType num_unknowns = 0;
396 int components_at_high_order_nodes = 0;
397 for (auto const& c : components)
398 {
399 if (partitioned_mesh.getNumberOfNodes() == c.getNodes().size())
400 {
401 components_at_high_order_nodes++;
402 num_unknowns += partitioned_mesh.getNumberOfGlobalNodes();
403 }
404 else
405 {
406 num_unknowns += partitioned_mesh.getNumberOfGlobalBaseNodes();
407 }
408 }
409
410 // construct dict (and here we number global_index by component type)
411 //
412 int const n_components = components.size();
413
414 int comp_id = 0;
415 int comp_id_at_high_order_node = 0;
416 _num_global_dof = 0;
417 _num_local_dof = 0;
418 for (auto const& c : components)
419 {
420 assert(dynamic_cast<MeshLib::NodePartitionedMesh const*>(
421 &c.getMesh()) != nullptr);
422 std::size_t const mesh_id = c.getMeshID();
423 const MeshLib::NodePartitionedMesh& partitioned_mesh =
424 static_cast<const MeshLib::NodePartitionedMesh&>(c.getMesh());
425 const auto& sub_mesh_nodes = c.getNodes();
426
427 // mesh items are ordered first by node, cell, ....
428 for (std::size_t j = 0; j < sub_mesh_nodes.size(); j++)
429 {
430 const auto node_id = sub_mesh_nodes[j]->getID();
431 const bool is_base_node =
432 MeshLib::isBaseNode(*sub_mesh_nodes[j],
433 partitioned_mesh.getElementsConnectedToNode(
434 *sub_mesh_nodes[j]));
435
436 const auto global_node_id =
437 partitioned_mesh.getGlobalNodeID(node_id);
438 GlobalIndexType global_index =
439 (!c.useTaylorHoodElements())
440 ? static_cast<GlobalIndexType>(
441 n_components * global_node_id + comp_id)
443 partitioned_mesh, global_node_id, n_components,
444 components_at_high_order_nodes, comp_id,
445 comp_id_at_high_order_node, is_base_node);
446 const bool is_ghost = partitioned_mesh.isGhostNode(node_id);
447 if (is_ghost)
448 {
449 _ghosts_indices.push_back(global_index);
450 global_index = -global_index;
451 // If the ghost entry has an index of 0,
452 // its index is set to the negative value of unknowns.
453 if (global_index == 0)
454 {
455 global_index = -num_unknowns;
456 }
457 }
458 else
459 {
461 }
462
463 _dict.insert(
464 Line(Location(mesh_id, MeshLib::MeshItemType::Node, node_id),
465 comp_id, global_index));
466 }
467
468 bool const use_whole_nodes =
469 (partitioned_mesh.getNumberOfNodes() == c.getNodes().size());
470 if (use_whole_nodes)
471 {
472 _num_global_dof += partitioned_mesh.getNumberOfGlobalNodes();
473 comp_id_at_high_order_node++;
474 }
475 else
476 {
477 _num_global_dof += partitioned_mesh.getNumberOfGlobalBaseNodes();
478 }
479
480 comp_id++;
481 }
482}
483#endif
484
485} // namespace NumLib
#define OGS_FATAL(...)
Definition Error.h:19
GlobalMatrix::IndexType GlobalIndexType
A subset of nodes on a single mesh.
Definition MeshSubset.h:17
Mesh const & getMesh() const
Definition MeshSubset.h:83
std::size_t getMeshID() const
return this mesh ID
Definition MeshSubset.h:67
std::vector< Node * > const & getNodes() const
Definition MeshSubset.h:81
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
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
std::size_t getPartitionID(const std::size_t global_node_id) const
bool isGhostNode(const std::size_t node_id) const
Check whether a node with ID of node_id is a ghost node.
std::size_t getNumberOfRegularHighOrderNodesAtRank(int const partition_id) const
std::size_t getGlobalNodeID(const std::size_t node_id) const
Get the global node ID of a node with its local ID.
std::size_t getNumberOfGlobalNodes() const
Get the number of all nodes of the global mesh.
std::size_t getNumberOfGlobalBaseNodes() const
Get the number of nodes of the global mesh for linear elements.
std::size_t getNumberOfRegularBaseNodesAtRank(int const partition_id) const
void createParallelMeshComponentMap(std::vector< MeshLib::MeshSubset > const &components, ComponentOrder order)
std::vector< int > getComponentIDs(const Location &l) const
MeshLib::Location Location
std::size_t _num_global_dof
Number of global unknowns. Used internally only.
MeshComponentMap(std::vector< MeshLib::MeshSubset > const &components, ComponentOrder order)
GlobalIndexType getGlobalIndex(Location const &l, int const comp_id) const
GlobalIndexType getLocalIndex(Location const &l, int const comp_id, std::size_t const range_begin, std::size_t const range_end) const
static constexpr NUMLIB_EXPORT GlobalIndexType const nop
MeshComponentMap getSubset(std::vector< MeshLib::MeshSubset > const &bulk_mesh_subsets, MeshLib::MeshSubset const &new_mesh_subset) const
detail::ComponentGlobalIndexDict _dict
std::vector< GlobalIndexType > getGlobalIndices(const Location &l) const
void renumberByLocation(GlobalIndexType offset=0)
std::vector< GlobalIndexType > _ghosts_indices
Global ID for ghost entries.
std::vector< GlobalIndexType > getGlobalIndicesByComponent(const std::vector< Location > &ls) const
void createSerialMeshComponentMap(std::vector< MeshLib::MeshSubset > const &components, ComponentOrder order)
std::vector< GlobalIndexType > getGlobalIndicesByLocation(const std::vector< Location > &ls) const
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:216
bool isBaseNode(Node const &node, std::vector< Element const * > const &elements_connected_to_node)
Definition Mesh.cpp:336
PropertyVector< std::size_t > const * bulkNodeIDs(Mesh const &mesh)
Definition Mesh.cpp:282
boost::multi_index::multi_index_container< Line, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< ByLocationAndComponent >, boost::multi_index::identity< Line >, LineByLocationAndComponentComparator >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ByLocation >, boost::multi_index::identity< Line >, LineByLocationComparator >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ByComponent >, boost::multi_index::member< Line, int, &Line::comp_id > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ByGlobalIndex >, boost::multi_index::member< Line, GlobalIndexType, &Line::global_index > > > > ComponentGlobalIndexDict
GlobalIndexType getGlobalIndexWithTaylorHoodElement(MeshLib::NodePartitionedMesh const &partitioned_mesh, std::size_t const global_node_id, int const number_of_components_at_base_node, int const number_of_components_at_high_order_node, int const component_id_at_base_node, int const component_id_at_high_order_node, bool const is_base_node)
ComponentOrder
Ordering of components in global matrix/vector.
@ BY_LOCATION
Ordering data by spatial location.