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 <iostream>
11#include <kernel/shape.hpp>
13#include <kernel/util/slotmap.hpp>
14
15#include <array>
16#include <cstdint>
17#include <utility>
18
19namespace FEAT::Geometry::Intern
20{
21
32 struct Layer
33 {
36 };
37
39 inline bool operator==(Layer lhs, Layer rhs)
40 {
41 return lhs.idx == rhs.idx;
42 }
43
45 inline bool operator!=(Layer lhs, Layer rhs)
46 {
47 return !(lhs == rhs);
48 }
49
50 inline bool operator<(Layer lhs, Layer rhs)
51 {
52 return lhs.idx < rhs.idx;
53 }
54
55 inline bool operator>(Layer lhs, Layer rhs)
56 {
57 return lhs.idx > rhs.idx;
58 }
59
60 inline bool operator<=(Layer lhs, Layer rhs)
61 {
62 return lhs.idx <= rhs.idx;
63 }
64
65 inline bool operator>=(Layer lhs, Layer rhs)
66 {
67 return lhs.idx >= rhs.idx;
68 }
69
78 template<int n>
80 {
81 ElementKey() = default;
82 ElementKey(std::uint32_t idx, std::uint32_t gen) : index(idx), generation(gen)
83 {
84 }
85
86 ElementKey(const ElementKey& other) = default;
87 ElementKey(ElementKey&& other) = default;
88
89 ElementKey& operator=(const ElementKey& other) = default;
90 ElementKey& operator=(ElementKey&& other) = default;
91
93 std::uint32_t index = 0;
95 std::uint32_t generation = 0;
96
113 bool is_permanent = false;
114 };
115
117 template<int dim_>
118 inline bool operator==(const ElementKey<dim_>& lhs, const ElementKey<dim_>& rhs)
119 {
120 return lhs.index == rhs.index && lhs.generation == rhs.generation && lhs.layer == rhs.layer &&
121 lhs.is_permanent == rhs.is_permanent;
122 }
123
125 template<int dim_>
126 inline bool operator!=(const ElementKey<dim_>& lhs, const ElementKey<dim_>& rhs)
127 {
128 return !(lhs == rhs);
129 }
130
131 template<int dim_>
132 inline std::ostream& operator<<(std::ostream& stream, const ElementKey<dim_> key)
133 {
134 stream
135 << "ElementKey<" << stringify(dim_)
136 << ">{ index = " << stringify(key.index)
137 << ", generation = " << stringify(key.generation)
138 << ", layer = Layer {" << stringify(key.layer.idx)
139 << "}, is_permanent = " << stringify(key.is_permanent) << " }";
140 return stream;
141 }
142
143 using VertexKey = ElementKey<0>;
144 using EdgeKey = ElementKey<1>;
145 using FaceKey = ElementKey<2>;
146 using CellKey = ElementKey<3>;
147
153 template<int n>
155 {
156 OrientedElement() = default;
157 OrientedElement(int o, ElementKey<n> k) : orientation(o), key(k)
158 {
159 }
160
161 int orientation = 0;
163 };
164
167
168 template<int dim_>
169 inline bool operator==(const OrientedElement<dim_>& lhs, const OrientedElement<dim_>& rhs)
170 {
171 return lhs.key == rhs.key && lhs.orientation == rhs.orientation;
172 }
173
174 template<int dim_>
175 inline bool operator!=(const OrientedElement<dim_>& lhs, const OrientedElement<dim_>& rhs)
176 {
177 return !(lhs == rhs);
178 }
179
194 template<typename TemplateSet_, typename Shape_, int dim_ = Shape_::dimension>
195 struct ElementChildren : public ElementChildren<TemplateSet_, Shape_, dim_ - 1>
196 {
198 static constexpr int max_children = TemplateSet_::template max_children<Shape_::dimension, dim_>();
199
201 std::array<Intern::ElementKey<dim_>, max_children> children;
202
203 template<int query_dim_>
204 std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim()
205 {
206 static_assert(query_dim_ <= Shape_::dimension);
207
209 }
210
211 template<int query_dim_>
212 const std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim() const
213 {
214 static_assert(query_dim_ <= Shape_::dimension);
215
217 }
218 };
219
236 template<typename TemplateSet_, typename Shape_>
237 struct ElementChildren<TemplateSet_, Shape_, 0>
238 {
240 static constexpr int max_children = TemplateSet_::template max_children<Shape_::dimension, 0>();
241
243 std::array<Intern::ElementKey<0>, max_children> children;
244
245 template<int query_dim_>
246 std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim()
247 {
248 static_assert(query_dim_ == 0);
249
250 return children;
251 }
252
253 template<int query_dim_>
254 const std::array<ElementKey<query_dim_>, TemplateSet_::template max_children<Shape_::dimension, query_dim_>()>& by_dim() const
255 {
256 static_assert(query_dim_ == 0);
257
258 return children;
259 }
260 };
261
270 template<typename Shape_, int dim_ = Shape_::dimension - 1>
271 struct ElementTopology : public ElementTopology<Shape_, dim_ - 1>
272 {
273 static_assert(dim_ >= 0);
274
277
279 std::array<OrientedElement<dim_>, num_entities> entities;
280
281 template<int key_dim_>
282 OrientedElement<key_dim_> key_by_dim(int idx) const
283 {
284 static_assert(key_dim_ < Shape_::dimension);
286
287 return ElementTopology<Shape_, key_dim_>::entities[std::size_t(idx)];
288 }
289
290 template<int query_dim_>
291 std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim()
292 {
293 static_assert(query_dim_ < Shape_::dimension);
294
296 }
297
298 template<int query_dim_>
299 const std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim() const
300 {
301 static_assert(query_dim_ < Shape_::dimension);
302
304 }
305
306 template<int query_dim_>
307 constexpr int size()
308 {
309 static_assert(query_dim_ <= Shape_::dimension);
310
312 }
313 };
314
315 template<typename Shape_>
316 struct ElementTopology<Shape_, 0>
317 {
320
322 std::array<OrientedElement<0>, num_entities> entities;
323
324 template<int key_dim_>
325 OrientedElement<key_dim_> key_by_dim(int idx) const
326 {
327 static_assert(key_dim_ == 0);
328 ASSERT(idx < num_entities);
329
330 return entities[std::size_t(idx)];
331 }
332
333 template<int query_dim_>
334 std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim()
335 {
336 static_assert(query_dim_ == 0);
337
338 return entities;
339 }
340
341 template<int query_dim_>
342 const std::array<OrientedElement<query_dim_>, Shape::FaceTraits<Shape_, query_dim_>::count>& by_dim() const
343 {
344 static_assert(query_dim_ == 0);
345
346 return entities;
347 }
348
349 template<int query_dim_>
350 constexpr int size()
351 {
352 static_assert(query_dim_ == 0);
353
355 }
356 };
357
365 template<typename TemplateSet_, typename Shape_>
367 {
368 static_assert(Shape_::dimension > 0);
369
370 using TemplateSet = TemplateSet_;
371
372 using RefinementType = typename TemplateSet::template RefinementTypeByDim<Shape_::dimension>;
373
374 AdaptiveElement(RefinementType t, Layer l, const ElementTopology<Shape_> topo) :
375 type(t),
376 layer(l),
377 topology(std::move(topo))
378 {
379 }
380
382 RefinementType type;
387
388 // OPTIMIZATION: We are allocating the space for the maximum number of
389 // children of any template of the template set. We can instead store
390 // children out-of-band in Util::SecondaryMaps with two advantages:
391 // * we do not need to allocate space for children of zero type elements
392 // * improved cache-behaviour when iterating over mesh elements, since most
393 // algorithms do not need the parent-child relations
398
399 static constexpr int num_neighbors = Shape::FaceTraits<Shape_, Shape_::dimension - 1>::count;
400 std::array<Intern::ElementKey<Shape_::dimension>, num_neighbors> neighbors;
401 };
402
410 template<typename VertexType>
412 {
413 AdaptiveVertex(VertexType v, Layer l) : vertex(v), layer(l), last_changed(l)
414 {
415 }
416
418 VertexType vertex;
423
424 // NOTE: last_changed is (so far) exclusively used for the
425 // BPXJacobiPreconditioner. The mesh should probably not directly know that this
426 // property is needed. Maybe introduce something like the PMP property system
427 // that allows dynamically adding data to any mesh entities.
428
431 };
432
446 template<typename TemplateSet_, typename MeshShape_, typename VertexType_, int element_dim_ = MeshShape_::dimension>
447 class MeshLayer : public MeshLayer<TemplateSet_, MeshShape_, VertexType_, element_dim_ - 1>
448 {
449 protected:
451
454
459
464
465 public:
475 template<typename Shape_>
477 {
479 key.is_permanent = true;
480 return key;
481 }
482
492 template<typename Shape_>
494 {
496 key.is_permanent = false;
497 return key;
498 }
499
505 template<int dim_>
507 {
508 if constexpr(dim_ == 0)
509 {
511 }
512 else
513 {
514 if(key.is_permanent)
515 {
517 }
518 else
519 {
521 }
522 }
523 }
524
531 template<int dim_>
533 {
534 if constexpr(dim_ == 0)
535 {
537 }
538 else
539 {
541 }
542 }
543
550 template<int dim_>
552 {
553 if constexpr(dim_ == 0)
554 {
555 return 0;
556 }
557 else
558 {
560 }
561 }
562
564 template<int dim_>
567 {
569 }
570
572 template<int dim_>
575 {
577 }
578
580 template<int dim_>
583 {
585 }
586
588 template<int dim_>
591 {
593 }
594
598 std::size_t bytes() const
599 {
600 return _permanent_entities.bytes() + _transient_entities.bytes() + BaseClass::bytes();
601 }
602
610 template<int dim_>
612 {
613 static_assert(dim_ >= 1);
614 if(key.is_permanent)
615 {
617 }
618 else
619 {
621 }
622 }
623
631 template<int dim_>
633 {
634 static_assert(dim_ >= 1);
635 if(key.is_permanent)
636 {
638 }
639 else
640 {
642 }
643 }
644 };
645
658 template<typename TemplateSet_, typename MeshShape_, typename VertexType_>
659 class MeshLayer<TemplateSet_, MeshShape_, VertexType_, 0>
660 {
661 protected:
664
665 public:
672 {
673 return _vertices.insert(vertex);
674 }
675
682 {
683 _vertices.erase(key);
684 }
685
690 {
691 return _vertices.size();
692 }
693
696 {
697 return _vertices;
698 }
699
702 {
703 return _vertices;
704 }
705
709 std::size_t bytes() const
710 {
711 return _vertices.bytes();
712 }
713
718 {
719 return _vertices[key];
720 }
721
726 {
727 return _vertices[key];
728 }
729 };
730
750 template<typename MeshShape_, typename TemplateSet_, typename VertexType_>
752 {
753 public:
755 using VertexType = VertexType_;
756
757 using CoordType = typename VertexType_::ValueType;
758
760 using TemplateSet = TemplateSet_;
761
763 template<int dim_>
765
767 template<int dim_>
769
771 template<int dim_>
773
775 template<int dim_>
777
779 template<int dim_>
781
784
788 enum class IterationOrder
789 {
790 PreOrder,
791 PostOrder
792 };
793
794 private:
797
798 static constexpr int num_coords = VertexType::n;
799
802
804 std::vector<MeshLayerType> _layers;
805
807 bool _is_indexed = false;
808
810 bool _has_neighbors = false;
811
812 public:
821 template<int dim>
822 typename TemplateSet::template RefinementTypeByDim<dim> type(ElementKey<dim> key)
823 {
824 return (*this)[key].type;
825 }
826
836 template<int dim_>
837 std::array<Index, 4> erase(ElementKey<dim_> key)
838 {
839 ASSERTM(key.layer.idx < _layers.size(), "Trying to erase adaptive mesh element of non-existing layer");
840
841 // Erasing an entity produces a gap in that layers indices. The mesh is
842 // thus no longer correctly indexed.
843 _is_indexed = false;
844 // Erasing an entity (most-likely) removed a neighbor of an element. Neighbors need to be re-determined.
845 _has_neighbors = false;
846
847 std::array<Index, 4> num_erased = {};
848 if constexpr(dim_ > 0)
849 {
850 // NOTE: Different mesh layers are stored separately. Deleting a child
851 // does thus not invalidate the references to the current entity or its
852 // children.
853 auto& entity = (*this)[key];
854 num_erased =
855 _erase_children<typename Shape::FaceTraits<MeshShape_, dim_>::ShapeType, dim_>(entity.type, entity.children);
856 }
857
858 // Actually delete current entity
859 _layers[key.layer.idx].erase(key);
860 num_erased[dim_] += 1;
861
862 return num_erased;
863 }
864
873 {
874 // Adding a new vertex to a layer shifts the indices of all vertices on
875 // further layers. These vertices stored indices are thus wrong, and need
876 // to be recomputed.
877 _is_indexed = false;
878
879 // Add additional mesh layers, if required
880 Layer layer = vertex.layer;
881 _add_mesh_layers(layer.idx);
882
883 // Add vertex
884 VertexKey key = _layers[layer.idx].insert_vertex(vertex);
885 key.layer = layer;
886 return key;
887 }
888
898 {
899 return insert(AdaptiveVertex(vertex, layer));
900 }
901
909 template<typename Shape_>
911 {
912 // Adding an entity might cause the indices of entities on further layers
913 // to be shifted. These entites stored indices are thus wrong and need to
914 // be recomputed.
915 _is_indexed = false;
916 // Neighbors for this new entity need to be determined.
917 _has_neighbors = false;
918
919 // Add additional mesh layers, if required
920 Layer layer = element.layer;
921 _add_mesh_layers(layer.idx);
922
924 bool is_permanent = element.type.is_zero_refinement();
925
926 if(is_permanent)
927 {
928 key = _layers[layer.idx].insert_permanent(element);
929 }
930 else
931 {
932 key = _layers[layer.idx].insert_transient(element);
933 }
934
935 // Add metadata to key
936 key.is_permanent = is_permanent;
937 key.layer = layer;
938
939 return key;
940 }
941
951 {
952 return _layers.size();
953 }
954
971 template<typename VisitorType_, int dim_>
973 ElementKey<dim_> root_key,
974 VisitorType_& visitor,
975 Layer max_depth,
976 IterationOrder order = IterationOrder::PreOrder) const
977 {
978 auto& root = (*this)[root_key];
979
980 // Abort if max_depth is reached
981 if(root.layer > max_depth)
982 {
983 return;
984 }
985
986 // Visit Root
987 if(order == IterationOrder::PreOrder)
988 {
989 visitor(root_key);
990 }
991
992 if constexpr(dim_ > 0)
993 {
994 _walk_subtree_children<typename Shape::FaceTraits<MeshShape_, dim_>::ShapeType>(root, visitor, max_depth);
995 }
996
997 // Visit Root
998 if(order == IterationOrder::PostOrder)
999 {
1000 visitor(root_key);
1001 }
1002 }
1003
1019 template<typename VisitorType_>
1020 void walk_tree(VisitorType_& visitor, Layer max_depth, IterationOrder order = IterationOrder::PreOrder) const
1021 {
1022 // There is nothing to iterate over if the mesh has no layers
1023 if(_layers.size() == 0)
1024 {
1025 return;
1026 }
1027
1028 const MeshLayerType& root_layer = _layers[0];
1029
1030 if constexpr(MeshShape_::dimension >= 0)
1031 {
1032 for(auto entry : root_layer.vertices())
1033 {
1034 walk_subtree(entry.key, visitor, max_depth, order);
1035 }
1036 }
1037
1038 if constexpr(MeshShape_::dimension >= 1)
1039 {
1040 for(auto entry : root_layer.template permanent_entities<1>())
1041 {
1042 walk_subtree(entry.key, visitor, max_depth, order);
1043 }
1044 for(auto entry : root_layer.template transient_entities<1>())
1045 {
1046 walk_subtree(entry.key, visitor, max_depth, order);
1047 }
1048 }
1049
1050 if constexpr(MeshShape_::dimension >= 2)
1051 {
1052 for(auto entry : root_layer.template permanent_entities<2>())
1053 {
1054 walk_subtree(entry.key, visitor, max_depth, order);
1055 }
1056 for(auto entry : root_layer.template transient_entities<2>())
1057 {
1058 walk_subtree(entry.key, visitor, max_depth, order);
1059 }
1060 }
1061
1062 if constexpr(MeshShape_::dimension >= 3)
1063 {
1064 for(auto entry : root_layer.template permanent_entities<3>())
1065 {
1066 walk_subtree(entry.key, visitor, max_depth, order);
1067 }
1068 for(auto entry : root_layer.template transient_entities<3>())
1069 {
1070 walk_subtree(entry.key, visitor, max_depth, order);
1071 }
1072 }
1073 }
1074
1083 Index num_entities(Layer layer, int dim) const
1084 {
1085 if(dim == 0)
1086 {
1087 return _num_entities<0>(layer);
1088 }
1089 if(dim == 1)
1090 {
1091 return _num_entities<1>(layer);
1092 }
1093 if(dim == 2)
1094 {
1095 return _num_entities<2>(layer);
1096 }
1097 if(dim == 3)
1098 {
1099 return _num_entities<3>(layer);
1100 }
1101 XABORTM("unsupported dimension in MeshStorage::num_entities");
1102 }
1103
1111 template<int dim_>
1113 {
1114 Index result = 0;
1115 for(auto& layer : _layers)
1116 {
1117 result += layer.template num_permanent_entities<dim_>();
1118 result += layer.template num_transient_entities<dim_>();
1119 }
1120
1121 return result;
1122 }
1123
1128 {
1129 static constexpr int shape_dim = MeshShape_::dimension;
1130 static constexpr int num_facets = Shape::FaceTraits<MeshShape_, shape_dim - 1>::count;
1131
1132 // OPTIMIZATION: This is the ConformalMesh::fill_neighbors() algorithm
1133 // ported to adaptive mesh keys. This information can be retrieved more
1134 // cheaply from the refinement templates themselves. Add this capability to
1135 // the template query (maybe optionally, with a boolean indicating support
1136 // on the template set), support it in the AdaptiveMesh code, and don't
1137 // invalidate neighbors when adding elements here if the template provide
1138 // neighbor information.
1139 // This method can then be left as a fallback.
1140
1141 if(_has_neighbors)
1142 {
1143 // Neighbors have already been determined since the last adaptation of
1144 // the mesh. No work to be done.
1145 return;
1146 }
1147
1148 std::cout << "Recalculating neighbors\n";
1149
1150 // In the following we are calling mesh entities of dimension shape_dim - 1 facets.
1151 // We are using the fact that each facet is shared by at most 2 elements.
1152 // We are goint to first determine which elements are adjacent to each
1153 // facet, by iterating over the elements and adding their keys to the
1154 // facet_neighbors of each of their facets. Then we can iterate over the
1155 // elements a second time and determine their neighbors as the element
1156 // registered for the facet, that is not itself.
1157
1158 // Maps of facet neighbors
1159 std::vector<std::vector<Util::SecondaryMap<std::array<ElementKey<shape_dim>, 2>, ElementKey<shape_dim - 1>>>>
1160 permanent_facet_neighbors(num_layers());
1161
1162 std::vector<std::vector<Util::SecondaryMap<std::array<ElementKey<shape_dim>, 2>, ElementKey<shape_dim - 1>>>>
1163 transient_facet_neighbors(num_layers());
1164
1165 for(Index i(0); i < num_layers(); i++)
1166 {
1167 permanent_facet_neighbors[i].resize(num_layers());
1168 transient_facet_neighbors[i].resize(num_layers());
1169 }
1170
1171 // Register element with their adjacent facets. Fills the facet_neighbors map.
1172 auto determine_facet_neighbors = [&](Layer layer, auto slotmap_entry)
1173 {
1174 // HACK: We have to recreate the "full" element key here.
1175 // The keys returned by the SlotMap iterators do not contain the
1176 // layer and permanency information we have added to the usual
1177 // slotmap data.
1178 // The proper way to this is to wrap the iterators in the MeshLayer
1179 // class and add this information there. As this is currently the
1180 // only place where we directly iterate over all elements of a layer
1181 // via the iterators, I am leaving that boilerplate out for now.
1182 ElementKey<shape_dim> element_key = slotmap_entry.key;
1183 element_key.layer = layer;
1184 element_key.is_permanent = slotmap_entry.value.type.is_zero_refinement();
1185
1186 // Iterate over all facets
1187 for(int facet_idx = 0; facet_idx < num_facets; facet_idx++)
1188 {
1189 // Retrieve key of facet
1190 auto key = slotmap_entry.value.topology.template key_by_dim<shape_dim - 1>(facet_idx).key;
1191
1192 // Init secondary map, if this is the first time we see this facet
1193 if(key.is_permanent && !permanent_facet_neighbors[layer.idx][key.layer.idx].contains_key(key))
1194 {
1195 permanent_facet_neighbors[layer.idx][key.layer.idx].insert(key, {neighbor_sentinel, neighbor_sentinel});
1196 }
1197
1198 if(!key.is_permanent && !transient_facet_neighbors[layer.idx][key.layer.idx].contains_key(key))
1199 {
1200 transient_facet_neighbors[layer.idx][key.layer.idx].insert(key, {neighbor_sentinel, neighbor_sentinel});
1201 }
1202
1203 auto& neighbors = key.is_permanent ? permanent_facet_neighbors[layer.idx][key.layer.idx][key] : transient_facet_neighbors[layer.idx][key.layer.idx][key];
1204
1205 if(neighbors[0] == neighbor_sentinel)
1206 {
1207 neighbors[0] = element_key;
1208 }
1209 else if(neighbors[1] == neighbor_sentinel)
1210 {
1211 neighbors[1] = element_key;
1212 }
1213 else
1214 {
1215 XABORTM("Facet has more than two neighbors!");
1216 }
1217 }
1218 };
1219
1220 // Determine neighbors by looking at registered facet neighbors.
1221 auto determine_neighbors = [&](Layer layer, auto slotmap_entry)
1222 {
1223 auto& element = slotmap_entry.value;
1224
1225 // Iterate over all facets
1226 for(int facet_idx = 0; facet_idx < num_facets; facet_idx++)
1227 {
1228 // Retrieve key of facet
1229 auto key = slotmap_entry.value.topology.template key_by_dim<shape_dim - 1>(facet_idx).key;
1230
1231 // HACK: We have to recreate the "full" element key here.
1232 // The keys returned by the SlotMap iterators do not contain the
1233 // layer and permanency information we have added to the usual
1234 // slotmap data.
1235 // The proper way to this is to wrap the iterators in the MeshLayer
1236 // class and add this information there. As this is currently the
1237 // only place where we directly iterate over all elements of a layer
1238 // via the iterators, I am leaving that boilerplate out for now.
1239 ElementKey<shape_dim> element_key = slotmap_entry.key;
1240 element_key.layer = layer;
1241 element_key.is_permanent = slotmap_entry.value.type.is_zero_refinement();
1242
1243 // Neighbor is the entity that is not the current entity
1244 auto& candidates = key.is_permanent ? permanent_facet_neighbors[layer.idx][key.layer.idx][key] : transient_facet_neighbors[layer.idx][key.layer.idx][key];
1245 if(candidates[0] == element_key)
1246 {
1247 element.neighbors[std::size_t(facet_idx)] = candidates[1];
1248 }
1249 else if(candidates[1] == element_key)
1250 {
1251 element.neighbors[std::size_t(facet_idx)] = candidates[0];
1252 }
1253 }
1254 };
1255
1256 // Find elements adjacent to all facets
1257 for(Index i(0); i < _layers.size(); i++)
1258 {
1259 for(auto entry : _layers[i].template permanent_entities<shape_dim>())
1260 {
1261 determine_facet_neighbors(Layer{i}, entry);
1262 }
1263 for(auto entry : _layers[i].template transient_entities<shape_dim>())
1264 {
1265 determine_facet_neighbors(Layer{i}, entry);
1266 }
1267 }
1268
1269 for(Index i(0); i < _layers.size(); i++)
1270 {
1271 for(auto entry : _layers[i].template permanent_entities<shape_dim>())
1272 {
1273 determine_neighbors(Layer{i}, entry);
1274 }
1275 for(auto entry : _layers[i].template transient_entities<shape_dim>())
1276 {
1277 determine_neighbors(Layer{i}, entry);
1278 }
1279 }
1280
1281 _has_neighbors = true;
1282 }
1283
1312 void transform(const VertexType& origin, const VertexType& angles, const VertexType& offset)
1313 {
1314 // create rotation matrix
1316 _aux_rot_mat(rot, angles);
1317
1318 // transform all vertices
1319 for(auto& layer : _layers)
1320 {
1321 for(auto entry : layer.vertices())
1322 {
1323 entry.value.set_mat_vec_mul(rot, entry.value - origin) += offset;
1324 }
1325 }
1326 }
1327
1334 void reindex()
1335 {
1336 // NOTE: The index-schema works as follows. On each layer of the mesh,
1337 // first the permanent entities get assigned indices, then the transient
1338 // entities get assigned indices. Indices are assigned in order,
1339 // starting on each layer with the index one beyond the last index of the
1340 // previous layers permanent indices. In other words, the transient
1341 // indices of each layer get reused by the next layer. This is fine,
1342 // because transient entities are replaced with their children on the
1343 // next layer and thus no longer require an index.
1344 //
1345 // Visually the indeces are thus staggered like this:
1346 //
1347 // L0: |-- Perm. Indices 0 --|---- Trans. Indices 0 ----|
1348 // L1: |-- Perm. Indices 0 --|-- Perm. Indices 1 --|- Trans. Indices 1 -|
1349 // L2: |-- Perm. Indices 0 --|-- Perm. Indices 1 --|---- Perm. Indices 2 ----|-- Trans. Indices 2 --|
1350
1351 Index next_vertex_index = 0;
1352 Index next_edge_index = 0;
1353 Index next_face_index = 0;
1354 Index next_cell_index = 0;
1355
1356 for(auto& layer : _layers)
1357 {
1358 if constexpr(MeshShape_::dimension >= 0)
1359 {
1360 // There are only permanent vertices. We can just index them without
1361 // having to worry about transient indices.
1362 for(auto entry : layer.vertices())
1363 {
1364 entry.value.index = next_vertex_index++;
1365 }
1366 }
1367
1368 if constexpr(MeshShape_::dimension >= 1)
1369 {
1370 _index_layer<1>(layer, next_edge_index);
1371 }
1372
1373 if constexpr(MeshShape_::dimension >= 2)
1374 {
1375 _index_layer<2>(layer, next_face_index);
1376 }
1377
1378 if constexpr(MeshShape_::dimension >= 3)
1379 {
1380 _index_layer<3>(layer, next_cell_index);
1381 }
1382 }
1383
1384 // Mesh is freshly indexed, by definition
1385 _is_indexed = true;
1386 }
1387
1389 // Index-based Accessors
1391
1403 {
1404 ASSERTM(layer.idx < _layers.size(), "Trying to retrieve vertex of non-existing mesh layer!");
1405
1406 // NOTE: We require the storage to be indexed, despite not making use of
1407 // the index member of any mesh element. This is so that, given a
1408 // ElementKey k pointing to a vertex v with index i on layer l, it is
1409 // impossible that get_index(k) != i or get_vertex_by_index(l, i) != v
1411
1412 // OPTIMIZATION: This is a O(num_layers) search for the right index
1413 // range. We can optimize this slightly by precomputing the index range
1414 // for each layer, eliminating the subtraction of the current idx. We
1415 // can then optimize this to O(log num_layers) by building a search tree.
1416 // And finally we can optimize the average case by caching the
1417 // index-range of the last access in a thread-local variable, allowing
1418 // linear iteration in O(1).
1419
1420 // Search through permanent edges of previous and current layer
1421 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1422 {
1423 const MeshLayerType& current_layer = _layers[layer_idx];
1424
1425 if(idx < current_layer.num_vertices())
1426 {
1427 return current_layer.vertices().data()[idx];
1428 }
1429 idx -= current_layer.num_vertices();
1430 }
1431
1432 XABORTM("Tried retrieving non-existent vertex index from AdaptiveMeshStorage!");
1433 }
1434
1446 {
1447 // Reuse const accessor by casting this to const and then removing const from the return value
1448 // SAFE: Casting to const is always fine
1449 // SAFE: Removing const is fine because this method was called on a non const value to begin with
1450 return const_cast<AdaptiveVertexType&>(std::as_const(*this).get_vertex_by_index(layer, idx));
1451 }
1452
1464 template<int dim_>
1466 {
1467 ASSERTM(layer.idx < _layers.size(), "Trying to retrieve entity of non-existing mesh layer!");
1468
1469 // NOTE: We require the storage to be indexed, despite not making use of
1470 // the index member of any mesh element. This is so that, given a
1471 // ElementKey k pointing to a mesh element e with index i on layer l, it is
1472 // impossible that get_index(k) != i or get_by_index(l, i) != e
1474
1475 // Search through permanent edges of previous and current layer
1476 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1477 {
1478 const MeshLayerType& current_layer = _layers[layer_idx];
1479
1480 if(idx < current_layer.template num_permanent_entities<dim_>())
1481 {
1482 return current_layer.template permanent_entities<dim_>().data()[idx];
1483 }
1484 idx -= current_layer.template num_permanent_entities<dim_>();
1485 }
1486
1487 const MeshLayerType& current_layer = _layers[layer.idx];
1488 if(idx < current_layer.template num_transient_entities<dim_>())
1489 {
1490 return current_layer.template transient_entities<dim_>().data()[idx];
1491 }
1492
1493 XABORTM("Trying to retrieve non-exisiting element from AdaptiveMeshStorage");
1494 }
1495
1507 template<int dim_>
1509 {
1510 // Reuse const accessor by casting this to const and then removing const from the return value
1511 // SAFE: Casting to const is always fine
1512 // SAFE: Removing const is fine because this method was called on a non const value to begin with
1513 return const_cast<AdaptiveElementByDim<dim_>&>(std::as_const(*this).template get_by_index<dim_>(layer, idx));
1514 }
1515
1521 Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
1522 {
1523 static constexpr int shape_dim = MeshShape_::dimension;
1526
1527 auto& element = get_by_index<shape_dim>(layer, element_idx);
1528 if(element.neighbors[neighbor_idx] != neighbor_sentinel)
1529 {
1530 return get_index(element.neighbors[neighbor_idx]);
1531 }
1532 return ~Index(0);
1533 }
1534
1536 // Key-based Access Operators
1538
1547 template<int dim_>
1549 {
1551 return (*this)[key].index;
1552 }
1553
1562 template<int dim_>
1564 {
1566 return (*this)[oriented_key.key].index;
1567 }
1568
1571 {
1572 ASSERT(key.layer.idx < _layers.size());
1573 return _layers[key.layer.idx].get_vertex(key);
1574 }
1575
1578 {
1579 ASSERT(key.layer.idx < _layers.size());
1580 return _layers[key.layer.idx].get_vertex(key);
1581 }
1582
1584 template<int dim_>
1586 {
1587 ASSERT(key.layer.idx < _layers.size());
1588 return _layers[key.layer.idx].get(key);
1589 }
1590
1592 template<int dim_>
1594 {
1595 ASSERT(key.layer.idx < _layers.size());
1596 return _layers[key.layer.idx].get(key);
1597 }
1598
1600 {
1601 return (*this)[ref.key];
1602 }
1603
1604 const AdaptiveVertexType& operator[](OrientedElement<0> ref) const
1605 {
1606 return (*this)[ref.key];
1607 }
1608
1610 template<int dim_>
1612 {
1613 return (*this)[ref.key];
1614 }
1615
1616 template<int dim_>
1617 const AdaptiveElementByDim<dim_>& operator[](OrientedElement<dim_> ref) const
1618 {
1619 return (*this)[ref.key];
1620 }
1621
1625 std::size_t bytes() const
1626 {
1627 std::size_t total = 0;
1628 for(auto& layer : _layers)
1629 {
1630 total += layer.bytes();
1631 }
1632 return total;
1633 }
1634
1635 private:
1644 template<int dim_>
1646 {
1647 if constexpr(dim_ > MeshShape_::dimension)
1648 {
1649 return 0;
1650 }
1651 else
1652 {
1653 ASSERT(layer.idx < _layers.size());
1654
1655 Index result = 0;
1656 for(Index layer_idx = 0; layer_idx <= layer.idx; layer_idx++)
1657 {
1658 result += _layers[layer_idx].template num_permanent_entities<dim_>();
1659 }
1660 result += _layers[layer.idx].template num_transient_entities<dim_>();
1661
1662 return result;
1663 }
1664 }
1665
1666 template<typename Shape_, int dim_ = Shape_::dimension>
1667 std::array<Index, 4> _erase_children(
1668 typename TemplateSet::template RefinementTypeByDim<Shape_::dimension> type,
1670 {
1671 if constexpr(dim_ >= 0)
1672 {
1673 auto result = _erase_children<Shape_, dim_ - 1>(type, children);
1674
1675 auto& array = children.template by_dim<dim_>();
1676 for(Index i(0); i < TemplateSet::template num_children<Shape_::dimension, dim_>(type); i++)
1677 {
1678 std::array<Index, 4> num_erased = erase(array[i]);
1679
1680 result[0] += num_erased[0];
1681 result[1] += num_erased[1];
1682 result[2] += num_erased[2];
1683 result[3] += num_erased[3];
1684 }
1685
1686 return result;
1687 }
1688 else
1689 {
1690 return {};
1691 }
1692 }
1693
1694 template<typename Shape_, int dim_ = Shape_::dimension, typename VisitorType>
1695 void _walk_subtree_children(const AdaptiveElement<TemplateSet, Shape_>& root, VisitorType& visitor, Layer max_depth) const
1696 {
1697 if constexpr(dim_ >= 0)
1698 {
1699 _walk_subtree_children<Shape_, dim_ - 1>(root, visitor, max_depth);
1700
1701 const auto& children = root.children.template by_dim<dim_>();
1702 for(Index i = 0; i < TemplateSet::template num_children<Shape_::dimension, dim_>(root.type); i++)
1703 {
1704 walk_subtree(children[i], visitor, max_depth);
1705 }
1706 }
1707 }
1708
1716 void _add_mesh_layers(Index new_top_layer)
1717 {
1718 while(_layers.size() <= new_top_layer)
1719 {
1720 _layers.push_back(MeshLayerType{});
1721 }
1722 }
1723
1732 template<int dim_>
1733 void _index_layer(MeshLayerType& layer, Index& next_permanent_index)
1734 {
1735 // First assign indices to all permanent mesh elements
1736 for(auto entry : layer.template permanent_entities<dim_>())
1737 {
1738 entry.value.index = next_permanent_index++;
1739 }
1740
1741 // Creat a copy of the current next index
1742 Index next_transient_index = next_permanent_index;
1743
1744 // Assign indices to all transient mesh elements, using the copied index
1745 // This causes these indices to be reused on the next layer, where the
1746 // transient elements have been replaced with their children and no longer
1747 // exist
1748 for(auto entry : layer.template transient_entities<dim_>())
1749 {
1750 entry.value.index = next_transient_index++;
1751 }
1752 }
1753
1757 template<int sm_, int sn_, int sv_>
1758 static void _aux_rot_mat(
1760 const Tiny::Vector<CoordType, 1, sv_>& /*unsused*/)
1761 {
1762 r.set_identity();
1763 }
1764
1768 template<int sm_, int sn_, int sv_>
1769 static void _aux_rot_mat(
1772 {
1773 r.set_rotation_2d(a[0]);
1774 }
1775
1779 template<int sm_, int sn_, int sv_>
1780 static void _aux_rot_mat(
1783 {
1784 r.set_rotation_3d(a[0], a[1], a[2]);
1785 }
1786 };
1787} // 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:177
void erase(const Key &key)
Remove a key from the SlotMap.
Definition: slotmap.hpp:255
Index size() const
Retrieve current size of the SlotMap.
Definition: slotmap.hpp:390
@ other
generic/other permutation strategy
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
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