Direction.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines class template Direction.
6 
7 #pragma once
8 
9 #include <array>
10 #include <cstddef>
11 #include <functional>
12 #include <iosfwd>
13 
14 #include "Domain/Side.hpp"
15 
16 namespace PUP {
17 class er;
18 } // namespace PUP
19 
20 /// \ingroup ComputationalDomainGroup
21 /// A particular Side along a particular coordinate Axis.
22 template <size_t VolumeDim>
23 class Direction {
24  public:
25  static constexpr const size_t volume_dim = VolumeDim;
26 
27  /// The logical-coordinate names of each dimension
28  enum class Axis;
29 
30  /// Construct by specifying an Axis and a Side.
31  Direction(Axis axis, Side side) noexcept : axis_(axis), side_(side) {}
32 
33  /// Construct by specifying a dimension and a Side.
34  Direction<VolumeDim>(size_t dimension, Side side) noexcept;
35 
36  /// Default constructor for Charm++ serialization.
37  Direction() noexcept;
38 
39  /// The dimension of the Direction
40  size_t dimension() const noexcept { return static_cast<size_t>(axis_); }
41 
42  /// The Axis of the Direction
43  Axis axis() const noexcept { return axis_; }
44 
45  /// The side of the Direction
46  Side side() const noexcept { return side_; }
47 
48  /// The sign for the normal to the Side.
49  double sign() const noexcept { return (Side::Lower == side_ ? -1.0 : 1.0); }
50 
51  /// The opposite Direction.
52  Direction<VolumeDim> opposite() const noexcept;
53 
54  // An array of all logical Directions for a given dimensionality.
55  static const std::array<Direction<VolumeDim>, 2 * VolumeDim>&
56  all_directions() noexcept;
57 
58  // {@
59  /// Helper functions for creating specific Directions.
60  /// These are labeled by the logical-coordinate names (Xi,Eta,Zeta).
61  // Note: these are functions because they contain static_assert.
62  static Direction<VolumeDim> lower_xi() noexcept;
63  static Direction<VolumeDim> upper_xi() noexcept;
64  static Direction<VolumeDim> lower_eta() noexcept;
65  static Direction<VolumeDim> upper_eta() noexcept;
66  static Direction<VolumeDim> lower_zeta() noexcept;
67  static Direction<VolumeDim> upper_zeta() noexcept;
68  // @}
69 
70  /// Serialization for Charm++
71  void pup(PUP::er& p) noexcept; // NOLINT
72 
73  private:
74  Axis axis_{Axis::Xi};
75  Side side_{Side::Lower};
76 };
77 
78 /// Output operator for a Direction.
79 template <size_t VolumeDim>
81  const Direction<VolumeDim>& direction) noexcept;
82 
83 //##############################################################################
84 // INLINE DEFINITIONS
85 //##############################################################################
86 
87 // clang-tidy: redundant declaration false positive. Needs to be here because of
88 // the Axis enum, otherwise won't compile.
89 template <size_t VolumeDim>
90 Direction<VolumeDim>::Direction() noexcept = default; // NOLINT
91 
92 // Needed in order to address warning; ignorning -Wpedantic is needed.
93 // Bug 61491
94 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61491
95 #pragma GCC diagnostic push
96 #pragma GCC diagnostic ignored "-Wpedantic"
97 template <>
98 enum class Direction<1>::Axis{Xi = 0};
99 
100 template <>
101 enum class Direction<2>::Axis{Xi = 0, Eta = 1};
102 
103 template <>
104 enum class Direction<3>::Axis{Xi = 0, Eta = 1, Zeta = 2};
105 #pragma GCC diagnostic pop
106 
107 template <size_t VolumeDim>
109  return Direction(Direction<VolumeDim>::Axis::Xi, Side::Lower);
110 }
111 
112 template <size_t VolumeDim>
114  return Direction(Direction<VolumeDim>::Axis::Xi, Side::Upper);
115 }
116 
117 template <size_t VolumeDim>
119  static_assert(VolumeDim == 2 or VolumeDim == 3, "VolumeDim must be 2 or 3.");
120  return Direction(Direction<VolumeDim>::Axis::Eta, Side::Lower);
121 }
122 
123 template <size_t VolumeDim>
125  static_assert(VolumeDim == 2 or VolumeDim == 3, "VolumeDim must be 2 or 3.");
126  return Direction(Direction<VolumeDim>::Axis::Eta, Side::Upper);
127 }
128 
129 template <size_t VolumeDim>
131  static_assert(VolumeDim == 3, "VolumeDim must be 3.");
132  return Direction(Direction<VolumeDim>::Axis::Zeta, Side::Lower);
133 }
134 
135 template <size_t VolumeDim>
137  static_assert(VolumeDim == 3, "VolumeDim must be 3.");
138  return Direction(Direction<VolumeDim>::Axis::Zeta, Side::Upper);
139 }
140 
141 template <size_t VolumeDim>
143  return Direction<VolumeDim>(axis_, ::opposite(side_));
144 }
145 
146 /// \cond NEVER
147 template <>
149  noexcept {
150  const static auto directions = std::array<Direction<1>, 2>{
152  return directions;
153 }
154 
155 template <>
157  noexcept {
158  const static auto directions = std::array<Direction<2>, 4>{
161  return directions;
162 }
163 
164 template <>
166  noexcept {
167  const static auto directions = std::array<Direction<3>, 6>{
171  return directions;
172 }
173 /// \endcond
174 
175 template <size_t VolumeDim>
176 bool operator==(const Direction<VolumeDim>& lhs,
177  const Direction<VolumeDim>& rhs) noexcept {
178  return lhs.dimension() == rhs.dimension() and lhs.sign() == rhs.sign();
179 }
180 
181 template <size_t VolumeDim>
182 bool operator!=(const Direction<VolumeDim>& lhs,
183  const Direction<VolumeDim>& rhs) noexcept {
184  return not(lhs == rhs);
185 }
186 
187 template <size_t VolumeDim>
188 size_t hash_value(const Direction<VolumeDim>& d) noexcept {
189  return std::hash<size_t>{}(d.dimension()) xor std::hash<double>{}(d.sign());
190 }
191 
192 namespace std {
193 template <size_t VolumeDim>
194 struct hash<Direction<VolumeDim>> {
195  size_t operator()(const Direction<VolumeDim>& d) const noexcept {
196  return hash_value(d);
197  }
198 };
199 } // namespace std
200 
201 /// \ingroup ComputationalDomainGroup
202 /// Provides a perfect hash if the size of the hash table is `2 * Dim`. To take
203 /// advantage of this, use the `FixedHashMap` class.
204 template <size_t Dim>
206  template <size_t MaxSize>
207  static constexpr bool is_perfect = MaxSize == 2 * Dim;
208 
209  size_t operator()(const Direction<Dim>& t) noexcept {
210  return 2 * t.dimension() + (t.side() == Side::Upper ? 1 : 0);
211  }
212 };
Definition: Strahlkorper.hpp:14
constexpr Side opposite(const Side side)
The opposite side.
Definition: Side.hpp:20
Direction(Axis axis, Side side) noexcept
Construct by specifying an Axis and a Side.
Definition: Direction.hpp:31
Side side() const noexcept
The side of the Direction.
Definition: Direction.hpp:46
Side
A label for the side of a manifold.
Definition: Side.hpp:17
Provides a perfect hash if the size of the hash table is 2 * Dim. To take advantage of this...
Definition: Direction.hpp:205
A particular Side along a particular coordinate Axis.
Definition: Direction.hpp:23
Direction< VolumeDim > opposite() const noexcept
The opposite Direction.
Definition: Direction.hpp:142
size_t dimension() const noexcept
The dimension of the Direction.
Definition: Direction.hpp:40
Axis axis() const noexcept
The Axis of the Direction.
Definition: Direction.hpp:43
std::ostream & operator<<(std::ostream &os, const Direction< VolumeDim > &direction) noexcept
Output operator for a Direction.
double sign() const noexcept
The sign for the normal to the Side.
Definition: Direction.hpp:49
static Direction< VolumeDim > lower_xi() noexcept
Helper functions for creating specific Directions. These are labeled by the logical-coordinate names ...
Definition: Direction.hpp:108
Direction() noexcept
Default constructor for Charm++ serialization.
Defines enum class Side.