Loading...
Searching...
No Matches
element.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#include <cassert>
26#include <limits>
27#include <set>
28
29#include "bitpit_common.hpp"
30#include "bitpit_CG.hpp"
31#include "bitpit_operators.hpp"
32
33#include "element.hpp"
34
35namespace bitpit {
36
44IBinaryStream& operator>>(IBinaryStream &buffer, Element &element)
45{
46 // Initialize the element
47 ElementType type;
48 buffer >> type;
49
50 long id;
51 buffer >> id;
52
53 int connectSize;
55 element._initialize(id, type);
56 connectSize = element.getConnectSize();
57 } else {
58 buffer >> connectSize;
59 element._initialize(id, type, connectSize);
60 }
61
62 // Set connectivity
63 buffer.read(reinterpret_cast<char *>(element.m_connect.get()), connectSize * sizeof(long));
64
65 // Set PID
66 int pid;
67 buffer >> pid;
68
69 element.setPID(pid);
70
71 return buffer;
72}
73
81OBinaryStream& operator<<(OBinaryStream &buffer, const Element &element)
82{
83 buffer << element.getType();
84 buffer << element.getId();
85
86 int connectSize = element.getConnectSize();
87 if (!ReferenceElementInfo::hasInfo(element.m_type)) {
88 buffer << connectSize;
89 }
90
91 buffer.write(reinterpret_cast<const char *>(element.m_connect.get()), connectSize * sizeof(long));
92
93 buffer << element.getPID();
94
95 return buffer;
96}
97
112Element::Tesselation::Tesselation()
113 : m_nTiles(0)
114{
115}
116
124int Element::Tesselation::importVertexCoordinates(const std::array<double, 3> &coordinates)
125{
126 return importVertexCoordinates(std::array<double, 3>(coordinates));
127}
128
136int Element::Tesselation::importVertexCoordinates(std::array<double, 3> &&coordinates)
137{
138 m_coordinates.push_back(std::move(coordinates));
139
140 return (m_coordinates.size() - 1);
141}
142
151std::vector<int> Element::Tesselation::importVertexCoordinates(const std::array<double, 3> *coordinates, int nVertices)
152{
153 int nStoredVertices = m_coordinates.size();
154 m_coordinates.reserve(nStoredVertices + nVertices);
155
156 std::vector<int> ids(nVertices);
157 for (int k = 0; k < nVertices; ++k) {
158 m_coordinates.push_back(coordinates[k]);
159 ids[k] = nStoredVertices++;
160 }
161
162 return ids;
163}
164
170void Element::Tesselation::importPolygon(const std::vector<int> &vertexIds)
171{
172 int nVertices = vertexIds.size();
173 if (nVertices == 3 || nVertices == 4) {
174 m_nTiles++;
175 m_types.push_back(nVertices == 3 ? ElementType::TRIANGLE : ElementType::QUAD);
176 m_connects.push_back(vertexIds);
177
178 return;
179 }
180
181 // Add the centroid
182 std::array<double, 3> centroid = {{0., 0., 0.}};
183 for (int k = 0; k < nVertices; ++k) {
184 centroid += m_coordinates[vertexIds[k]];
185 }
186 centroid = centroid / double(nVertices);
187
188 int centroidId = importVertexCoordinates(std::move(centroid));
189
190 // Decompose the polygon in triangles
191 //
192 // Each triangle is composed by the two vertices of a side and by the
193 // centroid.
194 ElementType tileType = ElementType::TRIANGLE;
195 int nTileVertices = ReferenceElementInfo::getInfo(tileType).nVertices;
196 int nSideVertices = ReferenceElementInfo::getInfo(ElementType::LINE).nVertices;
197
198 int nSides = nVertices;
199 m_types.resize(m_nTiles + nSides, tileType);
200 m_connects.resize(m_nTiles + nSides, std::vector<int>(nTileVertices));
201 for (int i = 0; i < nSides; ++i) {
202 m_nTiles++;
203 for (int k = 0; k < nSideVertices; ++k) {
204 m_connects[m_nTiles - 1][k] = vertexIds[(i + k) % nVertices];
205 }
206 m_connects[m_nTiles - 1][nSideVertices] = centroidId;
207 }
208}
209
216void Element::Tesselation::importPolyhedron(const std::vector<int> &vertexIds, const std::vector<std::vector<int>> &faceVertexIds)
217{
218 int nFaces = faceVertexIds.size();
219 int nVertices = vertexIds.size();
220
221 // Generate the tesselation of the surface
222 int nInitialTiles = m_nTiles;
223 for (int i = 0; i < nFaces; ++i) {
224 importPolygon(faceVertexIds[i]);
225 }
226 int nFinalTiles = m_nTiles;
227
228 // Add the centroid of the element to the tesselation
229 std::array<double, 3> centroid = {{0., 0., 0.}};
230 for (int k = 0; k < nVertices; ++k) {
231 centroid += m_coordinates[vertexIds[k]];
232 }
233 centroid = centroid / double(nVertices);
234
235 int centroidTesselationId = importVertexCoordinates(std::move(centroid));
236
237 // Decompose the polyhedron in prisms and pyramids.
238 //
239 // Each prism/pyramid has a tile of the surface tesselation as the
240 // base and the centroid of the element as the apex. Since we have
241 // already generated the surface tesselation, we can "convert" the
242 // two-dimensional tiles of that tesselation in three-dimensional
243 // tiles to obtain the volume tesselation.
244 for (int i = nInitialTiles; i < nFinalTiles; ++i) {
245 // Change the tile type
246 ElementType &tileType = m_types[i];
247 if (tileType == ElementType::TRIANGLE) {
248 tileType = ElementType::TETRA;
249 } else if (tileType == ElementType::QUAD) {
250 tileType = ElementType::PYRAMID;
251 } else {
252 BITPIT_UNREACHABLE("Unsupported tile");
253 throw std::runtime_error ("Unsupported tile");
254 }
255
256 // Fix the order of the connectivity the match the order of the
257 // three-dimensional element
258 if (tileType == ElementType::TETRA) {
259 std::swap(m_connects[i][0], m_connects[i][2]);
260 } else if (tileType == ElementType::PYRAMID) {
261 std::swap(m_connects[i][1], m_connects[i][3]);
262 }
263
264 // Add the centroid to the tile connectivity
265 m_connects[i].push_back(centroidTesselationId);
266 }
267}
268
274int Element::Tesselation::getTileCount() const
275{
276 return m_nTiles;
277}
278
285ElementType Element::Tesselation::getTileType(int tile) const
286{
287 return m_types[tile];
288}
289
296std::vector<std::array<double, 3>> Element::Tesselation::getTileVertexCoordinates(int tile) const
297{
298 const ElementType tileType = getTileType(tile);
299 const int nTileVertices = ReferenceElementInfo::getInfo(tileType).nVertices;
300 const std::vector<int> &tileConnect = m_connects[tile];
301
302 std::vector<std::array<double, 3>> coordinates(nTileVertices);
303 for (int i = 0; i < nTileVertices; ++i) {
304 coordinates[i] = m_coordinates[tileConnect[i]];
305 }
306
307 return coordinates;
308}
309
320const long Element::NULL_ID = std::numeric_limits<long>::min();
321
325Element::Element()
326{
327 _initialize(NULL_ID, ElementType::UNDEFINED);
328}
329
338Element::Element(long id, ElementType type, int connectSize)
339{
340 _initialize(id, type, connectSize);
341}
342
351Element::Element(long id, ElementType type, std::unique_ptr<long[]> &&connectStorage)
352{
353 _initialize(id, type, std::move(connectStorage));
354}
355
361Element::Element(const Element &other)
362{
363 int connectSize;
364 if (other.m_connect) {
365 connectSize = other.getConnectSize();
366 } else {
367 connectSize = 0;
368 }
369
370 _initialize(other.m_id, other.m_type, connectSize);
371
372 m_pid = other.m_pid;
373
374 if (other.m_connect) {
375 std::copy(other.m_connect.get(), other.m_connect.get() + connectSize, m_connect.get());
376 }
377}
378
384Element & Element::operator=(const Element &other)
385{
386 Element tmp(other);
387 swap(tmp);
388
389 return *this;
390}
391
399void Element::swap(Element &other) noexcept
400{
401 std::swap(other.m_id, m_id);
402 std::swap(other.m_type, m_type);
403 std::swap(other.m_pid, m_pid);
404 std::swap(other.m_connect, m_connect);
405}
406
415void Element::initialize(long id, ElementType type, int connectSize)
416{
417 _initialize(id, type, connectSize);
418}
419
428void Element::initialize(long id, ElementType type, std::unique_ptr<long[]> &&connectStorage)
429{
430 _initialize(id, type, std::move(connectStorage));
431}
432
441void Element::_initialize(long id, ElementType type, int connectSize)
442{
443 // Get previous connect size
444 int previousConnectSize = 0;
445 if (m_connect) {
446 if (hasInfo()) {
447 previousConnectSize = getInfo().nVertices;
448 }
449 }
450
451 // Initialize connectivity storage
452 if (ReferenceElementInfo::hasInfo(type)) {
453 connectSize = ReferenceElementInfo::getInfo(type).nVertices;
454 }
455
456 std::unique_ptr<long[]> connectStorage;
457 if (connectSize != previousConnectSize) {
458 connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
459 } else {
460 connectStorage = std::move(m_connect);
461 }
462
463 // Initialize element
464 _initialize(id, type, std::move(connectStorage));
465}
466
475void Element::_initialize(long id, ElementType type, std::unique_ptr<long[]> &&connectStorage)
476{
477 // Set the id
478 setId(id);
479
480 // Set type
481 setType(type);
482
483 // Initialize PID
484 setPID(0);
485
486 // Initialize connectivity
487 setConnect(std::move(connectStorage));
488}
489
498void Element::setId(long id)
499{
500 m_id = id;
501}
502
510long Element::getId() const
511{
512 return m_id;
513}
514
521bool Element::hasInfo() const
522{
523 return ReferenceElementInfo::hasInfo(m_type);
524}
525
531const ReferenceElementInfo & Element::getInfo() const
532{
533 return ReferenceElementInfo::getInfo(m_type);
534}
535
541void Element::setType(ElementType type)
542{
543 m_type = type;
544}
545
551ElementType Element::getType() const
552{
553 return m_type;
554}
555
566void Element::setPID(int pid)
567{
568 m_pid = pid;
569}
570
581int Element::getPID() const
582{
583 return m_pid;
584}
585
591void Element::setConnect(std::unique_ptr<long[]> &&connect)
592{
593 m_connect = std::move(connect);
594}
595
599void Element::unsetConnect()
600{
601 m_connect.reset(nullptr);
602}
603
609const long * Element::getConnect() const
610{
611 return m_connect.get();
612}
613
619long * Element::getConnect()
620{
621 return m_connect.get();
622}
623
629int Element::getConnectSize() const
630{
631 switch (m_type) {
632
633 case (ElementType::POLYGON):
634 return 1 + getVertexCount();
635
636 case (ElementType::POLYHEDRON):
637 return getFaceStreamSize();
638
639 default:
640 assert(m_type != ElementType::UNDEFINED);
641
642 return getVertexCount();
643
644 }
645}
646
655bool Element::hasSameConnect(const Element &other) const
656{
657 int cellConnectSize = getConnectSize();
658 if (other.getConnectSize() != cellConnectSize) {
659 return false;
660 }
661
662 const long *cellConnect = getConnect();
663 const long *otherConnect = other.getConnect();
664 for (int k = 0; k < cellConnectSize; ++k) {
665 if (cellConnect[k] != otherConnect[k]) {
666 return false;
667 }
668 }
669
670 return true;
671}
672
678int Element::getFaceCount() const
679{
680 switch (m_type) {
681
682 case (ElementType::POLYGON):
683 return countPolygonFaces(getConnect());
684
685 case (ElementType::POLYHEDRON):
686 return countPolyhedronFaces(getConnect());
687
688 default:
689 assert(m_type != ElementType::UNDEFINED);
690
691 return getInfo().nFaces;
692
693 }
694}
695
701ElementType Element::getFaceType(int face) const
702{
703 switch (m_type) {
704
705 case (ElementType::POLYGON):
706 {
707 return ElementType::LINE;
708 }
709
710 case (ElementType::POLYHEDRON):
711 {
712 int nFaceVertices = getFaceVertexCount(face);
713 switch (nFaceVertices) {
714
715 case 3:
716 return ElementType::TRIANGLE;
717
718 case 4:
719 return ElementType::QUAD;
720
721 default:
722 return ElementType::POLYGON;
723
724 }
725 }
726
727 default:
728 {
729 assert(m_type != ElementType::UNDEFINED);
730
731 return getInfo().faceTypeStorage[face];
732 }
733
734 }
735}
736
743int Element::getFaceVertexCount(int face) const
744{
745 switch (m_type) {
746
747 case (ElementType::POLYHEDRON):
748 {
749 const long *connectivity = getConnect();
750 int facePos = getFaceStreamPosition(connectivity, face);
751
752 return connectivity[facePos];
753 }
754
755 default:
756 {
757 assert(m_type != ElementType::UNDEFINED);
758
759 ElementType faceType = getFaceType(face);
760
761 return ReferenceElementInfo::getInfo(faceType).nVertices;
762 }
763
764 }
765}
766
773ConstProxyVector<int> Element::getFaceLocalConnect(int face) const
774{
775 switch (m_type) {
776
777 case (ElementType::POLYGON):
778 {
779 int nVertices = getVertexCount();
780
781 int faceConnectSize = getFaceVertexCount(face);
782
783 ConstProxyVector<int> localFaceConnect(ConstProxyVector<int>::INTERNAL_STORAGE, faceConnectSize);
784 ConstProxyVector<int>::storage_pointer localFaceConnectStorage = localFaceConnect.storedData();
785 for (int i = 0; i < faceConnectSize; ++i) {
786 localFaceConnectStorage[i] = (face + i) % nVertices;
787 }
788
789 return localFaceConnect;
790 }
791
792 case (ElementType::POLYHEDRON):
793 {
794 // Get face information
795 ElementType faceType = getFaceType(face);
796 bool faceHasReferenceInfo = ReferenceElementInfo::hasInfo(faceType);
797
798 // Get face vertices
799 ConstProxyVector<long> faceVertexIds = getFaceVertexIds(face);
800 int nFaceVertices = faceVertexIds.size();
801
802 // Get element vertices
803 ConstProxyVector<long> vertexIds = getVertexIds();
804
805 // Build list of local face verties
806 int faceConnectSize = nFaceVertices;
807 int localVertexOffset = 0;
808 if (!faceHasReferenceInfo) {
809 ++faceConnectSize;
810 ++localVertexOffset;
811 }
812
813 ConstProxyVector<int> localFaceConnect(ConstProxyVector<int>::INTERNAL_STORAGE, faceConnectSize);
814 ConstProxyVector<int>::storage_pointer localFaceConnectStorage = localFaceConnect.storedData();
815 if (!faceHasReferenceInfo) {
816 localFaceConnectStorage[0] = nFaceVertices;
817 }
818
819 for (int k = 0; k < nFaceVertices; ++k) {
820 int vertexId = faceVertexIds[k];
821 auto localVertexIdItr = std::find(vertexIds.begin(), vertexIds.end(), vertexId);
822 assert(localVertexIdItr != vertexIds.end() && *localVertexIdItr == vertexId);
823 localFaceConnectStorage[localVertexOffset + k] = static_cast<int>(std::distance(vertexIds.begin(), localVertexIdItr));
824 }
825
826 return localFaceConnect;
827 }
828
829 default:
830 {
831 assert(m_type != ElementType::UNDEFINED);
832
833 const int localConnectSize = getFaceVertexCount(face);
834 const int *localFaceConnect = getInfo().faceConnectStorage[face].data();
835
836 return ConstProxyVector<int>(localFaceConnect, localConnectSize);
837 }
838
839 }
840}
841
848ConstProxyVector<long> Element::getFaceConnect(int face) const
849{
850 const long *connectivity = getConnect();
851
852 switch (m_type) {
853
854 case (ElementType::POLYGON):
855 {
856 int connectSize = getConnectSize();
857
858 int facePos = 1 + face;
859 int faceConnectSize = getFaceVertexCount(face);
860 if (facePos + faceConnectSize <= connectSize) {
861 return ConstProxyVector<long>(connectivity + facePos, faceConnectSize);
862 } else {
864 ConstProxyVector<long>::storage_pointer faceConnectStorage = faceConnect.storedData();
865 for (int i = 0; i < faceConnectSize; ++i) {
866 int position = facePos + i;
867 if (position >= connectSize) {
868 position = position % connectSize + 1;
869 }
870
871 faceConnectStorage[i] = connectivity[position];
872 }
873
874 return faceConnect;
875 }
876 }
877
878 case (ElementType::POLYHEDRON):
879 {
880 ElementType faceType = getFaceType(face);
881
882 int facePos = getFaceStreamPosition(connectivity, face);
883 int faceConnectSize = connectivity[facePos];
884 int faceConnectBegin = facePos + 1;
885 if (!ReferenceElementInfo::hasInfo(faceType)) {
886 faceConnectSize++;
887 faceConnectBegin--;
888 }
889
890 return ConstProxyVector<long>(connectivity + faceConnectBegin, faceConnectSize);
891 }
892
893 default:
894 {
895 assert(m_type != ElementType::UNDEFINED);
896
897 // If we are here, the element has a reference element, therefore we
898 // can retrieve the local face connectivity directly form the info
899 // associated the to referenc element.
900 int faceConnectSize = getFaceVertexCount(face);
901 const int *localFaceConnect = getInfo().faceConnectStorage[face].data();
902
904 ConstProxyVector<long>::storage_pointer faceConnectStorage = faceConnect.storedData();
905 for (int k = 0; k < faceConnectSize; ++k) {
906 int localVertexId = localFaceConnect[k];
907 long vertexId = connectivity[localVertexId];
908 faceConnectStorage[k] = vertexId;
909 }
910
911 return faceConnect;
912 }
913
914 }
915}
916
922int Element::getEdgeCount() const
923{
924 switch (m_type) {
925
926 case (ElementType::POLYGON):
927 {
928 return getVertexCount();
929 }
930
931 case (ElementType::POLYHEDRON):
932 {
933 int nVertices = getVertexCount();
934 int nFaces = getFaceCount();
935 int nEdges = nVertices + nFaces - 2;
936
937 return nEdges;
938 }
939
940 default:
941 {
942 assert(m_type != ElementType::UNDEFINED);
943
944 return getInfo().nEdges;
945 }
946
947 }
948}
949
955ElementType Element::getEdgeType(int edge) const
956{
957 BITPIT_UNUSED(edge);
958
959 int dimension = getDimension();
960 switch (dimension) {
961
962 case 0:
963 return ElementType::UNDEFINED;
964
965 case 1:
966 case 2:
967 return ElementType::VERTEX;
968
969 default:
970 return ElementType::LINE;
971
972 }
973}
974
981int Element::getEdgeVertexCount(int edge) const
982{
983 ElementType edgeType = getEdgeType(edge);
984
985 return ReferenceElementInfo::getInfo(edgeType).nVertices;
986}
987
994ConstProxyVector<int> Element::getEdgeLocalConnect(int edge) const
995{
996 switch (m_type) {
997
998 case (ElementType::POLYGON):
999 {
1000 int nEdgeVertices = ReferenceElementInfo::getInfo(ElementType::VERTEX).nVertices;
1001
1002 ConstProxyVector<int> localEdgeConnect(ConstProxyVector<int>::INTERNAL_STORAGE, nEdgeVertices);
1003 ConstProxyVector<int>::storage_pointer localEdgeConnectStorage = localEdgeConnect.storedData();
1004 for (int k = 0; k < nEdgeVertices; ++k) {
1005 localEdgeConnectStorage[k] = k;
1006 }
1007
1008 return localEdgeConnect;
1009 }
1010
1011 case (ElementType::POLYHEDRON):
1012 {
1013 // Get edge vertices
1014 ConstProxyVector<long> edgeVertexIds = getEdgeVertexIds(edge);
1015 int nEdgeVertices = edgeVertexIds.size();
1016
1017 // Get element vertices
1018 ConstProxyVector<long> vertexIds = getVertexIds();
1019
1020 // Build local edge connectivity
1021 ConstProxyVector<int> localEdgeConnect(ConstProxyVector<int>::INTERNAL_STORAGE, nEdgeVertices);
1022 ConstProxyVector<int>::storage_pointer localEdgeConnectStorage = localEdgeConnect.storedData();
1023 for (int k = 0; k < nEdgeVertices; ++k) {
1024 int vertexId = edgeVertexIds[k];
1025 auto localVertexIdItr = std::find(vertexIds.begin(), vertexIds.end(), vertexId);
1026 assert(localVertexIdItr != vertexIds.end() && *localVertexIdItr == vertexId);
1027 localEdgeConnectStorage[k] = static_cast<int>(std::distance(vertexIds.begin(), localVertexIdItr));
1028 }
1029
1030 return localEdgeConnect;
1031 }
1032
1033 default:
1034 {
1035 assert(m_type != ElementType::UNDEFINED);
1036
1037 const int localConnectSize = getEdgeVertexCount(edge);
1038 const int *localEdgeConnect = getInfo().edgeConnectStorage[edge].data();
1039
1040 return ConstProxyVector<int>(localEdgeConnect, localConnectSize);
1041 }
1042
1043 }
1044}
1045
1052ConstProxyVector<long> Element::getEdgeConnect(int edge) const
1053{
1054 const long *connectivity = getConnect();
1055
1056 switch (m_type) {
1057
1058 case (ElementType::POLYGON):
1059 {
1060 return ConstProxyVector<long>(connectivity + 1 + edge, 1);
1061 }
1062
1063 case (ElementType::POLYHEDRON):
1064 {
1065 std::vector<ConstProxyVector<long>> edgeConnectStorage = evalEdgeConnects(edge + 1);
1066
1067 return edgeConnectStorage[edge];
1068 }
1069
1070 default:
1071 {
1072 assert(m_type != ElementType::UNDEFINED);
1073
1074 ConstProxyVector<int> localEdgeConnect = getEdgeLocalConnect(edge);
1075 int nEdgeVertices = localEdgeConnect.size();
1076
1078 ConstProxyVector<long>::storage_pointer edgeConnectStorage = edgeConnect.storedData();
1079 for (int k = 0; k < nEdgeVertices; ++k) {
1080 int localVertexId = localEdgeConnect[k];
1081 edgeConnectStorage[k] = connectivity[localVertexId];
1082 }
1083
1084 return edgeConnect;
1085 }
1086
1087 }
1088}
1089
1096int Element::getDimension(ElementType type)
1097{
1098 switch (type) {
1099
1100 case ElementType::POLYGON:
1101 return 2;
1102
1103 case ElementType::POLYHEDRON:
1104 return 3;
1105
1106 default:
1107 assert(type != ElementType::UNDEFINED);
1108
1109 return ReferenceElementInfo::getInfo(type).dimension;
1110
1111 }
1112}
1113
1119int Element::getDimension() const
1120{
1121 return getDimension(m_type);
1122}
1123
1131bool Element::isThreeDimensional(ElementType type)
1132{
1133 return (getDimension(type) == 3);
1134}
1135
1142bool Element::isThreeDimensional() const
1143{
1144 return (getDimension() == 3);
1145}
1146
1152int Element::getVertexCount() const
1153{
1154 switch (m_type) {
1155
1156 case (ElementType::POLYGON):
1157 {
1158 return countPolygonVertices(getConnect());
1159 }
1160
1161 case (ElementType::POLYHEDRON):
1162 {
1163 return getVertexIds().size();
1164 }
1165
1166 default:
1167 {
1168 assert(m_type != ElementType::UNDEFINED);
1169
1170 return getInfo().nVertices;
1171 }
1172
1173 }
1174}
1175
1181ConstProxyVector<long> Element::getVertexIds() const
1182{
1183 return getVertexIds(m_type, getConnect());
1184}
1185
1193ConstProxyVector<long> Element::getVertexIds(ElementType type, const long *connectivity)
1194{
1195 switch (type) {
1196
1197 case (ElementType::POLYGON):
1198 {
1199 return ConstProxyVector<long>(connectivity + 1, countPolygonVertices(connectivity));
1200 }
1201
1202 case (ElementType::POLYHEDRON):
1203 {
1204 int nFaces = countPolyhedronFaces(connectivity);
1205
1206 // Identify unique vertices
1207 //
1208 // We need to keep track of the order in which unique vertices are
1209 // identified (i.e., the order in which the vertices first appear in
1210 // the face stream), because the list of vertex ids should be filled
1211 // using the same order. This guarantees that vertices will be sorted
1212 // in the same order regardless of the id of the vertices. In this way
1213 // given an element, the list of its vertices generated by different
1214 // processes will iterate the vertices in the same order.
1215 std::unordered_map<long, std::size_t> uniqueVertexIds;
1216 for (int i = 0; i < nFaces; ++i) {
1217 int facePos = getFaceStreamPosition(connectivity, i);
1218
1219 int beginVertexPos = facePos + 1;
1220 int endVertexPos = facePos + 1 + connectivity[facePos];
1221 for (int vertexPos = beginVertexPos; vertexPos < endVertexPos; ++vertexPos) {
1222 long vertexId = connectivity[vertexPos];
1223 if (uniqueVertexIds.count(vertexId) != 0) {
1224 continue;
1225 }
1226
1227 std::size_t vertexSortIndex = uniqueVertexIds.size();
1228 uniqueVertexIds.insert({vertexId, vertexSortIndex});
1229 }
1230 }
1231
1232 // Fill list of element's vertices
1233 //
1234 // The list of unique vertices should contain the vertices sorted in
1235 // the same order they first appear in the face stream.
1236 std::size_t nVertices = uniqueVertexIds.size();
1237
1239 ConstProxyVector<long>::storage_pointer vertexIdsStorage = vertexIds.storedData();
1240 for (const auto &vertexEntry : uniqueVertexIds) {
1241 long vertexId = vertexEntry.first;
1242 std::size_t vertexSortIndex = vertexEntry.second;
1243 vertexIdsStorage[vertexSortIndex] = vertexId;
1244 }
1245
1246 return vertexIds;
1247 }
1248
1249 default:
1250 {
1251 assert(type != ElementType::UNDEFINED);
1252
1253 return ConstProxyVector<long>(connectivity, ReferenceElementInfo::getInfo(type).nVertices);
1254 }
1255
1256 }
1257}
1258
1269long Element::getVertexId(int vertex) const
1270{
1271 switch (m_type) {
1272
1273 case (ElementType::POLYGON):
1274 case (ElementType::POLYHEDRON):
1275 {
1276 ConstProxyVector<long> vertexIds = getVertexIds();
1277
1278 return vertexIds[vertex];
1279 }
1280
1281 default:
1282 {
1283 assert(m_type != ElementType::UNDEFINED);
1284
1285 const long *connectivity = getConnect();
1286
1287 return connectivity[vertex];
1288 }
1289
1290 }
1291}
1292
1302int Element::findVertex(long vertexId) const
1303{
1304 ConstProxyVector<long> cellVertexIds = getVertexIds();
1305
1306 auto localVertexItr = std::find(cellVertexIds.begin(), cellVertexIds.end(), vertexId);
1307 if (localVertexItr == cellVertexIds.end()) {
1308 return -1;
1309 }
1310
1311 return static_cast<int>(std::distance(cellVertexIds.begin(), localVertexItr));
1312}
1313
1320ConstProxyVector<long> Element::getFaceVertexIds(int face) const
1321{
1322 ConstProxyVector<long> vertexIds = getFaceConnect(face);
1323 if (m_type == ElementType::POLYHEDRON) {
1324 ElementType faceType = getFaceType(face);
1325 if (faceType == ElementType::POLYGON) {
1326 assert(!vertexIds.storedData());
1327 vertexIds.set(vertexIds.data() + 1, vertexIds.size() - 1);
1328 }
1329 }
1330
1331 return vertexIds;
1332}
1333
1343long Element::getFaceVertexId(int face, int vertex) const
1344{
1345 switch (m_type) {
1346
1347 case (ElementType::POLYGON):
1348 case (ElementType::POLYHEDRON):
1349 {
1350 ConstProxyVector<long> faceVertexIds = getFaceVertexIds(face);
1351
1352 return faceVertexIds[vertex];
1353 }
1354
1355 default:
1356 {
1357 ConstProxyVector<long> cellVertexIds = getVertexIds();
1358 ConstProxyVector<int> faceLocalVertexIds = getFaceLocalVertexIds(face);
1359
1360 return cellVertexIds[faceLocalVertexIds[vertex]];
1361 }
1362
1363 }
1364}
1365
1372ConstProxyVector<int> Element::getFaceLocalVertexIds(int face) const
1373{
1374 switch (m_type) {
1375
1376 case (ElementType::POLYHEDRON):
1377 {
1378 ElementType faceType = getFaceType(face);
1379 if (faceType != ElementType::POLYGON) {
1380 return getFaceLocalConnect(face);
1381 }
1382
1383 ConstProxyVector<int> faceLocalConnect = getFaceLocalConnect(face);
1384 std::size_t faceLocalConnectSize = faceLocalConnect.size();
1385
1386 std::size_t nFaceVertices = faceLocalConnectSize - 1;
1387 ConstProxyVector<int> faceLocalVertexIds(ConstProxyVector<int>::INTERNAL_STORAGE, nFaceVertices);
1388 ConstProxyVector<int>::storage_pointer faceLocalVertexIdsStorage = faceLocalVertexIds.storedData();
1389 for (std::size_t i = 0; i < nFaceVertices; ++i) {
1390 faceLocalVertexIdsStorage[i] = faceLocalConnect[i + 1];
1391 }
1392
1393 return faceLocalVertexIds;
1394 }
1395
1396 default:
1397 {
1398 return getFaceLocalConnect(face);
1399 }
1400
1401 }
1402}
1403
1410ConstProxyVector<long> Element::getEdgeVertexIds(int edge) const
1411{
1412 return getEdgeConnect(edge);
1413}
1414
1424long Element::getEdgeVertexId(int edge, int vertex) const
1425{
1426 ConstProxyVector<long> edgeVertexIds = getEdgeVertexIds(edge);
1427
1428 return edgeVertexIds[vertex];
1429}
1430
1437ConstProxyVector<int> Element::getEdgeLocalVertexIds(int edge) const
1438{
1439 return getEdgeLocalConnect(edge);
1440}
1441
1451int Element::renumberVertices(const std::unordered_map<long, long> &map)
1452{
1453 int nRenumberedVertices = 0;
1454 switch (m_type) {
1455
1456 case ElementType::POLYGON:
1457 {
1458 int nVertices = getVertexCount();
1459 long *connectivity = getConnect();
1460 for (int k = 1; k < nVertices + 1; ++k) {
1461 auto mapItr = map.find(connectivity[k]);
1462 if (mapItr != map.end()) {
1463 connectivity[k] = mapItr->second;
1464 ++nRenumberedVertices;
1465 }
1466 }
1467
1468 break;
1469 }
1470
1471 case ElementType::POLYHEDRON:
1472 {
1473 int nFaces = getFaceCount();
1474 long *connectivity = getConnect();
1475
1476 for (int i = 0; i < nFaces; ++i) {
1477 int facePos = getFaceStreamPosition(connectivity, i);
1478
1479 int beginVertexPos = facePos + 1;
1480 int endVertexPos = facePos + 1 + connectivity[facePos];
1481 for (int k = beginVertexPos; k < endVertexPos; ++k) {
1482 auto mapItr = map.find(connectivity[k]);
1483 if (mapItr != map.end()) {
1484 connectivity[k] = mapItr->second;
1485 ++nRenumberedVertices;
1486 }
1487 }
1488 }
1489
1490 break;
1491 }
1492
1493 default:
1494 {
1495 assert(m_type != ElementType::UNDEFINED);
1496
1497 int nVertices = getVertexCount();
1498 long *connectivity = getConnect();
1499 for (int k = 0; k < nVertices; ++k) {
1500 auto mapItr = map.find(connectivity[k]);
1501 if (mapItr != map.end()) {
1502 connectivity[k] = mapItr->second;
1503 ++nRenumberedVertices;
1504 }
1505 }
1506
1507 break;
1508 }
1509
1510 }
1511
1512 return nRenumberedVertices;
1513}
1514
1521std::array<double, 3> Element::evalCentroid(const std::array<double, 3> *coordinates) const
1522{
1523 int nVertices = getVertexCount();
1524 if (nVertices == 0) {
1525 return {{0., 0., 0.}};
1526 }
1527
1528 std::array<double, 3> centroid = coordinates[0];
1529 for (int i = 1; i < nVertices; ++i) {
1530 const std::array<double, 3> &vertexCoordinates = coordinates[i];
1531 for (int k = 0; k < 3; ++k) {
1532 centroid[k] += vertexCoordinates[k];
1533 }
1534 }
1535
1536 for (int k = 0; k < 3; ++k) {
1537 centroid[k] /= nVertices;
1538 }
1539
1540 return centroid;
1541}
1542
1549double Element::evalSize(const std::array<double, 3> *coordinates) const
1550{
1551 switch (m_type) {
1552
1553 case ElementType::POLYHEDRON:
1554 {
1555 // The characteristics size of a polyhedron is evaluated as the
1556 // volume divided by the area of the largest face.
1557 int nFaces = getFaceCount();
1558 BITPIT_CREATE_WORKSPACE(faceVertexCoords, std::array<double BITPIT_COMMA 3>, getVertexCount(), ReferenceElementInfo::MAX_ELEM_VERTICES);
1559
1560 double volume = evalVolume(coordinates);
1561
1562 double faceMaxArea = 0;
1563 for (int face = 0; face < nFaces; ++face) {
1564 ElementType faceType = getFaceType(face);
1565 bool faceHasReferenceInfo = ReferenceElementInfo::hasInfo(faceType);
1566
1567 ConstProxyVector<int> faceLocalVertexIds = getFaceLocalVertexIds(face);
1568 for (int n = 0; n < getFaceVertexCount(face); ++n) {
1569 faceVertexCoords[n] = coordinates[faceLocalVertexIds[n]];
1570 }
1571
1572 double faceArea;
1573 if (faceHasReferenceInfo) {
1574 const Reference2DElementInfo &faceInfo = static_cast<const Reference2DElementInfo &>(ReferenceElementInfo::getInfo(faceType));
1575 faceArea = faceInfo.evalArea(faceVertexCoords);
1576 } else {
1577 ConstProxyVector<long> faceConnect = getFaceConnect(face);
1578 std::size_t faceConnectSize = faceConnect.size();
1579
1580 Element faceElement(0, faceType, faceConnect.size());
1581 long *faceElementConnect = faceElement.getConnect();
1582 for (std::size_t i = 0; i < faceConnectSize; ++i) {
1583 faceElementConnect[i] = faceConnect[i];
1584 }
1585
1586 faceArea = faceElement.evalArea(faceVertexCoords);
1587 }
1588 faceMaxArea = std::max(faceArea, faceMaxArea);
1589 }
1590
1591 double size = volume / faceMaxArea;
1592
1593 return size;
1594 }
1595
1596 case ElementType::POLYGON:
1597 {
1598 // The characteristics size of a polygon is evaluated as the
1599 // area divided by the length of the longest face.
1600 int nFaces = getFaceCount();
1601 BITPIT_CREATE_WORKSPACE(faceVertexCoords, std::array<double BITPIT_COMMA 3>, getVertexCount(), ReferenceElementInfo::MAX_ELEM_VERTICES);
1602
1603 double area = evalArea(coordinates);
1604
1605 double faceMaxLength = 0;
1606 for (int face = 0; face < nFaces; ++face) {
1607 ElementType faceType = getFaceType(face);
1608 assert(ReferenceElementInfo::hasInfo(faceType));
1609
1610 ConstProxyVector<int> faceLocalVertexIds = getFaceLocalVertexIds(face);
1611 for (int n = 0; n < getFaceVertexCount(face); ++n) {
1612 faceVertexCoords[n] = coordinates[faceLocalVertexIds[n]];
1613 }
1614
1615 const Reference1DElementInfo &faceInfo = static_cast<const Reference1DElementInfo &>(ReferenceElementInfo::getInfo(faceType));
1616 faceMaxLength = std::max(faceInfo.evalLength(faceVertexCoords), faceMaxLength);
1617 }
1618
1619 double size = area / faceMaxLength;
1620
1621 return size;
1622 }
1623
1624 case ElementType::UNDEFINED:
1625 {
1626 return 0.;
1627 }
1628
1629 default:
1630 {
1631 const ReferenceElementInfo &referenceInfo = static_cast<const ReferenceElementInfo &>(getInfo());
1632
1633 return referenceInfo.evalSize(coordinates);
1634 }
1635
1636 }
1637}
1638
1639
1646double Element::evalVolume(const std::array<double, 3> *coordinates) const
1647{
1648 switch (m_type) {
1649
1650 case ElementType::POLYHEDRON:
1651 {
1652 Tesselation tesselation = generateTesselation(coordinates);
1653 int nTiles = tesselation.getTileCount();
1654
1655 double volume = 0.;
1656 for (int i = 0; i < nTiles; ++i) {
1657 ElementType tileType = tesselation.getTileType(i);
1658 const std::vector<std::array<double, 3>> tileCoordinates = tesselation.getTileVertexCoordinates(i);
1659 const Reference3DElementInfo &referenceInfo = static_cast<const Reference3DElementInfo &>(ReferenceElementInfo::getInfo(tileType));
1660
1661 volume += referenceInfo.evalVolume(tileCoordinates.data());
1662 }
1663
1664 return volume;
1665 }
1666
1667 default:
1668 {
1669 assert(getDimension() == 3);
1670
1671 const Reference3DElementInfo &referenceInfo = static_cast<const Reference3DElementInfo &>(getInfo());
1672
1673 return referenceInfo.evalVolume(coordinates);
1674 }
1675
1676 }
1677}
1678
1685double Element::evalArea(const std::array<double, 3> *coordinates) const
1686{
1687 switch (m_type) {
1688
1689 case ElementType::POLYGON:
1690 {
1691 Tesselation tesselation = generateTesselation(coordinates);
1692 int nTiles = tesselation.getTileCount();
1693
1694 double area = 0.;
1695 for (int i = 0; i < nTiles; ++i) {
1696 ElementType tileType = tesselation.getTileType(i);
1697 const std::vector<std::array<double, 3>> tileCoordinates = tesselation.getTileVertexCoordinates(i);
1698 const Reference2DElementInfo &referenceInfo = static_cast<const Reference2DElementInfo &>(ReferenceElementInfo::getInfo(tileType));
1699
1700 area += referenceInfo.evalArea(tileCoordinates.data());
1701 }
1702
1703 return area;
1704 }
1705
1706 default:
1707 {
1708 assert(getDimension() == 2);
1709
1710 const Reference2DElementInfo &referenceInfo = static_cast<const Reference2DElementInfo &>(getInfo());
1711
1712 return referenceInfo.evalArea(coordinates);
1713 }
1714
1715 }
1716}
1717
1724double Element::evalLength(const std::array<double, 3> *coordinates) const
1725{
1726 switch (m_type) {
1727
1728 case ElementType::POLYGON:
1729 case ElementType::POLYHEDRON:
1730 case ElementType::UNDEFINED:
1731 {
1732 return 0.;
1733 }
1734
1735 default:
1736 {
1737 assert(getDimension() == 1);
1738
1739 const Reference1DElementInfo &referenceInfo = static_cast<const Reference1DElementInfo &>(getInfo());
1740
1741 return referenceInfo.evalLength(coordinates);
1742 }
1743
1744 }
1745}
1746
1759std::array<double, 3> Element::evalNormal(const std::array<double, 3> *coordinates,
1760 const std::array<double, 3> &orientation,
1761 const std::array<double, 3> &point) const
1762{
1763 switch (m_type) {
1764
1765 case ElementType::POLYGON:
1766 {
1767 // The normal of a polygonal element is evaluated as the weighted average of the
1768 // normals of its tiles. The resulting vector should be normalized in order to
1769 // obtain a versor (because of triangular inequality it is not possible
1770 // to evaluate the weights in order to automatically obtain a versor).
1771 int dimension = getDimension();
1772
1773 Tesselation tesselation = generateTesselation(coordinates);
1774 int nTiles = tesselation.getTileCount();
1775
1776 std::array<double, 3> normal = {{0., 0., 0.}};
1777 for (int i = 0; i < nTiles; ++i) {
1778 ElementType tileType = tesselation.getTileType(i);
1779 const std::vector<std::array<double, 3>> tileCoordinates = tesselation.getTileVertexCoordinates(i);
1780 const Reference2DElementInfo &referenceInfo = static_cast<const Reference2DElementInfo &>(ReferenceElementInfo::getInfo(tileType));
1781
1782 double tileArea = referenceInfo.evalArea(tileCoordinates.data());
1783 std::array<double, 3> tileNormal = {{0., 0., 0.}};
1784 if (dimension == 2) {
1785 tileNormal = referenceInfo.evalNormal(tileCoordinates.data(), point);
1786 } else if (dimension == 1) {
1787 const Reference1DElementInfo &referenceInfo1D = static_cast<const Reference1DElementInfo &>(ReferenceElementInfo::getInfo(tileType));
1788 tileNormal = referenceInfo1D.evalNormal(tileCoordinates.data(), orientation, point);
1789 } else if (dimension == 0) {
1790 tileNormal = orientation;
1791 }
1792
1793 normal += tileArea * tileNormal;
1794 }
1795 normal /= norm2(normal);
1796
1797 return normal;
1798 }
1799
1800 default:
1801 {
1802 assert(getDimension() != 3);
1803
1804 int dimension = getDimension();
1805 if (dimension == 2) {
1806 const Reference2DElementInfo &referenceInfo = static_cast<const Reference2DElementInfo &>(getInfo());
1807
1808 return referenceInfo.evalNormal(coordinates, point);
1809 } else if (dimension == 1) {
1810 const Reference1DElementInfo &referenceInfo = static_cast<const Reference1DElementInfo &>(getInfo());
1811
1812 return referenceInfo.evalNormal(coordinates, orientation, point);
1813 } else {
1814 return orientation;
1815 }
1816 }
1817
1818 }
1819}
1820
1828double Element::evalPointDistance(const std::array<double, 3> &point, const std::array<double, 3> *coordinates) const
1829{
1830 double distance;
1831 std::array<double, 3> projection;
1832 evalPointProjection(point, coordinates, &projection, &distance);
1833
1834 return distance;
1835}
1836
1846void Element::evalPointProjection(const std::array<double, 3> &point, const std::array<double, 3> *coordinates,
1847 std::array<double, 3> *projection, double *distance) const
1848{
1849 switch (m_type) {
1850
1851 case ElementType::POLYGON:
1852 {
1853 int projectionFlag;
1854 *distance = CGElem::distancePointPolygon(point, getVertexCount(), coordinates, *projection, projectionFlag);
1855
1856 break;
1857 }
1858
1859 case ElementType::POLYHEDRON:
1860 {
1861 *distance = std::numeric_limits<double>::max();
1862
1863 int nFaces = getFaceCount();
1864 std::vector<std::array<double, 3>> faceCoordinates;
1865 for (int i = 0; i < nFaces; ++i) {
1866 ElementType faceType = getFaceType(i);
1867 ConstProxyVector<int> faceVertexIds = getFaceLocalVertexIds(i);
1868 int nFaceVertices = faceVertexIds.size();
1869 faceCoordinates.resize(nFaceVertices);
1870 for (int k = 0; k < nFaceVertices; ++k) {
1871 faceCoordinates[k] = coordinates[faceVertexIds[k]];
1872 }
1873
1874 double faceDistance;
1875 std::array<double, 3> faceProjection;
1876 bool faceHasReferenceInfo = ReferenceElementInfo::hasInfo(faceType);
1877 if (faceHasReferenceInfo) {
1878 ReferenceElementInfo::getInfo(faceType).evalPointProjection(point, faceCoordinates.data(), &faceProjection, &faceDistance);
1879 } else {
1880 int faceProjectionFlag;
1881 faceDistance = CGElem::distancePointPolygon(point, nFaceVertices, faceCoordinates.data(), faceProjection, faceProjectionFlag);
1882 }
1883
1884 if (faceDistance < *distance) {
1885 *distance = faceDistance;
1886 *projection = faceProjection;
1887 }
1888 }
1889
1890 break;
1891 }
1892
1893 default:
1894 {
1895 assert(ReferenceElementInfo::hasInfo(m_type));
1896
1897 getInfo().evalPointProjection(point, coordinates, projection, distance);
1898
1899 break;
1900 }
1901
1902 }
1903}
1904
1911Element::Tesselation Element::generateTesselation(const std::array<double, 3> *coordinates) const
1912{
1913 Tesselation tesselation;
1914
1915 // Add the coordinates of the vertices to the tesselation
1916 int nVertices = getVertexCount();
1917 std::vector<int> vertexTesselationIds = tesselation.importVertexCoordinates(coordinates, nVertices);
1918
1919 // Generate the tesselation
1920 ElementType type = getType();
1921 switch(type) {
1922
1923 case ElementType::POLYGON:
1924 {
1925 tesselation.importPolygon(vertexTesselationIds);
1926
1927 break;
1928 }
1929
1930 case ElementType::POLYHEDRON:
1931 {
1932 int nFaces = getFaceCount();
1933 std::vector<std::vector<int>> faceTesselationIds(nFaces);
1934 for (int i = 0; i < nFaces; ++i) {
1935 ConstProxyVector<int> localVertexIds = getFaceLocalVertexIds(i);
1936 int nFaceVertices = localVertexIds.size();
1937 faceTesselationIds[i].resize(nFaceVertices);
1938 for (int k = 0; k < nFaceVertices; ++k) {
1939 faceTesselationIds[i][k] = vertexTesselationIds[localVertexIds[k]];
1940 }
1941 }
1942
1943 tesselation.importPolyhedron(vertexTesselationIds, faceTesselationIds);
1944
1945 break;
1946 }
1947
1948 default:
1949 {
1950 assert(ReferenceElementInfo::hasInfo(type));
1951
1952 tesselation.m_nTiles = 1;
1953 tesselation.m_types.push_back(type);
1954 tesselation.m_connects.push_back(vertexTesselationIds);
1955
1956 break;
1957 }
1958
1959 }
1960
1961 return tesselation;
1962}
1963
1969int Element::getFaceStreamSize() const
1970{
1971 int nFaces = getFaceCount();
1972 int size = 1 + (getFaceStreamPosition(nFaces) - 1);
1973
1974 return size;
1975}
1976
1982std::vector<long> Element::getFaceStream() const
1983{
1984 int nFaces = getFaceCount();
1985 int faceStreamSize = getFaceStreamSize();
1986 std::vector<long> faceStream(faceStreamSize);
1987
1988 int pos = 0;
1989 faceStream[pos] = nFaces;
1990 for (int i = 0; i < nFaces; ++i) {
1991 ConstProxyVector<long> faceVertexIds = getFaceVertexIds(i);
1992 int nFaceVertices = faceVertexIds.size();
1993
1994 ++pos;
1995 faceStream[pos] = getFaceVertexCount(i);
1996 for (int k = 0; k < nFaceVertices; ++k) {
1997 ++pos;
1998 faceStream[pos] = faceVertexIds[k];
1999 }
2000 }
2001
2002 return faceStream;
2003}
2004
2012void Element::renumberFaceStream(const PiercedStorage<long, long> &map, std::vector<long> *faceStream)
2013{
2014 int pos = 0;
2015 int nFaces = (*faceStream)[pos];
2016 for (int i = 0; i < nFaces; ++i) {
2017 ++pos;
2018 int nFaceVertices = (*faceStream)[pos];
2019 for (int k = 0; k < nFaceVertices; ++k) {
2020 ++pos;
2021 auto mapItr = map.find((*faceStream)[pos]);
2022 if (mapItr != map.end()) {
2023 (*faceStream)[pos] = *mapItr;
2024 }
2025 }
2026 }
2027}
2028
2035int Element::getFaceStreamPosition(int face) const
2036{
2037 return getFaceStreamPosition(getConnect(), face);
2038}
2039
2047int Element::getFaceStreamPosition(const long *connectivity, int face)
2048{
2049 int position = 1;
2050 for (int i = 0; i < face; ++i) {
2051 position += 1 + connectivity[position];
2052 }
2053
2054 return position;
2055}
2056
2063int Element::countPolygonVertices(const long *connectivity)
2064{
2065 return connectivity[0];
2066}
2067
2074int Element::countPolygonFaces(const long *connectivity)
2075{
2076 return countPolygonVertices(connectivity);
2077}
2078
2085int Element::countPolyhedronFaces(const long *connectivity)
2086{
2087 return connectivity[0];
2088}
2089
2099std::vector<ConstProxyVector<long>> Element::evalEdgeConnects(int nRequestedEdges) const
2100{
2101 if (nRequestedEdges == -1) {
2102 nRequestedEdges = getEdgeCount();
2103 }
2104 assert(nRequestedEdges <= getEdgeCount());
2105
2106 std::set<std::pair<long, long>> edgeSet;
2107 std::vector<ConstProxyVector<long>> edgeConnectStorage(nRequestedEdges, ConstProxyVector<long>(ConstProxyVector<long>::INTERNAL_STORAGE, 2));
2108
2109 int nFaces = getFaceCount();
2110 for (int i = 0; i < nFaces; ++i) {
2111 ConstProxyVector<long> faceVertexIds = getFaceVertexIds(i);
2112 int nFaceVertices = faceVertexIds.size();
2113 for (int k = 0; k < nFaceVertices; ++k) {
2114 long vertex_A = faceVertexIds[k];
2115 long vertex_B = faceVertexIds[(k + 1) % nFaceVertices];
2116 if (vertex_A > vertex_B) {
2117 std::swap(vertex_A, vertex_B);
2118 }
2119
2120 std::pair<long, long> edgePair = std::pair<long, long>(vertex_A, vertex_B);
2121 std::pair<std::set<std::pair<long, long>>::iterator, bool> insertResult = edgeSet.insert(edgePair);
2122 if (insertResult.second) {
2123 ConstProxyVector<long>::storage_pointer connectStorage = edgeConnectStorage[edgeSet.size() - 1].storedData();
2124 connectStorage[0] = edgePair.first;
2125 connectStorage[1] = edgePair.second;
2126
2127 if (edgeSet.size() == (std::size_t) nRequestedEdges) {
2128 return edgeConnectStorage;
2129 }
2130 }
2131 }
2132 }
2133
2134 assert((int) edgeSet.size() == nRequestedEdges);
2135
2136 return edgeConnectStorage;
2137}
2138
2144unsigned int Element::getBinarySize() const
2145{
2146 unsigned int binarySize = sizeof(m_type) + sizeof(m_id) + getConnectSize() * sizeof(long) + sizeof(m_pid);
2148 binarySize += sizeof(int);
2149 }
2150
2151 return binarySize;
2152}
2153
2154// Explicit instantiation of the Element containers
2155template class PiercedVector<Element>;
2156
2157}
The Tesselation class allows to tessalete polygons and polyhedrons.
The Element class provides an interface for defining elements.
Definition element.hpp:46
double evalArea(const std::array< double, 3 > *coordinates) const
Definition element.cpp:1685
const long * getConnect() const
Definition element.cpp:609
int getConnectSize() const
Definition element.cpp:629
Metafunction for generating a pierced storage.
iterator end() noexcept
iterator find(const id_t &id) noexcept
Metafunction for generating a pierced vector.
Metafunction for generating a list of elements that can be either stored in an external vectror or,...
__PXV_ITERATOR__ begin()
container_type::pointer storage_pointer
std::size_t size() const
__PXV_POINTER__ data() noexcept
__PXV_ITERATOR__ end()
__PXV_STORAGE_POINTER__ storedData() noexcept
void set(__PXV_POINTER__ data, std::size_t size)
The Reference1DElementInfo class allows to define information about reference one-dimensional element...
The Reference2DElementInfo class allows to define information about reference two-dimensional element...
The Reference3DElementInfo class allows to define information about reference three-dimensional eleme...
The ReferenceElementInfo class allows to define information about reference elements.
static bool hasInfo(ElementType type)
double norm2(const std::array< T, d > &x)
#define BITPIT_UNREACHABLE(str)
Definition compiler.hpp:53
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
#define BITPIT_CREATE_WORKSPACE(workspace, item_type, size, stack_size)
Logger & operator<<(Logger &logger, LoggerManipulator< T > &&m)
Definition logger.hpp:367
--- layout: doxygen_footer ---