omega_h
Reliable mesh adaptation
Omega_h_align.hpp
1 #ifndef OMEGA_H_ALIGN_HPP
2 #define OMEGA_H_ALIGN_HPP
3 
4 #include <Omega_h_array.hpp>
5 #include <Omega_h_defines.hpp>
6 #include <Omega_h_fail.hpp>
7 #include <Omega_h_scalar.hpp>
8 
9 namespace Omega_h {
10 
11 /* A seven-bit code describes the alignment relationship
12  between a simplex and a lower-dimensional simplex
13  on its boundary:
14 
15  "which_down" given a canonical ordering of the
16  lower-dimensional simplices on the boundary, which
17  one is this one ?
18  (4 bits)
19 
20 The other two pieces describe alignment between two
21 representations of the same simplex.
22 
23  "rotation" curl-aligned, counterclockwise rotation
24  (indices move up in the canonical ordering).
25  0 1 2 -> 2 0 1 -> 1 2 0
26  (2 bits)
27 
28  "is_flipped" only applies to faces, swap
29  the two vertices adjacent to the first
30  0 1 2 -> 0 2 1
31  (1 bit)
32  0 1 2 3 -> 0 3 2 1
33  (1 bit)
34 
35 We define the rotation to take place first, so a
36 code containing both a flip and rotation means
37 that to get from one entity to another one must
38 first rotate and then flip the vertex list.
39 */
40 
41 OMEGA_H_INLINE constexpr bool code_is_flipped(I8 code) { return code & 1; }
42 
43 OMEGA_H_INLINE constexpr Int code_rotation(I8 code) { return (code >> 1) & 3; }
44 
45 OMEGA_H_INLINE constexpr Int code_which_down(I8 code) { return (code >> 3); }
46 
47 OMEGA_H_INLINE constexpr I8 make_code(
48  bool is_flipped, Int rotation, Int which_down) {
49  return static_cast<I8>((which_down << 3) | (rotation << 1) | Int(is_flipped));
50 }
51 
52 OMEGA_H_INLINE constexpr Int rotate_index(
53  Int nverts_per_ent, Int index, Int rotation) {
54  return (index + rotation) % nverts_per_ent;
55 }
56 
57 /* get the rotation code which, when compounded with the input rotation,
58  * produces an identity map */
59 OMEGA_H_INLINE constexpr Int invert_rotation(Int nverts_per_ent, Int rotation) {
60  return (nverts_per_ent - rotation) % nverts_per_ent;
61 }
62 
63 /* all the following can probably be optimized
64  down to a few integer ops by an expert... */
65 
66 OMEGA_H_INLINE constexpr Int reverse_index(Int n, Int i) { return n - 1 - i; }
67 
68 OMEGA_H_INLINE constexpr Int flip_vert_index(Int n, Int i) {
69  return (i == 0 ? 0 : (1 + reverse_index(n - 1, i - 1)));
70 }
71 
72 OMEGA_H_INLINE constexpr Int flip_edge_index(Int n, Int i) {
73  return reverse_index(n, i);
74 }
75 
76 OMEGA_H_INLINE constexpr Int align_vert_index(
77  Int nverts_per_ent, Int index, I8 code) {
78  return code_is_flipped(code)
79  ? flip_vert_index(nverts_per_ent,
80  rotate_index(nverts_per_ent, index, code_rotation(code)))
81  : rotate_index(nverts_per_ent, index, code_rotation(code));
82 }
83 
84 OMEGA_H_INLINE constexpr Int align_edge_index(
85  Int nverts_per_ent, Int index, I8 code) {
86  return code_is_flipped(code)
87  ? flip_edge_index(nverts_per_ent,
88  rotate_index(nverts_per_ent, index, code_rotation(code)))
89  : rotate_index(nverts_per_ent, index, code_rotation(code));
90 }
91 
92 OMEGA_H_INLINE constexpr Int align_index(
93  Int nverts_per_ent, Int index_dim, Int index, I8 code) {
94  return (index_dim == 0 ? align_vert_index(nverts_per_ent, index, code)
95  : align_edge_index(nverts_per_ent, index, code));
96 }
97 
98 OMEGA_H_INLINE constexpr Int rotation_to_first(
99  Int nverts_per_ent, Int new_first) {
100  return invert_rotation(nverts_per_ent, new_first);
101 }
102 
103 OMEGA_H_INLINE constexpr I8 invert_alignment(Int nverts_per_ent, I8 code) {
104  /* flipped codes are their own inverses */
105  return code_is_flipped(code)
106  ? code
107  : make_code(false,
108  invert_rotation(nverts_per_ent, code_rotation(code)), 0);
109 }
110 
111 /* returns the single transformation equivalent
112  to applying the (code1) transformation followed
113  by the (code2) one. */
114 template <Int nverts_per_ent>
115 OMEGA_H_INLINE I8 compound_alignments(I8 code1, I8 code2) {
116  /* we can look for the inverse of the compound
117  by looking at what happens to the vertex
118  that used to be first (0) */
119  Int old_first = align_vert_index(
120  nverts_per_ent, align_vert_index(nverts_per_ent, 0, code1), code2);
121  /* the inverse transformation would bring that
122  vertex back to being the first */
123  Int rotation = rotation_to_first(nverts_per_ent, old_first);
124  bool is_flipped = (code_is_flipped(code1) ^ code_is_flipped(code2));
125  return invert_alignment(nverts_per_ent, make_code(is_flipped, rotation, 0));
126 }
127 
128 OMEGA_H_INLINE I8 compound_alignments(Int deg, I8 code1, I8 code2) {
129  if (deg == 3) return compound_alignments<3>(code1, code2);
130  if (deg == 2) return compound_alignments<2>(code1, code2);
131  OMEGA_H_NORETURN(-1);
132 }
133 
134 template <Int nverts_per_ent, typename In, typename Out>
135 OMEGA_H_DEVICE void rotate_adj(
136  Int rotation, In const& in, LO in_offset, Out& out, LO out_offset) {
137  for (I8 j = 0; j < nverts_per_ent; ++j) {
138  auto out_j = rotate_index(nverts_per_ent, j, rotation);
139  out[out_offset + out_j] = in[in_offset + j];
140  }
141 }
142 
143 template <Int deg>
144 struct FlipAdj;
145 
146 template <>
147 struct FlipAdj<4> {
148  template <typename InOut>
149  OMEGA_H_DEVICE static void flip(InOut& adj, LO offset) {
150  swap2(adj[offset + 1], adj[offset + 3]);
151  }
152 };
153 
154 template <>
155 struct FlipAdj<3> {
156  template <typename InOut>
157  OMEGA_H_DEVICE static void flip(InOut& adj, LO offset) {
158  swap2(adj[offset + 1], adj[offset + 2]);
159  }
160 };
161 
162 template <>
163 struct FlipAdj<2> {
164  template <typename InOut>
165  OMEGA_H_DEVICE static void flip(InOut&, LO) {}
166 };
167 
168 template <Int deg, typename InOut>
169 OMEGA_H_DEVICE void flip_adj(InOut& adj, LO offset) {
170  FlipAdj<deg>::flip(adj, offset);
171 }
172 
173 template <Int nverts_per_ent, typename In, typename Out>
174 OMEGA_H_DEVICE void align_adj(
175  I8 code, In const& in, LO in_offset, Out& out, LO out_offset) {
176  rotate_adj<nverts_per_ent>(
177  code_rotation(code), in, in_offset, out, out_offset);
178  if (code_is_flipped(code)) flip_adj<nverts_per_ent>(out, out_offset);
179 }
180 
181 template <typename T>
182 Read<T> align_ev2v(Int deg, Read<T> ev2v, Read<I8> codes);
183 
184 #define INST_DECL(T) \
185  extern template Read<T> align_ev2v(Int deg, Read<T> ev2v, Read<I8> codes);
186 INST_DECL(LO)
187 INST_DECL(GO)
188 #undef INST_DECL
189 
190 } // end namespace Omega_h
191 
192 #endif
Definition: amr_mpi_test.cpp:6
Definition: Omega_h_align.hpp:144