OrientationMap.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <array>
7 #include <cstddef>
8 #include <iosfwd>
9 
10 #include "Domain/Direction.hpp"
11 #include "Domain/Mesh.hpp"
12 #include "Domain/SegmentId.hpp" // IWYU pragma: keep
13 #include "Domain/Side.hpp"
14 #include "Utilities/Gsl.hpp"
15 #include "Utilities/TypeTraits.hpp"
16 
17 namespace PUP {
18 class er;
19 } // namespace PUP
20 
21 /*!
22  * \ingroup DomainCreatorsGroup
23  * \brief A mapping of the logical coordinate axes of a host to the logical
24  * coordinate axes of a neighbor of the host.
25  * \usage Given a `size_t dimension`, a `Direction`, or a `SegmentId` of the
26  * host, an `OrientationMap` will give the corresponding value in the neighbor.
27  * \tparam VolumeDim the dimension of the blocks.
28  *
29  * See the [tutorial](@ref tutorial_orientations) for information on how
30  * OrientationMaps are used and constructed.
31  */
32 template <size_t VolumeDim>
33 class OrientationMap {
34  public:
35  /// The default orientation is the identity map on directions.
36  /// The bool `is_aligned_` is correspondingly set to `true`.
37  OrientationMap() noexcept;
38  explicit OrientationMap(
39  std::array<Direction<VolumeDim>, VolumeDim> mapped_directions) noexcept;
40  OrientationMap(
41  const std::array<Direction<VolumeDim>, VolumeDim>& directions_in_host,
42  const std::array<Direction<VolumeDim>, VolumeDim>&
43  directions_in_neighbor) noexcept;
44  ~OrientationMap() = default;
45  OrientationMap(const OrientationMap&) = default;
46  OrientationMap& operator=(const OrientationMap&) = default;
47  OrientationMap(OrientationMap&& /*rhs*/) noexcept = default;
48  OrientationMap& operator=(OrientationMap&& /*rhs*/) noexcept = default;
49 
50  /// True when mapped(Direction) == Direction
51  bool is_aligned() const noexcept { return is_aligned_; }
52 
53  /// The corresponding dimension in the neighbor.
54  size_t operator()(const size_t dim) const noexcept {
55  return gsl::at(mapped_directions_, dim).dimension();
56  }
57 
58  /// The corresponding direction in the neighbor.
59  Direction<VolumeDim> operator()(const Direction<VolumeDim>& direction) const
60  noexcept {
61  return direction.side() == Side::Upper
62  ? gsl::at(mapped_directions_, direction.dimension())
63  : gsl::at(mapped_directions_, direction.dimension()).opposite();
64  }
65 
66  /// The corresponding SegmentIds in the neighbor.
68  const std::array<SegmentId, VolumeDim>& segmentIds) const noexcept;
69 
70  /// The corresponding Mesh in the neighbor
71  Mesh<VolumeDim> operator()(const Mesh<VolumeDim>& mesh) const noexcept;
72 
73  /// An array whose elements are permuted such that
74  /// `result[d] = array_in_neighbor[this->operator()(d)]`
75  ///
76  /// \note the permutation depends only on how the dimension is mapped
77  /// and ignores the side of the mapped direction.
78  template <typename T>
79  std::array<T, VolumeDim> permute_from_neighbor(
80  const std::array<T, VolumeDim>& array_in_neighbor) const noexcept;
81 
82  /// The corresponding Orientation of the host in the frame of the neighbor.
83  OrientationMap<VolumeDim> inverse_map() const noexcept;
84 
85  /// Serialization for Charm++
86  void pup(PUP::er& p) noexcept; // NOLINT
87 
88  private:
89  friend bool operator==(const OrientationMap& lhs,
90  const OrientationMap& rhs) noexcept {
91  return (lhs.mapped_directions_ == rhs.mapped_directions_ and
92  lhs.is_aligned_ == rhs.is_aligned_);
93  }
94 
95  std::array<Direction<VolumeDim>, VolumeDim> mapped_directions_;
96  bool is_aligned_ = true;
97 };
98 
99 /// Output operator for OrientationMap.
100 template <size_t VolumeDim>
101 std::ostream& operator<<(std::ostream& os,
102  const OrientationMap<VolumeDim>& orientation) noexcept;
103 
104 template <size_t VolumeDim>
105 bool operator!=(const OrientationMap<VolumeDim>& lhs,
106  const OrientationMap<VolumeDim>& rhs) noexcept {
107  return not(lhs == rhs);
108 }
109 
110 template <size_t VolumeDim>
111 template <typename T>
112 std::array<T, VolumeDim> OrientationMap<VolumeDim>::permute_from_neighbor(
113  const std::array<T, VolumeDim>& array_in_neighbor) const noexcept {
114  std::array<T, VolumeDim> result = array_in_neighbor;
115  if (not is_aligned_ and VolumeDim > 1) {
116  for (size_t i = 0; i < VolumeDim; i++) {
117  gsl::at(result, i) = gsl::at(array_in_neighbor, this->operator()(i));
118  }
119  }
120  return result;
121 }
122 
123 /// \ingroup DomainCreatorsGroup
124 /// `OrientationMap`s define an active rotation of the logical axes that bring
125 /// the axes of a host block into alignment with the logical axes of the
126 /// neighbor block. `discrete_rotation` applies this active rotation on the
127 /// coordinates as opposed to the axes.
128 /// For a two-dimensional example, consider a host block and a neighbor block,
129 /// where the OrientationMap between them is \f$\{-\eta,+\xi\}\f$. A quarter-
130 /// turn counterclockwise of the host block's logical axes would bring them into
131 /// alignment with those of the neighbor. That is, after this active rotation,
132 /// the blocks would be Aligned. Now consider a point A with coordinates
133 /// (+1.0,-0.5). An active quarter-turn rotation counter-clockwise about the
134 /// origin, keeping the axes fixed, brings point A into the coordinates
135 /// (+0.5,+1.0). This is how `discrete_rotation` interprets the
136 /// `OrientationMap` passed to it.
137 template <size_t VolumeDim, typename T>
139  const OrientationMap<VolumeDim>& rotation,
140  std::array<T, VolumeDim> source_coords) noexcept {
141  using ReturnType = tt::remove_cvref_wrap_t<T>;
143  for (size_t i = 0; i < VolumeDim; i++) {
144  const auto new_direction = rotation(Direction<VolumeDim>(i, Side::Upper));
145  gsl::at(new_coords, i) =
146  std::move(gsl::at(source_coords, new_direction.dimension()));
147  if (new_direction.side() != Side::Upper) {
148  gsl::at(new_coords, i) *= -1.0;
149  }
150  }
151  return new_coords;
152 }
Defines class template Direction.
Definition: Strahlkorper.hpp:14
T operator!=(T... args)
constexpr Side opposite(const Side side)
The opposite side.
Definition: Side.hpp:20
Side side() const noexcept
The side of the Direction.
Definition: Direction.hpp:46
Holds the number of grid points, basis, and quadrature in each direction of the computational grid...
Definition: Mesh.hpp:49
A particular Side along a particular coordinate Axis.
Definition: Direction.hpp:23
std::array< tt::remove_cvref_wrap_t< T >, VolumeDim > discrete_rotation(const OrientationMap< VolumeDim > &rotation, std::array< T, VolumeDim > source_coords) noexcept
OrientationMaps define an active rotation of the logical axes that bring the axes of a host block int...
Definition: OrientationMap.hpp:138
Defines the class template Mesh.
Defines functions and classes from the GSL.
Defines type traits, some of which are future STL type_traits header.
Defines class SegmentId.
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid...
Definition: Gsl.hpp:124
Defines enum class Side.