SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps/TimeDependent - Rotation.hpp Hit Total Coverage
Commit: 37c384043430860f87787999aa7399d01bb3d213 Lines: 2 17 11.8 %
Date: 2024-04-20 02:24:02
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 <memory>
       9             : #include <optional>
      10             : #include <string>
      11             : #include <unordered_map>
      12             : #include <unordered_set>
      13             : 
      14             : #include "DataStructures/Tensor/TypeAliases.hpp"
      15             : #include "Utilities/TypeTraits/RemoveReferenceWrapper.hpp"
      16             : 
      17             : /// \cond
      18             : namespace domain {
      19             : namespace FunctionsOfTime {
      20             : class FunctionOfTime;
      21             : }  // namespace FunctionsOfTime
      22             : }  // namespace domain
      23             : namespace PUP {
      24             : class er;
      25             : }  // namespace PUP
      26             : /// \endcond
      27             : 
      28             : namespace domain {
      29             : namespace CoordinateMaps {
      30             : namespace TimeDependent {
      31             : 
      32             : /*!
      33             :  * \ingroup CoordMapsTimeDependentGroup
      34             :  * \brief Time-dependent spatial rotation in two or three dimensions.
      35             :  *
      36             :  * ### General Transformation
      37             :  *
      38             :  * Let the source coordinates \f$ \vec{\xi} \f$ be mapped to coordinates \f$
      39             :  * \vec{x} \f$ using the transformation
      40             :  *
      41             :  * \f[ \vec{x} = R(t)\vec{\xi}, \f]
      42             :  *
      43             :  * where \f$ R(t) \f$ is a rotation matrix of proper dimensionality (defined
      44             :  * below) and \f$ A\vec{v} \f$ is the standard matrix-vector multiplicaton. For
      45             :  * 2D rotation, \f$ \vec{\xi} = \left(\xi, \eta\right) \f$ and \f$ \vec{x} =
      46             :  * \left(x, y\right) \f$ while for 3D rotations \f$ \vec{\xi} = \left(\xi, \eta,
      47             :  * \zeta\right) \f$ and \f$ \vec{x} = \left(x, y, z\right) \f$.
      48             :  *
      49             :  * The inverse transformation is
      50             :  *
      51             :  * \f[ \vec{\xi} = R^T(t) \vec{x} \f]
      52             :  *
      53             :  * because the inverse of a rotation matrix is its transpose.
      54             :  *
      55             :  * The frame velocity \f$ \vec{v} = d\vec{x}/dt \f$ is
      56             :  *
      57             :  * \f[ \vec{v} = \frac{d}{dt}\big( R(t) \big) \vec{\xi} \f]
      58             :  *
      59             :  * where \f$ d(R(t))/dt \f$ is the time derivative of the rotation matrix.
      60             :  *
      61             :  * The components of the Jacobian \f$ \partial x^i/\partial\xi^j \f$ are
      62             :  * trivially related to the components of the rotation matrix by
      63             :  *
      64             :  * \f[ \partial x^i/\partial\xi^j = R_{ij}, \f]
      65             :  *
      66             :  * and similarly the components of the inverse Jacobian \f$ \partial
      67             :  * \xi^i/\partial x^j \f$ are
      68             :  *
      69             :  * \f[ \partial \xi^i/\partial x^j = R^{-1}_{ij} = R^T_{ij} = R_{ji}. \f]
      70             :  *
      71             :  * ### 2D Rotation Matrix
      72             :  *
      73             :  * The 2D rotaion matrix is defined in the usual way as
      74             :  *
      75             :  * \f[
      76             :  * R(t) =
      77             :  *   \begin{bmatrix}
      78             :  *   \cos(\theta(t)) & -\sin(\theta(t)) \\
      79             :  *   \sin(\theta(t)) &  \cos(\theta(t)) \\
      80             :  *   \end{bmatrix}.
      81             :  * \f]
      82             :  *
      83             :  * We associate the polar coordinates \f$ \left( \mathrm{P}, \Phi\right) \f$
      84             :  * with the unmapped coordinates \f$ \left(\xi, \eta\right) \f$ and the polar
      85             :  * coordinates \f$ \left(r,\phi\right) \f$ with the mapped coordinates \f$
      86             :  * \left(x, y\right) \f$. We then have \f$ \phi = \Phi + \theta(t) \f$.
      87             :  *
      88             :  * The derivative of the rotation matrix is then
      89             :  *
      90             :  * \f[
      91             :  * R(t) =
      92             :  *   \begin{bmatrix}
      93             :  *   -\omega(t) \sin(\theta(t)) & -\omega(t)\cos(\theta(t)) \\
      94             :  *    \omega(t) \cos(\theta(t)) & -\omega(t)\sin(\theta(t)) \\
      95             :  *   \end{bmatrix}.
      96             :  * \f]
      97             :  *
      98             :  * where \f$ \omega(t) = d\theta(t)/dt \f$.
      99             :  *
     100             :  * \note This 2D rotation is assumed to be in the \f$ xy \f$-plane (about the
     101             :  * \f$ z \f$-axis).
     102             :  *
     103             :  * ### 3D Rotation Matrix
     104             :  *
     105             :  * For 3D rotations, we use quaternions to represent rotations about an
     106             :  * arbitrary axis. We define a unit quaternion as
     107             :  *
     108             :  * \f[
     109             :  *   \mathbf{q}
     110             :  *     = \left(q_0, q_1, q_2, q_3\right)
     111             :  *     = \left(q_0, \vec{q}\right)
     112             :  *     = \left(\cos(\frac{\theta(t)}{2}),
     113             :  *             \hat{n}\sin(\frac{\theta(t)}{2})\right)
     114             :  * \f]
     115             :  *
     116             :  * where \f$ \hat{n} \f$ is our arbitrary rotation axis and \f$ \theta(t) \f$ is
     117             :  * the angle rotated about that axis. A rotation in 3D is then defined as
     118             :  *
     119             :  * \f[ \mathbf{x} = \mathbf{q}\mathbf{\xi}\mathbf{q}^* \f]
     120             :  *
     121             :  * where \f$ \mathbf{q}^* = \left(\cos(\theta(t)/2),
     122             :  * -\hat{n}\sin(\theta(t)/2)\right) \f$ and we promote the vectors to
     123             :  * quaternions as \f$ \mathbf{x} = \left(0, \vec{x}\right) \f$ and \f$
     124             :  * \mathbf{\xi} = \left(0, \vec{\xi}\right) \f$. This will rotate the vector \f$
     125             :  * \vec{\xi} \f$ about \f$ \hat{n} \f$ by an angle \f$ \theta(t) \f$,
     126             :  * transforming it into \f$ \vec{x} \f$.
     127             :  *
     128             :  * We can represent this rotation using quaternions as a rotation matrix of
     129             :  * the form
     130             :  *
     131             :  * \f[
     132             :  * R(t) =
     133             :  *   \begin{bmatrix}
     134             :  *   q_0^2 + q_1^2 - q_2^2 - q_3^2 & 2(q_1q_2 - q_0q_3) & 2(q_1q_3 + q_0q_2) \\
     135             :  *   2(q_1q_2 + q_0q_3) & q_0^2 + q_2^2 - q_1^2 - q_3^2 & 2(q_2q_3 - q_0q_1) \\
     136             :  *   2(q_1q_3 - q_0q_2) & 2(q_2q_3 + q_0q_1) & q_0^2 + q_3^2 - q_1^2 - q_2^2 \\
     137             :  *   \end{bmatrix}.
     138             :  * \f]
     139             :  *
     140             :  * The derivative of this rotation matrix can expressed in a similar form
     141             :  *
     142             :  * \f[
     143             :  * R(t) =
     144             :  *   \begin{bmatrix}
     145             :  *   2(q_0\dot{q_0} + q_1\dot{q_1} - q_2\dot{q_2} - q_3\dot{q_3})
     146             :  *     & 2(\dot{q_1}q_2 + q_1\dot{q_2} - \dot{q_0}q_3 - q_0\dot{q_3})
     147             :  *     & 2(\dot{q_1}q_3 + q_1\dot{q_3} + \dot{q_0}q_2 + q_0\dot{q_2}) \\
     148             :  *   2(\dot{q_1}q_2 + q_1\dot{q_2} + \dot{q_0}q_3 + q_0\dot{q_3})
     149             :  *     & 2(q_0\dot{q_0} + q_2\dot{q_2} - q_1\dot{q_1} - q_3\dot{q_3})
     150             :  *     & 2(\dot{q_2}q_3 + q_2\dot{q_3} - \dot{q_0}q_1 - q_0\dot{q_1}) \\
     151             :  *   2(\dot{q_1}q_3 + q_1\dot{q_3} - \dot{q_0}q_2 - q_0\dot{q_2})
     152             :  *     & 2(\dot{q_2}q_3 + q_2\dot{q_3} + \dot{q_0}q_1 + q_0\dot{q_1})
     153             :  *     & 2(q_0\dot{q_0} + q_3\dot{q_3} - q_1\dot{q_1} - q_2\dot{q_2}) \\
     154             :  *   \end{bmatrix}.
     155             :  * \f]
     156             :  *
     157             :  * \note If you choose \f$ \hat{n} = (0, 0, 1) \f$, this rotation will be
     158             :  * equivalent to the 2D rotation.
     159             :  */
     160             : template <size_t Dim>
     161           1 : class Rotation {
     162             :  public:
     163             :   static_assert(Dim == 2 or Dim == 3,
     164             :                 "Rotation map can only be constructed in 2 or 3 dimensions.");
     165           0 :   static constexpr size_t dim = Dim;
     166             : 
     167           0 :   explicit Rotation(std::string function_of_time_name);
     168           0 :   Rotation() = default;
     169             : 
     170             :   template <typename T>
     171           0 :   std::array<tt::remove_cvref_wrap_t<T>, Dim> operator()(
     172             :       const std::array<T, Dim>& source_coords, double time,
     173             :       const std::unordered_map<
     174             :           std::string,
     175             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     176             :           functions_of_time) const;
     177             : 
     178             :   /// The inverse function is only callable with doubles because the inverse
     179             :   /// might fail if called for a point out of range, and it is unclear
     180             :   /// what should happen if the inverse were to succeed for some points in a
     181             :   /// DataVector but fail for other points.
     182           1 :   std::optional<std::array<double, Dim>> inverse(
     183             :       const std::array<double, Dim>& target_coords, double time,
     184             :       const std::unordered_map<
     185             :           std::string,
     186             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     187             :           functions_of_time) const;
     188             : 
     189             :   template <typename T>
     190           0 :   std::array<tt::remove_cvref_wrap_t<T>, Dim> frame_velocity(
     191             :       const std::array<T, Dim>& source_coords, double time,
     192             :       const std::unordered_map<
     193             :           std::string,
     194             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     195             :           functions_of_time) const;
     196             : 
     197             :   template <typename T>
     198           0 :   tnsr::Ij<tt::remove_cvref_wrap_t<T>, Dim, Frame::NoFrame> jacobian(
     199             :       const std::array<T, Dim>& source_coords, double time,
     200             :       const std::unordered_map<
     201             :           std::string,
     202             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     203             :           functions_of_time) const;
     204             : 
     205             :   template <typename T>
     206           0 :   tnsr::Ij<tt::remove_cvref_wrap_t<T>, Dim, Frame::NoFrame> inv_jacobian(
     207             :       const std::array<T, Dim>& source_coords, double time,
     208             :       const std::unordered_map<
     209             :           std::string,
     210             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     211             :           functions_of_time) const;
     212             : 
     213             :   // NOLINTNEXTLINE(google-runtime-references)
     214           0 :   void pup(PUP::er& p);
     215             : 
     216           0 :   static bool is_identity() { return false; }
     217             : 
     218           0 :   const std::unordered_set<std::string>& function_of_time_names() const {
     219             :     return f_of_t_names_;
     220             :   }
     221             : 
     222             :  private:
     223             :   template <size_t LocalDim>
     224             :   // NOLINTNEXTLINE(readability-redundant-declaration)
     225           0 :   friend bool operator==(const Rotation<LocalDim>& lhs,
     226             :                          const Rotation<LocalDim>& rhs);
     227           0 :   std::string f_of_t_name_;
     228           0 :   std::unordered_set<std::string> f_of_t_names_;
     229             : };
     230             : 
     231             : template <size_t Dim>
     232           0 : bool operator!=(const Rotation<Dim>& lhs, const Rotation<Dim>& rhs);
     233             : 
     234             : }  // namespace TimeDependent
     235             : }  // namespace CoordinateMaps
     236             : }  // namespace domain

Generated by: LCOV version 1.14