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] = 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, Index 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)
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
645 std::optional<Index> get_overlap_cell(Index foundation_index)
646 {
647 std::unordered_map<Index, ElementRef<shape_dim>>& root_map = _roots.template by_dim<ShapeType::dimension>();
648
649 auto iter = root_map.find(foundation_index);
650 if(iter != root_map.end())
651 {
652 return _storage.get_index(iter->second);
653 }
654
655 return std::nullopt;
656 }
657
664 std::vector<Index> overlap_mapping()
665 {
666 std::vector<Index> result(_storage.num_entities(0, 0));
667
668 for(auto& entry : _roots.vertices)
669 {
670 result[_storage.get_index(entry.second)] = entry.first;
671 }
672
673 return result;
674 }
675
683 {
684 return _storage.num_layers();
685 }
686
701 {
702 // Get element roots
703 const std::unordered_map<Index, ElementRef<shape_dim>>& root_map = _roots.template by_dim<ShapeType::dimension>();
704
705 // Determine mesh part size
707 const Index overlap_cells = root_map.size();
708 const Index part_cells = total_cells - overlap_cells;
709 std::array<Index, shape_dim + 1> part_size = {};
710 part_size[shape_dim] = part_cells;
711
712 // Create mesh part without topology
713 MeshPart<FoundationMeshType> result(part_size.data(), false);
714 auto& target_set = result.template get_target_set<shape_dim>();
715
716 // Write foundation mesh indices into mesh part
717 Index tset_index = 0;
718 for(Index i(0); i < total_cells; ++i)
719 {
720 if(root_map.find(i) == root_map.end())
721 {
722 // Cell i is not a root of the adaptive mesh. Add it.
723 target_set[tset_index] = i;
724 tset_index++;
725 }
726 }
727
728 return result;
729 }
730
745 {
746 // Get element roots
747 const std::unordered_map<Index, ElementRef<shape_dim>>& root_map = _roots.template by_dim<ShapeType::dimension>();
748
749 // Determine result target set size
750 const Index overlap_cells = root_map.size();
751 std::array<Index, shape_dim + 1> part_size = {};
752 part_size[shape_dim] = overlap_cells;
753
754 // Create mesh part without topology
755 MeshPart<FoundationMeshType> result(part_size.data(), false);
756 auto& target_set = result.template get_target_set<shape_dim>();
757
758 // Write foundation mesh indices into mesh part
759 Index tset_index = 0;
760 for(auto& entry : root_map)
761 {
762 target_set[tset_index] = entry.first;
763 tset_index++;
764 }
765
766 return result;
767 }
768
783 {
785 const Layer fine_layer = Layer{num_layers - 1};
786 const Index num_base_vertices = _storage.num_entities(Layer{0}, 0);
787 const Index num_fine_vertices = _storage.num_entities(fine_layer, 0);
788
789 SubdivisionLevels result(num_base_vertices);
790
791 for(Index v_fine_idx = 0; v_fine_idx < num_fine_vertices; v_fine_idx++)
792 {
793 // Find vertex in foundation mesh that is closest to the current fine vertex
794 Real closest_distance = std::numeric_limits<Real>::max();
795 Index closest_vertex = 0;
796 for(Index v_base_idx = 0; v_base_idx < num_base_vertices; v_base_idx++)
797 {
798 const AdaptiveVertex& v_fine = _storage.get_vertex_by_index(fine_layer, v_fine_idx);
799 const AdaptiveVertex& v_base = _storage.get_vertex_by_index(Layer{0}, v_base_idx);
800 const Real distance = (v_fine.vertex - v_base.vertex).norm_euclid_sqr();
801 if(distance < closest_distance)
802 {
803 closest_distance = distance;
804 closest_vertex = v_base_idx;
805 }
806 }
807
808 // Assign the subdivision levels of the current vertex to the closest vertex in the foundation mesh
809 result[closest_vertex] = std::max(result[closest_vertex], lvls_in[v_fine_idx]);
810 }
811 return result;
812 }
813
818 {
820 }
821
827 Index get_neighbor(Layer layer, Index element_idx, Index neighbor_idx) const
828 {
829 return _storage.get_neighbor(layer, element_idx, neighbor_idx);
830 }
831
860 void transform(const VertexType& origin, const VertexType& angles, const VertexType& offset)
861 {
862 _storage.transform(origin, angles, offset);
863 }
864
865 private:
880 template<int dim_>
881 Intern::ElementKey<dim_> _build(Index depth, const LevelTuple<dim_>& levels, const ElementTopology<dim_>& topology)
882 {
883 ASSERT(_dbg_check_topology_unique<dim_>(topology));
884 ASSERT(_dbg_check_topology_orientations<dim_>(topology));
885 ASSERT(_dbg_is_topology_consistent<dim_>(topology));
886 ASSERT(_dbg_is_topology_layering_consistent<dim_>(Intern::Layer{depth}, topology));
887
888 _stats.added_element<dim_>();
889
890 auto type = typename TemplateSet::template RefinementTypeByDim<dim_>(levels);
891
892 //std::cout << "Building element of type " << type << "\n";
893 // Create tree root
894 auto self = AdaptiveElement<dim_>(type, Layer{depth}, topology);
895
896 if(type.is_zero_refinement())
897 {
898 // Zero type elements have no children. We are done here.
899 auto key = _storage.insert(self);
900 //std::cout << "Built element " << key << "\n";
901 return key;
902 }
903
904 using TemplateShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
905
906 static constexpr int num_vertices = Shape::FaceTraits<TemplateShape, 0>::count;
907
908 const RefinementTemplate<TemplateShape>& tmplt = TemplateSet::get_template(type);
909
910 // Build child vertices
911 _stats.added_element<0>(tmplt.template num_entities<0>());
912
913 // Retrieve vertex coordinates of topology for following vertex interpolation
914 std::array<VertexType, num_vertices> vertex_coordinates;
915
916 for(int i{0}; i < num_vertices; i++)
917 {
918 vertex_coordinates[i] = _storage[topology.template key_by_dim<0>(i)].vertex;
919 }
920
921 // Produce child vertices by linear interpolation
922 auto& child_vertices = self.children.template by_dim<0>();
923 for(Index i = 0; i < tmplt.template num_entities<0>(); i++)
924 {
925 const VertexType vertex(Intern::interpolate(vertex_coordinates, tmplt.get_vertex_coefficients()[i]));
926 child_vertices[i] = _storage.insert(AdaptiveVertex(vertex, Layer{depth + 1}));
927 }
928
929 // We are recording the last mesh layer on which any of the entities surrounding a vertex has changed.
930 // This allows disregarding these vertices in a BPX solver later.
931 // NOTE: This is quite specific. Can we move this out of the build routine somehow?
932 if(tmplt.template num_entities<0>() > 0)
933 {
934 // Parent vertices created new vertices at this depth.
935 // Increase referenced depth for BPX star-sum
936 auto& topo_vertices = self.topology.template by_dim<0>();
937 for(Index v = 0; v < topo_vertices.size(); v++)
938 {
939 auto& vertex = _storage[topo_vertices[v]];
940 if(depth + 1 > vertex.last_changed.idx)
941 {
942 vertex.last_changed = Layer{depth + 1};
943 }
944 }
945 }
946
947 // Build child edges
948 if constexpr(dim_ >= 1)
949 {
950 auto& children = self.children.template by_dim<1>();
951 const auto& topo_templates = tmplt.template get_topologies<1>();
952 for(Index i = 0; i < tmplt.template num_entities<1>(); i++)
953 {
954 ElementTopology<1> child_topo;
955 _build_topology<dim_, 1>(topo_templates[i], child_topo, topology, self.children);
956
957 children[i] = _build<1>(depth + 1, _levels<dim_, 1>(topo_templates[i], levels), child_topo);
958 }
959 }
960
961 // Build faces
962 if constexpr(dim_ >= 2)
963 {
964 auto& children = self.children.template by_dim<2>();
965 const auto& topo_templates = tmplt.template get_topologies<2>();
966 for(Index i = 0; i < tmplt.template num_entities<2>(); i++)
967 {
968 ElementTopology<2> child_topo;
969 _build_topology<dim_, 2>(topo_templates[i], child_topo, topology, self.children);
970
971 children[i] = _build<2>(depth + 1, _levels<dim_, 2>(topo_templates[i], levels), child_topo);
972 }
973 }
974
975 // Build cells
976 if constexpr(dim_ >= 3)
977 {
978 auto& children = self.children.template by_dim<3>();
979 const auto& topo_templates = tmplt.template get_topologies<3>();
980 for(Index i = 0; i < tmplt.template num_entities<3>(); i++)
981 {
982 ElementTopology<3> child_topo;
983 _build_topology<dim_, 3>(topo_templates[i], child_topo, topology, self.children);
984
985 children[i] = _build<3>(depth + 1, _levels<dim_, 3>(topo_templates[i], levels), child_topo);
986 }
987 }
988
989 return _storage.insert(self);
990 }
991
1006 template<int dim_>
1008 {
1009 // Algorithm for collecting topologies from the foundation mesh. Entry
1010 // dimension is dim_ - 1, because topologies only contain entities of
1011 // smaller dimension than the entity the topology belongs to.
1012 using TopologyCollector = Intern::FoundationTopologyCollector<AdaptiveMesh, dim_, dim_ - 1>;
1013
1014 // Vertices of foundation entities, for collecting subdivision levels
1015 auto& foundation_entities = _foundation_mesh.template get_index_set<dim_, 0>();
1016 auto& roots = _roots.template by_dim<dim_>();
1017
1018 for(Index idx : set.template by_dim<dim_>())
1019 {
1020 // Determine refinement type of current entity
1021 auto markings = sdls.get_tuple(foundation_entities[idx]);
1022 auto type = typename TemplateSet::template RefinementTypeByDim<dim_>(markings);
1023
1024 // Determine entities entry in mesh roots, if it exists
1025 auto iter = roots.find(idx);
1026 bool exists = iter != roots.end();
1027
1028 if(exists && _storage.type(iter->second) == type)
1029 {
1030 // Element already exists and its type has not changed.
1031 // Adapt its children further.
1032 _adapt_children<dim_>(iter->second, markings);
1033 }
1034 else
1035 {
1036 //std::cout << "Rebuilding element with new type " << type << "\n";
1037 //std::cout << "Markings: ";
1038 for(Index i(0); i < markings.size; i++)
1039 {
1040 //std::cout << markings[i] << ", ";
1041 }
1042 //std::cout << "\n";
1043 // Element either does not exist or its type has changed.
1044 // (Re)build it.
1045
1046 // We need the entity's topology to rebuild it.
1047 // NOTE: Even if the entity already exists in the mesh and is only
1048 // going to be replaced, we can not reuse its topology. If we entered
1049 // this branch the entity's refinement type has changed, which means
1050 // the refinement type of at least one sub-entity has also changed.
1051 // That sub-entity has itself been replaced at this point, and the
1052 // reference stored in this entity's topology is invalid.
1053
1054 // OPTIMIZATION: While it is true that we can't reuse the previous
1055 // topology, if it exists, we are currently doing some needless work
1056 // in that case. The topology collection also determines the
1057 // orientation of any references in the topology. Those orientations
1058 // don't change, so it would be enough to only update the references,
1059 // if the topology has been collected before.
1060 ElementTopology<dim_> topology;
1061 TopologyCollector::collect(topology, idx, *this);
1062
1063 if(exists)
1064 {
1065 // Entity already existed. Replace it.
1066 _erase(iter->second);
1067 iter->second = _build<dim_>(0, markings, topology);
1068 }
1069 else
1070 {
1071 // Entity is entirely new. Build it.
1072 roots[idx] = _build<dim_>(0, markings, topology);
1073 }
1074 }
1075 }
1076 }
1077
1092 {
1093 if constexpr(shape_dim >= 0)
1094 {
1095 auto& vertex_set = _foundation_mesh.get_vertex_set();
1096 auto& vertex_roots = _roots.template by_dim<0>();
1097 for(const auto& vert : set.vertices)
1098 {
1099 if(vertex_roots.find(vert) == vertex_roots.end())
1100 {
1101 _stats.template added_element<0>();
1102 vertex_roots[vert] = _storage.insert(vertex_set[vert], Layer{0});
1103 }
1104 else
1105 {
1106 _stats.template kept_element<0>();
1107 }
1108 }
1109 }
1110 if constexpr(shape_dim >= 1)
1111 {
1112 _adapt_roots_of_dim<1>(set, sdls);
1113 }
1114 if constexpr(shape_dim >= 2)
1115 {
1116 _adapt_roots_of_dim<2>(set, sdls);
1117 }
1118 if constexpr(shape_dim >= 3)
1119 {
1120 _adapt_roots_of_dim<3>(set, sdls);
1121 }
1122 }
1123
1136 template<int dim_>
1137 void _adapt_children(ElementRef<dim_> key, const LevelTuple<dim_>& levels)
1138 {
1139 // Calculate element type
1140 const auto type = _storage.type(key);
1141 const Index depth = _storage[key].layer.idx;
1142
1143 //std::cout << "Adapting element of type " << type << "\n";
1144 // Adapting an entity's children requires a valid topology for the parent
1145 // element. If this entity's type changed, then it should have been
1146 // rebuilt with a valid topology and calling _adapt_children is an error.
1147 XASSERTM(type == typename TemplateSet::template RefinementTypeByDim<dim_>(levels), "Called adapt_children on element with changed type.");
1148
1149 // We are keeping the current entity as part of the mesh
1150 _stats.kept_element<dim_>();
1151
1152 if(type.is_zero_refinement())
1153 {
1154 // Zero-type elements have no children that need further adaptation.
1155 return;
1156 }
1157
1158 // Retrieve reference to current entity
1159 auto& self = _storage[key];
1160
1161 using TemplateShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1162 const RefinementTemplate<TemplateShape>& tmplt = TemplateSet::get_template(type);
1163
1164 // Retrieve vertex query from template set. Vertices do not need
1165 // adaptation, but we guarantee template sets that we will construct all
1166 // template queries in order.
1167 _stats.kept_element<0>(tmplt.template num_entities<0>());
1168
1169 // Adapt child edges
1170 if constexpr(dim_ >= 1)
1171 {
1172 _adapt_sub_entities<dim_, 1>(depth, self, tmplt, levels);
1173
1174 // Adapt child faces
1175 if constexpr(dim_ >= 2)
1176 {
1177 _adapt_sub_entities<dim_, 2>(depth, self, tmplt, levels);
1178
1179 // Adapt child cells
1180 if constexpr(dim_ >= 3)
1181 {
1182 _adapt_sub_entities<dim_, 3>(depth, self, tmplt, levels);
1183 }
1184 }
1185 }
1186 }
1187
1188 protected:
1196 template<int dim_>
1198 {
1200 }
1201
1215 template<int parent_dim_, int child_dim_>
1217 Index depth,
1218 AdaptiveElement<parent_dim_>& self,
1220 const LevelTuple<parent_dim_>& levels)
1221 {
1222 // children is an std::array of slotmap keys
1223 auto& children = self.children.template by_dim<child_dim_>();
1224 auto& topo_templates = tmplt.template get_topologies<child_dim_>();
1225
1226 for(Index i = 0; i < tmplt.template num_entities<child_dim_>(); i++)
1227 {
1228 // Determine child SubdivisionLevels and type
1229 LevelTuple<child_dim_> child_levels = _levels<parent_dim_, child_dim_>(topo_templates[i], levels);
1230 auto child_type = typename TemplateSet::template RefinementTypeByDim<child_dim_>(child_levels);
1231
1232 if(_storage.type(children[i]) == child_type)
1233 {
1234 // Type is unchanged. Adapt children recursively.
1235 _adapt_children<child_dim_>(children[i], child_levels);
1236 }
1237 else
1238 {
1239 // Type is changed. Erase child and rebuild it.
1240 _erase(children[i]);
1241
1242 ElementTopology<child_dim_> child_topology;
1243 _build_topology<parent_dim_, child_dim_>(topo_templates[i], child_topology, self.topology, self.children);
1244
1245 children[i] = _build<child_dim_>(depth + 1, child_levels, child_topology);
1246 }
1247 }
1248 }
1249
1262 template<int parent_dim_, int entity_dim_>
1265 const LevelTuple<parent_dim_>& lvls)
1266 {
1267 // OPTIMIZATION(mmuegge): Currenlty a new minimum is calculated for all
1268 // vertices. We can use that all sibling vertices share the same new
1269 // marking. As do all vertices on any of the boundary elements. Add a
1270 // MarkingSpreader class or something like that and cache the results.
1271 using ParentShape = typename Shape::FaceTraits<ShapeType, parent_dim_>::ShapeType;
1272
1273 const auto& vertex_refs = tmplt.template get_references<0>();
1274
1276
1277 for(Index i(0); i < result.size; ++i)
1278 {
1279 result[i] = TemplateSet::template spread_refinement_field<ParentShape>(vertex_refs[i], lvls);
1280 }
1281
1282 return result;
1283 }
1284
1299 template<int parent_dim_, int topo_dim_, int dim_ = topo_dim_ - 1>
1302 ElementTopology<topo_dim_>& topo,
1303 const ElementTopology<parent_dim_>& parent_topo,
1304 const ElementChildren<parent_dim_>& siblings)
1305 {
1306 if constexpr(dim_ >= 0)
1307 {
1308 _build_topology<parent_dim_, topo_dim_, dim_ - 1>(tmplt, topo, parent_topo, siblings);
1309
1310 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1311 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1312
1313 auto& target = topo.template by_dim<dim_>();
1314 for(int i(0); i < num_entities; i++)
1315 {
1316 EntityReference ref = tmplt.template get_reference<dim_>(i);
1317 target[i] = _resolve_entity_reference<parent_dim_, dim_>(parent_topo, siblings, ref);
1318
1319 if constexpr(dim_ >= 1)
1320 {
1322 {
1323 // Calc orientation
1324 using ResultShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1325 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1326 using CongruencySampler = Intern::CongruencySampler<ResultShape>;
1327
1328 static constexpr int num_vertices = Shape::FaceTraits<ResultShape, 0>::count;
1329 std::array<ElementRef<0>, num_vertices> local_keys;
1330 std::array<ElementRef<0>, num_vertices> foreign_keys;
1331
1332 const auto& entity = _storage[target[i]];
1333 for(int vertex(0); vertex < num_vertices; vertex++)
1334 {
1335 Index local_vertex = FaceMapping::map(i, vertex);
1336 local_keys[vertex] = topo.template key_by_dim<0>(local_vertex).key;
1337 foreign_keys[vertex] = entity.topology.template key_by_dim<0>(vertex).key;
1338 }
1339
1340 target[i].orientation = CongruencySampler::compare(local_keys.data(), foreign_keys.data());
1341 }
1342 }
1343 }
1344 }
1345 }
1346
1347 /*
1348 * \brief Map a EntityReference to an OrientedElementRef
1349 *
1350 * \tparam entity_dim_ Dimension of the current entity
1351 * \tparam result_dim_ Dimension the reference refers to
1352 *
1353 * \param[in] topo Current topology
1354 * \param[in] siblings Current siblings
1355 * \param[in] ref EntityReference
1356 */
1357 template<int entity_dim_, int result_dim_>
1358 OrientedElementRef<result_dim_> _resolve_entity_reference(
1359 const ElementTopology<entity_dim_>& topo,
1360 const ElementChildren<entity_dim_>& siblings,
1361 const EntityReference& ref)
1362 {
1363 switch(ref.source)
1364 {
1366 return topo.template key_by_dim<result_dim_>(ref.index);
1368 return OrientedElementRef<result_dim_>(ref.orientation, siblings.template by_dim<result_dim_>()[ref.index]);
1370 {
1371 if constexpr (entity_dim_ >= 2 && result_dim_ <= 1)
1372 {
1373 return _resolve_boundary_entity_reference<entity_dim_, result_dim_, 1>(topo, ref);
1374 }
1375 }
1377 {
1378 if constexpr (entity_dim_ >= 3 && result_dim_ <= 2)
1379 {
1380 return _resolve_boundary_entity_reference<entity_dim_, result_dim_, 2>(topo, ref);
1381 }
1382 }
1383 default:
1384 XABORTM("select failed");
1385 }
1386 }
1387
1389 template<int entity_dim_, int result_dim_, int boundary_dim_>
1390 OrientedElementRef<result_dim_> _resolve_boundary_entity_reference(
1391 const ElementTopology<entity_dim_>& topo,
1392 const EntityReference& ref)
1393 {
1395
1396 // Retrieve type of boundary element
1397 using BoundaryShape = typename Shape::FaceTraits<ShapeType, boundary_dim_>::ShapeType;
1398 OrientedElementRef<boundary_dim_> boundary_ref = topo.template key_by_dim<boundary_dim_>(ref.entity);
1399 typename TemplateSet::template RefinementTypeByDim<boundary_dim_> type = _storage.type(boundary_ref.key);
1400
1401 // Use type and orientation to correct the index of the reference for orientation
1402 std::pair<Index, int> orientation_mapping =
1403 TemplateSet::template correct_for_orientation<BoundaryShape, result_dim_>(type, boundary_ref.orientation, ref.index);
1404
1405 // Retrieve correct child based on orientation mapping
1406 AdaptiveElement<boundary_dim_>& boundary_element = _storage[boundary_ref];
1407 ElementRef<result_dim_> result_ref =
1408 boundary_element.children.template by_dim<result_dim_>()[orientation_mapping.first];
1409
1410 // Return oriented reference
1411 return OrientedElementRef<result_dim_>(orientation_mapping.second, result_ref);
1412 }
1413
1422 template<int dim_>
1423 void _delete_unused(std::unordered_map<Index, ElementRef<dim_>>& roots, const std::set<Index>& elements)
1424 {
1425 auto iter = roots.begin();
1426 while(iter != roots.end())
1427 {
1428 if(elements.find(iter->first) == elements.end())
1429 {
1430 _erase(iter->second);
1431 iter = roots.erase(iter);
1432 }
1433 else
1434 {
1435 iter++;
1436 }
1437 }
1438 }
1439
1448 template<int dim_ = shape_dim>
1450 {
1451 if constexpr(dim_ >= 0)
1452 {
1453 _garbage_collect<dim_ -1>(roots, set);
1454 _delete_unused<dim_>(roots.template by_dim<dim_>(), set.by_dim<dim_>());
1455 }
1456 }
1457
1458 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1459 bool _dbg_check_topology_unique(const ElementTopology<topo_dim_>& topology)
1460 {
1461 if constexpr(dim_ >= 0)
1462 {
1463 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1464
1465 bool all_unique = true;
1466
1467 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1468
1469 const auto& entities = topology.template by_dim<dim_>();
1470 for(int i(0); i < num_entities; i++)
1471 {
1472 for(int j(0); j < num_entities; j++)
1473 {
1474 all_unique = all_unique && (i == j || (entities[i] != entities[j]));
1475 }
1476 }
1477
1478 return all_unique && _dbg_check_topology_unique<topo_dim_, dim_ - 1>(topology);
1479 }
1480 else
1481 {
1482 return true;
1483 }
1484 }
1485
1486 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1487 bool _dbg_check_topology_orientations(const ElementTopology<topo_dim_>& topology)
1488 {
1489 if constexpr(dim_ == 0)
1490 {
1491 return true;
1492 }
1493 else
1494 {
1495 bool is_oriented = true;
1496
1497 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1498 using EntityShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1499
1500 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1501 using CongruencySampler = Intern::CongruencySampler<EntityShape>;
1502
1503 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1504 static constexpr int num_vertices = Shape::FaceTraits<EntityShape, 0>::count;
1505
1506 const auto& entities = topology.template by_dim<dim_>();
1507
1508 for(int entity_idx(0); entity_idx < num_entities; entity_idx++)
1509 {
1510 const Intern::OrientedElement<dim_> o_ref = entities[entity_idx];
1511 const auto& entity = _storage[o_ref];
1512
1513 std::array<ElementRef<0>, num_vertices> local_keys;
1514 std::array<ElementRef<0>, num_vertices> foreign_keys;
1515
1516 for(int vertex(0); vertex < num_vertices; vertex++)
1517 {
1518 Index local_vertex = FaceMapping::map(entity_idx, vertex);
1519 local_keys[vertex] = topology.template key_by_dim<0>(local_vertex).key;
1520 foreign_keys[vertex] = entity.topology.template key_by_dim<0>(vertex).key;
1521 }
1522
1523 is_oriented = is_oriented && (CongruencySampler::compare(local_keys.data(), foreign_keys.data()) == o_ref.orientation);
1524 }
1525
1526 return is_oriented && _dbg_check_topology_orientations<topo_dim_, dim_ - 1>(topology);
1527 }
1528 }
1529
1530 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1531 bool _dbg_is_topology_consistent(const ElementTopology<topo_dim_>& topology)
1532 {
1533 if constexpr(dim_ == 0)
1534 {
1535 return true;
1536 }
1537 else
1538 {
1539 bool is_consistent = true;
1540
1541 using TopologyShape = typename Shape::FaceTraits<ShapeType, topo_dim_>::ShapeType;
1542 using EntityShape = typename Shape::FaceTraits<ShapeType, dim_>::ShapeType;
1543
1544 using FaceMapping = Intern::FaceIndexMapping<TopologyShape, dim_, 0>;
1545 using CongruencyMapping = Intern::CongruencyMapping<EntityShape, 0>;
1546
1547 static constexpr int num_entities = Shape::FaceTraits<TopologyShape, dim_>::count;
1548 static constexpr int num_vertices = Shape::FaceTraits<EntityShape, 0>::count;
1549
1550 const auto& entities = topology.template by_dim<dim_>();
1551 for(int entity_idx(0); entity_idx < num_entities; entity_idx++)
1552 {
1553 const auto& entity = _storage[entities[entity_idx]];
1554
1555 for(int vertex(0); vertex < num_vertices; vertex++)
1556 {
1557 ElementRef<0> v_topo = topology.template by_dim<0>()[FaceMapping::map(entity_idx, vertex)].key;
1558 int orientation = entities[entity_idx].orientation;
1559 Index mapped = CongruencyMapping::map(orientation, vertex);
1560 ElementRef<0> v_entity = entity.topology.template by_dim<0>()[mapped].key;
1561 is_consistent = is_consistent && (v_topo == v_entity);
1562
1563 if(v_topo != v_entity)
1564 {
1565 std::cout << "Inconsistent topology. Vertex " << vertex << " of entity " << entity_idx << " of dimension << " << dim_ << " mismatches!\n";
1566 }
1567 }
1568 }
1569
1570 return is_consistent && _dbg_is_topology_consistent<topo_dim_, dim_ - 1>(topology);
1571 }
1572 }
1573
1574 template<int topo_dim_, int dim_ = topo_dim_ - 1>
1575 bool _dbg_is_topology_layering_consistent(Intern::Layer layer, const ElementTopology<topo_dim_>& topology)
1576 {
1577 if constexpr(dim_ == 0)
1578 {
1579 bool is_consistent = true;
1580
1581 // Vertices are layered consistently as long as we pick no vertices from a higher layer
1582 // NOTE(mmuegge): This can be merged with the dim_ != 0 case, if we
1583 // mark vertices as permanent by default. Which we should do anyway,
1584 // because they are
1585 for(const auto& entity : topology.template by_dim<0>())
1586 {
1587 is_consistent = is_consistent && entity.key.layer <= layer;
1588 }
1589
1590 return is_consistent;
1591 }
1592 else
1593 {
1594 bool is_consistent = _dbg_is_topology_layering_consistent<topo_dim_, dim_ - 1>(layer, topology);
1595
1596 for(const auto& entity : topology.template by_dim<dim_>())
1597 {
1598 is_consistent = is_consistent && (entity.key.layer == layer || (entity.key.layer < layer && entity.key.is_permanent));
1599 }
1600
1601 return is_consistent;
1602 }
1603 }
1604 }; // class AdaptiveMesh
1605} // 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.
Index get_num_entities(Layer layer, int dim) const
Returns number of elements of dimension dim in layer layer.
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.
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.
std::optional< Index > get_overlap_cell(Index foundation_index)
Mapping of elements of the foundation mesh to elements of the AdaptiveMesh.
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.
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.
Index get_face_index(Layer layer, Index entity_idx, Index face_idx) const
Returns an index of a sub-entity, i.e. the index of a face of a cell.
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.
std::optional< Index > get_child(Layer layer, Index parent_idx, Index child)
Retrieve index of a 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.
static constexpr std::size_t size
Tuple size.
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