Line data Source code
1 0 : \cond NEVER
2 : Distributed under the MIT License.
3 : See LICENSE.txt for details.
4 : \endcond
5 : # OrientationMap {#tutorial_orientations}
6 :
7 : \tableofcontents
8 :
9 : ### Introduction
10 :
11 : This tutorial only applies to a Domain (or a region of the Domain) that is
12 : constructed from Blocks that are logical hypercubes where each Block has at
13 : most a single neighboring Block in each direction.
14 :
15 : Each element in a domain has a set of internal directions which it uses
16 : for computations in its own local coordinate system. These are referred to
17 : as the logical directions \f$\xi\f$, \f$\eta\f$, and \f$\zeta\f$, where
18 : \f$\xi\f$ is the first dimension, \f$\eta\f$ is the second dimension, and
19 : \f$\zeta\f$ is the third dimension. In a
20 : domain with multiple Blocks, the logical directions are not necessarily
21 : aligned on the interfaces between two Blocks, as shown in the figure below.
22 : As certain operations (e.g. fluxes, limiting) communicate information across
23 : the boundaries of adjacent elements, there needs to be a class that takes
24 : into account the relative orientations of elements which neighbor each other.
25 : This class is OrientationMap.
26 :
27 : ### %OrientationMaps between %Blocks
28 : Each Block in a Domain has a set of BlockNeighbors, which each hold an
29 : OrientationMap. In this scenario, the Block is referred to as the host, and
30 : the OrientationMap held by each BlockNeighbors is referred to as "the
31 : orientation the BlockNeighbors has with respect to the host Block." This is
32 : a convention, so we give an example of constructing and assigning the correct
33 : OrientationMaps:
34 :
35 : \image html twocubes.png "Two neighboring blocks."
36 :
37 : In the image above, we see a domain decomposition into two Blocks, which have
38 : their logical axes rotated relative to one another. With the left block as
39 : the host Block, we see that it has a neighbor in the \f$+\xi\f$ direction.
40 : The host Block holds a `std::unordered_map` from Directions to BlockNeighbors;
41 : the BlockNeighbors itself holds an OrientationMap that determines the mapping
42 : from each logical direction in the host Block to that in the neighboring Block.
43 : That is, the OrientationMap takes as input local information (i.e. logical
44 : directions in the host's coordinate system) and returns neighbor information
45 : (i.e. logical directions in the neighbor's coordinate system). An
46 : OrientationMap is constructed by passing in the block neighbor directions that
47 : correspond to the \f$+\xi\f$, \f$+\eta\f$, \f$+\zeta\f$ directions in the host.
48 : In this case, these directions in the host map to the \f$+\zeta\f$,
49 : \f$+\xi\f$, \f$+\eta\f$ directions in the neighbor, respectively.
50 : This BlockNeighbors thus holds the OrientationMap constructed with the list
51 : (\f$+\zeta\f$, \f$+\xi\f$, \f$+\eta\f$). With the right block as the host
52 : block, we see that it has a BlockNeighbors in the \f$-\zeta\f$ direction, and
53 : the OrientationMap held by this BlockNeighbors is the one constructed with the
54 : array (\f$+\eta\f$, \f$+\zeta\f$, \f$+\xi\f$). For convenience, OrientationMap
55 : has a method `inverse_map` which returns the OrientationMap that takes as input
56 : neighbor information and returns local information.
57 :
58 : OrientationMaps need to be provided for each BlockNeighbors in each direction
59 : for each Block. This quickly becomes too large of a number to determine by
60 : hand as the number of Blocks and the number of dimensions increases. A remedy
61 : to this problem is the corner numbering scheme.
62 :
63 : ### Encoding BlockNeighbors information using Corner Orderings and Numberings
64 : The orientation of the \f${dim}\f$ logical directions within each element
65 : determines an ordering of the \f$2^{dim}\f$ vertices of that element. This is
66 : called the local corner numbering scheme (Local CNS) with respect to that
67 : element. We give the ordering of the local corners below for the case of a
68 : three-dimensional element:
69 :
70 : \image html onecube_numbered.png "The local corner numbering."
71 :
72 : ```
73 : Corner 0 is the location of the lower xi, lower eta, lower zeta corner.
74 : Corner 1 is the location of the upper xi, lower eta, lower zeta corner.
75 : Corner 2 is the location of the lower xi, upper eta, lower zeta corner.
76 : Corner 3 is the location of the upper xi, upper eta, lower zeta corner.
77 : Corner 4 is the location of the lower xi, lower eta, upper zeta corner.
78 : Corner 5 is the location of the upper xi, lower eta, upper zeta corner.
79 : Corner 6 is the location of the lower xi, upper eta, upper zeta corner.
80 : Corner 7 is the location of the upper xi, upper eta, upper zeta corner.
81 : ```
82 :
83 : What remains is to endow the domain decomposition with a global corner
84 : numbering (Global CNS). We give an example below:
85 :
86 : \image html twocubes_numbered.png "A global corner numbering."
87 :
88 : In the image above, we see that each vertex of the two-block domain has
89 : been assigned a number. Although each block has eight corners, four are
90 : shared among them, so there are only twelve unique corners in this domain.
91 : Any numbering may be used in the global corner numbering, so long as the
92 : each distinct corner is given a single distinct corner number.
93 :
94 : \note This Global CNS assumes that there is no additional identifying of faces
95 : with one another for periodic boundary conditions. That is, each element must
96 : have \f$2^{dim}\f$ distinct corner numbers. If you wish to additionally
97 : identify faces of the same block with each other, that must be done in an
98 : additional step. This step is explained in the "Setting Periodic Boundary
99 : Conditions" section.
100 :
101 : ### The Ordered Subset of the Global CNS (Subset CNS):
102 : With the Global CNS in hand, each Block inherits an ordered subset of Global
103 : CNS. The ordering in this set is determined by the ordering of the Local CNS,
104 : and the elements of the set determined by how one assigned the Global CNS to
105 : the Domain. For the image above, the Subset CNS corresponding to the left block
106 : is {0, 1, 3, 4, 6, 7, 9, 10}, while the Subset CNS corresponding to the right
107 : block is {1, 4, 7, 10, 2, 5, 8, 11}. This ordering of the Subset CNS encodes
108 : the relative orientations between each Block. Subset CNSs need to be provided
109 : for each Block in a Domain. It turns out that for very regular domains,
110 : (i.e. spherical or rectilinear) we can generate the appropriate Subset CNSs.
111 : As this is a conceptual tutorial, how to construct these domains in SpECTRE
112 : is described in the \ref tutorial_domain_creation tutorial.
113 :
114 : ### Explanation of the Algorithms in DomainHelpers:
115 :
116 : For illustrative purposes, we will use the following Domain composed of two
117 : Blocks as described above as an example.
118 : Because there are 12 corners in this Domain, we will arbitrarily assign a
119 : unique id to each corner.
120 : Knowing the orientation of the logical axes within a block, we construct a
121 : Subset CNS for each Block.<br>
122 : Here is one possible result, given some relative orientation between the
123 : blocks:
124 :
125 : ```
126 : Block1: {0, 1, 3, 4, 6, 7, 9, 10}
127 : Block2: {1, 4, 7, 10, 2, 5, 8, 11}
128 : ```
129 :
130 : The values of the ids only serve to identify which corners are unique and which
131 : are shared. This is determined by the Global CNS. The order of the ids in the
132 : list is determined by the Local CNS. We take advantage of the fact that the
133 : array index of the global corner id is the number of the corner in the local
134 : CNS.
135 :
136 : The algorithm begins by determining the shared corners between the
137 : Blocks:
138 :
139 : ```
140 : result: {1, 4, 7, 10}
141 : ```
142 :
143 : The next step is to determine the local ids of these shared global ids:
144 :
145 : ```
146 : Block1 result: {1,3,5,7}
147 : Block2 result: {0,1,2,3}
148 : ```
149 :
150 : The next step is to convert these ids into their binary representation.
151 : For reference, we give the binary representation for each number 0-7:
152 :
153 : ```
154 : Corner 0: 000
155 : Corner 1: 001
156 : Corner 2: 010
157 : Corner 3: 011
158 : Corner 4: 100
159 : Corner 5: 101
160 : Corner 6: 110
161 : Corner 7: 111
162 : ```
163 :
164 : Here 0 and 1 indicate lower and upper in the corresponding axis (zeta,
165 : eta, xi), respectively, and the ordering has been reversed so that the
166 : rightmost column corresponds to the xi position and the leftmost column
167 : to the zeta position. Returning to the example at hand, we have:
168 :
169 :
170 : ```
171 : Block1 result: {001,011,101,111}
172 : Block2 result: {000,001,010,011}
173 : ```
174 :
175 : Note that we can now read off the shared face relative to each Block
176 : easily:
177 :
178 : ```
179 : Block1 result: Upper xi (All binary Block1 ids have a 1 in the third position)
180 : Block2 result: Lower zeta (All binary Block2 ids have a 0 in the first position)
181 : ```
182 :
183 : Now we know that `Direction<3>::%upper_xi()`
184 : in Block1 corresponds to `Direction<3>::%lower_zeta().%opposite()` in Block2.
185 :
186 : The use of `.%opposite()` is a result of the Directions to a Block face being
187 : anti-parallel because each Block lies on the opposite side of the shared face.
188 : <br>
189 :
190 : The remaining two correspondences are given by the alignment of the shared
191 : face. It is useful to know the following information:<br>
192 : In the Local CNS, if an edge lies along the xi direction, if one takes the
193 : two corners making up that edge and takes the difference of their ids, one
194 : always gets the result \f$ \pm 1\f$. Similarly, if the edge lies in the eta
195 : direction, the result will be \f$ \pm 2\f$. Finally, if the edge lies in the
196 : zeta direction, the result will be \f$ \pm 4\f$. We use this information to
197 : determine the alignment of the shared face:
198 :
199 : ```
200 : Block1: 3-1=2 => This edge is in the +eta direction.
201 : Block2: 1-0=1 => This edge is in the +xi direction.
202 : Then, +eta in Block1 corresponds to +xi in Block2.
203 :
204 : Block1: 5-1=4 => This edge is in the +zeta direction.
205 : Block2: 2-0=2 => This edge is in the +eta direction.
206 : Then, +zeta in Block1 corresponds to +eta in Block2.
207 : ```
208 :
209 : The corresponding directions in each Block have now been deduced.
210 :
211 : To confirm, we can use the other ids as well and arrive at the same result:<br>
212 :
213 : ```
214 : Block1: 7-5=2 => +eta
215 : Block2: 3-2=1 => +xi
216 :
217 : Block1: 7-3=4 => +zeta
218 : Block2: 3-1=2 => +eta
219 : ```
220 :
221 : ### Setting Periodic Boundary Conditions
222 : It is also possible to identify faces of a Block using the subset CNS. For
223 : example, to identify the lower zeta face with the upper zeta face of a Block
224 : where the corners are labeled `{3,0,4,1,9,6,10,7}`, one may supply the lists
225 : `{3,0,4,1}` and `{9,6,10,7}` to the `set_identified_boundaries` function.
226 : \note The `set_identified_boundaries` function is sensitive to the order of the
227 : corners in the lists supplied as arguments. This is because the function
228 : identifies corners and edges with each other as opposed to simply faces. This
229 : allows the user to specify more peculiar boundary conditions. For example,
230 : using `{3,0,4,1}` and `{6,7,9,10}` to set the periodic boundaries will identify
231 : the lower zeta face with the upper zeta face, but after a rotation of a
232 : quarter-turn.
233 :
234 : For reference, here are the corners to use for each face for a Block with
235 : corners labelled as `{0,1,2,3,4,5,6,7}` to set up periodic boundary conditions
236 : in each dimension, i.e. a \f$\mathrm{T}^3\f$ topology:
237 :
238 : Face | Corners
239 : ------|--------
240 : upper xi| `{1,3,5,7}`
241 : lower xi| `{0,2,4,6}`
242 : upper eta| `{2,3,6,7}`
243 : lower eta| `{0,1,4,5}`
244 : upper zeta| `{4,5,6,7}`
245 : lower zeta| `{0,1,2,3}`
|