SpECTRE Documentation Coverage Report
Current view: top level - Domain/Structure - OrientationMap.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 51.5 % 33 17
Test Date: 2026-10-22 17:29:42
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 2.0-1