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