SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps - FlatOffsetSphericalWedge.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 18.2 % 22 4
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 the class FlatOffsetSphericalWedge.
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <array>
      10              : #include <cstddef>
      11              : #include <limits>
      12              : #include <optional>
      13              : 
      14              : #include "DataStructures/Tensor/TypeAliases.hpp"
      15              : 
      16              : /// \cond
      17              : namespace PUP {
      18              : class er;
      19              : }  // namespace PUP
      20              : /// \endcond
      21              : 
      22              : namespace domain::CoordinateMaps {
      23              : 
      24              : /*!
      25              :  * \ingroup CoordinateMapsGroup
      26              :  *
      27              :  * \brief Map from a cube to a volume that connects four planes and
      28              :  * portions of two spherical surfaces.
      29              :  *
      30              :  * \image html FlatOffsetSphericalWedge.svg "Slices of FlatOffsetSphericalWedge"
      31              :  *
      32              :  * \details A cube is mapped to the volume shown in the figure.
      33              :  *
      34              :  * A $y=0$ slice through the volume is shown in the left
      35              :  * panel of the figure, and a $x=$const slice through the volume is shown
      36              :  * in the right panel of the figure.
      37              :  *
      38              :  * The lower-$z$ face of the volume is a portion of a spherical surface
      39              :  * of radius $R_1$ centered about point $C$ in the figure, which is along
      40              :  * the $x$-axis a distance $D$ from the origin (point $O$ in the figure).
      41              :  * The upper-$z$ face of the volume is a portion of a spherical surface
      42              :  * of radius $R_2$ centered about the origin.
      43              :  *
      44              :  * The lower-$x$ face of the volume is a portion of the plane at constant
      45              :  * $x=0$, and the upper-$x$ face of the volume is a portion of the plane
      46              :  * at constant $x=D$. See the $x$ extents of the left panel of the
      47              :  * figure.
      48              :  *
      49              :  * Every constant-$x$ cross section of the volume looks like the right
      50              :  * panel of the figure: it is a two-dimensional wedge with 45 degree
      51              :  * opening angle.  Both the inner and outer radii of this wedge vary
      52              :  * with $x$: The inner radius of the wedge is $R_1$ at $x=D$ and
      53              :  * $\sqrt{R_1^2-D^2}$ at $x=0$, and the outer radius of the wedge is
      54              :  * $R_2$ at $x=0$ and $\sqrt{R_2^2-D^2}$ at $x=D$.
      55              :  *
      56              :  * ### Relation to FlatOffsetWedge
      57              :  *
      58              :  * The lower-$z$ face of this FlatOffsetSphericalWedge is the same as
      59              :  * the upper-$z$ face of the similar map FlatOffsetWedge; Blocks using
      60              :  * these two maps are meant to abut at this surface.  The parameter
      61              :  * $D$ means the same thing for the two maps, and the parameter $R$ in
      62              :  * FlatOffsetWedge is the same as what we call $R_1$ here.
      63              :  * For abutting blocks, the corresponding parameters of the two maps should
      64              :  * be equal, and both maps should have the same origin.
      65              :  *
      66              :  * The formulas below will be similar to those of the FlatOffsetWedge map,
      67              :  * but slightly more complicated.
      68              :  *
      69              :  * ### Restrictions
      70              :  *
      71              :  * We require $D<R_1$ or else the lower-$x$ face of the mapped
      72              :  * volume lies outside of the sphere of radius $R_1$.
      73              :  * We also require that $R_2^2 > R_1^2+D^2$ or else the outer sphere
      74              :  * and inner sphere will intersect at the upper-$x$ face and the map
      75              :  * will be singular.
      76              :  *
      77              :  * ## Equations for the map
      78              :  * Given our cube coordinates $\xi,\eta,\zeta$, each taking on values from
      79              :  * $-1$ to $+1$, we can derive the formulas for the map.
      80              :  *
      81              :  * Define
      82              :  * \begin{align}
      83              :  *    q &\equiv \frac{D}{2R_1},\\
      84              :  *    v &\equiv \frac{R_1}{R_2}.
      85              :  * \end{align}
      86              :  *
      87              :  * Notice that $q<1/2$, because of the restriction $D<R_1$.  Also we
      88              :  * must have $v < \left(1+4q^2\right)^{-1/2}$ because of the
      89              :  * restriction $R_2^2 > R_1^2+D^2$.
      90              :  *
      91              :  * Note that $x$ is a function of $\xi$ only, for all points in the volume:
      92              :  * \begin{align}
      93              :  *  x(\xi,\eta,\zeta) &= q R (\xi+1).
      94              :  * \end{align}
      95              :  *
      96              :  * ### Surface map for bottom and top surfaces
      97              :  * The $y$ and $z$ coordinates of the bottom surface,
      98              :  * $\zeta=-1$, of the volume are given by
      99              :  * \begin{align}
     100              :  *   \begin{bmatrix}
     101              :  *      y(\xi,\eta,+1)\\
     102              :  *      z(\xi,\eta,+1)
     103              :  *   \end{bmatrix} =
     104              :  *     \frac{R_1}{\sqrt{1+\eta^2}}
     105              :  *               \sqrt{1-q^2(\xi-1)^2}
     106              :  *   \begin{bmatrix}
     107              :  *      \eta \\
     108              :  *      1
     109              :  *   \end{bmatrix}.
     110              :  * \end{align}
     111              :  * This is the same formula as for the upper face of the similar
     112              :  * FlatOffsetWedge map.
     113              :  *
     114              :  * The $y$ and $z$ coordinates for the mapped $\zeta=+1$ surface are
     115              :  * \begin{align}
     116              :  *   \begin{bmatrix}
     117              :  *      y(\xi,\eta,+1)\\
     118              :  *      z(\xi,\eta,+1)
     119              :  *   \end{bmatrix} =
     120              :  *     \frac{R_2}{\sqrt{1+\eta^2}}
     121              :  *              \sqrt{1-v^2q^2(\xi+1)^2}
     122              :  *   \begin{bmatrix}
     123              :  *      \eta \\
     124              :  *      1
     125              :  *   \end{bmatrix}.
     126              :  * \end{align}
     127              :  * Because of the above restrictions on $v$ and $q$, and because $\xi$ and
     128              :  * $\eta$ range between $-1$ and $+1$, the arguments of the square
     129              :  * roots above are always positive.
     130              :  *
     131              :  * ### Full volume map
     132              :  * Adding the $\zeta$ dependence by linear interpolation gives us
     133              :  * the full volume map for the $y$ and $z$ coordinates:
     134              :  *
     135              :  * \begin{align}
     136              :  *   \begin{bmatrix}
     137              :  *      y(\xi,\eta,\zeta)\\
     138              :  *      z(\xi,\eta,\zeta)
     139              :  *   \end{bmatrix} =
     140              :  *      \left[\frac{1+\zeta}{2}
     141              :  *        \frac{R_2}{\sqrt{1+\eta^2}}
     142              :  *                   \sqrt{1-v^2q^2(\xi+1)^2}
     143              :  *        + \frac{1-\zeta}{2}
     144              :  *          \frac{R_1}{\sqrt{1+\eta^2}}
     145              :  *           \sqrt{1-q^2(\xi-1)^2}\right]
     146              :  *   \begin{bmatrix}
     147              :  *      \eta \\
     148              :  *      1
     149              :  *   \end{bmatrix}.
     150              :  * \end{align}
     151              :  *
     152              :  * ## Inverse
     153              :  *
     154              :  * The map can be inverted analytically:
     155              :  *
     156              :  * \begin{align}
     157              :  *    \xi   &= \frac{x}{qR}-1\\
     158              :  *    \eta  &= \frac{y}{z}\\
     159              :  *    \zeta &= \frac{2z - W - P}{W-P},
     160              :  *              \label{eq:zetaFromxyz}
     161              :  * \end{align}
     162              :  * where
     163              :  * \begin{align}
     164              :  *   P &\equiv R_1\frac{\sqrt{1-(x-D)^2/R_1^2}}{\sqrt{1+y^2/z^2}}\\
     165              :  *     &= R_1\frac{\sqrt{1-q^2(\xi-1)^2}}{\sqrt{1+\eta^2}},
     166              :  *              \label{eq:Pdefinition} \\
     167              :  *   W &\equiv R_2\frac{\sqrt{1-x^2/R_2^2}}{\sqrt{1+y^2/z^2}}\\
     168              :  *     &= R_2\frac{\sqrt{1-v^2q^2(\xi+1)^2}}{\sqrt{1+\eta^2}}.
     169              :  *              \label{eq:Wdefinition}
     170              :  * \end{align}
     171              :  *
     172              :  * It is easy to determine whether a point $(x,y,z)$ lies within the volume:
     173              :  * First compute $\xi$ and $\eta$ and check that they are both in $[-1,1]$.
     174              :  * If so, then the arguments of the square roots in
     175              :  * Eq. ($\ref{eq:Pdefinition}$) and Eq. ($\ref{eq:Wdefinition}$) are
     176              :  * guaranteed positive, and the denominator
     177              :  * of Eq. ($\ref{eq:zetaFromxyz}$) is guaranteed positive
     178              :  * by our condition $v < 1/\sqrt{1+4q^2}$.
     179              :  * Then it is straightforward to
     180              :  * compute $\zeta$ and then check if it is in $[-1,1]$.
     181              :  *
     182              :  * ## Jacobian
     183              :  *
     184              :  * Straightforward differentiation gives
     185              :  *
     186              :  * \begin{align}
     187              :  *    \frac{\partial x}{\partial \xi}   &= qR_1,\\
     188              :  *    \frac{\partial x}{\partial \eta}   &= 0,\\
     189              :  *    \frac{\partial x}{\partial \zeta}   &= 0,\\
     190              :  *   \partial_\zeta \begin{bmatrix}
     191              :  *      y\\
     192              :  *      z
     193              :  *   \end{bmatrix} &= \frac{W-P}{2}
     194              :  *   \begin{bmatrix}
     195              :  *      \eta \\
     196              :  *      1
     197              :  *   \end{bmatrix}, \\
     198              :  *   \partial_\xi \begin{bmatrix}
     199              :  *      y\\
     200              :  *      z
     201              :  *   \end{bmatrix} &=
     202              :  *    \frac{q^2}{2}\left[
     203              :  *    P\frac{(1-\zeta)(1-\xi)}{1-q^2(1-\xi)^2}
     204              :  *    -W\frac{v^2(1+\zeta)(1+\xi)}{1-v^2q^2(1+\xi)^2}
     205              :  *    \right]
     206              :  *   \begin{bmatrix}
     207              :  *      \eta \\
     208              :  *      1
     209              :  *   \end{bmatrix}, \\
     210              :  *   \partial_\eta \begin{bmatrix}
     211              :  *      y\\
     212              :  *      z
     213              :  *   \end{bmatrix} &=
     214              :  *       -\frac{\eta}{2(1+\eta^2)}\left[
     215              :  *        W(1+\zeta)
     216              :  *       +P(1-\zeta)\right]
     217              :  *   \begin{bmatrix}
     218              :  *      \eta \\
     219              :  *      1
     220              :  *   \end{bmatrix}+
     221              :  *   \begin{bmatrix}
     222              :  *      z \\
     223              :  *      0
     224              :  *   \end{bmatrix}.
     225              :  * \end{align}
     226              :  *
     227              :  * Although it is straightforward to construct the inverse jacobian
     228              :  * analytically, for now we compute the inverse jacobian by numerically taking
     229              :  * the matrix inverse of the jacobian.
     230              :  *
     231              :  */
     232            1 : class FlatOffsetSphericalWedge {
     233              :  public:
     234            0 :   static constexpr size_t dim = 3;
     235              :   /*!
     236              :    * \brief Constructs a FlatOffsetSphericalWedge.
     237              :    *
     238              :    * \param lower_face_x_width The width $D$ of the lower face in
     239              :    * the $x$ direction.
     240              :    * \param inner_radius The inner radius $R_1$.
     241              :    * \param outer_radius The outer radius $R_2$.
     242              :    */
     243            1 :   FlatOffsetSphericalWedge(double lower_face_x_width, double inner_radius,
     244              :                            double outer_radius);
     245              : 
     246            0 :   FlatOffsetSphericalWedge() = default;
     247            0 :   ~FlatOffsetSphericalWedge() = default;
     248            0 :   FlatOffsetSphericalWedge(FlatOffsetSphericalWedge&&) = default;
     249            0 :   FlatOffsetSphericalWedge(const FlatOffsetSphericalWedge&) = default;
     250            0 :   FlatOffsetSphericalWedge& operator=(const FlatOffsetSphericalWedge&) =
     251              :       default;
     252            0 :   FlatOffsetSphericalWedge& operator=(FlatOffsetSphericalWedge&&) = default;
     253              : 
     254              :   template <typename T>
     255            0 :   std::array<T, 3> operator()(const std::array<T, 3>& source_coords) const;
     256              : 
     257              :   /// The inverse function is only callable with doubles because the inverse
     258              :   /// might fail if called for a point out of range, and it is unclear
     259              :   /// what should happen if the inverse were to succeed for some points in a
     260              :   /// DataVector but fail for other points.
     261            1 :   std::optional<std::array<double, 3>> inverse(
     262              :       const std::array<double, 3>& target_coords) const;
     263              : 
     264              :   template <typename T>
     265            0 :   tnsr::Ij<T, 3, Frame::NoFrame> jacobian(
     266              :       const std::array<T, 3>& source_coords) const;
     267              : 
     268              :   template <typename T>
     269            0 :   tnsr::Ij<T, 3, Frame::NoFrame> inv_jacobian(
     270              :       const std::array<T, 3>& source_coords) const;
     271              : 
     272              :   // clang-tidy: google runtime references
     273            0 :   void pup(PUP::er& p);  // NOLINT
     274              : 
     275            0 :   static bool is_identity() { return false; }
     276              : 
     277            0 :   static constexpr bool supports_hessian{false};
     278              : 
     279              :  private:
     280            0 :   friend bool operator==(const FlatOffsetSphericalWedge& lhs,
     281              :                          const FlatOffsetSphericalWedge& rhs);
     282            0 :   double lower_face_x_width_{std::numeric_limits<double>::signaling_NaN()};
     283            0 :   double inner_radius_{std::numeric_limits<double>::signaling_NaN()};
     284            0 :   double outer_radius_{std::numeric_limits<double>::signaling_NaN()};
     285              : };
     286              : 
     287            0 : bool operator!=(const FlatOffsetSphericalWedge& lhs,
     288              :                 const FlatOffsetSphericalWedge& rhs);
     289              : }  // namespace domain::CoordinateMaps
        

Generated by: LCOV version 2.0-1