FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
adaptive_mesh.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// includes, FEAT
9#include "kernel/geometry/intern/adaptive_refinement_utils.hpp"
10#include <kernel/geometry/templates/two_refinement_data.hpp>
11#include <kernel/geometry/intern/congruency_mapping.hpp>
12#include <kernel/geometry/intern/congruency_sampler.hpp>
13#include <kernel/geometry/intern/face_index_mapping.hpp>
14#include <kernel/geometry/templates/schneiders_data.hpp>
15#include <kernel/geometry/templates/sun_zhao_ma_data.hpp>
16#include <kernel/geometry/templates/sun_zhao_ma_expansion_data.hpp>
17#include <kernel/shape.hpp>
19#include <kernel/geometry/conformal_mesh.hpp>
20#include <kernel/geometry/intern/adaptive_mesh_algorithms.hpp>
21#include <kernel/geometry/intern/adaptive_mesh_storage.hpp>
22#include <kernel/geometry/intern/refinement_field.hpp>
23#include <kernel/geometry/mesh_part.hpp>
24#include <kernel/geometry/subdivision_levels.hpp>
25#include <kernel/geometry/template_interface.hpp>
27#include <kernel/geometry/template_sets.hpp>
28#include <kernel/geometry/template_builder.hpp>
29
30// includes, system
31#include <array>
32#include <limits>
33#include <set>
34#include <unordered_map>
35
36namespace FEAT::Geometry
37{
40
41 // Possible template sets
46
47 namespace Intern
48 {
52 template<int dim_>
53 struct MeshRoots : public MeshRoots<dim_ - 1>
54 {
55 std::unordered_map<Index, Intern::ElementKey<dim_>> roots;
56
57 template<int query_dim_>
58 std::unordered_map<Index, Intern::ElementKey<query_dim_>>& by_dim()
59 {
60 static_assert(query_dim_ <= dim_);
62 }
63
64 template<int query_dim_>
65 const std::unordered_map<Index, Intern::ElementKey<query_dim_>>& by_dim() const
66 {
67 static_assert(query_dim_ <= dim_);
69 }
70 };
71
75 template<>
76 struct MeshRoots<0>
77 {
78 std::unordered_map<Index, Intern::ElementKey<0>> roots;
79
80 template<int query_dim_>
81 std::unordered_map<Index, Intern::ElementKey<0>>& by_dim()
82 {
83 static_assert(query_dim_ == 0);
84 return roots;
85 }
86
87 template<int query_dim_>
88 const std::unordered_map<Index, Intern::ElementKey<0>>& by_dim() const
89 {
90 static_assert(query_dim_ == 0);
91 return roots;
92 }
93 };
94 }
95
102 {
108 std::array<Index, 4> added;
109
115 std::array<Index, 4> removed;
116
122 std::array<Index, 4> kept;
123
127 void reset()
128 {
129 added.fill(0);
130 removed.fill(0);
131 kept.fill(0);
132 }
133
140 template<int dim_>
141 void added_element(Index count = 1)
142 {
143 added[dim_] += count;
144 }
145
152 template<int dim_>
153 void removed_element(Index count = 1)
154 {
155 removed[dim_] += count;
156 }
157
163 void removed_elements(const std::array<Index, 4>& counts)
164 {
165 for(Index i = 0; i < 4; i++)
166 {
167 removed.at(i) += counts.at(i);
168 }
169 }
170
177 template<int dim_>
178 void kept_element(Index count = 1)
179 {
180 kept[dim_] += count;
181 }
182 };
183
206 template<
207 typename TemplateSet_,
208 typename Shape_,
209 int num_coords_ = Shape_::dimension,
210 typename Coord_ = Real>
212 {
213 static_assert(TemplateSet_::template is_shape_compatible<Shape_>());
214
215 public:
217 using ShapeType = Shape_;
218
220 static constexpr int shape_dim = ShapeType::dimension;
221
223 static constexpr int world_dim = ShapeType::dimension;
224
226 using CoordType = Coord_;
227
230
233
235 using TemplateSet = TemplateSet_;
236
243 enum class ImportBehaviour : std::uint8_t
244 {
246 All,
247 };
248
249 private:
252
253 // The following definitions are helpers for the code below
254
255 using VertexKey = typename MeshStorage::template ElementRefByDim<0>;
256 using EdgeKey = typename MeshStorage::template ElementRefByDim<1>;
257 using FaceKey = typename MeshStorage::template ElementRefByDim<2>;
258 using CellKey = typename MeshStorage::template ElementRefByDim<3>;
259
260 using OrientedEdge = typename MeshStorage::template OrientedElementRefByDim<1>;
261 using OrientedFace = typename MeshStorage::template OrientedElementRefByDim<2>;
262
263 using AdaptiveVertex = typename MeshStorage::AdaptiveVertexType;
264
265 template<int dim_>
266 using LevelTuple =
268 typename TemplateSet::VertexMarkerType,
270
271 template<int dim_>
272 using ElementRef = typename MeshStorage::template ElementRefByDim<dim_>;
273
274 template<int dim_>
275 using OrientedElementRef = typename MeshStorage::template OrientedElementRefByDim<dim_>;
276
277 template<int dim_>
278 using ElementTopology = typename MeshStorage::template ElementTopologyByDim<dim_>;
279
280 template<int dim_>
281 using ElementChildren = typename MeshStorage::template ElementChildrenByDim<dim_>;
282
283 template<int dim_>
284 using AdaptiveElement = typename MeshStorage::template AdaptiveElementByDim<dim_>;
285
287
288 using VertexMarkerType = typename TemplateSet::VertexMarkerType;
289
290 // Algorithms that interact with the foundation mesh are written to recurse
291 // over the dimension, similar to other algorithms in kernel/geometry. Some
292 // of these algorithms require access to internals of the AdaptiveMesh.
293
294 template<typename AdaptiveMeshType_, typename TargetMeshType_, typename AlgShape_>
295 friend struct Intern::MeshPartProjector;
296
297 template<typename AdaptiveMeshType_, int topology_dim_, int collection_dim_>
299
302
305
308
311
312 public:
319 explicit AdaptiveMesh(const FoundationMeshType& mesh) : _foundation_mesh(mesh) {}
320
322 AdaptiveMesh(AdaptiveMesh&& other) = delete;
323
324 AdaptiveMesh& operator=(AdaptiveMesh& other) = delete;
325 AdaptiveMesh& operator=(AdaptiveMesh&& other) = delete;
326
340 {
341 // We expect every vertex to be marked with a subdivision level
342 ASSERTM(foundation_levels.size() == _foundation_mesh.get_num_vertices(), "Invalid SDL size");
343
344 // Algorithm types
346
347 // Reset the adaption stats to zero
348 _stats.reset();
349
350 // Change foundation_levels to match template set requirements.
352 TemplateSet::make_refinement_field(_foundation_mesh, foundation_levels);
353
354 // We collect sets of all entities that are required to be added to layer
355 // 0 of the adaptive mesh. This includes in all cases all elements with
356 // non-zero refinement type and all entities making up those elements. Note
357 // that sub-entities are added irrespective of their own refinement type,
358 // as they are always required for producing a complete refinement tree.
360
361 // NOTE: Building the sets of all required entities is nice for
362 // determining which entities can be safely removed from the mesh, as we
363 // can just remove all elements not in the set. Otherwise we would need to
364 // determine which entities have both a zero refinement type and are not a
365 // sub-entity of an element with non-zero refinement type. We can change
366 // this if the hashing becomes a performance bottleneck or the memory-usage
367 // causes problems.
368
369 // Actually collect those sets of entities
370 bool import_all = import_behaviour == ImportBehaviour::All;
371 EntityCollector::collect(set, _foundation_mesh, r_field, import_all);
372
373 // Create, adapt, or replace refinement trees to match new subdivision levels.
374 _adapt_roots(set, r_field);
375
376 // Delete all refinement trees of entiites that were previously refined, but are no longer refined.
378
379 // Re-index the storage to allow for index-based access
381
382 // Return a copy of the stats for this adapatation.
383 return _stats;
384 }
385
401 template<typename VertexMarker_>
403 {
404 // Create subdivision levels
405 const Index num_vertices = foundation_mesh.get_num_vertices();
406 SubdivisionLevels sdls(num_vertices);
407
408 for(Index i(0); i < num_vertices; ++i)
409 {
410 sdls[i] = std::uint64_t(marker(i));
411 }
412
413 // Create mesh
414 AdaptiveMesh adaptive_mesh(foundation_mesh);
415 adaptive_mesh.adapt(sdls, ImportBehaviour::All);
416 return adaptive_mesh.to_conformal_mesh(Layer{adaptive_mesh.num_layers() - 1});
417 }
418
426 {
427 // Algorithm type
429
430 // Determine result mesh size
431 std::array<Index, 4> entities = {};
432 entities[0] = get_num_entities(layer, 0);
433 entities[1] = get_num_entities(layer, 1);
434 entities[2] = get_num_entities(layer, 2);
435 entities[3] = get_num_entities(layer, 3);
436 FoundationMeshType result(entities.data());
437
438 // Write mesh
439 MeshWriter::write_to_mesh(result, *this, layer);
440 result.fill_neighbors();
441
442 return result;
443 }
444
466 template<typename TargetMeshType_>
468 {
469 // Algorithm types
472
473 // For projecting a mesh part, we need to collect all child keys on the
474 // appropriate layers. This means both the keys of type zero entities
475 // that are (grand)-children of any entity in the original mesh part, as
476 // well as non-zero type elements on the target layer. The visitor will
477 // do so in a PreOrder iteration through the refinement trees,
478 // maintaining the relative order of entities.
479 Visitor visitor(_storage, layer);
480
481 // Collect keys of mesh part, performs a PreOrder iteration on all
482 // refinement trees rooted at an entity of the original mesh part
483 Projector::collect_keys(visitor, part, layer, _roots, _storage);
484
485 // Create result mesh part
486 std::array<Index, 4> num_elements =
487 {visitor.vertices.size(), visitor.edges.size(), visitor.faces.size(), visitor.cells.size()};
488 MeshPart<TargetMeshType_> result(num_elements.data(), false);
489
490 // Convert collected keys to indices and write into result mesh part
491 Projector::write_meshpart(visitor, result, _storage);
492
493 return result;
494 }
495
499 template<int dim_>
501 {
502 return _storage.template num_total_entities<dim_>();
503 }
504
508 VertexType& vertex(Layer layer, Index vertex_index)
509 {
510 return _storage.get_vertex_by_index(layer, vertex_index).vertex;
511 }
512
516 const VertexType& vertex(Layer layer, Index vertex_index) const
517 {
518 return _storage.get_vertex_by_index(layer, vertex_index).vertex;
519 }
520
530 template<int dim_, int codim_>
531 Index get_face_index(Layer layer, Index entity_idx, int face_idx) const
532 {
533 auto& entity = _storage.template get_by_index<dim_>(layer, entity_idx);
534
535 return _storage.get_index(entity.topology.template key_by_dim<codim_>(face_idx));
536 }
537
546 Index get_num_entities(Layer layer, int dim) const
547 {
548 return _storage.num_entities(layer, dim);
549 }
550
563 template<int dim_>
564 std::optional<Index> get_child(Layer layer, Index parent_idx, Index child) const
565 {
566 auto& element = _storage.template get_by_index<dim_>(layer, parent_idx);
567
568 if(element.type.is_zero_refinement())
569 {
570 // If the parent has no children, it will be part of all further layers with the same Index.
571 // For the purposes of transfer operators and similar, it is thus its own child
572 return parent_idx;
573 }
574
575 if(child < TemplateSet::template num_children<dim_, dim_>(element.type))
576 {
577 // A child with the wanted index exists. Retrieve the key and convert to index.
578 return _storage.get_index(element.children.template by_dim<dim_>()[child]);
579 }
580
581 // No child with the wanted index exists
582 return std::nullopt;
583 }
584
593 template<int dim>
595 {
596 auto type = _storage.template get_by_index<dim>(layer, elem).type;
597 if(!type.is_zero_refinement())
598 {
599 return TemplateSet::template num_children<dim, dim>(type);
600 }
601
602 return 1;
603 }
604
610 bool has_vertex_changed(Layer layer, Index vertex_idx) const
611 {
612 auto& vertex = _storage.get_vertex_by_index(layer, vertex_idx);
613 return vertex.layer <= layer && layer <= vertex.last_changed;
614 }
615
619 std::vector<std::pair<Index, Index>> bridge_pairs()
620 {
621 std::vector<std::pair<Index, Index>> pairs;
622
623 for(auto& iter : _roots.vertices)
624 {
625 pairs.emplace_back(std::make_pair(iter.first, _storage.get_index(iter.second)));
626 }
627
628 return pairs;
629 }
630
635 {
636 return _foundation_mesh;
637 }
638
643 {
644 return _foundation_mesh;
645 }
646
653 template<int dim_>
654 std::optional<Index> get_overlap_cell(Index foundation_index) const
655 {
656 const std::unordered_map<Index, ElementRef<dim_>>& root_map = _roots.template by_dim<dim_>();
657
658 auto iter = root_map.find(foundation_index);
659 if(iter != root_map.end())
660 {
661 return _storage.get_index(iter->second);
662 }
663
664 return std::nullopt;
665 }
666
673 std::vector<Index> overlap_mapping()
674 {
675 std::vector<Index> result(_storage.num_entities(0, 0));
676
677 for(auto& entry : _roots.vertices)
678 {
679 result[_storage.get_index(entry.second)] = entry.first;
680 }
681
682 return result;
683 }
684
692 {
693 return _storage.num_layers();
694 }
695
710 {
711 // Get element roots
712 const std::unordered_map<Index, ElementRef<shape_dim>>& root_map = _roots.template by_dim<ShapeType::dimension>();
713
714 // Determine mesh part size
716 const Index overlap_cells = root_map.size();
717 const Index part_cells = total_cells - overlap_cells;
718 std::array<Index, shape_dim + 1> part_size = {};
719 part_size[shape_dim] = part_cells;
720
721 // Create mesh part without topology
722 MeshPart<FoundationMeshType> result(part_size.data(), false);
723 auto& target_set = result.template get_target_set<shape_dim>();
724
725 // Write foundation mesh indices into mesh part
726 Index tset_index = 0;
727 for(Index i(0); i < total_cells; ++i)
728 {
729 if(root_map.find(i) == root_map.end())
730 {
731 // Cell i is not a root of the adaptive mesh. Add it.
732 target_set[tset_index] = i;
733 tset_index++;
734 }
735 }
736
737 return result;
738 }
739
754 {
755 // Get element roots
756 const std::unordered_map<Index, ElementRef<shape_dim>>& root_map = _roots.template by_dim<ShapeType::dimension>();
757
758 // Determine result target set size
759 const Index overlap_cells = root_map.size();
760 std::array<Index, shape_dim + 1> part_size = {};
761 part_size[shape_dim] = overlap_cells;
762
763 // Create mesh part without topology
764 MeshPart<FoundationMeshType> result(part_size.data(), false);
765 auto& target_set = result.template get_target_set<shape_dim>();
766
767 // Write foundation mesh indices into mesh part
768 Index tset_index = 0;
769 for(auto& entry : root_map)
770 {
771 target_set[tset_index] = entry.first;
772 tset_index++;
773 }
774
775 return result;
776 }
777
792 {
794 const Layer fine_layer = Layer{num_layers - 1};
795 const Index num_base_vertices = _storage.num_entities(Layer{0}, 0);
796 const Index num_fine_vertices = _storage.num_entities(fine_layer, 0);
797
798 SubdivisionLevels result(num_base_vertices);
799
800 for(Index v_fine_idx = 0; v_fine_idx < num_fine_vertices; v_fine_idx++)
801 {
802 // Find vertex in foundation mesh that is closest to the current fine vertex
803 Real closest_distance = std::numeric_limits<Real>::max();
804 Index closest_vertex = 0;
805 for(Index v_base_idx = 0; v_base_idx < num_base_vertices; v_base_idx++)
806 {
807 const AdaptiveVertex& v_fine = _storage.get_vertex_by_index(fine_layer, v_fine_idx);
808 const AdaptiveVertex& v_base = _storage.get_vertex_by_index(Layer{0}, v_base_idx);
809 const Real distance = (v_fine.vertex - v_base.vertex).norm_euclid_sqr();
810 if(distance < closest_distance)
811 {
812 closest_distance = distance;
813 closest_vertex = v_base_idx;
814 }
815 }
816
817 // Assign the subdivision levels of the current vertex to the closest vertex in the foundation mesh
818 result[closest_vertex] = std::max(result[closest_vertex], lvls_in[v_fine_idx]);
819 }
820 return result;
821 }
822
827 {
829 }
830
836 Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
837 {
838 return _storage.get_neighbor(layer, element_idx, neighbor_idx);
839 }
840
869 void transform(const VertexType& origin, const VertexType& angles, const VertexType& offset)
870 {
871 _storage.transform(origin, angles, offset);
872 }
873
874 private:
889 template<int dim_>
890 Intern::ElementKey<dim_> _build(Index depth, const LevelTuple<dim_>& levels, const ElementTopology<dim_>& topology)
891 {
892 ASSERT(_dbg_check_topology_unique<dim_>(topology));
893 ASSERT(_dbg_check_topology_orientations<dim_>(topology));
894 ASSERT(_dbg_is_topology_consistent<dim_>(topology));
895 ASSERT(_dbg_is_topology_layering_consistent<dim_>(Intern::Layer{depth}, topology));
896
897 _stats.added_element<dim_>();
898
899 auto type = typename TemplateSet::template RefinementTypeByDim<dim_>(levels);
900
901 //std::cout << "Building element of type " << type << "\n";
902 // Create tree root
903 auto self = AdaptiveElement<dim_>(type, Layer{depth}, topology);
904
905 if(type.is_zero_refinement())
906 {
907 // Zero type elements have no children. We are done here.
908 auto key = _storage.insert(self);
909 //std::cout << "Built element " << key << "\n";
910 return key;
911 }
912
913 using TemplateShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
914
915 static constexpr int num_vertices = Shape::FaceTraits<TemplateShape, 0>::count;
916
917 const RefinementTemplate<TemplateShape>& tmplt = TemplateSet::get_template(type);
918
919 // Build child vertices
920 _stats.added_element<0>(tmplt.template num_entities<0>());
921
922 // Retrieve vertex coordinates of topology for following vertex interpolation
923 std::array<VertexType, num_vertices> vertex_coordinates;
924
925 for(int i(0); i < num_vertices; i++)
926 {
927 vertex_coordinates[std::size_t(i)] = _storage[topology.template key_by_dim<0>(i)].vertex;
928 }
929
930 // Produce child vertices by linear interpolation
931 auto& child_vertices = self.children.template by_dim<0>();
932 for(Index i = 0; i < tmplt.template num_entities<0>(); i++)
933 {
934 const VertexType vertex(Intern::interpolate(vertex_coordinates, tmplt.get_vertex_coefficients()[i]));
935 child_vertices[i] = _storage.insert(AdaptiveVertex(vertex, Layer{depth + 1}));
936 }
937
938 // We are recording the last mesh layer on which any of the entities surrounding a vertex has changed.
939 // This allows disregarding these vertices in a BPX solver later.
940 // NOTE: This is quite specific. Can we move this out of the build routine somehow?
941 if(tmplt.template num_entities<0>() > 0)
942 {
943 // Parent vertices created new vertices at this depth.
944 // Increase referenced depth for BPX star-sum
945 auto& topo_vertices = self.topology.template by_dim<0>();
946 for(Index v = 0; v < topo_vertices.size(); v++)
947 {
948 auto& vertex = _storage[topo_vertices[v]];
949 if(depth + 1 > vertex.last_changed.idx)
950 {
951 vertex.last_changed = Layer{depth + 1};
952 }
953 }
954 }
955
956 // Build child edges
957 if constexpr(dim_ >= 1)
958 {
959 auto& children = self.children.template by_dim<1>();
960 const auto& topo_templates = tmplt.template get_topologies<1>();
961 for(Index i = 0; i < tmplt.template num_entities<1>(); i++)
962 {
963 ElementTopology<1> child_topo;
964 _build_topology<dim_, 1>(topo_templates[i], child_topo, topology, self.children);
965
966 children[i] = _build<1>(depth + 1, _levels<dim_, 1>(topo_templates[i], levels), child_topo);
967 }
968 }
969
970 // Build faces
971 if constexpr(dim_ >= 2)
972 {
973 auto& children = self.children.template by_dim<2>();
974 const auto& topo_templates = tmplt.template get_topologies<2>();
975 for(Index i = 0; i < tmplt.template num_entities<2>(); i++)
976 {
977 ElementTopology<2> child_topo;
978 _build_topology<dim_, 2>(topo_templates[i], child_topo, topology, self.children);
979
980 children[i] = _build<2>(depth + 1, _levels<dim_, 2>(topo_templates[i], levels), child_topo);
981 }
982 }
983
984 // Build cells
985 if constexpr(dim_ >= 3)
986 {
987 auto& children = self.children.template by_dim<3>();
988 const auto& topo_templates = tmplt.template get_topologies<3>();
989 for(Index i = 0; i < tmplt.template num_entities<3>(); i++)
990 {
991 ElementTopology<3> child_topo;
992 _build_topology<dim_, 3>(topo_templates[i], child_topo, topology, self.children);
993
994 children[i] = _build<3>(depth + 1, _levels<dim_, 3>(topo_templates[i], levels), child_topo);
995 }
996 }
997
998 return _storage.insert(self);
999 }
1000
1015 template<int dim_>
1017 {
1018 // Algorithm for collecting topologies from the foundation mesh. Entry
1019 // dimension is dim_ - 1, because topologies only contain entities of
1020 // smaller dimension than the entity the topology belongs to.
1021 using TopologyCollector = Intern::FoundationTopologyCollector<AdaptiveMesh, dim_, dim_ - 1>;
1022
1023 // Vertices of foundation entities, for collecting subdivision levels
1024 auto& foundation_entities = _foundation_mesh.template get_index_set<dim_, 0>();
1025 auto& roots = _roots.template by_dim<dim_>();
1026
1027 for(Index idx : set.template by_dim<dim_>())
1028 {
1029 // Determine refinement type of current entity
1030 auto markings = sdls.get_tuple(foundation_entities[idx]);
1031 auto type = typename TemplateSet::template RefinementTypeByDim<dim_>(markings);
1032
1033 // Determine entities entry in mesh roots, if it exists
1034 auto iter = roots.find(idx);
1035 bool exists = iter != roots.end();
1036
1037 if(exists && _storage.type(iter->second) == type)
1038 {
1039 // Element already exists and its type has not changed.
1040 // Adapt its children further.
1041 _adapt_children<dim_>(iter->second, markings);
1042 }
1043 else
1044 {
1045 //std::cout << "Rebuilding element with new type " << type << "\n";
1046 //std::cout << "Markings: ";
1047 for(Index i(0); i < markings.size; i++)
1048 {
1049 //std::cout << markings[i] << ", ";
1050 }
1051 //std::cout << "\n";
1052 // Element either does not exist or its type has changed.
1053 // (Re)build it.
1054
1055 // We need the entity's topology to rebuild it.
1056 // NOTE: Even if the entity already exists in the mesh and is only
1057 // going to be replaced, we can not reuse its topology. If we entered
1058 // this branch the entity's refinement type has changed, which means
1059 // the refinement type of at least one sub-entity has also changed.
1060 // That sub-entity has itself been replaced at this point, and the
1061 // reference stored in this entity's topology is invalid.
1062
1063 // OPTIMIZATION: While it is true that we can't reuse the previous
1064 // topology, if it exists, we are currently doing some needless work
1065 // in that case. The topology collection also determines the
1066 // orientation of any references in the topology. Those orientations
1067 // don't change, so it would be enough to only update the references,
1068 // if the topology has been collected before.
1069 ElementTopology<dim_> topology;
1070 TopologyCollector::collect(topology, idx, *this);
1071
1072 if(exists)
1073 {
1074 // Entity already existed. Replace it.
1075 _erase(iter->second);
1076 iter->second = _build<dim_>(0, markings, topology);
1077 }
1078 else
1079 {
1080 // Entity is entirely new. Build it.
1081 roots[idx] = _build<dim_>(0, markings, topology);
1082 }
1083 }
1084 }
1085 }
1086
1101 {
1102 if constexpr(shape_dim >= 0)
1103 {
1104 auto& vertex_set = _foundation_mesh.get_vertex_set();
1105 auto& vertex_roots = _roots.template by_dim<0>();
1106 for(const auto& vert : set.vertices)
1107 {
1108 if(vertex_roots.find(vert) == vertex_roots.end())
1109 {
1110 _stats.template added_element<0>();
1111 vertex_roots[vert] = _storage.insert(vertex_set[vert], Layer{0});
1112 }
1113 else
1114 {
1115 _stats.template kept_element<0>();
1116 }
1117 }
1118 }
1119 if constexpr(shape_dim >= 1)
1120 {
1121 _adapt_roots_of_dim<1>(set, sdls);
1122 }
1123 if constexpr(shape_dim >= 2)
1124 {
1125 _adapt_roots_of_dim<2>(set, sdls);
1126 }
1127 if constexpr(shape_dim >= 3)
1128 {
1129 _adapt_roots_of_dim<3>(set, sdls);
1130 }
1131 }
1132
1145 template<int dim_>
1146 void _adapt_children(ElementRef<dim_> key, const LevelTuple<dim_>& levels)
1147 {
1148 // Calculate element type
1149 const auto type = _storage.type(key);
1150 const Index depth = _storage[key].layer.idx;
1151
1152 //std::cout << "Adapting element of type " << type << "\n";
1153 // Adapting an entity's children requires a valid topology for the parent
1154 // element. If this entity's type changed, then it should have been
1155 // rebuilt with a valid topology and calling _adapt_children is an error.
1156 XASSERTM(type == typename TemplateSet::template RefinementTypeByDim<dim_>(levels), "Called adapt_children on element with changed type.");
1157
1158 // We are keeping the current entity as part of the mesh
1159 _stats.kept_element<dim_>();
1160
1161 if(type.is_zero_refinement())
1162 {
1163 // Zero-type elements have no children that need further adaptation.
1164 return;
1165 }
1166
1167 // Retrieve reference to current entity
1168 auto& self = _storage[key];
1169
1170 using TemplateShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1171 const RefinementTemplate<TemplateShape>& tmplt = TemplateSet::get_template(type);
1172
1173 // Retrieve vertex query from template set. Vertices do not need
1174 // adaptation, but we guarantee template sets that we will construct all
1175 // template queries in order.
1176 _stats.kept_element<0>(tmplt.template num_entities<0>());
1177
1178 // Adapt child edges
1179 if constexpr(dim_ >= 1)
1180 {
1181 _adapt_sub_entities<dim_, 1>(depth, self, tmplt, levels);
1182
1183 // Adapt child faces
1184 if constexpr(dim_ >= 2)
1185 {
1186 _adapt_sub_entities<dim_, 2>(depth, self, tmplt, levels);
1187
1188 // Adapt child cells
1189 if constexpr(dim_ >= 3)
1190 {
1191 _adapt_sub_entities<dim_, 3>(depth, self, tmplt, levels);
1192 }
1193 }
1194 }
1195 }
1196
1197 protected:
1205 template<int dim_>
1207 {
1209 }
1210
1224 template<int parent_dim_, int child_dim_>
1226 Index depth,
1227 AdaptiveElement<parent_dim_>& self,
1229 const LevelTuple<parent_dim_>& levels)
1230 {
1231 // children is an std::array of slotmap keys
1232 auto& children = self.children.template by_dim<child_dim_>();
1233 auto& topo_templates = tmplt.template get_topologies<child_dim_>();
1234
1235 for(Index i = 0; i < tmplt.template num_entities<child_dim_>(); i++)
1236 {
1237 // Determine child SubdivisionLevels and type
1238 LevelTuple<child_dim_> child_levels = _levels<parent_dim_, child_dim_>(topo_templates[i], levels);
1239 auto child_type = typename TemplateSet::template RefinementTypeByDim<child_dim_>(child_levels);
1240
1241 if(_storage.type(children[i]) == child_type)
1242 {
1243 // Type is unchanged. Adapt children recursively.
1244 _adapt_children<child_dim_>(children[i], child_levels);
1245 }
1246 else
1247 {
1248 // Type is changed. Erase child and rebuild it.
1249 _erase(children[i]);
1250
1251 ElementTopology<child_dim_> child_topology;
1252 _build_topology<parent_dim_, child_dim_>(topo_templates[i], child_topology, self.topology, self.children);
1253
1254 children[i] = _build<child_dim_>(depth + 1, child_levels, child_topology);
1255 }
1256 }
1257 }
1258
1271 template<int parent_dim_, int entity_dim_>
1274 const LevelTuple<parent_dim_>& lvls)
1275 {
1276 // OPTIMIZATION(mmuegge): Currenlty a new minimum is calculated for all
1277 // vertices. We can use that all sibling vertices share the same new
1278 // marking. As do all vertices on any of the boundary elements. Add a
1279 // MarkingSpreader class or something like that and cache the results.
1280 using ParentShape = typename Shape::FaceTraits<ShapeType, parent_dim_>::ShapeType;
1281
1282 const auto& vertex_refs = tmplt.template get_references<0>();
1283
1285
1286 for(int i(0); i < result.size; ++i)
1287 {
1288 result[i] = TemplateSet::template spread_refinement_field<ParentShape>(vertex_refs[std::size_t(i)], lvls);
1289 }
1290
1291 return result;
1292 }
1293
1308 template<int parent_dim_, int topo_dim_, int dim_ = topo_dim_ - 1>
1311 ElementTopology<topo_dim_>& topo,
1312 const ElementTopology<parent_dim_>& parent_topo,
1313 const ElementChildren<parent_dim_>& siblings)
1314 {
1315 if constexpr(dim_ >= 0)
1316 {
1317 _build_topology<parent_dim_, topo_dim_, dim_ - 1>(tmplt, topo, parent_topo, siblings);
1318
1319 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1320 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1321
1322 auto& target = topo.template by_dim<dim_>();
1323 for(int i(0); i < num_entities; i++)
1324 {
1325 EntityReference ref = tmplt.template get_reference<dim_>(i);
1326 target[std::size_t(i)] = _resolve_entity_reference<parent_dim_, dim_>(parent_topo, siblings, ref);
1327
1328 if constexpr(dim_ >= 1)
1329 {
1331 {
1332 // Calc orientation
1333 using ResultShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1334 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1335 using CongruencySampler = Intern::CongruencySampler<ResultShape>;
1336
1337 static constexpr int num_vertices = Shape::FaceTraits<ResultShape, 0>::count;
1338 std::array<ElementRef<0>, num_vertices> local_keys;
1339 std::array<ElementRef<0>, num_vertices> foreign_keys;
1340
1341 const auto& entity = _storage[target[std::size_t(i)]];
1342 for(int vertex(0); vertex < num_vertices; vertex++)
1343 {
1344 int local_vertex = FaceMapping::map(i, vertex);
1345 local_keys[std::size_t(vertex)] = topo.template key_by_dim<0>(local_vertex).key;
1346 foreign_keys[std::size_t(vertex)] = entity.topology.template key_by_dim<0>(vertex).key;
1347 }
1348
1349 target[std::size_t(i)].orientation = CongruencySampler::compare(local_keys.data(), foreign_keys.data());
1350 }
1351 }
1352 }
1353 }
1354 }
1355
1356 /*
1357 * \brief Map a EntityReference to an OrientedElementRef
1358 *
1359 * \tparam entity_dim_ Dimension of the current entity
1360 * \tparam result_dim_ Dimension the reference refers to
1361 *
1362 * \param[in] topo Current topology
1363 * \param[in] siblings Current siblings
1364 * \param[in] ref EntityReference
1365 */
1366 template<int entity_dim_, int result_dim_>
1367 OrientedElementRef<result_dim_> _resolve_entity_reference(
1368 const ElementTopology<entity_dim_>& topo,
1369 const ElementChildren<entity_dim_>& siblings,
1370 const EntityReference& ref)
1371 {
1372 switch(ref.source)
1373 {
1375 return topo.template key_by_dim<result_dim_>(ref.index);
1377 return OrientedElementRef<result_dim_>(ref.orientation, siblings.template by_dim<result_dim_>()[std::size_t(ref.index)]);
1379 {
1380 if constexpr (entity_dim_ >= 2 && result_dim_ <= 1)
1381 {
1382 return _resolve_boundary_entity_reference<entity_dim_, result_dim_, 1>(topo, ref);
1383 }
1384 else
1385 {
1386 XABORTM("_resolve_entity_reference failed: EntitySource::BoundaryEdge: Either source or target has invalid dimension");
1387 }
1388 }
1390 {
1391 if constexpr (entity_dim_ >= 3 && result_dim_ <= 2)
1392 {
1393 return _resolve_boundary_entity_reference<entity_dim_, result_dim_, 2>(topo, ref);
1394 }
1395 else
1396 {
1397 XABORTM("_resolve_entity_reference failed: EntitySource::BoundaryFace: Either source or target has invalid dimension");
1398 }
1399 }
1400 default:
1401 XABORTM("_resolve_entitiy_reference failed: Unkown EntitySource");
1402 }
1403 }
1404
1406 template<int entity_dim_, int result_dim_, int boundary_dim_>
1407 OrientedElementRef<result_dim_> _resolve_boundary_entity_reference(
1408 const ElementTopology<entity_dim_>& topo,
1409 const EntityReference& ref)
1410 {
1412
1413 // Retrieve type of boundary element
1414 using BoundaryShape = typename Shape::FaceTraits<ShapeType, boundary_dim_>::ShapeType;
1415 OrientedElementRef<boundary_dim_> boundary_ref = topo.template key_by_dim<boundary_dim_>(ref.entity);
1416 typename TemplateSet::template RefinementTypeByDim<boundary_dim_> type = _storage.type(boundary_ref.key);
1417
1418 // Use type and orientation to correct the index of the reference for orientation
1419 std::pair<Index, int> orientation_mapping =
1420 TemplateSet::template correct_for_orientation<BoundaryShape, result_dim_>(type, boundary_ref.orientation, ref.index);
1421
1422 // Retrieve correct child based on orientation mapping
1423 AdaptiveElement<boundary_dim_>& boundary_element = _storage[boundary_ref];
1424 ElementRef<result_dim_> result_ref =
1425 boundary_element.children.template by_dim<result_dim_>()[orientation_mapping.first];
1426
1427 // Return oriented reference
1428 return OrientedElementRef<result_dim_>(orientation_mapping.second, result_ref);
1429 }
1430
1439 template<int dim_>
1440 void _delete_unused(std::unordered_map<Index, ElementRef<dim_>>& roots, const std::set<Index>& elements)
1441 {
1442 auto iter = roots.begin();
1443 while(iter != roots.end())
1444 {
1445 if(elements.find(iter->first) == elements.end())
1446 {
1447 _erase(iter->second);
1448 iter = roots.erase(iter);
1449 }
1450 else
1451 {
1452 iter++;
1453 }
1454 }
1455 }
1456
1465 template<int dim_ = shape_dim>
1467 {
1468 if constexpr(dim_ >= 0)
1469 {
1470 _garbage_collect<dim_ -1>(roots, set);
1471 _delete_unused<dim_>(roots.template by_dim<dim_>(), set.by_dim<dim_>());
1472 }
1473 }
1474
1475 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1476 bool _dbg_check_topology_unique(const ElementTopology<topo_dim_>& topology)
1477 {
1478 if constexpr(dim_ >= 0)
1479 {
1480 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1481
1482 bool all_unique = true;
1483
1484 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1485
1486 const auto& entities = topology.template by_dim<dim_>();
1487 for(int i(0); i < num_entities; i++)
1488 {
1489 for(int j(0); j < num_entities; j++)
1490 {
1491 all_unique = all_unique && (i == j || (entities[std::size_t(i)] != entities[std::size_t(j)]));
1492 }
1493 }
1494
1495 return all_unique && _dbg_check_topology_unique<topo_dim_, dim_ - 1>(topology);
1496 }
1497 else
1498 {
1499 return true;
1500 }
1501 }
1502
1503 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1504 bool _dbg_check_topology_orientations(const ElementTopology<topo_dim_>& topology)
1505 {
1506 if constexpr(dim_ == 0)
1507 {
1508 return true;
1509 }
1510 else
1511 {
1512 bool is_oriented = true;
1513
1514 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1515 using EntityShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1516
1517 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1518 using CongruencySampler = Intern::CongruencySampler<EntityShape>;
1519
1520 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1521 static constexpr int num_vertices = Shape::FaceTraits<EntityShape, 0>::count;
1522
1523 const auto& entities = topology.template by_dim<dim_>();
1524
1525 for(int entity_idx(0); entity_idx < num_entities; entity_idx++)
1526 {
1527 const Intern::OrientedElement<dim_> o_ref = entities[std::size_t(entity_idx)];
1528 const auto& entity = _storage[o_ref];
1529
1530 std::array<ElementRef<0>, num_vertices> local_keys;
1531 std::array<ElementRef<0>, num_vertices> foreign_keys;
1532
1533 for(int vertex(0); vertex < num_vertices; vertex++)
1534 {
1535 const int local_vertex = int(FaceMapping::map(entity_idx, vertex));
1536 local_keys[std::size_t(vertex)] = topology.template key_by_dim<0>(local_vertex).key;
1537 foreign_keys[std::size_t(vertex)] = entity.topology.template key_by_dim<0>(vertex).key;
1538 }
1539
1540 is_oriented = is_oriented && (CongruencySampler::compare(local_keys.data(), foreign_keys.data()) == o_ref.orientation);
1541 }
1542
1543 return is_oriented && _dbg_check_topology_orientations<topo_dim_, dim_ - 1>(topology);
1544 }
1545 }
1546
1547 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1548 bool _dbg_is_topology_consistent(const ElementTopology<topo_dim_>& topology)
1549 {
1550 if constexpr(dim_ == 0)
1551 {
1552 return true;
1553 }
1554 else
1555 {
1556 bool is_consistent = true;
1557
1558 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1559 using EntityShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1560
1561 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1562 using CongruencyMapping = Intern::CongruencyMapping<EntityShape, 0>;
1563
1564 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1565 static constexpr int num_vertices = Shape::FaceTraits<EntityShape, 0>::count;
1566
1567 const auto& entities = topology.template by_dim<dim_>();
1568 for(int entity_idx(0); entity_idx < num_entities; entity_idx++)
1569 {
1570 const auto& entity = _storage[entities[std::size_t(entity_idx)]];
1571
1572 for(int vertex(0); vertex < num_vertices; vertex++)
1573 {
1574 ElementRef<0> v_topo = topology.template by_dim<0>()[std::size_t(FaceMapping::map(entity_idx, vertex))].key;
1575 const int orientation = entities[std::size_t(entity_idx)].orientation;
1576 const Index mapped = Index(CongruencyMapping::map(orientation, vertex));
1577 ElementRef<0> v_entity = entity.topology.template by_dim<0>()[mapped].key;
1578 is_consistent = is_consistent && (v_topo == v_entity);
1579
1580 if(v_topo != v_entity)
1581 {
1582 std::cout << "Inconsistent topology. Vertex " << vertex << " of entity " << entity_idx << " of dimension << " << dim_ << " mismatches!\n";
1583 }
1584 }
1585 }
1586
1587 return is_consistent && _dbg_is_topology_consistent<topo_dim_, dim_ - 1>(topology);
1588 }
1589 }
1590
1591 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1592 bool _dbg_is_topology_layering_consistent(Intern::Layer layer, const ElementTopology<topo_dim_>& topology)
1593 {
1594 if constexpr(dim_ == 0)
1595 {
1596 bool is_consistent = true;
1597
1598 // Vertices are layered consistently as long as we pick no vertices from a higher layer
1599 // NOTE(mmuegge): This can be merged with the dim_ != 0 case, if we
1600 // mark vertices as permanent by default. Which we should do anyway,
1601 // because they are
1602 for(const auto& entity : topology.template by_dim<0>())
1603 {
1604 is_consistent = is_consistent && entity.key.layer <= layer;
1605 }
1606
1607 return is_consistent;
1608 }
1609 else
1610 {
1611 bool is_consistent = _dbg_is_topology_layering_consistent<topo_dim_, dim_ - 1>(layer, topology);
1612
1613 for(const auto& entity : topology.template by_dim<dim_>())
1614 {
1615 is_consistent = is_consistent && (entity.key.layer == layer || (entity.key.layer < layer && entity.key.is_permanent));
1616 }
1617
1618 return is_consistent;
1619 }
1620 }
1621 }; // class AdaptiveMesh
1622} // namespace FEAT::Geometry
#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
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Dynamic mesh data structure.
Intern::MeshRoots< shape_dim > _roots
Mesh roots.
const FoundationMeshType & foundation_mesh() const
Accessor for foundation mesh.
Index get_num_entities(Layer layer, int dim) const
Returns number of elements of dimension dim in layer layer.
Index get_face_index(Layer layer, Index entity_idx, int face_idx) const
Returns an index of a sub-entity, i.e. the index of a face of a cell.
SubdivisionLevels transfer_sdls(SubdivisionLevels &lvls_in) const
Transfer subdivision levels from the adaptive mesh to the foundation mesh.
AdaptionStats adapt(SubdivisionLevels &foundation_levels, ImportBehaviour import_behaviour=ImportBehaviour::RequiredOnly)
Adapt the mesh to new SubdivisionLevels.
std::vector< Index > overlap_mapping()
Computes mapping from AdaptiveMesh elements to foundation mesh elements.
typename FoundationMeshType::VertexType VertexType
Vertex type.
std::optional< Index > get_child(Layer layer, Index parent_idx, Index child) const
Retrieve index of a child element.
MeshPart< FoundationMeshType > exclusive_meshpart() const
Exclusive MeshPart factory.
LevelTuple< entity_dim_ > _levels(const TopologyTemplate< typename Shape::FaceTraits< ShapeType, entity_dim_ >::ShapeType > &tmplt, const LevelTuple< parent_dim_ > &lvls)
Spread refinement levels to a child entity.
Coord_ CoordType
Coordinate type.
OrientedElementRef< result_dim_ > _resolve_boundary_entity_reference(const ElementTopology< entity_dim_ > &topo, const EntityReference &ref)
Helper-function for _resolve_entity_reference. Handles boundary entities of any dimension.
void _adapt_sub_entities(Index depth, AdaptiveElement< parent_dim_ > &self, const RefinementTemplate< typename Shape::FaceTraits< ShapeType, parent_dim_ >::ShapeType > &tmplt, const LevelTuple< parent_dim_ > &levels)
Adapts children of dimension dim_.
MeshStorage _storage
Mesh storage.
const VertexType & vertex(Layer layer, Index vertex_index) const
Retrieve vertex at index v from layer layer.
bool has_vertex_changed(Layer layer, Index vertex_idx) const
Indicates whether any mesh element adjacent to the given vertex has changed on the given layer.
VertexType & vertex(Layer layer, Index vertex_index)
Retrieve vertex at index v from layer layer.
std::optional< Index > get_overlap_cell(Index foundation_index) const
Mapping of elements of the foundation mesh to elements of the AdaptiveMesh.
void transform(const VertexType &origin, const VertexType &angles, const VertexType &offset)
Applies a "proper rigid" transformation onto the mesh vertices.
const FoundationMeshType & _foundation_mesh
Reference to foundation mesh.
AdaptionStats _stats
Stats of latest adaption.
void _erase(Intern::ElementKey< dim_ > key)
Erases an element and all its children from the mesh.
void fill_neighbors()
Computes neighboring elements for all mesh elements.
std::vector< std::pair< Index, Index > > bridge_pairs()
Computes mapping from elements of the foundation mesh to elements of the AdaptiveMesh.
static constexpr int shape_dim
Shape dimension.
void _garbage_collect(Intern::MeshRoots< shape_dim > &roots, const Intern::MeshIndexSet &set)
Delete all elements from the storage and mesh roots that are not in the index set.
void _adapt_roots(const Intern::MeshIndexSet &set, Intern::RefinementField< typename TemplateSet::VertexMarkerType > &sdls)
Adapts roots of refinement trees.
static constexpr int world_dim
World dimension.
MeshPart< TargetMeshType_ > project_meshpart(Layer layer, const MeshPart< FoundationMeshType > &part) const
Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
Returns the index of the n-th neighbor of the given element.
Shape_ ShapeType
Shape of this mesh.
void _adapt_children(ElementRef< dim_ > key, const LevelTuple< dim_ > &levels)
Adjusts the children of the given element to match new subdivision levels.
AdaptiveMesh(const FoundationMeshType &mesh)
Constructor.
MeshPart< FoundationMeshType > overlap_meshpart() const
Overlap MeshPart factory.
FoundationMeshType & foundation_mesh()
Accessor for foundation mesh.
Index num_total_entities() const
Returns the total number of entities of dimension dim_ across all mesh layers.
Index get_num_children(Layer layer, Index elem)
Returns the number of children of an element in the mesh.
Intern::ElementKey< dim_ > _build(Index depth, const LevelTuple< dim_ > &levels, const ElementTopology< dim_ > &topology)
Construct a new subtree.
FoundationMeshType to_conformal_mesh(Layer layer) const
Create a ConformalMesh from a layer.
static FoundationMeshType create_refined_mesh(const FoundationMeshType &foundation_mesh, const VertexMarker_ &marker)
Use the AdaptiveMesh as a generator for other meshes.
void _delete_unused(std::unordered_map< Index, ElementRef< dim_ > > &roots, const std::set< Index > &elements)
Helper for garbage_collect. Deletes all entities of dimension dim that are not in the given set.
void _adapt_roots_of_dim(const Intern::MeshIndexSet &set, Intern::RefinementField< typename TemplateSet::VertexMarkerType > &sdls)
Adapts roots of refinement trees.
void _build_topology(const TopologyTemplate< typename Shape::FaceTraits< ShapeType, topo_dim_ >::ShapeType > &tmplt, ElementTopology< topo_dim_ > &topo, const ElementTopology< parent_dim_ > &parent_topo, const ElementChildren< parent_dim_ > &siblings)
Construct a topology for a new child element.
TemplateSet_ TemplateSet
Template set used by this mesh.
ImportBehaviour
ImportBehaviour for this mesh.
@ RequiredOnly
Import only entites required for the current subdivision levels.
@ All
Import all entities. Useful for exporting the complete mesh later.
Index num_layers() const
Returns number of layers of the AdaptiveMesh.
Conformal mesh class template.
Index get_num_entities(int dim) const
Returns the number of entities.
VertexSetType::VertexType VertexType
Vertex type.
Index get_num_vertices() const
Returns the number of vertices.
VertexSetType & get_vertex_set()
Returns a reference to the vertex set of the mesh.
void fill_neighbors()
Fills the neighbor index set.
VertexKey insert(const AdaptiveVertexType &vertex)
Insert a vertex into the storage.
void fill_neighbors()
Determines neighboring elements for all mesh elements.
void transform(const VertexType &origin, const VertexType &angles, const VertexType &offset)
Applies a "proper rigid" transformation onto the mesh vertices.
const AdaptiveVertexType & get_vertex_by_index(Layer layer, Index idx) const
Retrieves a vertex of the mesh by its layer and index.
Index num_entities(Layer layer, int dim) const
Returns the number of mesh elements of the given dimension on the given layer.
Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
Returns the index of the n-th neighbor of the given element.
Index num_layers() const
Return the number of layers in this mesh.
TemplateSet::template RefinementTypeByDim< dim > type(ElementKey< dim > key)
Get refinement type of element.
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.
Schneiders template set for adaptive mesh refinement.
Class template for partial meshes.
Definition: mesh_part.hpp:90
Schneiders template set for adaptive mesh refinement.
Subdivision level markings for meshes.
Geometry namespace.
@ other
generic/other permutation strategy
@ BoundaryEdge
Entity is part of a boundary edge, i.e. a child of one of the parents edges.
@ ParentTopology
Entity is part of the parents topology.
@ BoundaryFace
Entity is part of a boundary face, i.e. a child of one of the parents faces.
@ Sibling
Entity is a sibling in the refinement tree.
double Real
Real data type.
std::uint64_t Index
Index data type.
Statistics about entities added, removed, and kept during a mesh adaption.
std::array< Index, 4 > removed
Statistics about removed entities.
void removed_element(Index count=1)
Indicate a entity was removed.
void reset()
Reset statistics to zero.
void removed_elements(const std::array< Index, 4 > &counts)
Indicate entities were removed.
void kept_element(Index count=1)
Indicate a entity was kept.
void added_element(Index count=1)
Indicate a entity was added.
std::array< Index, 4 > added
Statistics about added entities.
std::array< Index, 4 > kept
Statistics about kept entities.
Reference to another local mesh entity.
EntitySource source
Where to retrieve the entity from.
int entity
Index of boundary entity to retrieve entity from. Only set for boundary entities.
int orientation
Orientation of the retrieved entity relative to the retrieving entity. Only set for sibling entities.
Algorithm for exporting a layer of an AdaptiveMesh to a ConformalMesh.
SlotMap key for use by the AdaptiveMeshStorage class.
Alorithm for collecting mesh entities that must be adaptively refined.
Algorithm for collecting topologies from the foundation mesh.
Newtype wrapper for mesh layers.
Algorithm for projecting MeshParts of an underlying mesh onto its adaptive mesh.
Mapping from ConformalMesh Indices to MeshStorage keys.
Template for refining a mesh entity.
Construction rule for a single entities topology.
Face traits tag struct template.
Definition: shape.hpp:106
typedef ShapeType
Shape type of the face.
Definition: shape.hpp:108