FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
adaptive_mesh_storage.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include "kernel/util/string.hpp"
9#include "kernel/util/tiny_algebra.hpp"
10#include <kernel/shape.hpp>
12#include <kernel/util/slotmap.hpp>
13
14#include <array>
15#include <cstdint>
16#include <utility>
17
18namespace FEAT::Geometry::Intern
19{
20
31 struct Layer
32 {
35 };
36
38 inline bool operator==(Layer lhs, Layer rhs)
39 {
40 return lhs.idx == rhs.idx;
41 }
42
44 inline bool operator!=(Layer lhs, Layer rhs)
45 {
46 return !(lhs == rhs);
47 }
48
49 inline bool operator<(Layer lhs, Layer rhs)
50 {
51 return lhs.idx < rhs.idx;
52 }
53
54 inline bool operator>(Layer lhs, Layer rhs)
55 {
56 return lhs.idx > rhs.idx;
57 }
58
59 inline bool operator<=(Layer lhs, Layer rhs)
60 {
61 return lhs.idx <= rhs.idx;
62 }
63
64 inline bool operator>=(Layer lhs, Layer rhs)
65 {
66 return lhs.idx >= rhs.idx;
67 }
68
77 template<int n>
79 {
80 ElementKey() = default;
81 ElementKey(std::uint32_t idx, std::uint32_t gen) : index(idx), generation(gen)
82 {
83 }
84
85 ElementKey(const ElementKey& other) = default;
86 ElementKey(ElementKey&& other) = default;
87
88 ElementKey& operator=(const ElementKey& other) = default;
89 ElementKey& operator=(ElementKey&& other) = default;
90
92 std::uint32_t index = 0;
94 std::uint32_t generation = 0;
95
112 bool is_permanent = false;
113 };
114
116 template<int dim_>
117 inline bool operator==(const ElementKey<dim_>& lhs, const ElementKey<dim_>& rhs)
118 {
119 return lhs.index == rhs.index && lhs.generation == rhs.generation && lhs.layer == rhs.layer &&
120 lhs.is_permanent == rhs.is_permanent;
121 }
122
124 template<int dim_>
125 inline bool operator!=(const ElementKey<dim_>& lhs, const ElementKey<dim_>& rhs)
126 {
127 return !(lhs == rhs);
128 }
129
130 template<int dim_>
131 inline std::ostream& operator<<(std::ostream& stream, const ElementKey<dim_> key)
132 {
133 stream
134 << "ElementKey<" << stringify(dim_)
135 << ">{ index = " << stringify(key.index)
136 << ", generation = " << stringify(key.generation)
137 << ", layer = Layer {" << stringify(key.layer.idx)
138 << "}, is_permanent = " << stringify(key.is_permanent) << " }";
139 return stream;
140 }
141
142 using VertexKey = ElementKey<0>;
143 using EdgeKey = ElementKey<1>;
144 using FaceKey = ElementKey<2>;
145 using CellKey = ElementKey<3>;
146
152 template<int n>
154 {
155 OrientedElement() = default;
156 OrientedElement(int o, ElementKey<n> k) : orientation(o), key(k)
157 {
158 }
159
160 int orientation = 0;
162 };
163
166
167 template<int dim_>
168 inline bool operator==(const OrientedElement<dim_>& lhs, const OrientedElement<dim_>& rhs)
169 {
170 return lhs.key == rhs.key && lhs.orientation == rhs.orientation;
171 }
172
173 template<int dim_>
174 inline bool operator!=(const OrientedElement<dim_>& lhs, const OrientedElement<dim_>& rhs)
175 {
176 return !(lhs == rhs);
177 }
178
193 template<typename TemplateSet_, typename Shape_, int dim_ = Shape_::dimension>
194 struct ElementChildren : public ElementChildren<TemplateSet_, Shape_, dim_ - 1>
195 {
197 static constexpr int max_children = TemplateSet_::template max_children<Shape_::dimension, dim_>();
198
200 std::array<Intern::ElementKey<dim_>, max_children> children;
201
202 template<int query_dim_>
203 std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim()
204 {
205 static_assert(query_dim_ <= Shape_::dimension);
206
208 }
209
210 template<int query_dim_>
211 const std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim() const
212 {
213 static_assert(query_dim_ <= Shape_::dimension);
214
216 }
217 };
218
235 template<typename TemplateSet_, typename Shape_>
236 struct ElementChildren<TemplateSet_, Shape_, 0>
237 {
239 static constexpr int max_children = TemplateSet_::template max_children<Shape_::dimension, 0>();
240
242 std::array<Intern::ElementKey<0>, max_children> children;
243
244 template<int query_dim_>
245 std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim()
246 {
247 static_assert(query_dim_ == 0);
248
249 return children;
250 }
251
252 template<int query_dim_>
253 const std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim() const
254 {
255 static_assert(query_dim_ == 0);
256
257 return children;
258 }
259 };
260
269 template<typename Shape_, int dim_ = Shape_::dimension - 1>
270 struct ElementTopology : public ElementTopology<Shape_, dim_ - 1>
271 {
272 static_assert(dim_ >= 0);
273
276
278 std::array<OrientedElement<dim_>, num_entities> entities;
279
280 template<int key_dim_>
281 OrientedElement<key_dim_> key_by_dim(Index idx) const
282 {
283 static_assert(key_dim_ < Shape_::dimension);
285
287 }
288
289 template<int query_dim_>
290 std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim()
291 {
292 static_assert(query_dim_ < Shape_::dimension);
293
295 }
296
297 template<int query_dim_>
298 const std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim() const
299 {
300 static_assert(query_dim_ < Shape_::dimension);
301
303 }
304
305 template<int query_dim_>
306 constexpr int size()
307 {
308 static_assert(query_dim_ <= Shape_::dimension);
309
311 }
312 };
313
314 template<typename Shape_>
315 struct ElementTopology<Shape_, 0>
316 {
319
321 std::array<OrientedElement<0>, num_entities> entities;
322
323 template<int key_dim_>
324 OrientedElement<key_dim_> key_by_dim(Index idx) const
325 {
326 static_assert(key_dim_ == 0);
327 ASSERT(idx < num_entities);
328
329 return entities[idx];
330 }
331
332 template<int query_dim_>
333 std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim()
334 {
335 static_assert(query_dim_ == 0);
336
337 return entities;
338 }
339
340 template<int query_dim_>
341 const std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim() const
342 {
343 static_assert(query_dim_ == 0);
344
345 return entities;
346 }
347
348 template<int query_dim_>
349 constexpr int size()
350 {
351 static_assert(query_dim_ == 0);
352
354 }
355 };
356
364 template<typename TemplateSet_, typename Shape_>
366 {
367 static_assert(Shape_::dimension > 0);
368
369 using TemplateSet = TemplateSet_;
370
371 using RefinementType = typename TemplateSet::template RefinementTypeByDim<Shape_::dimension>;
372
373 AdaptiveElement(RefinementType t, Layer l, const ElementTopology<Shape_> topo) :
374 type(t),
375 layer(l),
376 topology(std::move(topo))
377 {
378 }
379
381 RefinementType type;
386
387 // OPTIMIZATION: We are allocating the space for the maximum number of
388 // children of any template of the template set. We can instead store
389 // children out-of-band in Util::SecondaryMaps with two advantages:
390 // * we do not need to allocate space for children of zero type elements
391 // * improved cache-behaviour when iterating over mesh elements, since most
392 // algorithms do not need the parent-child relations
397
398 static constexpr int num_neighbors = Shape::FaceTraits<Shape_, Shape_::dimension - 1>::count;
399 std::array<Intern::ElementKey<Shape_::dimension>, num_neighbors> neighbors;
400 };
401
409 template<typename VertexType>
411 {
412 AdaptiveVertex(VertexType v, Layer l) : vertex(v), layer(l), last_changed(l)
413 {
414 }
415
417 VertexType vertex;
422
423 // NOTE: last_changed is (so far) exclusively used for the
424 // BPXJacobiPreconditioner. The mesh should probably not directly know that this
425 // property is needed. Maybe introduce something like the PMP property system
426 // that allows dynamically adding data to any mesh entities.
427
430 };
431
445 template<typename TemplateSet_, typename MeshShape_, typename VertexType_, int element_dim_ = MeshShape_::dimension>
446 class MeshLayer : public MeshLayer<TemplateSet_, MeshShape_, VertexType_, element_dim_ - 1>
447 {
448 protected:
450
453
458
463
464 public:
474 template<typename Shape_>
476 {
478 key.is_permanent = true;
479 return key;
480 }
481
491 template<typename Shape_>
493 {
495 key.is_permanent = false;
496 return key;
497 }
498
504 template<int dim_>
506 {
507 if constexpr(dim_ == 0)
508 {
510 }
511 else
512 {
513 if(key.is_permanent)
514 {
516 }
517 else
518 {
520 }
521 }
522 }
523
530 template<int dim_>
532 {
533 if constexpr(dim_ == 0)
534 {
536 }
537 else
538 {
540 }
541 }
542
549 template<int dim_>
551 {
552 if constexpr(dim_ == 0)
553 {
554 return 0;
555 }
556 else
557 {
559 }
560 }
561
563 template<int dim_>
566 {
568 }
569
571 template<int dim_>
574 {
576 }
577
579 template<int dim_>
582 {
584 }
585
587 template<int dim_>
590 {
592 }
593
597 std::size_t bytes() const
598 {
599 return _permanent_entities.bytes() + _transient_entities.bytes() + BaseClass::bytes();
600 }
601
609 template<int dim_>
611 {
612 static_assert(dim_ >= 1);
613 if(key.is_permanent)
614 {
616 }
617 else
618 {
620 }
621 }
622
630 template<int dim_>
632 {
633 static_assert(dim_ >= 1);
634 if(key.is_permanent)
635 {
637 }
638 else
639 {
641 }
642 }
643 };
644
657 template<typename TemplateSet_, typename MeshShape_, typename VertexType_>
658 class MeshLayer<TemplateSet_, MeshShape_, VertexType_, 0>
659 {
660 protected:
663
664 public:
671 {
672 return _vertices.insert(vertex);
673 }
674
681 {
682 _vertices.erase(key);
683 }
684
689 {
690 return _vertices.size();
691 }
692
695 {
696 return _vertices;
697 }
698
701 {
702 return _vertices;
703 }
704
708 std::size_t bytes() const
709 {
710 return _vertices.bytes();
711 }
712
717 {
718 return _vertices[key];
719 }
720
725 {
726 return _vertices[key];
727 }
728 };
729
749 template<typename MeshShape_, typename TemplateSet_, typename VertexType_>
751 {
752 public:
754 using VertexType = VertexType_;
755
756 using CoordType = typename VertexType_::ValueType;
757
759 using TemplateSet = TemplateSet_;
760
762 template<int dim_>
764
766 template<int dim_>
768
770 template<int dim_>
772
774 template<int dim_>
776
778 template<int dim_>
780
783
787 enum class IterationOrder
788 {
789 PreOrder,
790 PostOrder
791 };
792
793 private:
796
797 static constexpr int num_coords = VertexType::n;
798
801
803 std::vector<MeshLayerType> _layers;
804
806 bool _is_indexed = false;
807
809 bool _has_neighbors = false;
810
811 public:
820 template<int dim>
821 typename TemplateSet::template RefinementTypeByDim<dim> type(ElementKey<dim> key)
822 {
823 return (*this)[key].type;
824 }
825
835 template<int dim_>
836 std::array<Index, 4> erase(ElementKey<dim_> key)
837 {
838 ASSERTM(key.layer.idx < _layers.size(), "Trying to erase adaptive mesh element of non-existing layer");
839
840 // Erasing an entity produces a gap in that layers indices. The mesh is
841 // thus no longer correctly indexed.
842 _is_indexed = false;
843 // Erasing an entity (most-likely) removed a neighbor of an element. Neighbors need to be re-determined.
844 _has_neighbors = false;
845
846 std::array<Index, 4> num_erased = {};
847 if constexpr(dim_ > 0)
848 {
849 // NOTE: Different mesh layers are stored separately. Deleting a child
850 // does thus not invalidate the references to the current entity or its
851 // children.
852 auto& entity = (*this)[key];
853 num_erased =
854 _erase_children<typename Shape::FaceTraits<MeshShape_, dim_>::ShapeType, dim_>(entity.type, entity.children);
855 }
856
857 // Actually delete current entity
858 _layers[key.layer.idx].erase(key);
859 num_erased[dim_] += 1;
860
861 return num_erased;
862 }
863
872 {
873 // Adding a new vertex to a layer shifts the indices of all vertices on
874 // further layers. These vertices stored indices are thus wrong, and need
875 // to be recomputed.
876 _is_indexed = false;
877
878 // Add additional mesh layers, if required
879 Layer layer = vertex.layer;
880 _add_mesh_layers(layer.idx);
881
882 // Add vertex
883 VertexKey key = _layers[layer.idx].insert_vertex(vertex);
884 key.layer = layer;
885 return key;
886 }
887
897 {
898 return insert(AdaptiveVertex(vertex, layer));
899 }
900
908 template<typename Shape_>
910 {
911 // Adding an entity might cause the indices of entities on further layers
912 // to be shifted. These entites stored indices are thus wrong and need to
913 // be recomputed.
914 _is_indexed = false;
915 // Neighbors for this new entity need to be determined.
916 _has_neighbors = false;
917
918 // Add additional mesh layers, if required
919 Layer layer = element.layer;
920 _add_mesh_layers(layer.idx);
921
923 bool is_permanent = element.type.is_zero_refinement();
924
925 if(is_permanent)
926 {
927 key = _layers[layer.idx].insert_permanent(element);
928 }
929 else
930 {
931 key = _layers[layer.idx].insert_transient(element);
932 }
933
934 // Add metadata to key
935 key.is_permanent = is_permanent;
936 key.layer = layer;
937
938 return key;
939 }
940
950 {
951 return _layers.size();
952 }
953
970 template<typename VisitorType_, int dim_>
972 ElementKey<dim_> root_key,
973 VisitorType_& visitor,
974 Layer max_depth,
975 IterationOrder order = IterationOrder::PreOrder) const
976 {
977 auto& root = (*this)[root_key];
978
979 // Abort if max_depth is reached
980 if(root.layer > max_depth)
981 {
982 return;
983 }
984
985 // Visit Root
986 if(order == IterationOrder::PreOrder)
987 {
988 visitor(root_key);
989 }
990
991 if constexpr(dim_ > 0)
992 {
993 _walk_subtree_children<typename Shape::FaceTraits<MeshShape_, dim_>::ShapeType>(root, visitor, max_depth);
994 }
995
996 // Visit Root
997 if(order == IterationOrder::PostOrder)
998 {
999 visitor(root_key);
1000 }
1001 }
1002
1018 template<typename VisitorType_>
1019 void walk_tree(VisitorType_& visitor, Layer max_depth, IterationOrder order = IterationOrder::PreOrder) const
1020 {
1021 // There is nothing to iterate over if the mesh has no layers
1022 if(_layers.size() == 0)
1023 {
1024 return;
1025 }
1026
1027 const MeshLayerType& root_layer = _layers[0];
1028
1029 if constexpr(MeshShape_::dimension >= 0)
1030 {
1031 for(auto entry : root_layer.vertices())
1032 {
1033 walk_subtree(entry.key, visitor, max_depth, order);
1034 }
1035 }
1036
1037 if constexpr(MeshShape_::dimension >= 1)
1038 {
1039 for(auto entry : root_layer.template permanent_entities<1>())
1040 {
1041 walk_subtree(entry.key, visitor, max_depth, order);
1042 }
1043 for(auto entry : root_layer.template transient_entities<1>())
1044 {
1045 walk_subtree(entry.key, visitor, max_depth, order);
1046 }
1047 }
1048
1049 if constexpr(MeshShape_::dimension >= 2)
1050 {
1051 for(auto entry : root_layer.template permanent_entities<2>())
1052 {
1053 walk_subtree(entry.key, visitor, max_depth, order);
1054 }
1055 for(auto entry : root_layer.template transient_entities<2>())
1056 {
1057 walk_subtree(entry.key, visitor, max_depth, order);
1058 }
1059 }
1060
1061 if constexpr(MeshShape_::dimension >= 3)
1062 {
1063 for(auto entry : root_layer.template permanent_entities<3>())
1064 {
1065 walk_subtree(entry.key, visitor, max_depth, order);
1066 }
1067 for(auto entry : root_layer.template transient_entities<3>())
1068 {
1069 walk_subtree(entry.key, visitor, max_depth, order);
1070 }
1071 }
1072 }
1073
1082 Index num_entities(Layer layer, int dim) const
1083 {
1084 if(dim == 0)
1085 {
1086 return _num_entities<0>(layer);
1087 }
1088 if(dim == 1)
1089 {
1090 return _num_entities<1>(layer);
1091 }
1092 if(dim == 2)
1093 {
1094 return _num_entities<2>(layer);
1095 }
1096 if(dim == 3)
1097 {
1098 return _num_entities<3>(layer);
1099 }
1100 XABORTM("unsupported dimension in MeshStorage::num_entities");
1101 }
1102
1110 template<int dim_>
1112 {
1113 Index result = 0;
1114 for(auto& layer : _layers)
1115 {
1116 result += layer.template num_permanent_entities<dim_>();
1117 result += layer.template num_transient_entities<dim_>();
1118 }
1119
1120 return result;
1121 }
1122
1127 {
1128 static constexpr int shape_dim = MeshShape_::dimension;
1129 static constexpr int num_facets = Shape::FaceTraits<MeshShape_, shape_dim - 1>::count;
1130
1131 // OPTIMIZATION: This is the ConformalMesh::fill_neighbors() algorithm
1132 // ported to adaptive mesh keys. This information can be retrieved more
1133 // cheaply from the refinement templates themselves. Add this capability to
1134 // the template query (maybe optionally, with a boolean indicating support
1135 // on the template set), support it in the AdaptiveMesh code, and don't
1136 // invalidate neighbors when adding elements here if the template provide
1137 // neighbor information.
1138 // This method can then be left as a fallback.
1139
1140 if(_has_neighbors)
1141 {
1142 // Neighbors have already been determined since the last adaptation of
1143 // the mesh. No work to be done.
1144 return;
1145 }
1146
1147 // In the following we are calling mesh entities of dimension shape_dim - 1 facets.
1148 // We are using the fact that each facet is shared by at most 2 elements.
1149 // We are goint to first determine which elements are adjacent to each
1150 // facet, by iterating over the elements and adding their keys to the
1151 // facet_neighbors of each of their facets. Then we can iterate over the
1152 // elements a second time and determine their neighbors as the element
1153 // registered for the facet, that is not itself.
1154
1155 // Map of facet neighbors
1157 facet_neighbors;
1158
1159 // Register element with their adjacent facets. Fills the facet_neighbors map.
1160 auto determine_facet_neighbors = [&](Layer layer, auto slotmap_entry)
1161 {
1162 // Iterate over all facets
1163 for(int facet_idx = 0; facet_idx < num_facets; facet_idx++)
1164 {
1165 // Retrieve key of facet
1166 auto key = slotmap_entry.value.topology.template key_by_dim<shape_dim - 1>(facet_idx).key;
1167
1168 // Init secondary map, if this is the first time we see this facet
1169 if(!facet_neighbors.contains_key(key))
1170 {
1171 facet_neighbors.insert(key, {neighbor_sentinel, neighbor_sentinel});
1172 }
1173
1174 auto& neighbors = facet_neighbors[key];
1175
1176 // HACK: We have to recreate the "full" element key here.
1177 // The keys returned by the SlotMap iterators do not contain the
1178 // layer and permanency information we have added to the usual
1179 // slotmap data.
1180 // The proper way to this is to wrap the iterators in the MeshLayer
1181 // class and add this information there. As this is currently the
1182 // only place where we directly iterate over all elements of a layer
1183 // via the iterators, I am leaving that boilerplate out for now.
1184 ElementKey<shape_dim> element_key = slotmap_entry.key;
1185 element_key.layer = layer;
1186 element_key.is_permanent = slotmap_entry.value.type.is_zero_refinement();
1187
1188 if(neighbors[0] == neighbor_sentinel)
1189 {
1190 neighbors[0] = element_key;
1191 }
1192 else if(neighbors[1] == neighbor_sentinel)
1193 {
1194 neighbors[1] = element_key;
1195 }
1196 else
1197 {
1198 XABORTM("Facet has more than two neighbors!");
1199 }
1200 }
1201 };
1202
1203 // Determine neighbors by looking at registered facet neighbors.
1204 auto determine_neighbors = [&](Layer layer, auto slotmap_entry)
1205 {
1206 auto& element = slotmap_entry.value;
1207
1208 // Iterate over all facets
1209 for(int facet_idx = 0; facet_idx < num_facets; facet_idx++)
1210 {
1211 // Retrieve key of facet
1212 auto key = slotmap_entry.value.topology.template key_by_dim<shape_dim - 1>(facet_idx).key;
1213
1214 // HACK: We have to recreate the "full" element key here.
1215 // The keys returned by the SlotMap iterators do not contain the
1216 // layer and permanency information we have added to the usual
1217 // slotmap data.
1218 // The proper way to this is to wrap the iterators in the MeshLayer
1219 // class and add this information there. As this is currently the
1220 // only place where we directly iterate over all elements of a layer
1221 // via the iterators, I am leaving that boilerplate out for now.
1222 ElementKey<shape_dim> element_key = slotmap_entry.key;
1223 element_key.layer = layer;
1224 element_key.is_permanent = slotmap_entry.value.type.is_zero_refinement();
1225
1226 // Neighbor is the entity that is not the current entity
1227 auto& candidates = facet_neighbors[key];
1228 if(candidates[0] == element_key)
1229 {
1230 element.neighbors[facet_idx] = candidates[1];
1231 }
1232 else if(candidates[1] == element_key)
1233 {
1234 element.neighbors[facet_idx] = candidates[0];
1235 }
1236 }
1237 };
1238
1239 // Find elements adjacent to all facets
1240 for(Index i(0); i < _layers.size(); i++)
1241 {
1242 for(auto entry : _layers[i].template permanent_entities<shape_dim>())
1243 {
1244 determine_facet_neighbors(Layer{i}, entry);
1245 }
1246 for(auto entry : _layers[i].template transient_entities<shape_dim>())
1247 {
1248 determine_facet_neighbors(Layer{i}, entry);
1249 }
1250 }
1251
1252 for(Index i(0); i < _layers.size(); i++)
1253 {
1254 for(auto entry : _layers[i].template permanent_entities<shape_dim>())
1255 {
1256 determine_neighbors(Layer{i}, entry);
1257 }
1258 for(auto entry : _layers[i].template transient_entities<shape_dim>())
1259 {
1260 determine_neighbors(Layer{i}, entry);
1261 }
1262 }
1263
1264 _has_neighbors = true;
1265 }
1266
1295 void transform(const VertexType& origin, const VertexType& angles, const VertexType& offset)
1296 {
1297 // create rotation matrix
1299 _aux_rot_mat(rot, angles);
1300
1301 // transform all vertices
1302 for(auto& layer : _layers)
1303 {
1304 for(auto entry : layer.vertices())
1305 {
1306 entry.value.set_mat_vec_mul(rot, entry.value - origin) += offset;
1307 }
1308 }
1309 }
1310
1317 void reindex()
1318 {
1319 // NOTE: The index-schema works as follows. On each layer of the mesh,
1320 // first the permanent entities get assigned indices, then the transient
1321 // entities get assigned indices. Indices are assigned in order,
1322 // starting on each layer with the index one beyond the last index of the
1323 // previous layers permanent indices. In other words, the transient
1324 // indices of each layer get reused by the next layer. This is fine,
1325 // because transient entities are replaced with their children on the
1326 // next layer and thus no longer require an index.
1327 //
1328 // Visually the indeces are thus staggered like this:
1329 //
1330 // L0: |-- Perm. Indices 0 --|---- Trans. Indices 0 ----|
1331 // L1: |-- Perm. Indices 0 --|-- Perm. Indices 1 --|- Trans. Indices 1 -|
1332 // L2: |-- Perm. Indices 0 --|-- Perm. Indices 1 --|---- Perm. Indices 2 ----|-- Trans. Indices 2 --|
1333
1334 Index next_vertex_index = 0;
1335 Index next_edge_index = 0;
1336 Index next_face_index = 0;
1337 Index next_cell_index = 0;
1338
1339 for(auto& layer : _layers)
1340 {
1341 if constexpr(MeshShape_::dimension >= 0)
1342 {
1343 // There are only permanent vertices. We can just index them without
1344 // having to worry about transient indices.
1345 for(auto entry : layer.vertices())
1346 {
1347 entry.value.index = next_vertex_index++;
1348 }
1349 }
1350
1351 if constexpr(MeshShape_::dimension >= 1)
1352 {
1353 _index_layer<1>(layer, next_edge_index);
1354 }
1355
1356 if constexpr(MeshShape_::dimension >= 2)
1357 {
1358 _index_layer<2>(layer, next_face_index);
1359 }
1360
1361 if constexpr(MeshShape_::dimension >= 3)
1362 {
1363 _index_layer<3>(layer, next_cell_index);
1364 }
1365 }
1366
1367 // Mesh is freshly indexed, by definition
1368 _is_indexed = true;
1369 }
1370
1372 // Index-based Accessors
1374
1386 {
1387 ASSERTM(layer.idx < _layers.size(), "Trying to retrieve vertex of non-existing mesh layer!");
1388
1389 // NOTE: We require the storage to be indexed, despite not making use of
1390 // the index member of any mesh element. This is so that, given a
1391 // ElementKey k pointing to a vertex v with index i on layer l, it is
1392 // impossible that get_index(k) != i or get_vertex_by_index(l, i) != v
1394
1395 // OPTIMIZATION: This is a O(num_layers) search for the right index
1396 // range. We can optimize this slightly by precomputing the index range
1397 // for each layer, eliminating the subtraction of the current idx. We
1398 // can then optimize this to O(log num_layers) by building a search tree.
1399 // And finally we can optimize the average case by caching the
1400 // index-range of the last access in a thread-local variable, allowing
1401 // linear iteration in O(1).
1402
1403 // Search through permanent edges of previous and current layer
1404 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1405 {
1406 const MeshLayerType& current_layer = _layers[layer_idx];
1407
1408 if(idx < current_layer.num_vertices())
1409 {
1410 return current_layer.vertices().data()[idx];
1411 }
1412 idx -= current_layer.num_vertices();
1413 }
1414
1415 XABORTM("Tried retrieving non-existent vertex index from AdaptiveMeshStorage!");
1416 }
1417
1429 {
1430 // Reuse const accessor by casting this to const and then removing const from the return value
1431 // SAFE: Casting to const is always fine
1432 // SAFE: Removing const is fine because this method was called on a non const value to begin with
1433 return const_cast<AdaptiveVertexType&>(std::as_const(*this).get_vertex_by_index(layer, idx));
1434 }
1435
1447 template<int dim_>
1449 {
1450 ASSERTM(layer.idx < _layers.size(), "Trying to retrieve entity of non-existing mesh layer!");
1451
1452 // NOTE: We require the storage to be indexed, despite not making use of
1453 // the index member of any mesh element. This is so that, given a
1454 // ElementKey k pointing to a mesh element e with index i on layer l, it is
1455 // impossible that get_index(k) != i or get_by_index(l, i) != e
1457
1458 // Search through permanent edges of previous and current layer
1459 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1460 {
1461 const MeshLayerType& current_layer = _layers[layer_idx];
1462
1463 if(idx < current_layer.template num_permanent_entities<dim_>())
1464 {
1465 return current_layer.template permanent_entities<dim_>().data()[idx];
1466 }
1467 idx -= current_layer.template num_permanent_entities<dim_>();
1468 }
1469
1470 const MeshLayerType& current_layer = _layers[layer.idx];
1471 if(idx < current_layer.template num_transient_entities<dim_>())
1472 {
1473 return current_layer.template transient_entities<dim_>().data()[idx];
1474 }
1475
1476 XABORTM("Trying to retrieve non-exisiting element from AdaptiveMeshStorage");
1477 }
1478
1490 template<int dim_>
1492 {
1493 // Reuse const accessor by casting this to const and then removing const from the return value
1494 // SAFE: Casting to const is always fine
1495 // SAFE: Removing const is fine because this method was called on a non const value to begin with
1496 return const_cast<AdaptiveElementByDim<dim_>&>(std::as_const(*this).template get_by_index<dim_>(layer, idx));
1497 }
1498
1504 Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
1505 {
1506 static constexpr int shape_dim = MeshShape_::dimension;
1509
1510 auto& element = get_by_index<shape_dim>(layer, element_idx);
1511 if(element.neighbors[neighbor_idx] != neighbor_sentinel)
1512 {
1513 return get_index(element.neighbors[neighbor_idx]);
1514 }
1515 return ~Index(0);
1516 }
1517
1519 // Key-based Access Operators
1521
1530 template<int dim_>
1532 {
1534 return (*this)[key].index;
1535 }
1536
1545 template<int dim_>
1547 {
1549 return (*this)[oriented_key.key].index;
1550 }
1551
1554 {
1555 ASSERT(key.layer.idx < _layers.size());
1556 return _layers[key.layer.idx].get_vertex(key);
1557 }
1558
1561 {
1562 ASSERT(key.layer.idx < _layers.size());
1563 return _layers[key.layer.idx].get_vertex(key);
1564 }
1565
1567 template<int dim_>
1569 {
1570 ASSERT(key.layer.idx < _layers.size());
1571 return _layers[key.layer.idx].get(key);
1572 }
1573
1575 template<int dim_>
1577 {
1578 ASSERT(key.layer.idx < _layers.size());
1579 return _layers[key.layer.idx].get(key);
1580 }
1581
1583 {
1584 return (*this)[ref.key];
1585 }
1586
1587 const AdaptiveVertexType& operator[](OrientedElement<0> ref) const
1588 {
1589 return (*this)[ref.key];
1590 }
1591
1593 template<int dim_>
1595 {
1596 return (*this)[ref.key];
1597 }
1598
1599 template<int dim_>
1600 const AdaptiveElementByDim<dim_>& operator[](OrientedElement<dim_> ref) const
1601 {
1602 return (*this)[ref.key];
1603 }
1604
1608 std::size_t bytes() const
1609 {
1610 std::size_t total = 0;
1611 for(auto& layer : _layers)
1612 {
1613 total += layer.bytes();
1614 }
1615 return total;
1616 }
1617
1618 private:
1627 template<int dim_>
1629 {
1630 if constexpr(dim_ > MeshShape_::dimension)
1631 {
1632 return 0;
1633 }
1634 else
1635 {
1636 ASSERT(layer.idx < _layers.size());
1637
1638 Index result = 0;
1639 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1640 {
1641 result += _layers[layer_idx].template num_permanent_entities<dim_>();
1642 }
1643 result += _layers[layer.idx].template num_transient_entities<dim_>();
1644
1645 return result;
1646 }
1647 }
1648
1649 template<typename Shape_, int dim_ = Shape_::dimension>
1650 std::array<Index, 4> _erase_children(
1651 typename TemplateSet::template RefinementTypeByDim<Shape_::dimension> type,
1653 {
1654 if constexpr(dim_ >= 0)
1655 {
1656 auto result = _erase_children<Shape_, dim_ - 1>(type, children);
1657
1658 auto& array = children.template by_dim<dim_>();
1659 for(Index i(0); i < TemplateSet::template num_children<Shape_::dimension, dim_>(type); i++)
1660 {
1661 std::array<Index, 4> num_erased = erase(array[i]);
1662
1663 result[0] += num_erased[0];
1664 result[1] += num_erased[1];
1665 result[2] += num_erased[2];
1666 result[3] += num_erased[3];
1667 }
1668
1669 return result;
1670 }
1671 else
1672 {
1673 return {};
1674 }
1675 }
1676
1677 template<typename Shape_, int dim_ = Shape_::dimension, typename VisitorType>
1678 void _walk_subtree_children(const AdaptiveElement<TemplateSet, Shape_>& root, VisitorType& visitor, Layer max_depth) const
1679 {
1680 if constexpr(dim_ >= 0)
1681 {
1682 _walk_subtree_children<Shape_, dim_ - 1>(root, visitor, max_depth);
1683
1684 const auto& children = root.children.template by_dim<dim_>();
1685 for(Index i = 0; i < TemplateSet::template num_children<Shape_::dimension, dim_>(root.type); i++)
1686 {
1687 walk_subtree(children[i], visitor, max_depth);
1688 }
1689 }
1690 }
1691
1699 void _add_mesh_layers(Index new_top_layer)
1700 {
1701 while(_layers.size() <= new_top_layer)
1702 {
1703 _layers.push_back(MeshLayerType{});
1704 }
1705 }
1706
1715 template<int dim_>
1716 void _index_layer(MeshLayerType& layer, Index& next_permanent_index)
1717 {
1718 // First assign indices to all permanent mesh elements
1719 for(auto entry : layer.template permanent_entities<dim_>())
1720 {
1721 entry.value.index = next_permanent_index++;
1722 }
1723
1724 // Creat a copy of the current next index
1725 Index next_transient_index = next_permanent_index;
1726
1727 // Assign indices to all transient mesh elements, using the copied index
1728 // This causes these indices to be reused on the next layer, where the
1729 // transient elements have been replaced with their children and no longer
1730 // exist
1731 for(auto entry : layer.template transient_entities<dim_>())
1732 {
1733 entry.value.index = next_transient_index++;
1734 }
1735 }
1736
1740 template<int sm_, int sn_, int sv_>
1741 static void _aux_rot_mat(
1743 const Tiny::Vector<CoordType, 1, sv_>& /*unsused*/)
1744 {
1745 r.set_identity();
1746 }
1747
1751 template<int sm_, int sn_, int sv_>
1752 static void _aux_rot_mat(
1755 {
1756 r.set_rotation_2d(a[0]);
1757 }
1758
1762 template<int sm_, int sn_, int sv_>
1763 static void _aux_rot_mat(
1766 {
1767 r.set_rotation_3d(a[0], a[1], a[2]);
1768 }
1769 };
1770} // namespace FEAT::Geometry::Intern
#define ASSERT(expr)
Debug-Assertion macro definition.
Definition: assertion.hpp:229
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
VertexKey insert(const AdaptiveVertexType &vertex)
Insert a vertex into the storage.
void fill_neighbors()
Determines neighboring elements for all mesh elements.
void _index_layer(MeshLayerType &layer, Index &next_permanent_index)
Assigns indexes to all elemens of a layer.
ElementKey< Shape_::dimension > insert(const AdaptiveElement< TemplateSet, Shape_ > &element)
Insert an adaptive element into the storage.
AdaptiveElementByDim< dim_ > & operator[](ElementKey< dim_ > key)
Retrieve element by key.
VertexKey insert(VertexType vertex, Layer layer)
Insert a vertex into the storage.
VertexType_ VertexType
Type of vertices in this mesh.
Index num_total_entities() const
Returns the total number of all mesh elements in the storage.
static void _aux_rot_mat(Tiny::Matrix< CoordType, 3, 3, sm_, sn_ > &r, const Tiny::Vector< CoordType, 3, sv_ > &a)
Helper for transform method.
void transform(const VertexType &origin, const VertexType &angles, const VertexType &offset)
Applies a "proper rigid" transformation onto the mesh vertices.
AdaptiveElementByDim< dim_ > & operator[](OrientedElement< dim_ > ref)
Retrieve element by oriented reference.
AdaptiveElementByDim< dim_ > & get_by_index(Layer layer, Index idx)
Retrieves an element of the mesh by its layer and index.
const AdaptiveVertexType & get_vertex_by_index(Layer layer, Index idx) const
Retrieves a vertex of the mesh by its layer and index.
static void _aux_rot_mat(Tiny::Matrix< CoordType, 2, 2, sm_, sn_ > &r, const Tiny::Vector< CoordType, 2, sv_ > &a)
Helper for transform method.
Index num_entities(Layer layer, int dim) const
Returns the number of mesh elements of the given dimension on the given layer.
std::size_t bytes() const
Returns the number of bytes used by this class.
AdaptiveVertexType & operator[](VertexKey key)
Retrieve vertex by key.
static void _aux_rot_mat(Tiny::Matrix< CoordType, 1, 1, sm_, sn_ > &r, const Tiny::Vector< CoordType, 1, sv_ > &)
Helper for transform method.
Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
Returns the index of the n-th neighbor of the given element.
void walk_tree(VisitorType_ &visitor, Layer max_depth, IterationOrder order=IterationOrder::PreOrder) const
Index get_index(OrientedElement< dim_ > oriented_key) const
Get the numeric mesh index of the element pointed to by key.
void _add_mesh_layers(Index new_top_layer)
Adds additional mesh layers, such that.
const AdaptiveElementByDim< dim_ > & operator[](ElementKey< dim_ > key) const
Retrieve element by key.
static const constexpr ElementKey< MeshShape_::dimension > neighbor_sentinel
Sentinel key for non-existing neighbors, e.g. for boundary elements.
const AdaptiveElementByDim< dim_ > & get_by_index(Layer layer, Index idx) const
Retrieves an element of the mesh by its layer and index.
Index _num_entities(Layer layer) const
Returns the number of mesh elements of the given dimension on the given layer.
Index num_layers() const
Return the number of layers in this mesh.
bool _is_indexed
Indicates whether this mesh has been indexed since the last modification.
TemplateSet_ TemplateSet
Template set to be used for refinement.
std::vector< MeshLayerType > _layers
List of MeshLayers for this mesh.
bool _has_neighbors
Indicates whether neighbors have been calculated for this mesh.
AdaptiveVertex< VertexType > AdaptiveVertexType
Adaptive vertex type.
TemplateSet::template RefinementTypeByDim< dim > type(ElementKey< dim > key)
Get refinement type of element.
void walk_subtree(ElementKey< dim_ > root_key, VisitorType_ &visitor, Layer max_depth, IterationOrder order=IterationOrder::PreOrder) const
const AdaptiveVertexType & operator[](VertexKey key) const
Retrieve vertex by key.
AdaptiveVertexType & get_vertex_by_index(Layer layer, Index idx)
Retrieves a vertex of the mesh by its layer and index.
std::array< Index, 4 > erase(ElementKey< dim_ > key)
Erases an element and all its children from the storage.
Index get_index(ElementKey< dim_ > key) const
Get the numeric mesh index of the element pointed to by key.
Util::SlotMap< AdaptiveVertex< VertexType_ >, ElementKey< 0 > > _vertices
SlotMap for this layers vertices.
ElementKey< 0 > insert_vertex(const AdaptiveVertex< VertexType_ > &vertex)
Insert a vertex into this layer.
AdaptiveVertex< VertexType_ > & get_vertex(ElementKey< 0 > key)
Retrieve a reference to the AdaptiveVertex pointed to by key.
Util::SlotMap< AdaptiveVertex< VertexType_ >, ElementKey< 0 > > & vertices()
Vertex SlotMap accessor.
const Util::SlotMap< AdaptiveVertex< VertexType_ >, ElementKey< 0 > > & vertices() const
Vertex SlotMap accessor.
const AdaptiveVertex< VertexType_ > & get_vertex(ElementKey< 0 > key) const
Retrieve a reference to the AdaptiveVertex pointed to by key.
Index num_vertices() const
Returns the number of vertices in this layer.
std::size_t bytes() const
Returns the number of bytes used by this layer.
Storage class for a single layer of the adaptive mesh.
Util::SlotMap< AdaptiveElementType, ElementKeyType > _permanent_entities
Slotmap for permanent mesh elements.
Index num_permanent_entities() const
Get number of permanent entities of dimension dim_ in this layer.
Index num_transient_entities() const
Get number of transient entities of dimension dim_ in this layer.
ElementKey< Shape_::dimension > insert_transient(const AdaptiveElement< TemplateSet_, Shape_ > &element)
Insert a transient element into this layer.
std::size_t bytes() const
Returns number of bytes used by this layer.
AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType > & get(ElementKey< dim_ > key)
Retrieve the AdaptiveElement belonging to the given key.
const AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType > & get(ElementKey< dim_ > key) const
Retrieve the AdaptiveElement belonging to the given key.
typename Shape::FaceTraits< MeshShape_, element_dim_ >::ShapeType ShapeType
Shape type of entities stored in this layer of dimension element_dim_.
const Util::SlotMap< AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType >, ElementKey< dim_ > > & transient_entities() const
Transient element SlotMap accessor.
void erase(ElementKey< dim_ > key)
Erase an element from this layer.
Util::SlotMap< AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType >, ElementKey< dim_ > > & permanent_entities()
Permanent element SlotMap accessor.
Util::SlotMap< AdaptiveElementType, ElementKeyType > _transient_entities
Slotmap for transient mesh elements.
ElementKey< Shape_::dimension > insert_permanent(const AdaptiveElement< TemplateSet_, Shape_ > &element)
Insert a permanent element into this layer.
const Util::SlotMap< AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType >, ElementKey< dim_ > > & permanent_entities() const
Permanent element SlotMap accessor.
Util::SlotMap< AdaptiveElement< TemplateSet_, typename Shape::FaceTraits< MeshShape_, dim_ >::ShapeType >, ElementKey< dim_ > > & transient_entities()
Transient element SlotMap accessor.
Tiny Matrix class template.
CUDA_HOST_DEVICE Matrix & set_rotation_3d(T_ yaw, T_ pitch, T_ roll)
Sets this matrix to a 3D yaw-pitch-roll rotation matrix.
CUDA_HOST_DEVICE Matrix & set_rotation_2d(T_ angle)
Sets this matrix to a 2D rotation matrix.
CUDA_HOST_DEVICE Matrix & set_identity()
Sets this matrix to the identity matrix.
Tiny Vector class template.
High-performance associative container.
Definition: slotmap.hpp:149
Key insert(V &&value)
Insert value into the SlotMap.
Definition: slotmap.hpp:171
void erase(const Key &key)
Remove a key from the SlotMap.
Definition: slotmap.hpp:249
Index size() const
Retrieve current size of the SlotMap.
Definition: slotmap.hpp:384
@ other
generic/other permutation strategy
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.
ElementChildren< TemplateSet_, Shape_ > children
Child element references.
RefinementType type
The elements refinement type.
ElementTopology< Shape_ > topology
Surrounding element references.
Layer last_changed
Depth the vertex was last used as a parent vertex.
Index index
This elements index in the mesh layers it is a part of.
Layer layer
This elements depth in the refinement tree.
std::array< Intern::ElementKey< 0 >, max_children > children
Children of dimension 0.
static constexpr int max_children
Maximum number of children of dimension dim_.
std::array< Intern::ElementKey< dim_ >, max_children > children
Children of dimension dim_.
SlotMap key for use by the AdaptiveMeshStorage class.
std::uint32_t index
Index into the SlotMaps' slots. See SlotMapKey for details.
std::uint32_t generation
Generation of this key. See SlotMapKey for details.
std::array< OrientedElement< 0 >, num_entities > entities
Surrounding entities at dimension dim_.
Surrounding elements of a mesh element.
static constexpr int num_entities
Number of surrounding elements at dimension dim_.
std::array< OrientedElement< dim_ >, num_entities > entities
Surrounding entities at dimension dim_.
Newtype wrapper for mesh layers.
Orientation-aware reference to another mesh element.
Face traits tag struct template.
Definition: shape.hpp:106