SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps/TimeDependent/ShapeMapTransitionFunctions - Wedge.hpp Hit Total Coverage
Commit: 47355bc26b45b897defe322cc093c7b7b3155e93 Lines: 8 29 27.6 %
Date: 2024-05-04 22:40:33
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 <limits>
       9             : #include <memory>
      10             : #include <optional>
      11             : #include <pup.h>
      12             : 
      13             : #include "DataStructures/DataVector.hpp"
      14             : #include "Domain/CoordinateMaps/TimeDependent/ShapeMapTransitionFunctions/ShapeMapTransitionFunction.hpp"
      15             : 
      16             : namespace domain::CoordinateMaps::ShapeMapTransitionFunctions {
      17             : /*!
      18             :  * \brief A transition function that falls off linearly from an inner surface of
      19             :  * a wedge to an outer surface of a wedge. Meant to be used in
      20             :  * `domain::CoordinateMaps::Wedge` blocks.
      21             :  *
      22             :  * \details The functional form of this transition is
      23             :  *
      24             :  * \begin{equation}
      25             :  * f(r, \theta, \phi) = \frac{D_{\text{out}}(r, \theta, \phi) -
      26             :  * r}{D_{\text{out}}(r, \theta, \phi) - D_{\text{in}}(r, \theta, \phi)},
      27             :  * \label{eq:transition_func}
      28             :  * \end{equation}
      29             :  *
      30             :  * where
      31             :  *
      32             :  * \begin{equation}
      33             :  * D(r, \theta, \phi) = R\left(\frac{1 -
      34             :  * s}{\sqrt{3}\max(|\sin{\theta}\cos{\phi}|,|\sin{\theta}\sin{\phi}|,
      35             :  * |\cos{\theta}|)} + s\right),
      36             :  * \label{eq:distance}
      37             :  * \end{equation}
      38             :  *
      39             :  * where $s$ is the sphericity of the surface which goes from 0 (flat) to 1
      40             :  * (spherical), $R$ is the radius of the spherical surface, $\text{out}$ is the
      41             :  * outer surface, and $\text{in}$ is the inner surface. If the sphericity is 1,
      42             :  * then the surface is a sphere so $D = R$. If the sphericity is 0, then the
      43             :  * surface is a cube. This cube is circumscribed by a sphere of radius $R$. See
      44             :  * `domain::CoordinateMaps::Wedge` for more of an explanation of these boundary
      45             :  * surfaces and their sphericities.
      46             :  *
      47             :  * \note Because the shape map distorts only radii and does not affect angles,
      48             :  * $D$ is not a function of $r$ so we have that $D(r,\theta,\phi) =
      49             :  * D(\theta, \phi)$.
      50             :  *
      51             :  * There are several assumptions made for this mapping:
      52             :  *
      53             :  * - The `domain::CoordinateMaps::Wedge`s have an opening angle of
      54             :  *   $\frac{\pi}{2}$ in each direction.
      55             :  * - The coordinates $r, \theta, \phi$ are assumed to be from the center of the
      56             :  *   wedge, not the center of the computational domain.
      57             :  * - The wedges are concentric. (see the constructor)
      58             :  * - The $\max$ in the denominator of $\ref{eq:distance}$ can be simplified a
      59             :  *   bit to $\max(|x|, |y|, |z|)/r$. It was written the other way in
      60             :  *   $\ref{eq:distance}$ to emphasize that $D$ has no radial dependence.
      61             :  *
      62             :  * ## Gradient
      63             :  *
      64             :  * The cartesian gradient of the transition function is
      65             :  *
      66             :  * \begin{equation}
      67             :  * \frac{\partial f}{\partial x_i} = \frac{\frac{\partial
      68             :  * D_{\text{out}}}{\partial x_i} - \frac{x_i}{r}}{D_{\text{out}} -
      69             :  * D_{\text{in}}} - \frac{\left(D_{\text{out}} - r\right)\left(\frac{\partial
      70             :  * D_{\text{out}}}{\partial x_i} - \frac{\partial
      71             :  * D_{\text{in}}}{\partial x_i} \right)}{\left(D_{\text{out}} -
      72             :  * D_{\text{in}}\right)^2}.
      73             :  * \end{equation}
      74             :  *
      75             :  * The computation of the gradient of $D$ depends on the result of the $\max$ in
      76             :  * the denominator of $\ref{eq:distance}$. To simplify the expression, let $j
      77             :  * \in \{0,1,2\}$ correspond to the $\max(|x|, |y|, |z|)$ such that $j=0$ if
      78             :  * $|x|$ is the $\max$, and so on. Then we can write the gradient of $D$ as
      79             :  *
      80             :  * \f{align}{
      81             :  * \frac{\partial D}{\partial x_j} &= -\text{sgn}(x_j)\frac{R(1-s)\left(r^2 -
      82             :  * x_j^2\right)}{r x_j^2 \sqrt{3}} \\
      83             :  * \frac{\partial D}{\partial x_{j+1}} &= \frac{R(1-s)x_{j+1}}{r |x_j| \sqrt{3}}
      84             :  * \\
      85             :  * \frac{\partial D}{\partial x_{j+2}} &= \frac{R(1-s)x_{j+2}}{r |x_j| \sqrt{3}}
      86             :  * \f}
      87             :  *
      88             :  * where $j+1$ and $j+2$ are understood to be $\mod 3$. Also since we don't
      89             :  * allow points at the origin of these wedges, we can be assured that for
      90             :  * whichever $j$ is max, that $x_j$ won't be zero.
      91             :  *
      92             :  * ## Original radius divided by mapped radius
      93             :  *
      94             :  * Given an already mapped point and the distorted radius $\Sigma(\theta, \phi)
      95             :  * = \sum_{\ell,m}\lambda_{\ell m}Y_{\ell m}(\theta, \phi)$, we can figure out
      96             :  * the ratio of the original radius $r$ to the mapped $\tilde{r}$ by solving
      97             :  *
      98             :  * \begin{equation}
      99             :  * \frac{r}{\tilde{r}} =
     100             :  * \frac{1}{1-\frac{f(r,\theta,\phi)}{r}\Sigma(\theta,\phi)}
     101             :  * \end{equation}
     102             :  *
     103             :  * After plugging in the transition and solving, we get
     104             :  *
     105             :  * \begin{equation}
     106             :  * \frac{r}{\tilde{r}} = \frac{1 + \frac{D_{\text{out}}\Sigma(\theta,
     107             :  * \phi)}{\tilde{r}(D_{\text{out}} - D_{\text{in}})}}{1 + \frac{\Sigma(\theta,
     108             :  * \phi)}{D_{\text{out}} - D_{\text{in}}}}
     109             :  * \label{eq:r_over_rtil}
     110             :  * \end{equation}
     111             :  *
     112             :  * \note Since $D$ is not a function of the radius, we can compute the angles
     113             :  * using $\tilde{r}$ in Eq. $\ref{eq:r_over_rtil}$.
     114             :  *
     115             :  * ## Special cases
     116             :  *
     117             :  * The equations above become simpler if the inner boundary, outer boundary, or
     118             :  * both are spherical ($s = 1$). If a boundary is spherical, then $D = R$ and
     119             :  * $\frac{\partial D}{\partial x_i} = 0$. This simplifies the expanded form of
     120             :  * the gradient significantly.
     121             :  */
     122           1 : class Wedge final : public ShapeMapTransitionFunction {
     123           0 :   struct Surface {
     124           0 :     double radius{};
     125           0 :     double sphericity{};
     126             : 
     127             :     // This is the distance from the center (assumed to be 0,0,0) to this
     128             :     // surface in the same direction as coords. The calculation is cheaper if
     129             :     // you know the axis ahead of time
     130             :     template <typename T>
     131           0 :     T distance(const std::array<T, 3>& coords,
     132             :                const std::optional<size_t>& axis = std::nullopt) const;
     133             : 
     134           0 :     void pup(PUP::er& p);
     135             : 
     136           0 :     bool operator==(const Surface& other) const;
     137           0 :     bool operator!=(const Surface& other) const;
     138             :   };
     139             : 
     140             :  public:
     141           0 :   explicit Wedge() = default;
     142             : 
     143             :   /*!
     144             :    * \brief Construct a Wedge transition for a wedge block in a given direction.
     145             :    *
     146             :    * \details Many concentric wedges can be part of the same falloff from 1 at
     147             :    * the inner boundary of the innermost wedge, to 0 at the outer boundary of
     148             :    * the outermost wedge.
     149             :    *
     150             :    * \param inner_radius Inner radius of innermost wedge
     151             :    * \param outer_radius Outermost radius of outermost wedge
     152             :    * \param inner_sphericity Sphericity of innermost surface of innermost wedge
     153             :    * \param outer_sphericity Sphericity of outermost surface of outermost wedge
     154             :    * \param axis The direction that this wedge is in. Both the positive and
     155             :    * negative direction get the same axis.
     156             :    */
     157           1 :   Wedge(double inner_radius, double outer_radius, double inner_sphericity,
     158             :         double outer_sphericity, size_t axis);
     159             : 
     160           1 :   double operator()(const std::array<double, 3>& source_coords) const override;
     161           1 :   DataVector operator()(
     162             :       const std::array<DataVector, 3>& source_coords) const override;
     163             : 
     164           1 :   std::optional<double> original_radius_over_radius(
     165             :       const std::array<double, 3>& target_coords,
     166             :       double distorted_radius) const override;
     167             : 
     168           1 :   std::array<double, 3> gradient(
     169             :       const std::array<double, 3>& source_coords) const override;
     170           1 :   std::array<DataVector, 3> gradient(
     171             :       const std::array<DataVector, 3>& source_coords) const override;
     172             : 
     173           0 :   WRAPPED_PUPable_decl_template(Wedge);
     174           0 :   explicit Wedge(CkMigrateMessage* msg);
     175           0 :   void pup(PUP::er& p) override;
     176             : 
     177           1 :   std::unique_ptr<ShapeMapTransitionFunction> get_clone() const override {
     178             :     return std::make_unique<Wedge>(*this);
     179             :   }
     180             : 
     181           0 :   bool operator==(const ShapeMapTransitionFunction& other) const override;
     182           0 :   bool operator!=(const ShapeMapTransitionFunction& other) const override;
     183             : 
     184             :  private:
     185             :   template <typename T>
     186           0 :   T call_impl(const std::array<T, 3>& source_coords) const;
     187             : 
     188             :   template <typename T>
     189           0 :   std::array<T, 3> gradient_impl(const std::array<T, 3>& source_coords) const;
     190             : 
     191             :   template <typename T>
     192           0 :   void check_distances(const std::array<T, 3>& coords) const;
     193             : 
     194           0 :   Surface inner_surface_{};
     195           0 :   Surface outer_surface_{};
     196           0 :   size_t axis_{};
     197           0 :   static constexpr double eps_ = std::numeric_limits<double>::epsilon() * 100;
     198             : };
     199             : }  // namespace domain::CoordinateMaps::ShapeMapTransitionFunctions

Generated by: LCOV version 1.14