SpECTRE Documentation Coverage Report
Current view: top level - Domain/Structure - Direction.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 53.8 % 39 21
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            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/Structure/Side.hpp"
      15              : #include "Utilities/ErrorHandling/Assert.hpp"
      16              : 
      17              : namespace PUP {
      18              : class er;
      19              : }  // namespace PUP
      20              : 
      21              : /// \ingroup ComputationalDomainGroup
      22              : /// A particular Side along a particular coordinate Axis.
      23              : template <size_t VolumeDim>
      24            1 : class Direction {
      25              :  public:
      26            0 :   static constexpr const size_t volume_dim = VolumeDim;
      27            0 :   static constexpr uint8_t axis_mask = 0b0011;
      28            0 :   static constexpr uint8_t side_mask = 0b1100;
      29            0 :   static constexpr uint8_t all_mask = 0b1111;
      30            0 :   static constexpr uint8_t number_of_bits = 4;
      31              : 
      32              :   /// The logical-coordinate names of each dimension
      33              :   enum class Axis : uint8_t;
      34              : 
      35              :   /// Construct by specifying an Axis and a Side.
      36            1 :   Direction(Axis axis, Side side);
      37              : 
      38              :   /// Construct by specifying a dimension and a Side.
      39            1 :   Direction(size_t dimension, Side side);
      40              : 
      41              :   /// Default constructor for Charm++ serialization.
      42            1 :   Direction();
      43              : 
      44              :   /// Get a Direction representing "self" or "no direction"
      45            1 :   static Direction<VolumeDim> self();
      46              : 
      47              :   /// The dimension of the Direction
      48            1 :   size_t dimension() const {
      49              :     ASSERT(bit_field_ != 0, "Cannot use an uninitialized Direction");
      50              :     return static_cast<uint8_t>(axis());
      51              :   }
      52              : 
      53              :   /// The Axis of the Direction
      54            1 :   Axis axis() const {
      55              :     ASSERT(bit_field_ != 0, "Cannot use an uninitialized Direction");
      56              :     return static_cast<Axis>(bit_field_ bitand axis_mask);
      57              :   }
      58              : 
      59              :   /// The side of the Direction
      60            1 :   Side side() const { return static_cast<Side>(bit_field_ bitand side_mask); }
      61              : 
      62              :   /// The sign for the normal to the Side.
      63              :   ///
      64              :   /// This is `+1.0` if `side() == Side::Upper` and `-1.0` if
      65              :   /// `side() == Side::Lower`, otherwise an `ASSERT` is triggered.
      66            1 :   double sign() const {
      67              :     ASSERT(Side::Lower == side() or Side::Upper == side(),
      68              :            "sign() is only defined for Side::Lower and Side::Upper, not "
      69              :                << side());
      70              :     return (Side::Lower == side() ? -1.0 : 1.0);
      71              :   }
      72              : 
      73              :   /// The opposite Direction.
      74            1 :   Direction<VolumeDim> opposite() const;
      75              : 
      76              :   // An array of all logical Directions for a given dimensionality.
      77              :   static const std::array<Direction<VolumeDim>, 2 * VolumeDim>&
      78            0 :   all_directions();
      79              : 
      80              :   /// @{
      81              :   /// Helper functions for creating specific Directions.
      82              :   /// These are labeled by the logical-coordinate names (Xi,Eta,Zeta).
      83              :   // Note: these are functions because they contain static_assert.
      84            1 :   static Direction<VolumeDim> lower_xi();
      85            1 :   static Direction<VolumeDim> upper_xi();
      86            1 :   static Direction<VolumeDim> lower_eta();
      87            1 :   static Direction<VolumeDim> upper_eta();
      88            1 :   static Direction<VolumeDim> lower_zeta();
      89            1 :   static Direction<VolumeDim> upper_zeta();
      90              :   /// @}
      91              : 
      92            0 :   uint8_t bits() const { return bit_field_; }
      93              : 
      94              :   /// Serialization for Charm++
      95              :   // NOLINTNEXTLINE(google-runtime-references)
      96            1 :   void pup(PUP::er& p);
      97              : 
      98              :  private:
      99              :   template <size_t LocalVolumeDim>
     100            0 :   friend bool operator==(const Direction<LocalVolumeDim>& lhs,
     101              :                          const Direction<LocalVolumeDim>& rhs);
     102              :   template <size_t LocalVolumeDim>
     103            0 :   friend size_t hash_value(const Direction<LocalVolumeDim>& d);
     104              : 
     105            0 :   uint8_t bit_field_{0};
     106              : };
     107              : 
     108              : /// Output operator for a Direction.
     109              : template <size_t VolumeDim>
     110            1 : std::ostream& operator<<(std::ostream& os,
     111              :                          const Direction<VolumeDim>& direction);
     112              : 
     113              : //##############################################################################
     114              : // INLINE DEFINITIONS
     115              : //##############################################################################
     116              : 
     117              : /// \cond
     118              : // clang-tidy: redundant declaration false positive. Needs to be here because of
     119              : // the Axis enum, otherwise won't compile.
     120              : template <size_t VolumeDim>
     121              : Direction<VolumeDim>::Direction() = default;  // NOLINT
     122              : 
     123              : // Needed in order to address warning; ignorning -Wpedantic is needed.
     124              : // Bug 61491
     125              : // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61491
     126              : #pragma GCC diagnostic push
     127              : #pragma GCC diagnostic ignored "-Wpedantic"
     128              : template <>
     129              : enum class Direction<1>::Axis : uint8_t{Xi = 0};
     130              : 
     131              : template <>
     132              : enum class Direction<2>::Axis : uint8_t{Xi = 0, Eta = 1};
     133              : 
     134              : template <>
     135              : enum class Direction<3>::Axis : uint8_t{Xi = 0, Eta = 1, Zeta = 2};
     136              : #pragma GCC diagnostic pop
     137              : 
     138              : template <size_t VolumeDim>
     139              : inline Direction<VolumeDim> Direction<VolumeDim>::lower_xi() {
     140              :   return Direction(Direction<VolumeDim>::Axis::Xi, Side::Lower);
     141              : }
     142              : 
     143              : template <size_t VolumeDim>
     144              : inline Direction<VolumeDim> Direction<VolumeDim>::upper_xi() {
     145              :   return Direction(Direction<VolumeDim>::Axis::Xi, Side::Upper);
     146              : }
     147              : 
     148              : template <size_t VolumeDim>
     149              : inline Direction<VolumeDim> Direction<VolumeDim>::lower_eta() {
     150              :   static_assert(VolumeDim == 2 or VolumeDim == 3, "VolumeDim must be 2 or 3.");
     151              :   return Direction(Direction<VolumeDim>::Axis::Eta, Side::Lower);
     152              : }
     153              : 
     154              : template <size_t VolumeDim>
     155              : inline Direction<VolumeDim> Direction<VolumeDim>::upper_eta() {
     156              :   static_assert(VolumeDim == 2 or VolumeDim == 3, "VolumeDim must be 2 or 3.");
     157              :   return Direction(Direction<VolumeDim>::Axis::Eta, Side::Upper);
     158              : }
     159              : 
     160              : template <size_t VolumeDim>
     161              : inline Direction<VolumeDim> Direction<VolumeDim>::lower_zeta() {
     162              :   static_assert(VolumeDim == 3, "VolumeDim must be 3.");
     163              :   return Direction(Direction<VolumeDim>::Axis::Zeta, Side::Lower);
     164              : }
     165              : 
     166              : template <size_t VolumeDim>
     167              : inline Direction<VolumeDim> Direction<VolumeDim>::upper_zeta() {
     168              :   static_assert(VolumeDim == 3, "VolumeDim must be 3.");
     169              :   return Direction(Direction<VolumeDim>::Axis::Zeta, Side::Upper);
     170              : }
     171              : 
     172              : template <size_t VolumeDim>
     173              : inline Direction<VolumeDim> Direction<VolumeDim>::opposite() const {
     174              :   ASSERT(bit_field_ != 0, "Cannot use an uninitialized Direction");
     175              :   return Direction<VolumeDim>(axis(), ::opposite(side()));
     176              : }
     177              : 
     178              : template <>
     179              : inline const std::array<Direction<1>, 2>& Direction<1>::all_directions() {
     180              :   const static auto directions = std::array<Direction<1>, 2>{
     181              :       {Direction<1>::lower_xi(), Direction<1>::upper_xi()}};
     182              :   return directions;
     183              : }
     184              : 
     185              : template <>
     186              : inline const std::array<Direction<2>, 4>& Direction<2>::all_directions() {
     187              :   const static auto directions = std::array<Direction<2>, 4>{
     188              :       {Direction<2>::lower_xi(), Direction<2>::upper_xi(),
     189              :        Direction<2>::lower_eta(), Direction<2>::upper_eta()}};
     190              :   return directions;
     191              : }
     192              : 
     193              : template <>
     194              : inline const std::array<Direction<3>, 6>& Direction<3>::all_directions() {
     195              :   const static auto directions = std::array<Direction<3>, 6>{
     196              :       {Direction<3>::lower_xi(), Direction<3>::upper_xi(),
     197              :        Direction<3>::lower_eta(), Direction<3>::upper_eta(),
     198              :        Direction<3>::lower_zeta(), Direction<3>::upper_zeta()}};
     199              :   return directions;
     200              : }
     201              : /// \endcond
     202              : 
     203              : template <size_t VolumeDim>
     204            0 : bool operator==(const Direction<VolumeDim>& lhs,
     205              :                 const Direction<VolumeDim>& rhs) {
     206              :   return lhs.bit_field_ == rhs.bit_field_;
     207              : }
     208              : 
     209              : template <size_t VolumeDim>
     210            0 : bool operator!=(const Direction<VolumeDim>& lhs,
     211              :                 const Direction<VolumeDim>& rhs) {
     212              :   return not(lhs == rhs);
     213              : }
     214              : 
     215              : /// Define an ordering of directions first by axis (xi, eta, zeta), then by side
     216              : /// (lower, upper). There's no particular reason for this choice of ordering.
     217              : template <size_t VolumeDim>
     218            1 : bool operator<(const Direction<VolumeDim>& lhs,
     219              :                const Direction<VolumeDim>& rhs);
     220              : 
     221              : template <size_t VolumeDim>
     222            0 : bool operator>(const Direction<VolumeDim>& lhs,
     223              :                const Direction<VolumeDim>& rhs) {
     224              :   return rhs < lhs;
     225              : }
     226              : template <size_t VolumeDim>
     227            0 : bool operator<=(const Direction<VolumeDim>& lhs,
     228              :                 const Direction<VolumeDim>& rhs) {
     229              :   return !(lhs > rhs);
     230              : }
     231              : template <size_t VolumeDim>
     232            0 : bool operator>=(const Direction<VolumeDim>& lhs,
     233              :                 const Direction<VolumeDim>& rhs) {
     234              :   return !(lhs < rhs);
     235              : }
     236              : 
     237              : template <size_t VolumeDim>
     238            0 : size_t hash_value(const Direction<VolumeDim>& d) {
     239              :   return d.bit_field_;
     240              : }
     241              : 
     242              : namespace std {
     243              : template <size_t VolumeDim>
     244              : struct hash<Direction<VolumeDim>> {
     245              :   size_t operator()(const Direction<VolumeDim>& d) const {
     246              :     return hash_value(d);
     247              :   }
     248              : };
     249              : }  // namespace std
     250              : 
     251              : /// \ingroup ComputationalDomainGroup
     252              : /// Provides a perfect hash if the size of the hash table is `2 * Dim`. To take
     253              : /// advantage of this, use the `FixedHashMap` class.
     254              : template <size_t Dim>
     255            1 : struct DirectionHash {
     256              :   template <size_t MaxSize>
     257            0 :   static constexpr bool is_perfect = MaxSize == 2 * Dim;
     258              : 
     259            0 :   size_t operator()(const Direction<Dim>& t) {
     260              :     return 2 * t.dimension() + (t.side() == Side::Upper ? 1 : 0);
     261              :   }
     262              : };
        

Generated by: LCOV version 2.0-1