FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
adaptive_mesh_layer.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include "kernel/geometry/mesh_permutation.hpp"
9#include "kernel/shape.hpp"
10#include "kernel/util/string.hpp"
11#include <kernel/adjacency/permutation.hpp>
13#include <kernel/geometry/adaptive_mesh.hpp>
14#include <kernel/util/tiny_algebra.hpp>
15
16#include <memory>
17#include <optional>
18#include <utility>
19
20namespace FEAT::Geometry
21{
22
33 template<typename AdaptiveMeshType_>
35 {
36 public:
38 using AdaptiveMeshType = AdaptiveMeshType_;
39
41 static constexpr int num_coords = AdaptiveMeshType::world_dim;
42
44 using CoordType = typename AdaptiveMeshType::CoordType;
45
47 using VertexType = typename AdaptiveMeshType::VertexType;
48
49 private:
51 std::shared_ptr<AdaptiveMeshType> _mesh;
52
53 // Mesh layer we refer to
54 Layer _layer;
55
56 // Vertex permutation
57 // Stored, because we can not apply it to the vertex set directly, as the
58 // underlying memory is shared between all AdaptiveVertexSets.
59 // Stored as an optional to avoid allocating a permutation if no permutation
60 // is required by the user.
61 std::optional<Adjacency::Permutation> _perm;
62
63 public:
70 AdaptiveVertexSet(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) : _mesh(std::move(mesh)), _layer(layer)
71 {
72 }
73
82 {
83 return AdaptiveVertexSet(_mesh, _layer);
84 }
85
86 std::size_t bytes() const
87 {
88 // We are just a view into data stored elsewhere.
89 return 0;
90 }
91
95 int get_num_coords() const
96 {
97 return num_coords;
98 }
99
104 {
105 return _mesh->get_num_entities(_layer, 0);
106 }
107
116 {
117 if(_perm)
118 {
119 return _mesh->vertex(_layer, _perm.value().map(idx));
120 }
121 return _mesh->vertex(_layer, idx);
122 }
123
125 const VertexType& operator[](Index idx) const
126 {
127 if(_perm)
128 {
129 return _mesh->vertex(_layer, _perm.value().map(idx));
130 }
131 return _mesh->vertex(_layer, idx);
132 }
133
134 // NOTE: Unsupported on purpose. Transform underlying mesh if required.
135 //void transform(const VertexType& origin, const VertexType& angles, const VertexType& offset)
136
149 void permute(const Adjacency::Permutation& perm, bool invert = false)
150 {
151 if(!_perm)
152 {
153 _perm = std::optional{invert ? perm.inverse() : perm.clone()};
154 }
155 else
156 {
157 if(invert)
158 {
159 _perm.value().concat(perm.inverse());
160 }
161 else
162 {
163 _perm.value().concat(perm);
164 }
165 }
166 }
167
168 static String name()
169 {
170 return "AdaptiveVertexSet<...>";
171 }
172 };
173
184 template<typename AdaptiveMeshType_, int cell_dim_, int face_dim_>
186 {
187 public:
189 using AdaptiveMeshType = AdaptiveMeshType_;
190
191 private:
193 std::shared_ptr<AdaptiveMeshType> _mesh;
199 std::optional<Adjacency::Permutation> _inv_perm;
200
201 public:
202 // Wrapper Code
203
205 static constexpr int num_indices = Shape::FaceTraits<Shape::Hypercube<cell_dim_>, face_dim_>::count;
206
214 AdaptiveIndexTuple(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer, Index entity_idx) :
215 _mesh(std::move(mesh)),
216 _layer(layer),
217 _entity_idx(entity_idx),
218 _inv_perm(std::nullopt)
219 {
220 }
221
224
225 AdaptiveIndexTuple& operator=(const AdaptiveIndexTuple& other) = default;
226 AdaptiveIndexTuple& operator=(AdaptiveIndexTuple&& other) = default;
227
229 Index operator[](int idx) const
230 {
231 ASSERT(idx >= 0);
232 ASSERT(idx < num_indices);
233 Index result = _mesh->template get_face_index<cell_dim_, face_dim_>(_layer, _entity_idx, idx);
234 if(_inv_perm)
235 {
236 return _inv_perm.value().map(result);
237 }
238 return result;
239 }
240
253 {
254 if(_inv_perm)
255 {
256 _inv_perm.value().concat(inv_perm);
257 }
258 else
259 {
260 _inv_perm = inv_perm.clone();
261 }
262 }
263 };
264
275 template<typename AdaptiveMeshType_, int cell_dim_, int face_dim_>
277 {
278 public:
280 using AdaptiveMeshType = AdaptiveMeshType_;
281
283 static constexpr int num_indices = Shape::FaceTraits<Shape::Hypercube<cell_dim_>, face_dim_>::count;
284
287 {
288 // Adaptive mesh reference
289 std::shared_ptr<AdaptiveMeshType> _mesh;
290 Layer _layer;
291
292 // Iterator state
293 Index _domain_node;
294 Index _next;
295
296 public:
297 AdaptiveIndexSetAdjactor(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer, Index domain_node, Index next) :
298 _mesh(std::move(mesh)),
299 _layer(layer),
300 _domain_node(domain_node),
301 _next(next)
302 {
303 }
304
305 bool operator==(const AdaptiveIndexSetAdjactor& other) const
306 {
307 return _domain_node == other._domain_node && _next == other._next && _layer == other._layer &&
308 _mesh == other._mesh;
309 }
310
311 bool operator!=(const AdaptiveIndexSetAdjactor& other) const
312 {
313 return !(*this == other);
314 }
315
316 AdaptiveIndexSetAdjactor& operator++()
317 {
318 _next++;
319 return *this;
320 }
321
322 Index operator*() const
323 {
324 return _mesh->template get_face_index<cell_dim_, face_dim_>(_layer, _domain_node, _next);
325 }
326 };
327
330
333
334 private:
335 // Mesh reference
336 std::shared_ptr<AdaptiveMeshType> _mesh;
337 Layer _layer;
338
339 std::optional<Adjacency::Permutation> _permutation;
340 std::optional<Adjacency::Permutation> _inverse_face_permutation;
341
342 public:
349 AdaptiveIndexSet(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) : _mesh(std::move(mesh)), _layer(layer)
350 {
351 }
352
353 AdaptiveIndexSet(const AdaptiveIndexSet& other) = default;
355
356 AdaptiveIndexSet& operator=(const AdaptiveIndexSet& other) = default;
357 AdaptiveIndexSet& operator=(AdaptiveIndexSet&& other) = default;
358
367 {
368 return AdaptiveIndexSet(_mesh, _layer);
369 }
370
374 std::size_t bytes() const
375 {
376 return 0;
377 }
378
381 {
382 if(_permutation)
383 {
384 return _mesh->template get_face_index<cell_dim_, face_dim_>(
385 _layer,
386 _permutation.value().map(i),
387 _inverse_face_permutation.value().map(j)
388 );
389 }
390 return _mesh->template get_face_index<cell_dim_, face_dim_>(_layer, i, j);
391 }
392
394 Index operator()(Index i, int j) const
395 {
396 if(_permutation)
397 {
398 return _mesh->template get_face_index<cell_dim_, face_dim_>(
399 _layer,
400 _permutation.value().map(i),
401 _inverse_face_permutation.value().map(j)
402 );
403 }
404 return _mesh->template get_face_index<cell_dim_, face_dim_>(_layer, i, j);
405 }
406
415 {
417 if(_permutation)
418 {
419 auto tuple = IndexTupleType(_mesh, _layer, _permutation.value().map(i));
420 tuple.permute_map(_inverse_face_permutation.value());
421 return tuple;
422 }
423 return IndexTupleType(_mesh, _layer, i);
424 }
425
428 {
430 if(_permutation)
431 {
432 auto tuple = IndexTupleType(_mesh, _layer, _permutation.value().map(i));
433 tuple.permute_map(_inverse_face_permutation.value());
434 return tuple;
435 }
436 return IndexTupleType(_mesh, _layer, i);
437 }
438
443 {
444 return _mesh->get_num_entities(_layer, cell_dim_);
445 }
446
450 int get_num_indices() const
451 {
452 return num_indices;
453 }
454
459 {
460 return _mesh->get_num_entities(_layer, face_dim_);
461 }
462
463 // Unsupported.
464 // IndexSet API depends on pointer arithmetic that we can not support.
465 // Rewrite IndexSet API first, if this is required somewhere
466 //AdaptiveIndexTuple* get_indices()
467 //const AdaptiveIndexTuple* get_indices() const
468
469 void permute(const Adjacency::Permutation& perm, const Adjacency::Permutation& inv_perm_face)
470 {
471 // Permute index tuples
472 if(_permutation)
473 {
474 _permutation.value().concat(perm);
475 }
476 else
477 {
478 _permutation = perm.clone();
479 }
480
481 // Permute indices by the inverse face permutation
482 if(_inverse_face_permutation)
483 {
484 _inverse_face_permutation.value().concat(inv_perm_face);
485 }
486 else
487 {
488 _inverse_face_permutation = inv_perm_face.clone();
489 }
490 }
491
492 static String name()
493 {
494 return "AdaptiveIndexSet<" + stringify(cell_dim_) + ", " + stringify(face_dim_) + ">";
495 }
496
497 // Adjactor Interface
498
499 Index get_num_nodes_domain() const
500 {
501 return get_num_entities();
502 }
503
504 Index get_num_nodes_image() const
505 {
506 return _mesh->get_num_entities(_layer, face_dim_);
507 }
508
509 AdaptiveIndexSetAdjactor image_begin(Index domain_node) const
510 {
511 return AdaptiveIndexSetAdjactor(_mesh, _layer, domain_node, 0);
512 }
513
514 AdaptiveIndexSetAdjactor image_end(Index domain_node) const
515 {
516 return AdaptiveIndexSetAdjactor(_mesh, _layer, domain_node, num_indices);
517 }
518 };
519
520 template<
521 typename AdaptiveMeshType_,
522 typename Shape_,
523 int face_dim_ = Shape_::dimension - 1>
525 public AdaptiveIndexSetWrapper<AdaptiveMeshType_, Shape_, face_dim_ - 1>
526 {
527 static_assert(face_dim_ < Shape_::dimension, "invalid face dimension");
528 static_assert(face_dim_ > 0, "invalid face dimension");
529
530 public:
531 using AdaptiveMeshType = AdaptiveMeshType_;
532
533 static constexpr int cell_dim = Shape_::dimension;
534
535 using BaseClass =
536 AdaptiveIndexSetWrapper<AdaptiveMeshType_, Shape_, face_dim_ - 1>;
537
538 using IndexSetType =
540
541
542 protected:
543 template<int face_dim__>
546
547 std::shared_ptr<AdaptiveMeshType> _mesh;
548 Layer _layer;
549
550 IndexSetType _index_set;
551
552 public:
553 AdaptiveIndexSetWrapper(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) :
554 BaseClass(mesh, layer),
555 _mesh(mesh),
556 _layer(layer),
557 _index_set(mesh, layer)
558 {
559 }
560
563
564 AdaptiveIndexSetWrapper& operator=(const AdaptiveIndexSetWrapper& other) = default;
566
567 void clone(const AdaptiveIndexSetWrapper& other)
568 {
569 BaseClass::clone(other);
570 _index_set = other._index_set;
571 }
572
573 AdaptiveIndexSetWrapper clone() const
574 {
575 return AdaptiveIndexSetWrapper(_mesh, _layer);
576 }
577
578 template<int face_dim__>
580 {
581 static_assert(face_dim__ >= 0, "invalid face dimension");
582 static_assert(face_dim__ < Shape_::dimension, "invalid face dimension");
583
585 }
586
587 template<int face_dim__>
588 const AdaptiveIndexSetByFaceDim<face_dim__>& get_index_set() const
589 {
590 static_assert(face_dim__ >= 0, "invalid face dimension");
591 static_assert(face_dim__ < Shape_::dimension, "invalid face dimension");
592
594 }
595
596 template<std::size_t np_>
597 void permute(const Adjacency::Permutation& shape_perm,
598 const std::array<Adjacency::Permutation, np_>& inv_perm)
599 {
600 BaseClass::permute(shape_perm, inv_perm);
601 _index_set.permute(shape_perm, inv_perm.at(face_dim_));
602 }
603
604 static String name()
605 {
606 return "AdaptiveIndexSetWrapper<" + Shape_::name() + ", " + stringify(face_dim_) + ">";
607 }
608
609 std::size_t bytes()
610 {
611 return BaseClass::bytes() + _index_set.bytes();
612 }
613 };
614
615 template<typename AdaptiveMeshType_, typename Shape_>
616 class AdaptiveIndexSetWrapper<AdaptiveMeshType_, Shape_, 0>
617 {
618 static_assert(Shape_::dimension > 0, "invalid shape dimension");
619
620 public:
621 using AdaptiveMeshType = AdaptiveMeshType_;
622
623 static constexpr int cell_dim = Shape_::dimension;
624
625 using IndexSetType =
627
628
629 protected:
630 template<int face_dim__>
633
634 std::shared_ptr<AdaptiveMeshType> _mesh;
635 Layer _layer;
636
637 IndexSetType _index_set;
638
639 public:
640 AdaptiveIndexSetWrapper(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) :
641 _mesh(mesh),
642 _layer(layer),
643 _index_set(mesh, layer)
644 {
645 }
646
649
650 AdaptiveIndexSetWrapper& operator=(const AdaptiveIndexSetWrapper& other) = default;
652
653 void clone(const AdaptiveIndexSetWrapper& other)
654 {
655 _index_set = other._index_set;
656 }
657
658 AdaptiveIndexSetWrapper clone() const
659 {
660 return AdaptiveIndexSetWrapper(_mesh, _layer);
661 }
662
663 template<int face_dim__>
665 {
666 static_assert(face_dim__ == 0, "invalid face dimension");
667
669 }
670
671 template<int face_dim__>
672 const AdaptiveIndexSetByFaceDim<face_dim__>& get_index_set() const
673 {
674 static_assert(face_dim__ == 0, "invalid face dimension");
675
677 }
678
679 template<std::size_t np_>
680 void permute(const Adjacency::Permutation& shape_perm,
681 const std::array<Adjacency::Permutation, np_>& inv_perm)
682 {
683 _index_set.permute(shape_perm, inv_perm.at(0));
684 }
685
686 static String name()
687 {
688 return "AdaptiveIndexSetWrapper<" + Shape_::name() + ",0>";
689 }
690
691 std::size_t bytes() const
692 {
693 return _index_set.bytes();
694 }
695 };
696
707 template<typename AdaptiveMeshType_, typename Shape_>
710 AdaptiveMeshType_,
711 typename Shape::FaceTraits<Shape_, Shape_::dimension - 1>::ShapeType>
712 {
714 using AdaptiveMeshType = AdaptiveMeshType_;
715
717 AdaptiveMeshType_,
718 typename Shape::FaceTraits<Shape_, Shape_::dimension - 1>::ShapeType>;
719
721
722 protected:
723 template<int shape_dim_>
728
729 std::shared_ptr<AdaptiveMeshType> _mesh;
730 Layer _layer;
731
732 IndexSetWrapperType _index_set_wrapper;
733
734 public:
735 AdaptiveIndexSetHolder(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) :
736 BaseClass(mesh, layer),
737 _mesh(mesh),
738 _layer(layer),
739 _index_set_wrapper(mesh, layer)
740 {
741 }
742
745
746 AdaptiveIndexSetHolder& operator=(const AdaptiveIndexSetHolder& other) = default;
748
749 void clone(const AdaptiveIndexSetHolder& other)
750 {
751 BaseClass::clone(other);
752 _index_set_wrapper.clone(other._index_set_wrapper);
753 }
754
755 AdaptiveIndexSetHolder clone() const
756 {
757 return AdaptiveIndexSetHolder(_mesh, _layer);
758 }
759
760 template<int shape_dim_>
761 AdaptiveIndexSetWrapperByShapeDim<shape_dim_>& get_index_set_wrapper()
762 {
763 static_assert(shape_dim_ > 0, "invalid shape dimension");
764 static_assert(shape_dim_ <= Shape_::dimension, "invalid shape dimension");
765 typedef typename Shape::FaceTraits<Shape_, shape_dim_>::ShapeType ShapeType;
766 return AdaptiveIndexSetHolder<AdaptiveMeshType, ShapeType>::_index_set_wrapper;
767 }
768
769 template<int shape_dim_>
770 const AdaptiveIndexSetWrapperByShapeDim<shape_dim_>& get_index_set_wrapper() const
771 {
772 static_assert(shape_dim_ > 0, "invalid shape dimension");
773 static_assert(shape_dim_ <= Shape_::dimension, "invalid shape dimension");
774 typedef typename Shape::FaceTraits<Shape_, shape_dim_>::ShapeType ShapeType;
775 return AdaptiveIndexSetHolder<AdaptiveMeshType, ShapeType>::_index_set_wrapper;
776 }
777
778 template<int cell_dim_, int face_dim_>
779 AdaptiveIndexSet<AdaptiveMeshType, cell_dim_, face_dim_>& get_index_set()
780 {
781 static_assert(cell_dim_ <= Shape_::dimension, "invalid cell dimension");
782 static_assert(face_dim_ < cell_dim_, "invalid face/cell dimension");
783 static_assert(face_dim_ >= 0, "invalid face dimension");
784 return get_index_set_wrapper<cell_dim_>().template get_index_set<face_dim_>();
785 }
786
787 template<int cell_dim_, int face_dim_>
788 const AdaptiveIndexSet<AdaptiveMeshType, cell_dim_, face_dim_>& get_index_set() const
789 {
790 static_assert(cell_dim_ <= Shape_::dimension, "invalid cell dimension");
791 static_assert(face_dim_ < cell_dim_, "invalid face/cell dimension");
792 static_assert(face_dim_ >= 0, "invalid face dimension");
793 return get_index_set_wrapper<cell_dim_>().template get_index_set<face_dim_>();
794 }
795
796 template<std::size_t np_>
797 void permute(const std::array<Adjacency::Permutation, np_>& perms,
798 const std::array<Adjacency::Permutation, np_>& inv_perms)
799 {
800 BaseClass::permute(perms, inv_perms);
801 _index_set_wrapper.permute(perms.at(Shape_::dimension), inv_perms);
802 }
803
804 static String name()
805 {
806 return "AdaptiveIndexSetHolder<" + Shape_::name() + ">";
807 }
808
809 std::size_t bytes() const
810 {
811 return BaseClass::bytes() + _index_set_wrapper.bytes();
812 }
813 };
814
815 template<typename AdaptiveMeshType_>
816 class AdaptiveIndexSetHolder<AdaptiveMeshType_, Shape::Vertex>
817 {
818 public:
819 AdaptiveIndexSetHolder() = default;
820
821 AdaptiveIndexSetHolder(std::shared_ptr<AdaptiveMeshType_> /*mesh*/, Layer /*layer*/){
822 }
823
826
827 AdaptiveIndexSetHolder& operator=(const AdaptiveIndexSetHolder& other) = default;
829
830 void clone(const AdaptiveIndexSetHolder& /*unused*/)
831 {
832 }
833
834 AdaptiveIndexSetHolder clone() const
835 {
836 return AdaptiveIndexSetHolder();
837 }
838
839 template<std::size_t np_>
840 void permute(const std::array<Adjacency::Permutation, np_>&,
841 const std::array<Adjacency::Permutation, np_>&)
842 {
843 }
844
845 static String name()
846 {
847 return "AdaptiveIndexSetHolder<Vertex>";
848 }
849
850 std::size_t bytes() const
851 {
852 return std::size_t(0);
853 }
854 };
855
859 template<typename AdaptiveMeshType_>
861 {
862 protected:
863 using AdaptiveMeshType = AdaptiveMeshType_;
864
865 std::shared_ptr<AdaptiveMeshType> _mesh;
866 Layer _layer;
867
868 public:
869
871 static constexpr int num_indices =
873
876 {
877 // Adaptive mesh reference
878 std::shared_ptr<AdaptiveMeshType> _mesh;
879 Layer _layer;
880
881 // Iterator state
882 Index _domain_node;
883 Index _next;
884
885 std::optional<Adjacency::Permutation> _inverse_face_permutation = std::nullopt;
886
887 public:
888 AdaptiveNeighborsAdjactor(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer, Index domain_node, Index next) :
889 _mesh(std::move(mesh)),
890 _layer(layer),
891 _domain_node(domain_node),
892 _next(next)
893 {
894 }
895
897 std::shared_ptr<AdaptiveMeshType> mesh,
898 Layer layer,
899 Index domain_node,
900 Index next,
901 Adjacency::Permutation inverse_face_permutation) :
902 _mesh(std::move(mesh)),
903 _layer(layer),
904 _domain_node(domain_node),
905 _next(next),
906 _inverse_face_permutation(std::move(inverse_face_permutation))
907 {
908 }
909
910 bool operator==(const AdaptiveNeighborsAdjactor& other) const
911 {
912 return _domain_node == other._domain_node && _next == other._next && _layer == other._layer &&
913 _mesh == other._mesh;
914 }
915
916 bool operator!=(const AdaptiveNeighborsAdjactor& other) const
917 {
918 return !(*this == other);
919 }
920
921 AdaptiveNeighborsAdjactor& operator++()
922 {
923 _next++;
924 return *this;
925 }
926
927 Index operator*() const
928 {
929 if(_inverse_face_permutation)
930 {
931 return _mesh->get_neighbor(_layer, _domain_node, _inverse_face_permutation.value().map(_next));
932 }
933 return _mesh->get_neighbor(_layer, _domain_node, _next);
934 }
935 };
936
939
940 private:
941 // Mesh reference
942 std::optional<Adjacency::Permutation> _permutation;
943 std::optional<Adjacency::Permutation> _inverse_face_permutation;
944
945 public:
952 AdaptiveNeighbors(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) : _mesh(std::move(mesh)), _layer(layer)
953 {
954 }
955
956 AdaptiveNeighbors(const AdaptiveNeighbors& other) = default;
958
959 AdaptiveNeighbors& operator=(const AdaptiveNeighbors& other) = default;
960 AdaptiveNeighbors& operator=(AdaptiveNeighbors&& other) = default;
961
970 {
971 return AdaptiveNeighbors(_mesh, _layer);
972 }
973
977 std::size_t bytes() const
978 {
979 return 0;
980 }
981
984 {
985 if(_permutation)
986 {
987 return _mesh->get_neighbor(
988 _layer,
989 _permutation.value().map(i),
990 _inverse_face_permutation.value().map(j)
991 );
992 }
993 return _mesh->get_neighbor(_layer, i, j);
994 }
995
997 Index operator()(Index i, int j) const
998 {
999 if(_permutation)
1000 {
1001 return _mesh->get_neighbor(
1002 _layer,
1003 _permutation.value().map(i),
1004 _inverse_face_permutation.value().map(j)
1005 );
1006 }
1007 return _mesh->get_neighbor(_layer, i, j);
1008 }
1009
1014 {
1015 return _mesh->get_num_entities(_layer, AdaptiveMeshType::ShapeType::dimension);
1016 }
1017
1022 {
1023 return num_indices;
1024 }
1025
1030 {
1031 return _mesh->get_num_entities(_layer, AdaptiveMeshType::ShapeType::dimension);
1032 }
1033
1034 // Unsupported.
1035 // IndexSet API depends on pointer arithmetic that we can not support.
1036 // Rewrite IndexSet API first, if this is required somewhere
1037 //AdaptiveIndexTuple* get_indices()
1038 //const AdaptiveIndexTuple* get_indices() const
1039
1040 void permute(const Adjacency::Permutation& perm, const Adjacency::Permutation& inv_perm_face)
1041 {
1042 // Permute index tuples
1043 if(_permutation)
1044 {
1045 _permutation.value().concat(perm);
1046 }
1047 else
1048 {
1049 _permutation = perm.clone();
1050 }
1051
1052 // Permute indices by the inverse face permutation
1053 if(_inverse_face_permutation)
1054 {
1055 _inverse_face_permutation.value().concat(inv_perm_face);
1056 }
1057 else
1058 {
1059 _inverse_face_permutation = inv_perm_face.clone();
1060 }
1061 }
1062
1063 static String name()
1064 {
1065 return "AdaptiveNeighbors";
1066 }
1067
1068 // Adjactor Interface
1069
1070 Index get_num_nodes_domain() const
1071 {
1072 return get_num_entities();
1073 }
1074
1075 Index get_num_nodes_image() const
1076 {
1077 return _mesh->get_num_entities(_layer, AdaptiveMeshType::ShapeType::dimension);
1078 }
1079
1080 AdaptiveNeighborsAdjactor image_begin(Index domain_node) const
1081 {
1082 if(_permutation)
1083 {
1084 return AdaptiveIndexSetAdjactor(_mesh, _layer, _permutation.value().map(domain_node), 0, _inverse_face_permutation.value());
1085 }
1086 return AdaptiveIndexSetAdjactor(_mesh, _layer, domain_node, 0);
1087 }
1088
1089 AdaptiveNeighborsAdjactor image_end(Index domain_node) const
1090 {
1091 if(_permutation)
1092 {
1093 return AdaptiveIndexSetAdjactor(_mesh, _layer, _permutation.value().map(domain_node), num_indices, _inverse_face_permutation.value());
1094 }
1095 return AdaptiveIndexSetAdjactor(_mesh, _layer, domain_node, num_indices);
1096 }
1097 };
1098
1109 template<typename AdaptiveMeshType_>
1111 {
1112 public:
1114 using AdaptiveMeshType = AdaptiveMeshType_;
1115
1118
1119 // Conformal Mesh Interface
1120
1122 using ShapeType = typename AdaptiveMeshType::ShapeType;
1123
1126
1128 using VertexType = typename AdaptiveMeshType::VertexType;
1129
1132
1134 static constexpr int shape_dim = AdaptiveMeshType::shape_dim;
1135
1137 static constexpr int world_dim = AdaptiveMeshType::world_dim;
1138
1140 static constexpr bool is_structured = false;
1141
1144
1146 template<int cell_dim_, int face_dim_>
1148 {
1150 };
1151
1152 private:
1153 std::shared_ptr<AdaptiveMeshType> _mesh;
1154 Layer _layer;
1155
1156 VertexSetType _vertex_set;
1157 IndexSetHolderType _index_set_holder;
1158
1159 MeshPermutation<ShapeType> _permutation;
1160
1161 public:
1168 AdaptiveMeshLayer(std::shared_ptr<AdaptiveMeshType> mesh, Layer layer) :
1169 _mesh(mesh),
1170 _layer(layer),
1171 _vertex_set(VertexSetType(_mesh, layer)),
1172 _index_set_holder(_mesh, layer),
1173 _permutation()
1174 {
1175 }
1176
1177 AdaptiveMeshLayer(const AdaptiveMeshLayer& other) = default;
1179
1180 AdaptiveMeshLayer& operator=(const AdaptiveMeshLayer& other) = default;
1181 AdaptiveMeshLayer& operator=(AdaptiveMeshLayer&& other) = default;
1182
1183 void clone(const AdaptiveMeshLayer& other)
1184 {
1185 _mesh = other._mesh;
1186 _layer = other._layer;
1187 _vertex_set = other._vertex_set;
1188 _index_set_holder = other._index_set_holder;
1189 _permutation = other._permutation.clone();
1190 }
1191
1192 AdaptiveMeshLayer clone() const
1193 {
1194 AdaptiveMeshLayer result(_mesh, _layer);
1195 result._vertex_set = _vertex_set;
1196 result._index_set_holder = _index_set_holder;
1197 result._permutation = _permutation;
1198 return result;
1199 }
1200
1201 std::size_t bytes() const
1202 {
1203 return _vertex_set.bytes() + _index_set_holder.bytes() + _permutation.bytes();
1204 }
1205
1212 {
1213 return _mesh->get_num_entities(_layer, dim);
1214 }
1215
1220 {
1221 return get_num_entities(0);
1222 }
1223
1228 {
1229 return get_num_entities(ShapeType::dimension);
1230 }
1231
1237 bool is_permuted() const
1238 {
1239 return !_permutation.empty();
1240 }
1241
1246 {
1247 return _permutation;
1248 }
1249
1268 {
1269 // make sure that we don't already have a permutation
1270 XASSERTM(this->_permutation.empty(), "mesh is already permuted!");
1271
1272 // create the permutation
1273 this->_permutation.create(strategy, this->_index_set_holder, this->_vertex_set);
1274
1275 // permute vertex set
1276 this->_vertex_set.permute(this->_permutation.get_perm(0));
1277
1278 // permute index sets
1279 this->_index_set_holder.permute(this->_permutation.get_perms(), this->_permutation.get_inv_perms());
1280 }
1281
1299 {
1300 // make sure that we don't already have a permutation
1301 XASSERTM(this->_permutation.empty(), "mesh is already permuted!");
1302
1303 // check the dimensions
1304 const std::array<Index, 4> mesh_size {
1309 };
1310 XASSERTM(mesh_perm.validate_sizes(mesh_size.data()) == 0, "mesh permutation has invalid size!");
1311
1312 // save the permutation
1313 this->_permutation = std::forward<MeshPermutationType>(mesh_perm);
1314
1315 // permute vertex set
1316 this->_vertex_set.permute(this->_permutation.get_perm(0));
1317
1318 // permute index sets
1319 this->_index_set_holder.permute(this->_permutation.get_perms(), this->_permutation.get_inv_perms());
1320 }
1321
1331 {
1332 // no coloring?
1333 const std::vector<Index>& coloring = this->get_mesh_permutation().get_element_coloring();
1334 if(coloring.empty())
1335 return true;
1336
1337 // get vertices-at-element index set
1338 const auto& verts_at_elem = this->template get_index_set<shape_dim, 0>();
1339
1340 // render transpose
1341 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
1342
1343 // loop over all color blocks
1344 for(std::size_t icol(0); icol+1u < coloring.size(); ++icol)
1345 {
1346 // get the bounds of our current color block
1347 const Index iel_beg = coloring[icol];
1348 const Index iel_end = coloring[icol+1u];
1349
1350 // loop over all elements in the current color block
1351 for(Index iel(iel_beg); iel < iel_end; ++iel)
1352 {
1353 // loop over all vertices adjacent to this element
1354 for(int ivt(0); ivt < verts_at_elem.num_indices; ++ivt)
1355 {
1356 // loop over all elements adjacent to this vertex
1357 const Index ivtx = verts_at_elem(iel, ivt);
1358 for(auto it = elems_at_vert.image_begin(ivtx); it != elems_at_vert.image_end(ivtx); ++it)
1359 {
1360 // two adjacent element must not be in the same color block
1361 if((iel_beg <= *it) && (*it < iel_end) && (*it != iel))
1362 return false; // invalid coloring
1363 }
1364 }
1365 }
1366 } // next color block
1367
1368 // ok, coloring is valid
1369 return true;
1370 }
1371
1381 {
1382 // no layering?
1383 const std::vector<Index>& layering = this->get_mesh_permutation().get_element_layering();
1384 if(layering.empty())
1385 return true;
1386
1387 // get vertices-at-element index set
1388 const auto& verts_at_elem = this->template get_index_set<shape_dim, 0>();
1389
1390 // render transpose
1391 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
1392
1393 // loop over all layers
1394 for(std::size_t ilay(0); ilay+1u < layering.size(); ++ilay)
1395 {
1396 // get the bounds of our current layer
1397 const Index iel_beg = layering[ilay];
1398 const Index iel_end = layering[ilay+1u];
1399
1400 // get the lower bound for valid neighbors of our current layer = beginning of previous layer
1401 const Index iel_lower = layering[Math::max(ilay, std::size_t(1)) - 1u];
1402
1403 // get the upper bound for valid neighbors of our current layer = end of next layer
1404 const Index iel_upper = layering[Math::min(ilay+2u, layering.size()-1u)];
1405
1406 // loop over all elements in the current layer
1407 for(Index iel(iel_beg); iel < iel_end; ++iel)
1408 {
1409 // loop over all vertices adjacent to this element
1410 for(int ivt(0); ivt < verts_at_elem.num_indices; ++ivt)
1411 {
1412 // loop over all elements adjacent to this vertex
1413 const Index ivtx = verts_at_elem(iel, ivt);
1414 for(auto it = elems_at_vert.image_begin(ivtx); it != elems_at_vert.image_end(ivtx); ++it)
1415 {
1416 // adjacent element outside of adjacent layers?
1417 if(!((iel_lower <= *it) && (*it < iel_upper)))
1418 return false; // invalid layer
1419 }
1420 }
1421 }
1422 } // next color block
1423
1424 // ok, layering is valid
1425 return true;
1426 }
1427
1428 void fill_neighbours()
1429 {
1430 _mesh->fill_neighbors();
1431 }
1432
1433 AdaptiveNeighborsType get_neighbors()
1434 {
1435 return AdaptiveNeighbors(_mesh, _layer);
1436 }
1437
1438 AdaptiveNeighborsType get_neighbors() const
1439 {
1440 return AdaptiveNeighbors(_mesh, _layer);
1441 }
1442
1447 {
1448 return _vertex_set;
1449 }
1450
1455 {
1456 return _vertex_set;
1457 }
1458
1465 template<int cell_dim_, int face_dim_>
1467 {
1468 return _index_set_holder.template get_index_set<cell_dim_, face_dim_>();
1469 }
1470
1477 template<int cell_dim_, int face_dim_>
1478 const auto& get_index_set() const
1479 {
1480 return _index_set_holder.template get_index_set<cell_dim_, face_dim_>();
1481 }
1482
1487 {
1488 return _index_set_holder;
1489 }
1490
1495 {
1496 return _index_set_holder;
1497 }
1498
1499 IndexSetHolderType& get_topology()
1500 {
1501 return _index_set_holder;
1502 }
1503
1504 const IndexSetHolderType& get_topology() const
1505 {
1506 return _index_set_holder;
1507 }
1508
1509 // Wrapper specific code
1510
1521 std::optional<Index> get_child(Index elem, Index child)
1522 {
1523 return _mesh->template get_child<ShapeType::dimension>(_layer, elem, child);
1524 }
1525
1532 {
1533 return _mesh->template get_num_children<ShapeType::dimension>(_layer, elem);
1534 }
1535
1536 static String name()
1537 {
1538 return "AdaptiveMeshLayer<...>";
1539 }
1540
1546 bool has_vertex_changed(Index vertex_idx) const
1547 {
1548 return _mesh->has_vertex_changed(_layer, vertex_idx);
1549 }
1550
1552 typename AdaptiveMeshType::FoundationMeshType& foundation_mesh()
1553 {
1554 return _mesh->foundation_mesh();
1555 }
1556
1559 {
1560 return *_mesh;
1561 }
1562 };
1563
1569 template<typename AdaptiveMeshLayerType>
1571 {
1572 public:
1574 {
1575 public:
1576 ChildCellIterator(AdaptiveMeshLayerType& coarse, Index cell, Index child) :
1577 _coarse(coarse),
1578 _cell(cell),
1579 _child(child)
1580 {
1581 }
1582
1583 Index operator*() const
1584 {
1585 return _coarse.get_child(_cell, _child).value_or(0);
1586 }
1587
1588 ChildCellIterator& operator++()
1589 {
1590 _child++;
1591 return *this;
1592 }
1593
1594 bool operator!=(const ChildCellIterator& other)
1595 {
1596 return _cell != other._cell || _child != other._child;
1597 }
1598
1599 private:
1600 static constexpr int dim = AdaptiveMeshLayerType::ShapeType::dimension;
1601
1602 AdaptiveMeshLayerType& _coarse;
1603 Index _cell;
1604 Index _child;
1605 };
1606
1608
1609 private:
1610 // TODO: Should these be std::shared_ptrs?
1611 AdaptiveMeshLayerType& _coarse;
1612 AdaptiveMeshLayerType& _fine;
1613
1614 public:
1615 AdaptiveChildMapping(AdaptiveMeshLayerType& coarse, AdaptiveMeshLayerType& fine) : _coarse(coarse), _fine(fine)
1616 {
1617 }
1618
1619 Index get_num_nodes_domain() const
1620 {
1621 return _coarse.get_num_elements();
1622 }
1623
1624 Index get_num_nodes_image() const
1625 {
1626 return _fine.get_num_elements();
1627 }
1628
1629 ChildCellIterator image_begin(Index domain_node) const
1630 {
1631 return ChildCellIterator(_coarse, domain_node, 0);
1632 }
1633
1634 ChildCellIterator image_end(Index domain_node) const
1635 {
1636 Index num_children = _coarse.get_num_children(domain_node);
1637 return ChildCellIterator(_coarse, domain_node, num_children);
1638 }
1639 };
1640} // namespace FEAT::Geometry
#define ASSERT(expr)
Debug-Assertion macro definition.
Definition: assertion.hpp:229
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Adjacency Graph implementation.
Definition: graph.hpp:34
ImageIterator image_begin(Index domain_node) const
Returns an iterator for the first adjacent image node.
Definition: graph.hpp:958
ImageIterator image_end(Index domain_node) const
Returns an iterator for the first position past the last adjacent image node.
Definition: graph.hpp:966
void concat(const Permutation &p)
concatenates two permutations
Permutation inverse() const
Computes the inverse permutation.
Permutation clone() const
Clones this permutation.
Adjactor for iterating over children of adaptive mesh elements.
IndexSetHolder interface for adaptive meshes.
AdaptiveMeshType_ AdaptiveMeshType
Type of underlying mesh.
IndexSet interface for adaptive meshes.
std::size_t bytes() const
Returns the size of dynamically allocated memory in bytes.
Index operator()(Index i, int j) const
access operator
Index operator()(Index i, int j)
access operator
AdaptiveIndexSet clone() const
Returns a clone of this index set.
IndexTupleType operator[](Index i)
Returns an adaptive index tuple.
Index get_num_entities() const
Returns the number of entities.
int get_num_indices() const
Returns the number of indices per entity.
AdaptiveIndexSet(std::shared_ptr< AdaptiveMeshType > mesh, Layer layer)
Constructor.
AdaptiveIndexTuple< AdaptiveMeshType, cell_dim_, face_dim_ > IndexTupleType
Tuple type.
Index get_index_bound() const
Returns the maximum index of any face returned by this index set.
IndexTupleType operator[](Index i) const
Returns an adaptive index tuple.
static constexpr int num_indices
Number of indices per entry.
AdaptiveMeshType_ AdaptiveMeshType
Type of underlying mesh.
IndexTuple interface for adaptive meshes.
Index operator[](int idx) const
access operator
AdaptiveMeshType_ AdaptiveMeshType
Type of underlying adaptive mesh.
static constexpr int num_indices
Number of indices per tuple.
AdaptiveIndexTuple(std::shared_ptr< AdaptiveMeshType > mesh, Layer layer, Index entity_idx)
Constructor.
void permute_map(const Adjacency::Permutation &inv_perm)
Permute this index tuple.
std::shared_ptr< AdaptiveMeshType > _mesh
Pointer to underlying mesh.
std::optional< Adjacency::Permutation > _inv_perm
Permutation of this tuple.
Layer _layer
Layer this tuple refers to.
Index _entity_idx
Index of entity this tuple refers to.
ConformalMesh interface for adaptive meshes.
const MeshPermutation< ShapeType > & get_mesh_permutation() const
Returns the permutation applied to the mesh.
auto & get_index_set()
Returns a reference to an index set of this mesh.
AdaptiveMeshType::FoundationMeshType & foundation_mesh()
accessor for foundation mesh
AdaptiveMeshLayer(std::shared_ptr< AdaptiveMeshType > mesh, Layer layer)
Constructor.
static constexpr int world_dim
World dimension.
bool validate_element_layering() const
Validates the element layering.
AdaptiveMeshType & adaptive_mesh()
accessor for adaptive mesh
typename AdaptiveMeshType::ShapeType ShapeType
Shape type.
VertexSetType & get_vertex_set()
Returns the vertex set of this mesh.
typename AdaptiveMeshType::VertexType VertexType
Vertex type.
Index get_num_children(Index elem)
Returns the number of children of mesh a mesh element.
const VertexSetType & get_vertex_set() const
Returns the vertex set of this mesh.
bool validate_element_coloring() const
Validates the element coloring.
Index get_num_elements() const
Returns the number of elements (highest dimension entities) in the mesh.
Index get_num_vertices() const
Returns the number of vertices in the mesh.
const auto & get_index_set() const
Returns a reference to an index set of this mesh.
bool has_vertex_changed(Index vertex_idx) const
Indicates whether any mesh element adjacent to the given vertex has changed on the given layer.
std::optional< Index > get_child(Index elem, Index child)
Retrieve index of a child element.
static constexpr bool is_structured
This is an unstructured mesh.
AdaptiveMeshType_ AdaptiveMeshType
Type of underlying mesh.
void set_permutation(MeshPermutationType &&mesh_perm)
Sets a custom mesh permutation for this mesh.
static constexpr int shape_dim
Shape dimension.
IndexSetHolderType & get_index_set_holder()
Returns a reference to the index set holder of this mesh.
const IndexSetHolderType & get_index_set_holder() const
Returns a reference to the index set holder of this mesh.
AdaptiveIndexSetHolder< AdaptiveMeshType, ShapeType > IndexSetHolderType
IndexSetHolder type.
Index get_num_entities(int dim) const
Returns the number of entities of dimension dim in the mesh.
AdaptiveNeighbors< AdaptiveMeshType > AdaptiveNeighborsType
Type of neighbors wrapper.
bool is_permuted() const
Checks whether the mesh is permuted.
void create_permutation(PermutationStrategy strategy)
Creates a mesh permutation based on one of the standard permutation strategies.
Gives access to neighbor information on a mesh layer.
Index operator()(Index i, int j)
access operator
static constexpr int num_indices
Number of indices per entry.
Index get_index_bound() const
Returns the maximum index of any face returned by this index set.
std::size_t bytes() const
Returns the size of dynamically allocated memory in bytes.
AdaptiveNeighbors clone() const
Returns a clone of this index set.
int get_num_indices() const
Returns the number of indices per entity.
AdaptiveNeighbors(std::shared_ptr< AdaptiveMeshType > mesh, Layer layer)
Constructor.
Index operator()(Index i, int j) const
access operator
Index get_num_entities() const
Returns the number of entities.
VertexSet interface for adaptive meshes.
void permute(const Adjacency::Permutation &perm, bool invert=false)
Permutes this vertex set.
AdaptiveMeshType_ AdaptiveMeshType
Type of underlying adaptive mesh.
AdaptiveVertexSet(std::shared_ptr< AdaptiveMeshType > mesh, Layer layer)
Constructor.
int get_num_coords() const
Returns the number of coordinates per vertex.
VertexType & operator[](Index idx)
Returns a reference to a vertex.
typename AdaptiveMeshType::VertexType VertexType
Vertex type.
typename AdaptiveMeshType::CoordType CoordType
Type of single vertex coordinate.
Index get_num_vertices() const
Returns the number of vertices in the vertex set.
AdaptiveVertexSet clone() const
Returns a clone of this vertex set.
std::shared_ptr< AdaptiveMeshType > _mesh
Underlying adaptive mesh.
static constexpr int num_coords
Number of coordinates per vertex.
const VertexType & operator[](Index idx) const
Returns a reference to a vertex.
const std::vector< Index > & get_element_layering() const
Returns a const reference to the element layering vector.
const PermArray & get_perms() const
bool empty() const
Checks whether this permutation is empty.
const std::vector< Index > & get_element_coloring() const
Returns a const reference to the element coloring vector.
void create(PermutationStrategy strategy, const IndexSetHolder< Shape_ > &ish, const VertexSet< num_coords_, Coord_ > &vtx)
Creates a mesh permutation for a conformal mesh.
const Adjacency::Permutation & get_perm(int dim=shape_dim) const
Returns a const reference to a (forward) permutation.
String class implementation.
Definition: string.hpp:46
@ transpose
Render-Transpose mode.
Geometry namespace.
PermutationStrategy
Mesh permutation strategy enumeration.
@ other
generic/other permutation strategy
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
static constexpr bool operator*(TrafoTags a)
bool conversion operator
Definition: eval_tags.hpp:81
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.
Used for return type of get_index_set.
Newtype wrapper for mesh layers.
Face traits tag struct template.
Definition: shape.hpp:106
typedef ShapeType
Shape type of the face.
Definition: shape.hpp:108