SpECTRE Documentation Coverage Report
Current view: top level - __w/spectre/spectre/docs/Tutorials - Orientation.md Hit Total Coverage
Commit: 4d43624d64e749c1edac1bf2b22ce14141d2836f Lines: 0 1 0.0 %
Date: 2026-08-12 22:55:12
Legend: Lines: hit not hit

          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}`

Generated by: LCOV version 1.14