SpECTRE Documentation Coverage Report
Current view: top level - Domain/Structure - OrientationMap.hpp Hit Total Coverage
Commit: ecb8a275e1aebab77dcce48a5e098ed4e486ab4b Lines: 17 33 51.5 %
Date: 2026-08-22 01:05:40
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // 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 "DataStructures/Tensor/TypeAliases.hpp"
      11             : #include "Domain/Structure/Direction.hpp"
      12             : #include "Domain/Structure/SegmentId.hpp"
      13             : #include "Domain/Structure/Side.hpp"
      14             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      15             : #include "Utilities/Gsl.hpp"
      16             : 
      17             : namespace PUP {
      18             : class er;
      19             : }  // namespace PUP
      20             : 
      21             : /*!
      22             :  * \ingroup ComputationalDomainGroup
      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             :  *
      26             :  * Given a `size_t dimension`, a `Direction`, a `SegmentId`, or a `Mesh` of the
      27             :  * host, an `OrientationMap` will give the corresponding value in the neighbor.
      28             :  *
      29             :  * \tparam VolumeDim the dimension of the blocks.
      30             :  *
      31             :  * See the [tutorial](@ref tutorial_orientations) for information on how
      32             :  * OrientationMaps are used and constructed.
      33             :  *
      34             :  * \note If there is no discrete rotation between logical coordinates (e.g. the
      35             :  * angular coordinates of a spherical shell abutting a wedge of a cubed sphere)
      36             :  * specify Direction<VolumeDim>::self() as the mapped direction
      37             :  *
      38             :  */
      39             : template <size_t VolumeDim>
      40           1 : class OrientationMap {
      41             :  public:
      42           0 :   static constexpr uint16_t aligned_mask = 0b1000000000000000;
      43           0 :   static constexpr uint16_t version_mask = 0b0111000000000000;
      44             : 
      45             :   /// \brief Creates an OrientationMap in an uninitialized state.
      46             :   ///
      47             :   /// This can be helpful for debugging code. If you would like the identity
      48             :   /// map, please use `create_aligned()`.
      49           1 :   OrientationMap();
      50             :   /// Mapped directions relative to the positive (`Side::Upper`) direction in
      51             :   /// each logical direction.
      52           1 :   explicit OrientationMap(
      53             :       std::array<Direction<VolumeDim>, VolumeDim> mapped_directions);
      54           0 :   OrientationMap(
      55             :       const std::array<Direction<VolumeDim>, VolumeDim>& directions_in_host,
      56             :       const std::array<Direction<VolumeDim>, VolumeDim>&
      57             :           directions_in_neighbor);
      58           0 :   ~OrientationMap() = default;
      59           0 :   OrientationMap(const OrientationMap&) = default;
      60           0 :   OrientationMap& operator=(const OrientationMap&) = default;
      61           0 :   OrientationMap(OrientationMap&& /*rhs*/) = default;
      62           0 :   OrientationMap& operator=(OrientationMap&& /*rhs*/) = default;
      63             : 
      64             :   /// Creates an OrientationMap that is the identity map on directions.
      65             :   /// `is_aligned()` is `true` in this case.
      66           1 :   static OrientationMap<VolumeDim> create_aligned();
      67             : 
      68             :   /// True when mapped(Direction) == Direction
      69           1 :   bool is_aligned() const {
      70             :     ASSERT(bit_field_ != static_cast<uint16_t>(0b1 << 15),
      71             :            "Cannot use a default-constructed OrientationMap");
      72             :     return (bit_field_ bitand aligned_mask) == aligned_mask;
      73             :   }
      74             : 
      75             :   /// The corresponding dimension in the neighbor.
      76           1 :   size_t operator()(const size_t dim) const {
      77             :     ASSERT(bit_field_ != static_cast<uint16_t>(0b1 << 15),
      78             :            "Cannot use a default-constructed OrientationMap");
      79             :     const auto neighbor_direction = get_direction(dim);
      80             :     ASSERT(neighbor_direction.side() != Side::Self,
      81             :            "There is no corresponding dimension");
      82             :     return neighbor_direction.dimension();
      83             :   }
      84             : 
      85             :   /// The corresponding direction in the neighbor.
      86           1 :   Direction<VolumeDim> operator()(const Direction<VolumeDim>& direction) const {
      87             :     ASSERT(bit_field_ != static_cast<uint16_t>(0b1 << 15),
      88             :            "Cannot use a default-constructed OrientationMap");
      89             :     return direction.side() == Side::Upper
      90             :                ? get_direction(direction.dimension())
      91             :                : get_direction(direction.dimension()).opposite();
      92             :   }
      93             : 
      94             :   /// The corresponding SegmentIds in the neighbor.
      95           1 :   std::array<SegmentId, VolumeDim> operator()(
      96             :       const std::array<SegmentId, VolumeDim>& segmentIds) const;
      97             : 
      98             :   /// The corresponding Mesh in the neighbor
      99           1 :   Mesh<VolumeDim> operator()(const Mesh<VolumeDim>& mesh) const;
     100             : 
     101             :   /// An array whose elements are permuted such that
     102             :   /// `result[this->operator()(d)] = array_to_permute[d]`.
     103             :   ///
     104             :   /// \note the permutation depends only on how the dimension is mapped
     105             :   /// and ignores the side of the mapped direction.
     106             :   template <typename T>
     107           1 :   std::array<T, VolumeDim> permute_to_neighbor(
     108             :       const std::array<T, VolumeDim>& array_to_permute) const;
     109             : 
     110             :   /// An array whose elements are permuted such that
     111             :   /// `result[d] = array_in_neighbor[this->operator()(d)]`
     112             :   ///
     113             :   /// \note the permutation depends only on how the dimension is mapped
     114             :   /// and ignores the side of the mapped direction.
     115             :   template <typename T>
     116           1 :   std::array<T, VolumeDim> permute_from_neighbor(
     117             :       const std::array<T, VolumeDim>& array_in_neighbor) const;
     118             : 
     119             :   /// The corresponding Orientation of the host in the frame of the neighbor.
     120           1 :   OrientationMap<VolumeDim> inverse_map() const;
     121             : 
     122             :   /// Serialization for Charm++
     123             :   // NOLINTNEXTLINE(google-runtime-references)
     124           1 :   void pup(PUP::er& p);
     125             : 
     126             :  private:
     127           0 :   friend bool operator==(const OrientationMap& lhs, const OrientationMap& rhs) {
     128             :     return lhs.bit_field_ == rhs.bit_field_;
     129             :   }
     130             : 
     131           0 :   Direction<VolumeDim> get_direction(size_t dim) const;
     132           0 :   void set_direction(size_t dim, const Direction<VolumeDim>& direction);
     133           0 :   void set_aligned(bool is_aligned);
     134           0 :   std::set<size_t> set_of_dimensions() const;
     135             : 
     136           0 :   uint16_t bit_field_{0b1 << 15};
     137             : };
     138             : 
     139             : /// Output operator for OrientationMap.
     140             : template <size_t VolumeDim>
     141           1 : std::ostream& operator<<(std::ostream& os,
     142             :                          const OrientationMap<VolumeDim>& orientation);
     143             : 
     144             : template <size_t VolumeDim>
     145           0 : bool operator!=(const OrientationMap<VolumeDim>& lhs,
     146             :                 const OrientationMap<VolumeDim>& rhs) {
     147             :   return not(lhs == rhs);
     148             : }
     149             : 
     150             : template <size_t VolumeDim>
     151             : template <typename T>
     152             : std::array<T, VolumeDim> OrientationMap<VolumeDim>::permute_to_neighbor(
     153             :     const std::array<T, VolumeDim>& array_to_permute) const {
     154             :   std::array<T, VolumeDim> array_in_neighbor = array_to_permute;
     155             :   if (is_aligned() or VolumeDim <= 1) {
     156             :     return array_in_neighbor;
     157             :   }
     158             :   for (size_t i = 0; i < VolumeDim; i++) {
     159             :     gsl::at(array_in_neighbor, this->operator()(i)) =
     160             :         gsl::at(array_to_permute, i);
     161             :   }
     162             :   return array_in_neighbor;
     163             : }
     164             : 
     165             : template <size_t VolumeDim>
     166             : template <typename T>
     167             : std::array<T, VolumeDim> OrientationMap<VolumeDim>::permute_from_neighbor(
     168             :     const std::array<T, VolumeDim>& array_in_neighbor) const {
     169             :   std::array<T, VolumeDim> result = array_in_neighbor;
     170             :   if (not is_aligned() and VolumeDim > 1) {
     171             :     for (size_t i = 0; i < VolumeDim; i++) {
     172             :       gsl::at(result, i) = gsl::at(array_in_neighbor, this->operator()(i));
     173             :     }
     174             :   }
     175             :   return result;
     176             : }
     177             : 
     178             : /// \ingroup ComputationalDomainGroup
     179             : /// `OrientationMap`s define an active rotation of the logical axes that bring
     180             : /// the axes of a host block into alignment with the logical axes of the
     181             : /// neighbor block. `discrete_rotation` applies this active rotation on the
     182             : /// coordinates as opposed to the axes.
     183             : /// For a two-dimensional example, consider a host block and a neighbor block,
     184             : /// where the OrientationMap between them is \f$\{-\eta,+\xi\}\f$. A quarter-
     185             : /// turn counterclockwise of the host block's logical axes would bring them into
     186             : /// alignment with those of the neighbor. That is, after this active rotation,
     187             : /// the blocks would be Aligned. Now consider a point A with coordinates
     188             : /// (+1.0,-0.5). An active quarter-turn rotation counter-clockwise about the
     189             : /// origin, keeping the axes fixed, brings point A into the coordinates
     190             : /// (+0.5,+1.0). This is how `discrete_rotation` interprets the
     191             : /// `OrientationMap` passed to it.
     192             : template <size_t VolumeDim, typename T>
     193           1 : std::array<T, VolumeDim> discrete_rotation(
     194             :     const OrientationMap<VolumeDim>& rotation,
     195             :     std::array<T, VolumeDim> source_coords);
     196             : 
     197             : /*!
     198             :  * \ingroup ComputationalDomainGroup
     199             :  * \brief Computes the Jacobian of the transformation that is computed by
     200             :  * `discrete_rotation()`
     201             :  *
     202             :  * \note This always returns a `double` because the Jacobian is spatially
     203             :  * constant.
     204             :  */
     205             : template <size_t VolumeDim>
     206           1 : tnsr::Ij<double, VolumeDim, Frame::NoFrame> discrete_rotation_jacobian(
     207             :     const OrientationMap<VolumeDim>& orientation);
     208             : 
     209             : /*!
     210             :  * \ingroup ComputationalDomainGroup
     211             :  * \brief Computes the inverse Jacobian of the transformation that is computed
     212             :  * by `discrete_rotation()`
     213             :  */
     214             : template <size_t VolumeDim>
     215           1 : tnsr::Ij<double, VolumeDim, Frame::NoFrame> discrete_rotation_inverse_jacobian(
     216             :     const OrientationMap<VolumeDim>& orientation);

Generated by: LCOV version 1.14