IOSS 2.0
Loading...
Searching...
No Matches
Iotm_TextMeshAdjacencyGraph.h
Go to the documentation of this file.
1// Copyright(C) 1999-2020, 2022, 2023 National Technology & Engineering Solutions
2// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
3// NTESS, the U.S. Government retains certain rights in this software.
4
5#pragma once
6
7// ####################### Start Clang Header Tool Managed Headers ########################
8// clang-format off
9#include <ctype.h> // for toupper
10#include <stddef.h> // for size_t
11#include <algorithm> // for remove, etc
12#include <iterator> // for insert_iterator
13#include <map>
14#include <set> // for set
15#include <sstream> // for operator<<, etc
16#include <string> // for basic_string, etc
17#include <utility> // for pair
18#include <vector> // for vector
19#include <unordered_map>
20#include <sstream> // for ostringstream
21#include <iostream>
22#include <functional>
23#include <stdexcept>
24#include <numeric>
25#include <strings.h>
26
27#include "Iotm_TextMeshFuncs.h"
29
30// clang-format on
31// ####################### End Clang Header Tool Managed Headers ########################
32namespace Iotm {
33 namespace text_mesh {
34
35 using ErrorHandler = std::function<void(const std::ostringstream &)>;
36
37 template <typename EntityId, typename Topology> struct TextMeshData;
38
39 template <typename EntityId, typename Topology> struct ElementData;
40
41 // Side (or face-face) adjacency is a means to compute neighbors of elements based on
42 // node connectivity of the sides bordering neighboring elements. The provided elements
43 // are defined in the [ std::vector<ElementData<EntityId, Topology>> elementDataVec ]
44 // member of the [ TextMeshData<EntityId, Topology> ] object and since neighbor connectivity
45 // based on element id will involve a search on this object, this implementation is based on
46 // indexing into this object for performance. Indices are zero-based and sides are one-based
47 //
48 // The adjacency graph may be created with element filtering based on proc and/or a list of
49 // selected element blocks. Any element which is selected by the filter (or all elements)
50 // is used as a basis to compute the list of filter nodes which is then used to compute a
51 // final list of "local" and "aura" elements which have any connection to these filter nodes.
52 // A map is also constructed for the list of these connected elements per filter node
53 //
54 // For every element in this final list, we can get the list of nodes of per side (based on
55 // topology) and using an intersection, find the list of common elements that share all the
56 // nodes on that side. These are the neighboring elements and we must determine how to connect
57 // the neighboring elements based on solid/shell connectivity rules. The basic rule is that
58 // shells act as "blockers" to solid-solid connections
59 //
60 // Polarity of faces is one determining factor and this is defined based on the relative
61 // permutation of the nodes on both faces under consideration
62 // +ve/+ve or -ve/-ve => same polarity
63 // -ve/+ve or +ve/-ve => opposite polarity
64 //
65 // {this face / that face}
66 // -----------------------
67 // Solid/solid connection:
68 // -> always allowed unless there is a shell already connected to either face or both
69 // faces have the same polarity (partially connected solids not allowed)
70 // Solid/shell connection:
71 // -> only allowed if both faces are opposite polarity. If the solid face is already
72 // connected
73 // to another solid, break the existing connection to insert the shell connection
74 // Shell/solid connection:
75 // -> only allowed if both faces are opposite polarity. If the solid face is already
76 // connected
77 // to another solid, break the existing connection to insert the shell connection
78 // Shell/shell connection:
79 // -> only allowed if both faces are opposite polarity AND neither shell face is already
80 // connected to another shell face
81 //
82 // Stacked shells on a solid element must also obey the rule that all the shells must live on
83 // the same processor. This is enforced as it is an error and unsupported in STK
84 //
85 template <typename EntityId, typename Topology> class SideAdjacencyGraph
86 {
87 public:
88 using IndexType = int64_t;
89
90 static constexpr int ANY_PROC = -1;
91 static constexpr int INVALID_SIDE = -1;
92 static constexpr IndexType INVALID_INDEX = -1;
93
95 {
98
99 FaceConnection(int thisSide_, IndexType otherElement_, int otherSide_)
100 : thisSide(thisSide_), thatElement(otherElement_), thatSide(otherSide_)
101 {
102 }
103
104 bool operator==(const FaceConnection &rhs) const
105 {
106 return ((thisSide == rhs.thisSide) && (thatElement == rhs.thatElement) &&
107 (thatSide == rhs.thatSide));
108 }
109
110 bool operator!=(const FaceConnection &rhs) const
111 {
112 return ((thisSide != rhs.thisSide) || (thatElement != rhs.thatElement) ||
113 (thatSide != rhs.thatSide));
114 }
115
116 bool operator<(const FaceConnection &rhs) const
117 {
118 if (thisSide < rhs.thisSide)
119 return true;
120 else if (thisSide == rhs.thisSide && thatElement < rhs.thatElement)
121 return true;
122 else if (thisSide == rhs.thisSide && thatElement == rhs.thatElement &&
123 thatSide < rhs.thatSide)
124 return true;
125 else
126 return false;
127 }
128
132 };
133
135 {
137 explicit FaceConnections(unsigned numSides_)
138 : numSides(numSides_), sideReference(numSides_, 0)
139 {
140 }
141
142 bool has_any_connection(int thisSide) const
143 {
144 FaceConnection minConnection(thisSide, INVALID_INDEX, 0);
145 typename std::set<FaceConnection>::iterator lowerBound =
146 std::lower_bound(connections.begin(), connections.end(), minConnection);
147
148 return (lowerBound != connections.end() && lowerBound->thisSide == thisSide);
149 }
150
151 bool has_any_connection(int thisSide, IndexType thatElem) const
152 {
153 FaceConnection minConnection(thisSide, thatElem, 0);
154 typename std::set<FaceConnection>::iterator lowerBound =
155 std::lower_bound(connections.begin(), connections.end(), minConnection);
156
157 return (lowerBound != connections.end() && lowerBound->thisSide == thisSide &&
158 lowerBound->thatElement == thatElem);
159 }
160
161 void add(const FaceConnection &connection)
162 {
163 auto iter = connections.find(connection);
164 if (iter == connections.end()) {
165 sideReference[connection.thisSide - 1]++;
166 connections.insert(connection);
167 }
168 }
169
170 void remove(const FaceConnection &connection)
171 {
172 auto iter = connections.find(connection);
173 if (iter != connections.end()) {
174 sideReference[connection.thisSide - 1]--;
175 connections.erase(iter);
176 }
177 }
178
179 // Number of sides defined by topology for this element entry
180 unsigned numSides{0};
181
182 // Number of references to given side based on entries to the connections member: for
183 // performance
184 std::vector<int> sideReference{};
185
186 // Collection of all face connections for the element. Number might be more than numSides
187 // based on solid/shell connections e.e solid connected to multiple stacked shells
188 std::set<FaceConnection> connections{};
189 };
190
191 virtual size_t get_num_elements() const = 0;
192 virtual int get_element_proc(const size_t elemIndex) const = 0;
193 virtual bool element_has_any_node_on_proc(const size_t elemIndex, int proc) const = 0;
194 virtual const std::string &get_element_block_name(const size_t elemIndex) const = 0;
195 virtual const std::vector<EntityId> &get_element_node_ids(const size_t elemIndex) const = 0;
196 virtual const Topology &get_element_topology(const size_t elemIndex) const = 0;
197 virtual EntityId get_element_id(const size_t elemIndex) const = 0;
198
200 {
201 ErrorHandler errorHandler = [](const std::ostringstream &errmsg) {
202 default_error_handler(errmsg);
203 };
204 set_error_handler(errorHandler);
205 }
206
207 virtual ~SideAdjacencyGraph() = default;
208
209 void create_graph(int proc = ANY_PROC) { create_graph({}, proc); }
210
211 void create_graph(const std::vector<std::string> &selectedBlocks, int proc = ANY_PROC)
212 {
213 m_indexGraph.clear();
214 std::vector<size_t> localAndAuraElementIndex =
215 get_local_and_aura_elements(selectedBlocks, proc);
216 std::unordered_map<EntityId, std::set<size_t>> elementsForNode =
217 get_elements_for_node_map(localAndAuraElementIndex);
218 build_side_connectivity_graph(localAndAuraElementIndex, elementsForNode);
219 }
220
221 void set_error_handler(ErrorHandler errorHandler) { m_errorHandler = errorHandler; }
222
223 void dump(std::ostream &out = std::cout)
224 {
225 for (const auto &iter : m_indexGraph) {
226 if (!iter.second.connections.empty()) {
227 out << "Element index: " << iter.first << std::endl;
228 }
229 for (const auto &entry : iter.second.connections) {
230 out << "\tConnected on side: " << entry.thisSide
231 << " to element index: " << entry.thatElement << " and side: " << entry.thatSide
232 << std::endl;
233 }
234 }
235 }
236
237 void dump(const std::vector<ElementData<EntityId, Topology>> &elemDataVec,
238 std::ostream &out = std::cout)
239 {
240 for (const auto &iter : m_indexGraph) {
241 if (!iter.second.connections.empty()) {
242 out << "Element: " << elemDataVec[iter.first].identifier << " {"
243 << elemDataVec[iter.first].topology << "}" << std::endl;
244 }
245 for (const auto &entry : iter.second.connections) {
246 out << "\tConnected on side: " << entry.thisSide
247 << " to element: " << elemDataVec[entry.thatElement].identifier << " {"
248 << elemDataVec[entry.thatElement].topology << "}" << " and side: " << entry.thatSide
249 << std::endl;
250 }
251 }
252 }
253
254 const FaceConnections &operator[](const IndexType elemIndex) const
255 {
256 auto it = m_indexGraph.find(elemIndex);
257
258 if (it == m_indexGraph.end()) {
259 std::ostringstream errmsg;
260 errmsg << "Could not find element index " << elemIndex;
261 m_errorHandler(errmsg);
262 }
263
264 return it->second;
265 }
266
267 size_t size() const { return m_indexGraph.size(); }
268
269 typename std::unordered_map<size_t, FaceConnections>::const_iterator begin() const
270 {
271 return m_indexGraph.begin();
272 }
273 typename std::unordered_map<size_t, FaceConnections>::const_iterator end() const
274 {
275 return m_indexGraph.end();
276 }
277
278 protected:
281
283 {
284 bool operator()(const std::string &lhs, const std::string &rhs)
285 {
286 return (strcasecmp(lhs.c_str(), rhs.c_str()) < 0);
287 };
288 };
289
290 // Current element and side under consideration
292 {
293 CurrentAdjacency(size_t elementIndex_, int side_) : elementIndex(elementIndex_), side(side_)
294 {
295 }
296
298 int side;
299
300 // Scratch space that is filled on-the-fly: for performance
301 std::vector<int> connectedSides;
302 };
303
305 const size_t elemIndex, int side,
306 const std::unordered_map<EntityId, std::set<size_t>> &elementsForNode)
307 {
308 std::set<size_t> neighbors;
309 std::vector<OrdinalType> sideNodeIndices =
311
312 const std::vector<EntityId> &elementNodeIds = get_element_node_ids(elemIndex);
313
314 if (!sideNodeIndices.empty()) {
315 EntityId firstSideNode = elementNodeIds[sideNodeIndices[0]];
316 neighbors = elementsForNode.at(firstSideNode);
317 }
318
319 for (size_t i = 1; i < sideNodeIndices.size(); ++i) {
320 OrdinalType sideNodeIndex = sideNodeIndices[i];
321 EntityId sideNode = elementNodeIds[sideNodeIndex];
322 const std::set<size_t> &sideNodeElementIndices = elementsForNode.at(sideNode);
323
324 std::set<size_t> intersection;
325 std::set_intersection(neighbors.begin(), neighbors.end(), sideNodeElementIndices.begin(),
326 sideNodeElementIndices.end(),
327 std::inserter(intersection, intersection.begin()));
328
329 neighbors = intersection;
330 }
331
332 return neighbors;
333 }
334
335 std::vector<EntityId> get_side_nodes(const size_t elemIndex, const int side)
336 {
337 std::vector<OrdinalType> sideNodeIndices =
339 std::vector<EntityId> sideNodes(sideNodeIndices.size());
340 const std::vector<EntityId> &elementNodeIds = get_element_node_ids(elemIndex);
341
342 for (size_t i = 0; i < sideNodeIndices.size(); ++i) {
343 OrdinalType sideNodeIndex = sideNodeIndices[i];
344 sideNodes[i] = elementNodeIds[sideNodeIndex];
345 }
346
347 return sideNodes;
348 }
349
350 std::vector<EntityId> get_sorted_side_nodes(const size_t elemIndex, const int side)
351 {
352 std::vector<EntityId> sideNodes = get_side_nodes(elemIndex, side);
353 std::sort(sideNodes.begin(), sideNodes.end());
354
355 return sideNodes;
356 }
357
358 // Fill scratch space with side connection info to neighbor element
360 size_t neighborElementIndex)
361 {
362 adjacency.connectedSides.clear();
363
364 std::vector<EntityId> sideNodes =
365 get_sorted_side_nodes(adjacency.elementIndex, adjacency.side);
366
367 for (int otherSide = 1;
368 otherSide <= get_element_topology(neighborElementIndex).num_face_sides();
369 ++otherSide) {
370 std::vector<EntityId> otherSideNodes =
371 get_sorted_side_nodes(neighborElementIndex, otherSide);
372 if (sideNodes == otherSideNodes) {
373 adjacency.connectedSides.push_back(otherSide);
374 }
375 }
376 }
377
378 // Find and validate connected sides to neighbor element
380 size_t neighborElementIndex)
381 {
382 internal_fill_sides_for_connected_element(adjacency, neighborElementIndex);
383
384 if (adjacency.connectedSides.empty()) {
385 std::ostringstream errmsg;
386 errmsg << "Neighboring reciprocity check for elements "
387 << get_element_id(adjacency.elementIndex) << " and "
388 << get_element_id(neighborElementIndex) << " failed.";
389 m_errorHandler(errmsg);
390 }
391 }
392
393 // Check to see if two set of nodes are equivalent based on permutation list
394 bool equivalent_node_permutation(const std::vector<EntityId> &controlNodes,
395 const std::vector<EntityId> &permutedNodes,
396 const std::vector<OrdinalType> &permutationOrdinals)
397 {
398 const size_t numNodes = permutationOrdinals.size();
399
400 if ((numNodes > permutedNodes.size()) || (numNodes > controlNodes.size())) {
401 return false;
402 }
403
404 bool equivalent = true;
405 for (size_t i = 0; equivalent && i < numNodes; ++i) {
406 equivalent = controlNodes[permutationOrdinals[i]] == permutedNodes[i];
407 }
408
409 return equivalent;
410 }
411
412 // Get the permutation that makes one set of nodes equivalent to the other
413 std::pair<bool, PermutationType> get_permutation(const Topology &topology,
414 const std::vector<EntityId> &controlNodes,
415 const std::vector<EntityId> &permutedNodes,
416 PermutationType numPermutations)
417 {
419 bool equivalent = false;
420
421 if (controlNodes.size() != permutedNodes.size())
422 return std::make_pair(equivalent, permutation);
423
424 if (numPermutations > topology.num_permutations()) {
425 std::ostringstream errmsg;
426 errmsg << "Invalid number of permutations to check: " << numPermutations;
427 m_errorHandler(errmsg);
428 }
429
430 std::vector<OrdinalType> permutationOrdinals;
431
432 for (PermutationType i = 0; i < numPermutations; ++i) {
433 if (topology.fill_permutation_indices(i, permutationOrdinals)) {
434 if (equivalent_node_permutation(controlNodes, permutedNodes, permutationOrdinals)) {
435 equivalent = true;
436 permutation = i;
437 break;
438 }
439 }
440 }
441
442 return std::make_pair(equivalent, permutation);
443 }
444
445 std::pair<bool, PermutationType> get_permutation(const Topology &topology,
446 const std::vector<EntityId> &controlNodes,
447 const std::vector<EntityId> &permutedNodes)
448 {
449 return get_permutation(topology, controlNodes, permutedNodes, topology.num_permutations());
450 }
451
452 std::pair<bool, PermutationType>
453 get_positive_permutation(const Topology &topology, const std::vector<EntityId> &controlNodes,
454 const std::vector<EntityId> &permutedNodes)
455 {
456 return get_permutation(topology, controlNodes, permutedNodes,
457 topology.num_positive_permutations());
458 }
459
460 bool has_same_polarity(const size_t thisElem, const int thisSide, const size_t thatElem,
461 const int thatSide)
462 {
463 std::vector<EntityId> thisNodes = get_side_nodes(thisElem, thisSide);
464 std::vector<EntityId> thatNodes = get_side_nodes(thatElem, thatSide);
465
466 const Topology &sideTopo = get_element_topology(thisElem).side_topology(thisSide);
467 std::pair<bool, PermutationType> result =
468 get_positive_permutation(sideTopo, thisNodes, thatNodes);
469
470 bool samePolarity = result.first;
471 return samePolarity;
472 }
473
474 // Check for valid element/side pair
475 bool verify_entry(IndexType elemIndex, int side)
476 {
477 if (INVALID_INDEX == elemIndex)
478 return false;
479
480 auto it = m_indexGraph.find(elemIndex);
481 if (it == m_indexGraph.end())
482 return false;
483
484 int numSides = it->second.numSides;
485 if (side < 1 || side > numSides)
486 return false;
487
488 return true;
489 }
490
491 // Given a current element/side pair, find all other defined reciprocal element connections
492 std::vector<FaceConnection> get_reciprocity(CurrentAdjacency &adjacency)
493 {
494 std::vector<FaceConnection> reciprocity;
495 const FaceConnections &thisEntry = m_indexGraph[adjacency.elementIndex];
496
497 for (const FaceConnection &connectionToThatElement : thisEntry.connections) {
498 IndexType thatIndex = connectionToThatElement.thatElement;
499 int thatSide = connectionToThatElement.thatSide;
500
501 if (!verify_entry(thatIndex, thatSide))
502 continue;
503 const FaceConnections &thatEntry = m_indexGraph[thatIndex];
504
505 const FaceConnection connectionToThisElement(thatSide, adjacency.elementIndex,
506 adjacency.side);
507 if (std::binary_search(thatEntry.connections.begin(), thatEntry.connections.end(),
508 connectionToThisElement)) {
509 reciprocity.push_back(connectionToThatElement);
510 }
511 }
512
513 return reciprocity;
514 }
515
516 // Break all current reciprocal connections to this element/side pair
518 {
519 std::vector<FaceConnection> reciprocity = get_reciprocity(adjacency);
520
521 if (!reciprocity.empty()) {
522 FaceConnections &thisEntry = m_indexGraph[adjacency.elementIndex];
523
524 for (const FaceConnection &connectionToThatElement : reciprocity) {
525 IndexType thatIndex = connectionToThatElement.thatElement;
526 int thatSide = connectionToThatElement.thatSide;
527
528 FaceConnections &thatEntry = m_indexGraph[thatIndex];
529 FaceConnection connectionToThisElement(thatSide, adjacency.elementIndex,
530 adjacency.side);
531
532 thisEntry.remove(connectionToThatElement);
533 thatEntry.remove(connectionToThisElement);
534 }
535 }
536 }
537
538 inline bool is_shell_shell_connection(const Topology &thisElemTopology,
539 const Topology &thatElemTopology)
540 {
541 return thisElemTopology.is_shell() && thatElemTopology.is_shell();
542 }
543
544 inline bool is_shell_shell_connection(const size_t thisElem, const size_t thatElem)
545 {
547 get_element_topology(thatElem));
548 }
549
550 inline bool is_shell_solid_connection(const Topology &thisElemTopology,
551 const Topology &thatElemTopology)
552 {
553 return thisElemTopology.is_shell() && !thatElemTopology.is_shell();
554 }
555
556 inline bool is_shell_solid_connection(const size_t thisElem, const size_t thatElem)
557 {
559 get_element_topology(thatElem));
560 }
561
562 inline bool is_solid_shell_connection(const Topology &thisElemTopology,
563 const Topology &thatElemTopology)
564 {
565 return !thisElemTopology.is_shell() && thatElemTopology.is_shell();
566 }
567
568 inline bool is_solid_shell_connection(const size_t thisElem, const size_t thatElem)
569 {
571 get_element_topology(thatElem));
572 }
573
574 inline bool is_solid_solid_connection(const Topology &thisElemTopology,
575 const Topology &thatElemTopology)
576 {
577 return !thisElemTopology.is_shell() && !thatElemTopology.is_shell();
578 }
579
580 inline bool is_solid_solid_connection(const size_t thisElem, const size_t thatElem)
581 {
583 get_element_topology(thatElem));
584 }
585
586 using Criterion = std::function<bool(const Topology &topo1, const Topology &topo2)>;
587
588 bool has_connection_type_on_side(size_t thisIndex, int thisSide, Criterion criterion)
589 {
590 const FaceConnections &thisEntry = m_indexGraph[thisIndex];
591
592 for (const FaceConnection &connection : thisEntry.connections) {
593 IndexType thatIndex = connection.thatElement;
594
595 if (connection.thisSide != thisSide || INVALID_INDEX == thatIndex)
596 continue;
597
598 if (criterion(get_element_topology(thisIndex), get_element_topology(thatIndex))) {
599 return true;
600 }
601 }
602
603 return false;
604 }
605
606 bool has_any_shell_connection_on_side(size_t thisIndex, int thisSide)
607 {
608 Criterion criterion = [&](const Topology & /* topo1 */, const Topology &topo2) {
609 return topo2.is_shell();
610 };
611
612 return has_connection_type_on_side(thisIndex, thisSide, criterion);
613 }
614
615 bool has_shell_shell_connection_on_side(size_t thisIndex, int thisSide)
616 {
617 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
618 return is_shell_shell_connection(topo1, topo2);
619 };
620
621 return has_connection_type_on_side(thisIndex, thisSide, criterion);
622 }
623
624 bool has_shell_solid_connection_on_side(size_t thisIndex, int thisSide)
625 {
626 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
627 return is_shell_solid_connection(topo1, topo2);
628 };
629
630 return has_connection_type_on_side(thisIndex, thisSide, criterion);
631 }
632
633 bool has_solid_shell_connection_on_side(size_t thisIndex, int thisSide)
634 {
635 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
636 return is_solid_shell_connection(topo1, topo2);
637 };
638
639 return has_connection_type_on_side(thisIndex, thisSide, criterion);
640 }
641
642 bool has_solid_solid_connection_on_side(size_t thisIndex, int thisSide)
643 {
644 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
645 return is_solid_solid_connection(topo1, topo2);
646 };
647
648 return has_connection_type_on_side(thisIndex, thisSide, criterion);
649 }
650
651 void add_connection(CurrentAdjacency &adjacency, size_t connectedElementIndex, int otherSide)
652 {
653 const size_t thisElem = adjacency.elementIndex;
654 const size_t thatElem = connectedElementIndex;
655
656 bool doConnect = false;
657 bool breakConnection = false;
658
659 if (is_shell_solid_connection(thisElem, thatElem)) {
660 doConnect = !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
661
662 if (has_solid_solid_connection_on_side(connectedElementIndex, otherSide)) {
663 breakConnection = doConnect;
664 }
665 }
666 else if (is_solid_shell_connection(thisElem, thatElem)) {
667 doConnect = !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
668
669 if (has_solid_solid_connection_on_side(adjacency.elementIndex, adjacency.side)) {
670 breakConnection = doConnect;
671 }
672 }
673 else if (is_solid_solid_connection(thisElem, thatElem)) {
674 doConnect = !has_any_shell_connection_on_side(adjacency.elementIndex, adjacency.side) &&
675 !has_any_shell_connection_on_side(connectedElementIndex, otherSide) &&
676 !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
677 }
678
679 if (breakConnection) {
681 }
682
683 if (doConnect) {
684 m_indexGraph[adjacency.elementIndex].add(
685 FaceConnection(adjacency.side, connectedElementIndex, otherSide));
686 m_indexGraph[connectedElementIndex].add(
687 FaceConnection(otherSide, adjacency.elementIndex, adjacency.side));
688 }
689 }
690
691 void set_side_connectivity(CurrentAdjacency &adjacency, size_t connectedElementIndex)
692 {
693 fill_sides_for_connected_element(adjacency, connectedElementIndex);
694
695 for (int otherSide : adjacency.connectedSides) {
696 add_connection(adjacency, connectedElementIndex, otherSide);
697 }
698 }
699
701 IndexType connectedElemIndex2)
702 {
703 if (get_element_topology(connectedElemIndex1).is_shell() &&
704 get_element_topology(connectedElemIndex2).is_shell()) {
705 if (get_element_proc(connectedElemIndex1) != get_element_proc(connectedElemIndex2)) {
706 std::ostringstream errmsg;
707 errmsg << "Invalid proc ownership for co-incident shells "
708 << get_element_id(connectedElemIndex1) << " (proc "
709 << get_element_proc(connectedElemIndex1) << ") and "
710 << get_element_proc(connectedElemIndex2) << " (proc "
711 << get_element_proc(connectedElemIndex2) << ")."
712 << " Co-incident shells must all exist on the same processor";
713 m_errorHandler(errmsg);
714 }
715 }
716 }
717
719 CurrentAdjacency &adjacency,
720 const std::unordered_map<EntityId, std::set<size_t>> &elementsForNode)
721 {
722 int side = adjacency.side;
723
724 std::set<size_t> elementIndicesConnectedToSide =
726 elementsForNode);
727 for (size_t connectedElementIndex : elementIndicesConnectedToSide) {
728 if (connectedElementIndex != adjacency.elementIndex) {
729 enforce_coincident_shell_ownership(adjacency.elementIndex, connectedElementIndex);
730 set_side_connectivity(adjacency, connectedElementIndex);
731 }
732 }
733 }
734
736 const std::vector<size_t> &elementIndices,
737 const std::unordered_map<EntityId, std::set<size_t>> &elementsForNode)
738 {
740
741 for (size_t elementIndex : elementIndices) {
742 int numSides = get_element_topology(elementIndex).num_face_sides();
743 for (int side = 1; side <= numSides; ++side) {
744 if (m_indexGraph[elementIndex].sideReference[side - 1] == 0) {
745 CurrentAdjacency adjacency(elementIndex, side);
746 process_side_connectivity(adjacency, elementsForNode);
747 }
748 }
749 }
750 }
751
752 void initialize_side_connectivity_graph(const std::vector<size_t> &elementIndices)
753 {
754 for (size_t elementIndex : elementIndices) {
755 m_indexGraph[elementIndex] =
756 FaceConnections(get_element_topology(elementIndex).num_face_sides());
757 }
758 }
759
760 std::unordered_map<EntityId, std::set<size_t>>
761 get_elements_for_node_map(const std::vector<size_t> &elementIndices)
762 {
763 std::unordered_map<EntityId, std::set<size_t>> elementsForNode;
764 for (size_t index : elementIndices) {
765 for (const EntityId nodeId : get_element_node_ids(index)) {
766 elementsForNode[nodeId].insert(index);
767 }
768 }
769
770 return elementsForNode;
771 }
772
773 bool element_is_in_selected_blocks(const size_t elemIndex,
774 const std::vector<std::string> &sortedSelectedBlocks)
775 {
776 if (sortedSelectedBlocks.empty())
777 return true;
778
779 const std::string &partName = get_element_block_name(elemIndex);
780
781 return std::binary_search(sortedSelectedBlocks.begin(), sortedSelectedBlocks.end(),
782 partName, StringCaseCompLess());
783 }
784
785 bool is_selected_element(const size_t elemIndex,
786 const std::vector<std::string> &sortedSelectedBlocks, int proc)
787 {
788 bool isGloballySelected = (ANY_PROC == proc);
789 bool isLocallySelected = (get_element_proc(elemIndex) == proc);
790 bool hasLocalNode = element_has_any_node_on_proc(elemIndex, proc);
791 bool isInSelectedBlocks = element_is_in_selected_blocks(elemIndex, sortedSelectedBlocks);
792
793 return isInSelectedBlocks && (isGloballySelected || isLocallySelected || hasLocalNode);
794 }
795
796 std::vector<size_t>
797 get_local_and_aura_elements(const std::vector<std::string> &selectedBlocks, int proc)
798 {
799 std::vector<size_t> localAndAuraElementIndex;
800 localAndAuraElementIndex.reserve(get_num_elements());
801
802 std::vector<std::string> sortedSelectedBlocks;
803 for (const std::string &block : selectedBlocks) {
804 sortedSelectedBlocks.push_back(block);
805 }
806 std::sort(sortedSelectedBlocks.begin(), sortedSelectedBlocks.end(), StringCaseCompLess());
807
808 for (size_t i = 0; i < get_num_elements(); ++i) {
809 if (is_selected_element(i, sortedSelectedBlocks, proc)) {
810 localAndAuraElementIndex.push_back(i);
811 }
812 }
813
814 localAndAuraElementIndex.resize(localAndAuraElementIndex.size());
815 return localAndAuraElementIndex;
816 }
817
819 std::unordered_map<size_t, FaceConnections> m_indexGraph;
820 };
821
822 } // namespace text_mesh
823} // namespace Iotm
Definition Iotm_TextMeshTopologyMapping.h:33
std::vector< Ordinal > side_topology_node_indices(unsigned side) const
Definition Iotm_TextMeshTopologyMapping.h:131
static constexpr Permutation InvalidPermutation
Definition Iotm_TextMeshTopologyMapping.h:39
uint8_t Permutation
Definition Iotm_TextMeshTopologyMapping.h:36
unsigned num_positive_permutations() const
Definition Iotm_TextMeshTopologyMapping.h:152
bool is_shell() const
Definition Iotm_TextMeshTopologyMapping.h:148
bool fill_permutation_indices(Permutation permutation, std::vector< Ordinal > &nodeOrdinalVector) const
Definition Iotm_TextMeshTopologyMapping.h:167
int num_face_sides() const
Definition Iotm_TextMeshTopologyMapping.h:83
uint16_t Ordinal
Definition Iotm_TextMeshTopologyMapping.h:35
unsigned num_permutations() const
Definition Iotm_TextMeshTopologyMapping.h:150
const TopologyMapEntry & side_topology(unsigned side) const
Definition Iotm_TextMeshTopologyMapping.h:115
Definition Iotm_TextMeshAdjacencyGraph.h:86
void create_graph(int proc=ANY_PROC)
Definition Iotm_TextMeshAdjacencyGraph.h:209
size_t size() const
Definition Iotm_TextMeshAdjacencyGraph.h:267
void add_connection(CurrentAdjacency &adjacency, size_t connectedElementIndex, int otherSide)
Definition Iotm_TextMeshAdjacencyGraph.h:651
bool element_is_in_selected_blocks(const size_t elemIndex, const std::vector< std::string > &sortedSelectedBlocks)
Definition Iotm_TextMeshAdjacencyGraph.h:773
static constexpr int INVALID_SIDE
Definition Iotm_TextMeshAdjacencyGraph.h:91
virtual size_t get_num_elements() const =0
ErrorHandler m_errorHandler
Definition Iotm_TextMeshAdjacencyGraph.h:818
virtual const Topology & get_element_topology(const size_t elemIndex) const =0
bool is_shell_shell_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:544
bool is_shell_solid_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:556
void create_graph(const std::vector< std::string > &selectedBlocks, int proc=ANY_PROC)
Definition Iotm_TextMeshAdjacencyGraph.h:211
bool is_selected_element(const size_t elemIndex, const std::vector< std::string > &sortedSelectedBlocks, int proc)
Definition Iotm_TextMeshAdjacencyGraph.h:785
virtual const std::string & get_element_block_name(const size_t elemIndex) const =0
bool has_any_shell_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:606
void fill_sides_for_connected_element(CurrentAdjacency &adjacency, size_t neighborElementIndex)
Definition Iotm_TextMeshAdjacencyGraph.h:379
void break_reciprocal_connections(CurrentAdjacency &adjacency)
Definition Iotm_TextMeshAdjacencyGraph.h:517
void build_side_connectivity_graph(const std::vector< size_t > &elementIndices, const std::unordered_map< EntityId, std::set< size_t > > &elementsForNode)
Definition Iotm_TextMeshAdjacencyGraph.h:735
const FaceConnections & operator[](const IndexType elemIndex) const
Definition Iotm_TextMeshAdjacencyGraph.h:254
std::vector< FaceConnection > get_reciprocity(CurrentAdjacency &adjacency)
Definition Iotm_TextMeshAdjacencyGraph.h:492
bool has_same_polarity(const size_t thisElem, const int thisSide, const size_t thatElem, const int thatSide)
Definition Iotm_TextMeshAdjacencyGraph.h:460
std::pair< bool, PermutationType > get_permutation(const Topology &topology, const std::vector< EntityId > &controlNodes, const std::vector< EntityId > &permutedNodes, PermutationType numPermutations)
Definition Iotm_TextMeshAdjacencyGraph.h:413
void initialize_side_connectivity_graph(const std::vector< size_t > &elementIndices)
Definition Iotm_TextMeshAdjacencyGraph.h:752
virtual EntityId get_element_id(const size_t elemIndex) const =0
std::unordered_map< EntityId, std::set< size_t > > get_elements_for_node_map(const std::vector< size_t > &elementIndices)
Definition Iotm_TextMeshAdjacencyGraph.h:761
typename Topology::Ordinal OrdinalType
Definition Iotm_TextMeshAdjacencyGraph.h:279
std::vector< size_t > get_local_and_aura_elements(const std::vector< std::string > &selectedBlocks, int proc)
Definition Iotm_TextMeshAdjacencyGraph.h:797
virtual int get_element_proc(const size_t elemIndex) const =0
bool equivalent_node_permutation(const std::vector< EntityId > &controlNodes, const std::vector< EntityId > &permutedNodes, const std::vector< OrdinalType > &permutationOrdinals)
Definition Iotm_TextMeshAdjacencyGraph.h:394
void internal_fill_sides_for_connected_element(CurrentAdjacency &adjacency, size_t neighborElementIndex)
Definition Iotm_TextMeshAdjacencyGraph.h:359
bool has_solid_solid_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:642
bool is_shell_solid_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:550
void enforce_coincident_shell_ownership(IndexType connectedElemIndex1, IndexType connectedElemIndex2)
Definition Iotm_TextMeshAdjacencyGraph.h:700
std::unordered_map< size_t, FaceConnections >::const_iterator end() const
Definition Iotm_TextMeshAdjacencyGraph.h:273
std::pair< bool, PermutationType > get_permutation(const Topology &topology, const std::vector< EntityId > &controlNodes, const std::vector< EntityId > &permutedNodes)
Definition Iotm_TextMeshAdjacencyGraph.h:445
bool has_solid_shell_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:633
int64_t IndexType
Definition Iotm_TextMeshAdjacencyGraph.h:88
void dump(std::ostream &out=std::cout)
Definition Iotm_TextMeshAdjacencyGraph.h:223
void dump(const std::vector< ElementData< EntityId, Topology > > &elemDataVec, std::ostream &out=std::cout)
Definition Iotm_TextMeshAdjacencyGraph.h:237
std::vector< EntityId > get_side_nodes(const size_t elemIndex, const int side)
Definition Iotm_TextMeshAdjacencyGraph.h:335
bool verify_entry(IndexType elemIndex, int side)
Definition Iotm_TextMeshAdjacencyGraph.h:475
bool is_solid_shell_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:568
static constexpr IndexType INVALID_INDEX
Definition Iotm_TextMeshAdjacencyGraph.h:92
std::unordered_map< size_t, FaceConnections >::const_iterator begin() const
Definition Iotm_TextMeshAdjacencyGraph.h:269
std::pair< bool, PermutationType > get_positive_permutation(const Topology &topology, const std::vector< EntityId > &controlNodes, const std::vector< EntityId > &permutedNodes)
Definition Iotm_TextMeshAdjacencyGraph.h:453
std::function< bool(const Topology &topo1, const Topology &topo2)> Criterion
Definition Iotm_TextMeshAdjacencyGraph.h:586
bool is_solid_shell_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:562
void process_side_connectivity(CurrentAdjacency &adjacency, const std::unordered_map< EntityId, std::set< size_t > > &elementsForNode)
Definition Iotm_TextMeshAdjacencyGraph.h:718
bool has_shell_shell_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:615
virtual bool element_has_any_node_on_proc(const size_t elemIndex, int proc) const =0
std::unordered_map< size_t, FaceConnections > m_indexGraph
Definition Iotm_TextMeshAdjacencyGraph.h:819
bool has_shell_solid_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:624
bool is_solid_solid_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:580
typename Topology::Permutation PermutationType
Definition Iotm_TextMeshAdjacencyGraph.h:280
virtual const std::vector< EntityId > & get_element_node_ids(const size_t elemIndex) const =0
static constexpr int ANY_PROC
Definition Iotm_TextMeshAdjacencyGraph.h:90
void set_side_connectivity(CurrentAdjacency &adjacency, size_t connectedElementIndex)
Definition Iotm_TextMeshAdjacencyGraph.h:691
bool has_connection_type_on_side(size_t thisIndex, int thisSide, Criterion criterion)
Definition Iotm_TextMeshAdjacencyGraph.h:588
void set_error_handler(ErrorHandler errorHandler)
Definition Iotm_TextMeshAdjacencyGraph.h:221
bool is_shell_shell_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:538
bool is_solid_solid_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:574
std::vector< EntityId > get_sorted_side_nodes(const size_t elemIndex, const int side)
Definition Iotm_TextMeshAdjacencyGraph.h:350
std::set< size_t > get_element_indices_with_common_nodes_on_side(const size_t elemIndex, int side, const std::unordered_map< EntityId, std::set< size_t > > &elementsForNode)
Definition Iotm_TextMeshAdjacencyGraph.h:304
SideAdjacencyGraph()
Definition Iotm_TextMeshAdjacencyGraph.h:199
std::function< void(const std::ostringstream &)> ErrorHandler
Definition Iotm_TextMeshAdjacencyGraph.h:35
void default_error_handler(const std::ostringstream &message)
Definition Iotm_TextMeshFuncs.h:32
A namespace for the textmesh database format.
Definition Iotm_DatabaseIO.C:95
int64_t EntityId
Definition Iotm_TextMesh.h:33
Definition Iotm_TextMeshDataTypes.h:277
Definition Iotm_TextMeshAdjacencyGraph.h:292
std::vector< int > connectedSides
Definition Iotm_TextMeshAdjacencyGraph.h:301
size_t elementIndex
Definition Iotm_TextMeshAdjacencyGraph.h:297
CurrentAdjacency(size_t elementIndex_, int side_)
Definition Iotm_TextMeshAdjacencyGraph.h:293
int side
Definition Iotm_TextMeshAdjacencyGraph.h:298
Definition Iotm_TextMeshAdjacencyGraph.h:95
bool operator==(const FaceConnection &rhs) const
Definition Iotm_TextMeshAdjacencyGraph.h:104
bool operator<(const FaceConnection &rhs) const
Definition Iotm_TextMeshAdjacencyGraph.h:116
bool operator!=(const FaceConnection &rhs) const
Definition Iotm_TextMeshAdjacencyGraph.h:110
int thisSide
Definition Iotm_TextMeshAdjacencyGraph.h:129
IndexType thatElement
Definition Iotm_TextMeshAdjacencyGraph.h:130
int thatSide
Definition Iotm_TextMeshAdjacencyGraph.h:131
FaceConnection()
Definition Iotm_TextMeshAdjacencyGraph.h:96
FaceConnection(int thisSide_, IndexType otherElement_, int otherSide_)
Definition Iotm_TextMeshAdjacencyGraph.h:99
Definition Iotm_TextMeshAdjacencyGraph.h:135
FaceConnections(unsigned numSides_)
Definition Iotm_TextMeshAdjacencyGraph.h:137
std::vector< int > sideReference
Definition Iotm_TextMeshAdjacencyGraph.h:184
bool has_any_connection(int thisSide, IndexType thatElem) const
Definition Iotm_TextMeshAdjacencyGraph.h:151
bool has_any_connection(int thisSide) const
Definition Iotm_TextMeshAdjacencyGraph.h:142
std::set< FaceConnection > connections
Definition Iotm_TextMeshAdjacencyGraph.h:188
FaceConnections()
Definition Iotm_TextMeshAdjacencyGraph.h:136
unsigned numSides
Definition Iotm_TextMeshAdjacencyGraph.h:180
void remove(const FaceConnection &connection)
Definition Iotm_TextMeshAdjacencyGraph.h:170
void add(const FaceConnection &connection)
Definition Iotm_TextMeshAdjacencyGraph.h:161
Definition Iotm_TextMeshAdjacencyGraph.h:283
bool operator()(const std::string &lhs, const std::string &rhs)
Definition Iotm_TextMeshAdjacencyGraph.h:284
Definition Iotm_TextMeshDataTypes.h:315