FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
mesh_permutation.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#pragma once
6
7// includes, FEAT
9#include <kernel/adjacency/coloring.hpp>
10#include <kernel/adjacency/cuthill_mckee.hpp>
11#include <kernel/adjacency/graph.hpp>
12#include <kernel/adjacency/permutation.hpp>
13#include <kernel/geometry/index_set.hpp>
14#include <kernel/geometry/target_set.hpp>
15#include <kernel/geometry/vertex_set.hpp>
16
17// includes, system
18#include <algorithm>
19#include <array>
20#include <set>
21#include <vector>
22
23namespace FEAT
24{
25 namespace Geometry
26 {
28 namespace Intern
29 {
30 template<typename Shape_, int face_dim_ = Shape_::dimension-1>
31 class ISWRenderer
32 {
33 public:
34 static void render(std::array<Adjacency::Graph, Shape_::dimension>& idx,
35 const IndexSetWrapper<Shape_, face_dim_>& isw)
36 {
37 ISWRenderer<Shape_, face_dim_-1>::render(idx, isw);
38 idx.at(face_dim_) = Adjacency::Graph(Adjacency::RenderType::as_is,
39 isw.template get_index_set<face_dim_>());
40 }
41 };
42
43 template<typename Shape_>
44 class ISWRenderer<Shape_, 0>
45 {
46 public:
47 static void render(std::array<Adjacency::Graph, Shape_::dimension>& idx,
48 const IndexSetWrapper<Shape_, 0>& isw)
49 {
50 idx.at(0) = Adjacency::Graph(Adjacency::RenderType::as_is,
51 isw.template get_index_set<0>());
52 }
53 };
54
56 template<typename Coord_, int dim_>
57 class LexiPoint
58 {
59 public:
61 Index idx;
63 Tiny::Vector<Coord_, dim_> v;
64
65 // tolerance for coordinate equality check
66 static constexpr Coord_ tol_ = Coord_(1e-6);
67
68 LexiPoint()
69 {
70 }
71
72 explicit LexiPoint(Index _idx) :
73 idx(_idx),
74 v(Coord_(0))
75 {
76 }
77
78 template<int s_>
79 explicit LexiPoint(Index _idx, const Tiny::Vector<Coord_, dim_, s_>& _vtx) :
80 idx(_idx),
81 v(_vtx)
82 {
83 }
84
85 void format()
86 {
87 v.format();
88 }
89
90 template<int s_>
91 void add(const Tiny::Vector<Coord_, dim_, s_>& vtx)
92 {
93 v += vtx;
94 }
95
96 bool operator<(const LexiPoint& other) const
97 {
98 // loop over the higher dimension coordinates
99 for(int i(dim_-1); i > 0; --i)
100 {
101 if(v[i] + tol_ < other.v[i])
102 return true;
103 if(other.v[i] + tol_ <= v[i])
104 return false;
105 }
106 // all coordinates of dimension > 1 are equal, so check the X-coordinate
107 return v[0] < other.v[0];
108 }
109 }; // class LexiPoint
110
112 template<typename Shape_, int shape_dim_ = Shape_::dimension>
113 class LexiPermuter
114 {
115 public:
116 template<int nc_, typename Coord_>
117 static void compute(
118 std::array<Adjacency::Permutation, Shape_::dimension + 1>& perms,
119 const IndexSetHolder<Shape_>& ish, const VertexSet<nc_, Coord_>& vtx)
120 {
121 // recurse down
122 LexiPermuter<Shape_, shape_dim_-1>::compute(perms, ish, vtx);
123
124 // get the vertices-at-shape index set
125 const auto& idx = ish.template get_index_set<shape_dim_, 0>();
126 const Index n = idx.get_num_entities();
127 const int nidx = idx.get_num_indices();
128
129 std::vector<LexiPoint<Coord_, nc_>> vset(n);
130
131 // loop over all entities and accumulate all vertices adjacent to that entity
132 for(Index i(0); i < n; ++i)
133 {
134 LexiPoint<Coord_, nc_> v(i);
135 for(int j(0); j < nidx; ++j)
136 v.add(vtx[idx(i,j)]);
137 vset.at(i) = v;
138 }
139
140 // sort lexicographically
141 std::sort(vset.begin(), vset.end());
142
143 // create permutation
144 Adjacency::Permutation p(n);
145 Index* vp = p.get_perm_pos();
146 for(auto it = vset.begin(); it != vset.end(); ++it, ++vp)
147 *vp = it->idx;
148 p.calc_swap_from_perm();
149 perms.at(shape_dim_) = std::move(p);
150 }
151 }; // class LexiPermuter
152
154 template<typename Shape_>
155 class LexiPermuter<Shape_, 0>
156 {
157 public:
158 template<int nc_, typename Coord_>
159 static void compute(
160 std::array<Adjacency::Permutation, Shape_::dimension + 1>& perms,
161 const IndexSetHolder<Shape_>&, const VertexSet<nc_, Coord_>& vtx)
162 {
163 const Index n = vtx.get_num_vertices();
164 std::vector<LexiPoint<Coord_, nc_>> vset(n);
165
166 // loop over all entities and accumulate all vertices adjacent to that entity
167 for(Index i(0); i < n; ++i)
168 {
169 vset.at(i) = LexiPoint<Coord_, nc_>(i, vtx[i]);
170 }
171
172 // sort lexicographically
173 std::sort(vset.begin(), vset.end());
174
175 // create permutation
176 Adjacency::Permutation p(n);
177 Index* vp = p.get_perm_pos();
178 for(auto it = vset.begin(); it != vset.end(); ++it, ++vp)
179 *vp = it->idx;
180 p.calc_swap_from_perm();
181 perms.front() = std::move(p);
182 }
183 }; // class LexiPermuter<...,0>
184 } // namespace Intern
186
191 {
197 none = 0,
198
207 other,
208
218 random,
219
233
247 colored,
248
263
278
289
300 }; // enum class PermutationStrategy
301
359 template<typename Shape_>
361 {
362 public:
364 typedef Shape_ ShapeType;
365
367 static constexpr int shape_dim = ShapeType::dimension;
368
370 typedef std::array<Adjacency::Permutation, shape_dim+1> PermArray;
371
372 protected:
381 std::vector<Index> _element_coloring;
384 std::vector<Index> _element_layering;
385
386 public:
390 {
391 }
392
405 template<int num_coords_, typename Coord_>
407 PermutationStrategy strategy,
408 const IndexSetHolder<Shape_>& ish,
411 {
412 this->create(strategy, ish, vtx);
413 }
414
418 _perms(std::forward<PermArray>(other._perms)),
419 _inv_perms(std::forward<PermArray>(other._inv_perms)),
420 _element_coloring(std::forward<std::vector<Index>>(other._element_coloring)),
421 _element_layering(std::forward<std::vector<Index>>(other._element_layering))
422 {
423 }
424
427 {
428 if(this == &other)
429 return *this;
430 _strategy = other._strategy;
431 _perms = std::forward<PermArray>(other._perms);
432 _inv_perms = std::forward<PermArray>(other._inv_perms);
433 _element_coloring = std::forward<std::vector<Index>>(other._element_coloring);
434 _element_layering = std::forward<std::vector<Index>>(other._element_layering);
435 return *this;
436 }
437
442
445 {
446 }
447
455 {
456 this->_strategy = other._strategy;
457 for(std::size_t i(0); i <= std::size_t(shape_dim); ++i)
458 {
459 this->_perms[i] = other._perms[i].clone();
460 this->_inv_perms[i] = other._inv_perms[i].clone();
461 }
462 this->_element_coloring = other._element_coloring;
463 this->_element_layering = other._element_layering;
464 }
465
468 {
470 mp.clone(*this);
471 return mp;
472 }
473
475 std::size_t bytes() const
476 {
477 std::size_t b = sizeof(Index) * (_element_coloring.size() + _element_layering.size());
478 for(std::size_t i(0); i <= std::size_t(shape_dim); ++i)
479 b += sizeof(Index) * 2u * (_perms.at(i).size() + _inv_perms.at(i).size());
480 return b;
481 }
482
490 bool empty() const
491 {
492 return this->_strategy == PermutationStrategy::none;
493 }
494
497 {
498 return this->_strategy;
499 }
500
502 const PermArray& get_perms() const
503 {
504 return this->_perms;
505 }
506
508 const PermArray& get_inv_perms() const
509 {
510 return this->_inv_perms;
511 }
512
523 {
524 XASSERT((0 <= dim) && (dim <= shape_dim));
525 return this->_perms.at(std::size_t(dim));
526 }
527
538 {
539 XASSERT((0 <= dim) && (dim <= shape_dim));
540 return this->_inv_perms.at(std::size_t(dim));
541 }
542
551 const std::vector<Index>& get_element_coloring() const
552 {
553 return this->_element_coloring;
554 }
555
564 const std::vector<Index>& get_element_layering() const
565 {
566 return this->_element_layering;
567 }
568
584 template<int num_coords_, typename Coord_>
585 void create(PermutationStrategy strategy, const IndexSetHolder<Shape_>& ish, const VertexSet<num_coords_, Coord_>& vtx)
586 {
587 switch(strategy)
588 {
590 break;
591
593 XABORTM("use the MeshPermutation::create_other() function");
594 break;
595
597 create_random(ish);
598 break;
599
601 create_lexicographic(ish, vtx);
602 break;
603
605 create_colored(ish);
606 break;
607
609 create_cmk(ish, false);
610 break;
611
613 create_cmk(ish, true);
614 break;
615
617 create_gcmk(ish, vtx, false);
618 break;
619
621 create_gcmk(ish, vtx, true);
622 break;
623 }
624 }
625
641 {
642 XASSERTM(this->_strategy == PermutationStrategy::none, "permutation already created!");
643 this->_strategy = PermutationStrategy::other;
644 return this->_perms;
645 }
646
656 void create_random(const IndexSetHolder<Shape_>& ish)
657 {
658 Random rng;
659 create_random(ish, rng);
660 }
661
674 void create_random(const IndexSetHolder<Shape_>& ish, Random& rng)
675 {
676 XASSERTM(this->_strategy == PermutationStrategy::none, "permutation already created!");
677 Index num_entities[shape_dim+1];
678 NumEntitiesExtractor<shape_dim>::set_num_entities_with_numverts(ish, num_entities);
679 for(std::size_t dim(0); dim <= std::size_t(shape_dim); ++dim)
680 {
681 _perms.at(dim) = Adjacency::Permutation(num_entities[dim], rng);
682 _inv_perms.at(dim) = _perms.at(dim).inverse();
683 }
684 this->_strategy = PermutationStrategy::random;
685 }
686
699 template<int num_coords_, typename Coord_>
700 void create_lexicographic(const IndexSetHolder<Shape_>& ish, const VertexSet<num_coords_, Coord_>& vtx)
701 {
702 XASSERTM(this->_strategy == PermutationStrategy::none, "permutation already created!");
703
704 // call the actual helper class
705 Intern::LexiPermuter<ShapeType>::compute(this->_perms, ish, vtx);
706
707 // compute inverse permutations
708 for(std::size_t dim(0); dim <= std::size_t(shape_dim); ++dim)
709 {
710 _inv_perms.at(dim) = _perms.at(dim).inverse();
711 }
712
713 // save strategy
714 this->_strategy = PermutationStrategy::lexicographic;
715 }
716
730 void create_colored(const IndexSetHolder<Shape_>& ish)
731 {
732 XASSERTM(this->_strategy == PermutationStrategy::none, "permutation already created!");
733
734 const auto& verts_at_elem = ish.template get_index_set<shape_dim, 0>();
735 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
736 Adjacency::Graph elems_at_elem(Adjacency::RenderType::injectify, verts_at_elem, elems_at_vert);
737
738 // create coloring
739 Adjacency::Coloring col(elems_at_elem);
740
741 // create coloring partition graph
743
744 // get the total number of colors
745 const Index num_elems = elems_at_elem.get_num_nodes_domain();
746 const Index num_colors = cparti.get_num_nodes_domain();
747
748 XASSERT(num_elems == cparti.get_num_indices());
749
750 // create element permutation
752 _inv_perms.back() = _perms.back().inverse();
753
754 // store element coloring
755 const Index* dom_ptr = cparti.get_domain_ptr();
756 this->_element_coloring.assign(dom_ptr, &dom_ptr[num_colors]);
757
758 // save strategy
759 this->_strategy = PermutationStrategy::colored;
760 }
761
778 void create_cmk(const IndexSetHolder<Shape_>& ish, bool reverse)
779 {
780 XASSERTM(this->_strategy == PermutationStrategy::none, "permutation already created!");
781
782 const auto& verts_at_elem = ish.template get_index_set<shape_dim, 0>();
783 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
784 Adjacency::Graph elems_at_elem(Adjacency::RenderType::injectify, verts_at_elem, elems_at_vert);
785
786 // create Cuthill-McKee permutation
787 _perms.back() = Adjacency::CuthillMcKee::compute(this->_element_layering, elems_at_elem, reverse,
789 _inv_perms.back() = _perms.back().inverse();
790
791 // save strategy
793 }
794
818 template<int num_coords_, typename Coord_>
819 void create_gcmk(const IndexSetHolder<Shape_>& ish, const VertexSet<num_coords_, Coord_>& DOXY(vtx), bool reverse)
820 {
821 // render all <k-faces>-at-element index sets into graph array for convenience
822 std::array<Adjacency::Graph, shape_dim> idx_set;
823 Intern::ISWRenderer<Shape_>::render(idx_set, ish.template get_index_set_wrapper<shape_dim>());
824
825 // transpose vertices-at-element graph
826 Adjacency::Graph& verts_at_elem = idx_set.front();
827 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
828
829 // get the number of entities in the mesh
830 Index num_entities[shape_dim+1];
831 NumEntitiesExtractor<shape_dim>::set_num_entities_with_numverts(ish, num_entities);
832
833 // get number of vertices and elements
834 const Index num_verts = num_entities[0];
835 const Index num_elems = num_entities[shape_dim];
836
837 // allocate temporary permutation vectors
838 std::array<std::vector<Index>, shape_dim+1> perms;
839 for(std::size_t i(0); i <= std::size_t(shape_dim); ++i)
840 perms.at(i).reserve(num_entities[i]);
841
842 // create mask vectors and initialize them to 0
843 // a mask value != 0 indicates that the entity has already been processed
844 std::array<std::vector<int>, shape_dim+1> masks;
845 for(std::size_t i(0); i <= std::size_t(shape_dim); ++i)
846 masks.at(i).resize(num_entities[i]);
847
848 // initialize layer vectors
849 std::vector<Index> layer_cur, layer_vert, layer_next;
850 layer_cur.reserve(num_elems);
851 layer_next.reserve(num_elems);
852 layer_vert.reserve(num_verts);
853
854 // initialize element layering
855 this->_element_layering.clear();
856 this->_element_layering.push_back(Index(0));
857
858 // loop until all elements are processed; this loop performs 1 iteration per domain
859 // connectivity region (so usually 1), but it may perform several iterations in case the
860 // elements of this domain are not connected -- this may happen e.g. in the MPI parallel
861 // case where our local domain is actually just a partition of the whole (connected) domain
862 while(Index(perms.back().size()) < num_elems)
863 {
864 layer_cur.clear();
865
866 // pick a root element of minimal degree (least amount of neighbors)
867 // this chosen root element will usually be a boundary or even a corner element
868 Index idx = _pick_gcmk_root(idx_set.front(), elems_at_vert, masks.back());
869 layer_cur.push_back(idx);
870 masks.back()[idx] = 1;
871
872 // loop through the current element layer
873 while(!layer_cur.empty())
874 {
875 // loop over all elements in current layer
876 layer_next.clear();
877 for(auto it = layer_cur.begin(); it != layer_cur.end(); ++it)
878 {
879 // get and add current element
880 const Index cur_elem = *it;
881 perms.back().push_back(cur_elem);
882
883 // add all vertices adjacent to the current element to the next vertex layer
884 layer_vert.clear();
885 for(auto kt = verts_at_elem.image_begin(cur_elem); kt != verts_at_elem.image_end(cur_elem); ++kt)
886 {
887 const Index cur_vert = *kt;
888 // already processed?
889 if(masks.front()[cur_vert] != 0)
890 continue;
891 // add layer vertex
892 layer_vert.push_back(cur_vert);
893 perms.front().push_back(cur_vert);
894 masks.front()[cur_vert] = 1;
895 }
896
897 // add all k-faces (edges, faces, ...) adjacent to the current element to the next k-face layer
898 for(std::size_t k(1); k < std::size_t(shape_dim); ++k)
899 {
900 for(auto kt = idx_set.at(k).image_begin(cur_elem); kt != idx_set.at(k).image_end(cur_elem); ++kt)
901 {
902 const Index cur_face = *kt;
903 if(masks.at(k)[cur_face] != 0)
904 continue;
905 perms.at(k).push_back(cur_face);
906 masks.at(k)[cur_face] = 1;
907 }
908 }
909
910 // add all elements adjacent via a vertex to the next element layer
911 for(auto jt = layer_vert.begin(); jt != layer_vert.end(); ++jt)
912 {
913 const Index cur_vert = *jt;
914 for(auto kt = elems_at_vert.image_begin(cur_vert); kt != elems_at_vert.image_end(cur_vert); ++kt)
915 {
916 const Index next_elem = *kt;
917 if(masks.back()[next_elem] != 0)
918 continue;
919 layer_next.push_back(next_elem);
920 masks.back()[next_elem] = 1;
921 }
922 }
923 }
924
925 // continue with next element layer
926 layer_cur.swap(layer_next);
927
928 // store element layer size
929 this->_element_layering.push_back(Index(perms.back().size()));
930
931 } // while(!layer_cur.empty())
932 } // while(perms.back().size() < num_elems)
933
934 // revert if desired
935 if(reverse)
936 {
937 // reverse permutations
938 for(std::size_t dim(0); dim <= std::size_t(shape_dim); ++dim)
939 {
940 for(std::size_t i(0), j(perms[dim].size()-1); i < j; ++i, --j)
941 std::swap(perms[dim][i], perms[dim][j]);
942 }
943
944 // reverse layers
945 const Index lay_back = Index(this->_element_layering.size()) - 1u;
946 for(Index k(lay_back); k > 0u; --k)
947 {
948 // compute layer sizes from offsets
949 this->_element_layering.at(k) -= this->_element_layering.at(k-1u);
950 }
951 for(Index k(1u), l(lay_back); k < l; ++k, --l)
952 {
953 // reverse layer sizes
954 std::swap(this->_element_layering.at(k), this->_element_layering.at(l));
955 }
956 for(Index k(1u); k <= lay_back; ++k)
957 {
958 // compute layering offsets from sizes
959 this->_element_layering.at(k) += this->_element_layering.at(k-1u);
960 }
961 }
962
963 // create the actual permutation objects
964 for(std::size_t dim(0); dim <= std::size_t(shape_dim); ++dim)
965 {
966 // sanity check: all entities should have been processed
967 XASSERT(Index(perms.at(dim).size()) == num_entities[dim]);
968
969 // create actual permutation and its inverse
970 _perms.at(dim) = Adjacency::Permutation(Index(perms.at(dim).size()),
971 Adjacency::Permutation::ConstrType::perm, perms.at(dim).data());
972 _inv_perms.at(dim) = _perms.at(dim).inverse();
973 }
974
975 // save strategy
977 }
978
983 {
984 for(std::size_t dim(0); dim <= std::size_t(shape_dim); ++dim)
985 {
986 if(_perms.at(dim).empty())
988 else
989 _inv_perms.at(dim) = _perms.at(dim).inverse();
990 }
991 }
992
1003 int validate_sizes(const Index* num_entities) const
1004 {
1005 XASSERT(num_entities != nullptr);
1006
1007 // check permutations
1008 for(std::size_t i(0); i <= std::size_t(shape_dim); ++i)
1009 {
1010 const Adjacency::Permutation& perm = this->_perms.at(i);
1011 const Adjacency::Permutation& iperm = this->_inv_perms.at(i);
1012
1013 if(!perm.empty() && (perm.size() != num_entities[i]))
1014 return 2*int(i)+1;
1015 if(!iperm.empty() && (iperm.size() != num_entities[i]))
1016 return 2*int(i)+2;
1017 }
1018
1019 // ok
1020 return 0;
1021 }
1022
1023 protected:
1027 static Index _pick_gcmk_root(const Adjacency::Graph& v_at_e, const Adjacency::Graph& e_at_v,
1028 const std::vector<int>& mask)
1029 {
1030 std::set<Index> iset;
1031
1032 // pick a root node of minimal degree
1033 Index deg = v_at_e.get_num_nodes_domain() + e_at_v.get_num_nodes_domain();
1034 Index idx(0);
1035 for(Index i(0); i < v_at_e.get_num_nodes_domain(); ++i)
1036 {
1037 // skip masked elements
1038 if(mask[i] != 0)
1039 continue;
1040
1041 // compute degree
1042 iset.clear();
1043 for(auto it = v_at_e.image_begin(i); it != v_at_e.image_end(i); ++it)
1044 for(auto jt = e_at_v.image_begin(*it); jt != e_at_v.image_end(*it); ++jt)
1045 iset.insert(*jt);
1046
1047 // is this the new minimum?
1048 Index d = Index(iset.size());
1049 if(d < deg)
1050 {
1051 idx = i;
1052 deg = d;
1053 }
1054 }
1055
1056 return idx;
1057 }
1058 }; // class MeshPermutation<ConformalMesh<...>>
1059 } // namespace Geometry
1060} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Coloring object implementation.
Definition: coloring.hpp:37
Graph create_partition_graph() const
Creates a color partition graph.
Definition: coloring.cpp:292
static Permutation compute(std::vector< Index > &layers, const Graph &graph, bool reverse=false, CuthillMcKee::RootType r_type=RootType::standard, CuthillMcKee::SortType t_type=SortType::standard)
Cuthill-McKee permutation computation function.
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
Index * get_domain_ptr()
Returns the domain pointer array.
Definition: graph.hpp:359
ImageIterator image_end(Index domain_node) const
Returns an iterator for the first position past the last adjacent image node.
Definition: graph.hpp:966
Index * get_image_idx()
Returns the image node index array.
Definition: graph.hpp:374
Index get_num_indices() const
Returns the total number indices.
Definition: graph.hpp:390
Index size() const
returns the size of the permutation
bool empty() const
Checks whether the permutation is empty.
@ perm
create from permutation array
Mesh permutation class template.
void clone(const MeshPermutation &other)
Clones another mesh permutation object into this object.
const std::vector< Index > & get_element_layering() const
Returns a const reference to the element layering vector.
void create_random(const IndexSetHolder< Shape_ > &ish, Random &rng)
Creates random mesh permutation for a conformal mesh.
void create_cmk(const IndexSetHolder< Shape_ > &ish, bool reverse)
Creates a (reversed) algebraic Cuthill-McKee mesh permutation for a conformal mesh.
void create_gcmk(const IndexSetHolder< Shape_ > &ish, const VertexSet< num_coords_, Coord_ > &vtx, bool reverse)
Creates a (reversed) geometric Cuthill-McKee mesh permutation for a conformal mesh.
PermArray _inv_perms
the inverse permutations
MeshPermutation & operator=(const MeshPermutation &)=delete
delete copy-assign operator
int validate_sizes(const Index *num_entities) const
Validates the permutation sizes.
std::vector< Index > _element_coloring
const PermArray & get_perms() const
const Adjacency::Permutation & get_inv_perm(int dim=shape_dim) const
Returns a const reference to an inverse permutation.
std::vector< Index > _element_layering
void create_lexicographic(const IndexSetHolder< Shape_ > &ish, const VertexSet< num_coords_, Coord_ > &vtx)
Creates a lexicographic mesh permutation for a conformal mesh.
void create_colored(const IndexSetHolder< Shape_ > &ish)
Creates a colored mesh permutation for a conformal mesh.
void create_inverse_permutations()
(Re)Creates the inverse permutations from the forward ones.
static Index _pick_gcmk_root(const Adjacency::Graph &v_at_e, const Adjacency::Graph &e_at_v, const std::vector< int > &mask)
Auxiliary helper function: pick an unmasked root element for GCMK.
PermArray & create_other()
Initializes a custom permutation.
PermutationStrategy _strategy
the permutation strategy
MeshPermutation(MeshPermutation &&other)
move constructor
Shape_ ShapeType
the underlying shape type
PermutationStrategy get_strategy() const
bool empty() const
Checks whether this permutation is empty.
PermArray _perms
the actual permutations
std::array< Adjacency::Permutation, shape_dim+1 > PermArray
permutation array typedef
MeshPermutation(PermutationStrategy strategy, const IndexSetHolder< Shape_ > &ish, const VertexSet< num_coords_, Coord_ > &vtx)
Creates a mesh permutation for a conformal mesh.
const PermArray & get_inv_perms() const
MeshPermutation & operator=(MeshPermutation &&other)
move-assignment operator
MeshPermutation()
standard constructor
static constexpr int shape_dim
the shape dimension
const std::vector< Index > & get_element_coloring() const
Returns a const reference to the element coloring vector.
void create_random(const IndexSetHolder< Shape_ > &ish)
Creates random mesh permutation for a conformal mesh.
virtual ~MeshPermutation()
virtual destructor
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.
MeshPermutation(const MeshPermutation &)=delete
delete copy constructor
Pseudo-Random Number Generator.
Definition: random.hpp:54
@ transpose
Render-Transpose mode.
@ injectify
Render-Injectified mode.
PermutationStrategy
Mesh permutation strategy enumeration.
@ colored
colored permutation strategy a.k.a. "red-black" strategy
@ none
no permutation strategy
@ cuthill_mckee_reversed
reversed (algebraic) Cuthill-McKee permutation strategy
@ other
generic/other permutation strategy
@ cuthill_mckee
(algebraic) Cuthill-McKee permutation strategy
@ random
random permutation strategy
@ geometric_cuthill_mckee_reversed
reversed geometric Cuthill-McKee permutation strategy
@ lexicographic
lexicographic permutation strategy
@ geometric_cuthill_mckee
geometric Cuthill-McKee permutation strategy
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.
Fixed-Sized Vertex Set class template.
Definition: vertex_set.hpp:37