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; otherSide <= get_element_topology(neighborElementIndex).num_sides();
368 ++otherSide) {
369 std::vector<EntityId> otherSideNodes =
370 get_sorted_side_nodes(neighborElementIndex, otherSide);
371 if (sideNodes == otherSideNodes) {
372 adjacency.connectedSides.push_back(otherSide);
373 }
374 }
375 }
376
377 // Find and validate connected sides to neighbor element
379 size_t neighborElementIndex)
380 {
381 internal_fill_sides_for_connected_element(adjacency, neighborElementIndex);
382
383 if (adjacency.connectedSides.empty()) {
384 std::ostringstream errmsg;
385 errmsg << "Neighboring reciprocity check for elements "
386 << get_element_id(adjacency.elementIndex) << " and "
387 << get_element_id(neighborElementIndex) << " failed.";
388 m_errorHandler(errmsg);
389 }
390 }
391
392 // Check to see if two set of nodes are equivalent based on permutation list
393 bool equivalent_node_permutation(const std::vector<EntityId> &controlNodes,
394 const std::vector<EntityId> &permutedNodes,
395 const std::vector<OrdinalType> &permutationOrdinals)
396 {
397 const size_t numNodes = permutationOrdinals.size();
398
399 if ((numNodes > permutedNodes.size()) || (numNodes > controlNodes.size())) {
400 return false;
401 }
402
403 bool equivalent = true;
404 for (size_t i = 0; equivalent && i < numNodes; ++i) {
405 equivalent = controlNodes[permutationOrdinals[i]] == permutedNodes[i];
406 }
407
408 return equivalent;
409 }
410
411 // Get the permutation that makes one set of nodes equivalent to the other
412 std::pair<bool, PermutationType> get_permutation(const Topology &topology,
413 const std::vector<EntityId> &controlNodes,
414 const std::vector<EntityId> &permutedNodes,
415 PermutationType numPermutations)
416 {
418 bool equivalent = false;
419
420 if (controlNodes.size() != permutedNodes.size())
421 return std::make_pair(equivalent, permutation);
422
423 if (numPermutations > topology.num_permutations()) {
424 std::ostringstream errmsg;
425 errmsg << "Invalid number of permutations to check: " << numPermutations;
426 m_errorHandler(errmsg);
427 }
428
429 std::vector<OrdinalType> permutationOrdinals;
430
431 for (PermutationType i = 0; i < numPermutations; ++i) {
432 if (topology.fill_permutation_indices(i, permutationOrdinals)) {
433 if (equivalent_node_permutation(controlNodes, permutedNodes, permutationOrdinals)) {
434 equivalent = true;
435 permutation = i;
436 break;
437 }
438 }
439 }
440
441 return std::make_pair(equivalent, permutation);
442 }
443
444 std::pair<bool, PermutationType> get_permutation(const Topology &topology,
445 const std::vector<EntityId> &controlNodes,
446 const std::vector<EntityId> &permutedNodes)
447 {
448 return get_permutation(topology, controlNodes, permutedNodes, topology.num_permutations());
449 }
450
451 std::pair<bool, PermutationType>
452 get_positive_permutation(const Topology &topology, const std::vector<EntityId> &controlNodes,
453 const std::vector<EntityId> &permutedNodes)
454 {
455 return get_permutation(topology, controlNodes, permutedNodes,
456 topology.num_positive_permutations());
457 }
458
459 bool has_same_polarity(const size_t thisElem, const int thisSide, const size_t thatElem,
460 const int thatSide)
461 {
462 std::vector<EntityId> thisNodes = get_side_nodes(thisElem, thisSide);
463 std::vector<EntityId> thatNodes = get_side_nodes(thatElem, thatSide);
464
465 const Topology &sideTopo = get_element_topology(thisElem).side_topology(thisSide);
466 std::pair<bool, PermutationType> result =
467 get_positive_permutation(sideTopo, thisNodes, thatNodes);
468
469 bool samePolarity = result.first;
470 return samePolarity;
471 }
472
473 // Check for valid element/side pair
474 bool verify_entry(IndexType elemIndex, int side)
475 {
476 if (INVALID_INDEX == elemIndex)
477 return false;
478
479 auto it = m_indexGraph.find(elemIndex);
480 if (it == m_indexGraph.end())
481 return false;
482
483 int numSides = it->second.numSides;
484 if (side < 1 || side > numSides)
485 return false;
486
487 return true;
488 }
489
490 // Given a current element/side pair, find all other defined reciprocal element connections
491 std::vector<FaceConnection> get_reciprocity(CurrentAdjacency &adjacency)
492 {
493 std::vector<FaceConnection> reciprocity;
494 const FaceConnections &thisEntry = m_indexGraph[adjacency.elementIndex];
495
496 for (const FaceConnection &connectionToThatElement : thisEntry.connections) {
497 IndexType thatIndex = connectionToThatElement.thatElement;
498 int thatSide = connectionToThatElement.thatSide;
499
500 if (!verify_entry(thatIndex, thatSide))
501 continue;
502 const FaceConnections &thatEntry = m_indexGraph[thatIndex];
503
504 const FaceConnection connectionToThisElement(thatSide, adjacency.elementIndex,
505 adjacency.side);
506 if (std::binary_search(thatEntry.connections.begin(), thatEntry.connections.end(),
507 connectionToThisElement)) {
508 reciprocity.push_back(connectionToThatElement);
509 }
510 }
511
512 return reciprocity;
513 }
514
515 // Break all current reciprocal connections to this element/side pair
517 {
518 std::vector<FaceConnection> reciprocity = get_reciprocity(adjacency);
519
520 if (!reciprocity.empty()) {
521 FaceConnections &thisEntry = m_indexGraph[adjacency.elementIndex];
522
523 for (const FaceConnection &connectionToThatElement : reciprocity) {
524 IndexType thatIndex = connectionToThatElement.thatElement;
525 int thatSide = connectionToThatElement.thatSide;
526
527 FaceConnections &thatEntry = m_indexGraph[thatIndex];
528 FaceConnection connectionToThisElement(thatSide, adjacency.elementIndex,
529 adjacency.side);
530
531 thisEntry.remove(connectionToThatElement);
532 thatEntry.remove(connectionToThisElement);
533 }
534 }
535 }
536
537 inline bool is_shell_shell_connection(const Topology &thisElemTopology,
538 const Topology &thatElemTopology)
539 {
540 return thisElemTopology.is_shell() && thatElemTopology.is_shell();
541 }
542
543 inline bool is_shell_shell_connection(const size_t thisElem, const size_t thatElem)
544 {
546 get_element_topology(thatElem));
547 }
548
549 inline bool is_shell_solid_connection(const Topology &thisElemTopology,
550 const Topology &thatElemTopology)
551 {
552 return thisElemTopology.is_shell() && !thatElemTopology.is_shell();
553 }
554
555 inline bool is_shell_solid_connection(const size_t thisElem, const size_t thatElem)
556 {
558 get_element_topology(thatElem));
559 }
560
561 inline bool is_solid_shell_connection(const Topology &thisElemTopology,
562 const Topology &thatElemTopology)
563 {
564 return !thisElemTopology.is_shell() && thatElemTopology.is_shell();
565 }
566
567 inline bool is_solid_shell_connection(const size_t thisElem, const size_t thatElem)
568 {
570 get_element_topology(thatElem));
571 }
572
573 inline bool is_solid_solid_connection(const Topology &thisElemTopology,
574 const Topology &thatElemTopology)
575 {
576 return !thisElemTopology.is_shell() && !thatElemTopology.is_shell();
577 }
578
579 inline bool is_solid_solid_connection(const size_t thisElem, const size_t thatElem)
580 {
582 get_element_topology(thatElem));
583 }
584
585 using Criterion = std::function<bool(const Topology &topo1, const Topology &topo2)>;
586
587 bool has_connection_type_on_side(size_t thisIndex, int thisSide, Criterion criterion)
588 {
589 const FaceConnections &thisEntry = m_indexGraph[thisIndex];
590
591 for (const FaceConnection &connection : thisEntry.connections) {
592 IndexType thatIndex = connection.thatElement;
593
594 if (connection.thisSide != thisSide || INVALID_INDEX == thatIndex)
595 continue;
596
597 if (criterion(get_element_topology(thisIndex), get_element_topology(thatIndex))) {
598 return true;
599 }
600 }
601
602 return false;
603 }
604
605 bool has_any_shell_connection_on_side(size_t thisIndex, int thisSide)
606 {
607 Criterion criterion = [&](const Topology & /* topo1 */, const Topology &topo2) {
608 return topo2.is_shell();
609 };
610
611 return has_connection_type_on_side(thisIndex, thisSide, criterion);
612 }
613
614 bool has_shell_shell_connection_on_side(size_t thisIndex, int thisSide)
615 {
616 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
617 return is_shell_shell_connection(topo1, topo2);
618 };
619
620 return has_connection_type_on_side(thisIndex, thisSide, criterion);
621 }
622
623 bool has_shell_solid_connection_on_side(size_t thisIndex, int thisSide)
624 {
625 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
626 return is_shell_solid_connection(topo1, topo2);
627 };
628
629 return has_connection_type_on_side(thisIndex, thisSide, criterion);
630 }
631
632 bool has_solid_shell_connection_on_side(size_t thisIndex, int thisSide)
633 {
634 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
635 return is_solid_shell_connection(topo1, topo2);
636 };
637
638 return has_connection_type_on_side(thisIndex, thisSide, criterion);
639 }
640
641 bool has_solid_solid_connection_on_side(size_t thisIndex, int thisSide)
642 {
643 Criterion criterion = [&](const Topology &topo1, const Topology &topo2) {
644 return is_solid_solid_connection(topo1, topo2);
645 };
646
647 return has_connection_type_on_side(thisIndex, thisSide, criterion);
648 }
649
650 void add_connection(CurrentAdjacency &adjacency, size_t connectedElementIndex, int otherSide)
651 {
652 const size_t thisElem = adjacency.elementIndex;
653 const size_t thatElem = connectedElementIndex;
654
655 bool doConnect = false;
656 bool breakConnection = false;
657
658 if (is_shell_solid_connection(thisElem, thatElem)) {
659 doConnect = !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
660
661 if (has_solid_solid_connection_on_side(connectedElementIndex, otherSide)) {
662 breakConnection = doConnect;
663 }
664 }
665 else if (is_solid_shell_connection(thisElem, thatElem)) {
666 doConnect = !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
667
668 if (has_solid_solid_connection_on_side(adjacency.elementIndex, adjacency.side)) {
669 breakConnection = doConnect;
670 }
671 }
672 else if (is_solid_solid_connection(thisElem, thatElem)) {
673 doConnect = !has_any_shell_connection_on_side(adjacency.elementIndex, adjacency.side) &&
674 !has_any_shell_connection_on_side(connectedElementIndex, otherSide) &&
675 !has_same_polarity(thisElem, adjacency.side, thatElem, otherSide);
676 }
677
678 if (breakConnection) {
680 }
681
682 if (doConnect) {
683 m_indexGraph[adjacency.elementIndex].add(
684 FaceConnection(adjacency.side, connectedElementIndex, otherSide));
685 m_indexGraph[connectedElementIndex].add(
686 FaceConnection(otherSide, adjacency.elementIndex, adjacency.side));
687 }
688 }
689
690 void set_side_connectivity(CurrentAdjacency &adjacency, size_t connectedElementIndex)
691 {
692 fill_sides_for_connected_element(adjacency, connectedElementIndex);
693
694 for (int otherSide : adjacency.connectedSides) {
695 add_connection(adjacency, connectedElementIndex, otherSide);
696 }
697 }
698
700 IndexType connectedElemIndex2)
701 {
702 if (get_element_topology(connectedElemIndex1).is_shell() &&
703 get_element_topology(connectedElemIndex2).is_shell()) {
704 if (get_element_proc(connectedElemIndex1) != get_element_proc(connectedElemIndex2)) {
705 std::ostringstream errmsg;
706 errmsg << "Invalid proc ownership for co-incident shells "
707 << get_element_id(connectedElemIndex1) << " (proc "
708 << get_element_proc(connectedElemIndex1) << ") and "
709 << get_element_proc(connectedElemIndex2) << " (proc "
710 << get_element_proc(connectedElemIndex2) << ")."
711 << " Co-incident shells must all exist on the same processor";
712 m_errorHandler(errmsg);
713 }
714 }
715 }
716
718 CurrentAdjacency &adjacency,
719 const std::unordered_map<EntityId, std::set<size_t>> &elementsForNode)
720 {
721 int side = adjacency.side;
722
723 std::set<size_t> elementIndicesConnectedToSide =
725 elementsForNode);
726 for (size_t connectedElementIndex : elementIndicesConnectedToSide) {
727 if (connectedElementIndex != adjacency.elementIndex) {
728 enforce_coincident_shell_ownership(adjacency.elementIndex, connectedElementIndex);
729 set_side_connectivity(adjacency, connectedElementIndex);
730 }
731 }
732 }
733
735 const std::vector<size_t> &elementIndices,
736 const std::unordered_map<EntityId, std::set<size_t>> &elementsForNode)
737 {
739
740 for (size_t elementIndex : elementIndices) {
741 int numSides = get_element_topology(elementIndex).num_sides();
742 for (int side = 1; side <= numSides; ++side) {
743 if (m_indexGraph[elementIndex].sideReference[side - 1] == 0) {
744 CurrentAdjacency adjacency(elementIndex, side);
745 process_side_connectivity(adjacency, elementsForNode);
746 }
747 }
748 }
749 }
750
751 void initialize_side_connectivity_graph(const std::vector<size_t> &elementIndices)
752 {
753 for (size_t elementIndex : elementIndices) {
754 m_indexGraph[elementIndex] =
755 FaceConnections(get_element_topology(elementIndex).num_sides());
756 }
757 }
758
759 std::unordered_map<EntityId, std::set<size_t>>
760 get_elements_for_node_map(const std::vector<size_t> &elementIndices)
761 {
762 std::unordered_map<EntityId, std::set<size_t>> elementsForNode;
763 for (size_t index : elementIndices) {
764 for (const EntityId nodeId : get_element_node_ids(index)) {
765 elementsForNode[nodeId].insert(index);
766 }
767 }
768
769 return elementsForNode;
770 }
771
772 bool element_is_in_selected_blocks(const size_t elemIndex,
773 const std::vector<std::string> &sortedSelectedBlocks)
774 {
775 if (sortedSelectedBlocks.empty())
776 return true;
777
778 const std::string &partName = get_element_block_name(elemIndex);
779
780 return std::binary_search(sortedSelectedBlocks.begin(), sortedSelectedBlocks.end(),
781 partName, StringCaseCompLess());
782 }
783
784 bool is_selected_element(const size_t elemIndex,
785 const std::vector<std::string> &sortedSelectedBlocks, int proc)
786 {
787 bool isGloballySelected = (ANY_PROC == proc);
788 bool isLocallySelected = (get_element_proc(elemIndex) == proc);
789 bool hasLocalNode = element_has_any_node_on_proc(elemIndex, proc);
790 bool isInSelectedBlocks = element_is_in_selected_blocks(elemIndex, sortedSelectedBlocks);
791
792 return isInSelectedBlocks && (isGloballySelected || isLocallySelected || hasLocalNode);
793 }
794
795 std::vector<size_t>
796 get_local_and_aura_elements(const std::vector<std::string> &selectedBlocks, int proc)
797 {
798 std::vector<size_t> localAndAuraElementIndex;
799 localAndAuraElementIndex.reserve(get_num_elements());
800
801 std::vector<std::string> sortedSelectedBlocks;
802 for (const std::string &block : selectedBlocks) {
803 sortedSelectedBlocks.push_back(block);
804 }
805 std::sort(sortedSelectedBlocks.begin(), sortedSelectedBlocks.end(), StringCaseCompLess());
806
807 for (size_t i = 0; i < get_num_elements(); ++i) {
808 if (is_selected_element(i, sortedSelectedBlocks, proc)) {
809 localAndAuraElementIndex.push_back(i);
810 }
811 }
812
813 localAndAuraElementIndex.resize(localAndAuraElementIndex.size());
814 return localAndAuraElementIndex;
815 }
816
818 std::unordered_map<size_t, FaceConnections> m_indexGraph;
819 };
820
821 } // namespace text_mesh
822} // namespace Iotm
Definition Iotm_TextMeshTopologyMapping.h:34
std::vector< Ordinal > side_topology_node_indices(unsigned side) const
Definition Iotm_TextMeshTopologyMapping.h:130
static constexpr Permutation InvalidPermutation
Definition Iotm_TextMeshTopologyMapping.h:40
uint8_t Permutation
Definition Iotm_TextMeshTopologyMapping.h:37
unsigned num_positive_permutations() const
Definition Iotm_TextMeshTopologyMapping.h:151
bool is_shell() const
Definition Iotm_TextMeshTopologyMapping.h:147
bool fill_permutation_indices(Permutation permutation, std::vector< Ordinal > &nodeOrdinalVector) const
Definition Iotm_TextMeshTopologyMapping.h:166
int num_sides() const
Definition Iotm_TextMeshTopologyMapping.h:84
uint16_t Ordinal
Definition Iotm_TextMeshTopologyMapping.h:36
unsigned num_permutations() const
Definition Iotm_TextMeshTopologyMapping.h:149
const TopologyMapEntry & side_topology(unsigned side) const
Definition Iotm_TextMeshTopologyMapping.h:114
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:650
bool element_is_in_selected_blocks(const size_t elemIndex, const std::vector< std::string > &sortedSelectedBlocks)
Definition Iotm_TextMeshAdjacencyGraph.h:772
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:817
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:543
bool is_shell_solid_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:555
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:784
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:605
void fill_sides_for_connected_element(CurrentAdjacency &adjacency, size_t neighborElementIndex)
Definition Iotm_TextMeshAdjacencyGraph.h:378
void break_reciprocal_connections(CurrentAdjacency &adjacency)
Definition Iotm_TextMeshAdjacencyGraph.h:516
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:734
const FaceConnections & operator[](const IndexType elemIndex) const
Definition Iotm_TextMeshAdjacencyGraph.h:254
std::vector< FaceConnection > get_reciprocity(CurrentAdjacency &adjacency)
Definition Iotm_TextMeshAdjacencyGraph.h:491
bool has_same_polarity(const size_t thisElem, const int thisSide, const size_t thatElem, const int thatSide)
Definition Iotm_TextMeshAdjacencyGraph.h:459
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:412
void initialize_side_connectivity_graph(const std::vector< size_t > &elementIndices)
Definition Iotm_TextMeshAdjacencyGraph.h:751
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:760
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:796
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:393
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:641
bool is_shell_solid_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:549
void enforce_coincident_shell_ownership(IndexType connectedElemIndex1, IndexType connectedElemIndex2)
Definition Iotm_TextMeshAdjacencyGraph.h:699
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:444
bool has_solid_shell_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:632
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:474
bool is_solid_shell_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:567
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:452
std::function< bool(const Topology &topo1, const Topology &topo2)> Criterion
Definition Iotm_TextMeshAdjacencyGraph.h:585
bool is_solid_shell_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:561
void process_side_connectivity(CurrentAdjacency &adjacency, const std::unordered_map< EntityId, std::set< size_t > > &elementsForNode)
Definition Iotm_TextMeshAdjacencyGraph.h:717
bool has_shell_shell_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:614
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:818
bool has_shell_solid_connection_on_side(size_t thisIndex, int thisSide)
Definition Iotm_TextMeshAdjacencyGraph.h:623
bool is_solid_solid_connection(const size_t thisElem, const size_t thatElem)
Definition Iotm_TextMeshAdjacencyGraph.h:579
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:690
bool has_connection_type_on_side(size_t thisIndex, int thisSide, Criterion criterion)
Definition Iotm_TextMeshAdjacencyGraph.h:587
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:537
bool is_solid_solid_connection(const Topology &thisElemTopology, const Topology &thatElemTopology)
Definition Iotm_TextMeshAdjacencyGraph.h:573
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 generated 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