SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps/TimeDependent/ShapeMapTransitionFunctions - Wedge.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 7 44 15.9 %
Date: 2025-12-05 05:03:31
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 <ostream>
      12             : #include <pup.h>
      13             : 
      14             : #include "DataStructures/DataVector.hpp"
      15             : #include "Domain/CoordinateMaps/TimeDependent/ShapeMapTransitionFunctions/ShapeMapTransitionFunction.hpp"
      16             : 
      17             : namespace domain::CoordinateMaps::ShapeMapTransitionFunctions {
      18             : /*!
      19             :  * \brief A transition function $G(r,\theta,\phi)$ with $f(r,\theta,\phi)$ that
      20             :  * falls off linearly from an inner surface of a wedge to an outer surface of a
      21             :  * wedge. Meant to be used in `domain::CoordinateMaps::Wedge` blocks.
      22             :  *
      23             :  * \details The functional form of this transition is
      24             :  *
      25             :  * \begin{equation}
      26             :  *     G(r,\theta,\phi) = \frac{f(r,\theta,\phi)}{r}
      27             :  *     \label{eq:transition_func}
      28             :  * \end{equation}
      29             :  *
      30             :  * where
      31             :  *
      32             :  * \begin{equation}
      33             :  *     f(r, \theta, \phi) = \frac{D_{\text{out}}(r, \theta, \phi) -
      34             :  *     r}{D_{\text{out}}(r, \theta, \phi) - D_{\text{in}}(r, \theta, \phi)},
      35             :  * \label{eq:linear_transition_func}
      36             :  * \end{equation}
      37             :  *
      38             :  * where, in general,
      39             :  *
      40             :  * \begin{equation}
      41             :  * D(r, \theta, \phi) = R\left(\frac{1 -
      42             :  * s}{\sqrt{3}\max(|\sin{\theta}\cos{\phi}|,|\sin{\theta}\sin{\phi}|,
      43             :  * |\cos{\theta}|)} + s\right).
      44             :  * \label{eq:distance}
      45             :  * \end{equation}
      46             :  *
      47             :  * Here, $s$ is the sphericity of the surface which goes from 0 (flat) to 1
      48             :  * (spherical), $R$ is the radius of the spherical surface, $\text{out}$ is the
      49             :  * outer surface, and $\text{in}$ is the inner surface. If the sphericity is 1,
      50             :  * then the surface is a sphere so $D = R$. If the sphericity is 0, then the
      51             :  * surface is a cube. This cube is circumscribed by a sphere of radius $R$. See
      52             :  * `domain::CoordinateMaps::Wedge` for more of an explanation of these boundary
      53             :  * surfaces and their sphericities.
      54             :  *
      55             :  * \note If \p reverse is true, then the functional form of the transition is
      56             :  * actually
      57             :  * \begin{equation}
      58             :  * f(r, \theta, \phi) = 1 - \frac{D_{\text{out}}(r, \theta, \phi) -
      59             :  * r}{D_{\text{out}}(r, \theta, \phi) - D_{\text{in}}(r, \theta, \phi)} =
      60             :  * \frac{r - D_{\text{in}}(r, \theta, \phi)}
      61             :  * {D_{\text{out}}(r, \theta, \phi) - D_{\text{in}}(r, \theta, \phi)}.
      62             :  * \label{eq:linear_transition_func_reverse}
      63             :  * \end{equation}
      64             :  *
      65             :  * \parblock
      66             :  *
      67             :  * \note Because the shape map distorts only radii and does not affect angles,
      68             :  * $D$ is not a function of $r$ so we have that $D(r,\theta,\phi) =
      69             :  * D(\theta, \phi)$.
      70             :  *
      71             :  * \endparblock
      72             :  *
      73             :  * The transition function is also defined within $D_{\text{in}}(r, \theta,
      74             :  * \phi)$ if the axis is `Axis::Interior`. Within $D_{\text{in}}(r, \theta,
      75             :  * \phi)$, the transition function is
      76             :  *
      77             :  * \begin{equation}
      78             :  *     \label{eq:interior_transition_func}
      79             :  *     G(r,\theta,\phi) = \frac{r^2}{D_{\text{in}}(r, \theta, \phi)^3} =
      80             :  *     \frac{r^3}{R_0^3}
      81             :  * \end{equation}
      82             :  *
      83             :  * and none of the vector formulation is necessary. This is chosen to match Eq.
      84             :  * $\ref{eq:transition_func}$ at $D_{\text{in}}(r, \theta, \phi)$ and go to 0 at
      85             :  * $r=0$. The second equality is explained by one of the following bullets.
      86             :  *
      87             :  * There are several assumptions made for this mapping:
      88             :  *
      89             :  * - The coordinates $r, \theta, \phi$ are assumed to be from the center of the
      90             :  *   inner surface, not the center of the computational domain.
      91             :  * - The wedges are concentric. (see the constructor) This is also enforced by
      92             :  *   the center of the inner surface being within the outer surface.
      93             :  * - If the centers of the inner and outer surface are different, then the inner
      94             :  *   sphericity must be 1 (i.e. $D_{\text{in}} = R$).
      95             :  * - If the axis is `Axis::Interior`, then the inner sphericity must be 1 and
      96             :  *    \p reverse must be false.
      97             :  * - The $\max$ in the denominator of $\ref{eq:distance}$ can be simplified a
      98             :  *   bit to $\max(|x|, |y|, |z|)/r$. It was written the other way in
      99             :  *   $\ref{eq:distance}$ to emphasize that $D$ has no radial dependence.
     100             :  *
     101             :  * ### Vector formulation
     102             :  *
     103             :  * \image html WedgeTransition.jpg "Useful vectors for Wedge transition"
     104             :  *
     105             :  * It can be more convenient to work with vectors rather than just distances for
     106             :  * the following equations. Therefore, we define the projection center $\vec P$
     107             :  * which points from the center of the outer surface to the center of the inner
     108             :  * surface. If the centers of the inner and outer surface are the same, then
     109             :  * $\vec P = 0$. Then, we define $\vec x$ as the vector from the center of the
     110             :  * outer surface to the coordinate we are interested in. We define $\vec x_0$ as
     111             :  * the vector from the center of the outer surface to the point along ray $\vec
     112             :  * x - \vec P$ which intersects the inner surface. Similarly, $\vec x_1$
     113             :  * intersects the outer surface along the same ray as $\vec x - \vec P$. Any
     114             :  * cube has a side length of $2L$.
     115             :  *
     116             :  * In this way, we can reformulate Eq. $\ref{eq:linear_transition_func}$ as
     117             :  *
     118             :  * \begin{equation}\label{eq:linear_transition_func_vec}
     119             :  *     f(\vec x) = \frac{|\vec x_1 - \vec P| - r}{|\vec x_1 - \vec P| - |\vec
     120             :  * x_0 - \vec P|}
     121             :  * \end{equation}
     122             :  *
     123             :  * where
     124             :  *
     125             :  * \begin{equation}
     126             :  *     r  = |\vec x - P|
     127             :  * \end{equation}
     128             :  *
     129             :  * #### Computing vector to inner surface
     130             :  *
     131             :  * Similar to Eq. $\ref{eq:distance}$ we can define $\vec x_0$ as
     132             :  *
     133             :  * \begin{equation}\label{eq:x_0_vector}
     134             :  *     \vec x_0 = R_0\left( \frac{r(1-s_0)}{\sqrt{3}\max{(x_i - P_i)}} +
     135             :  * s\right) \hat r + \vec P
     136             :  * \end{equation}
     137             :  *
     138             :  * with
     139             :  *
     140             :  * \begin{equation}
     141             :  *     \hat r = \frac{\vec x - \vec P}{|\vec x - \vec P|}.
     142             :  * \end{equation}
     143             :  *
     144             :  * and also
     145             :  *
     146             :  * \begin{equation}\label{eq:x_0_norm}
     147             :  *     |\vec x_0 - \vec P| = R_0\left( \frac{r(1-s_0)}{\sqrt{3}\max{(x_i -
     148             :  * P_i)}} + s_0\right)
     149             :  * \end{equation}
     150             :  *
     151             :  * ### Computing vector to outer surface
     152             :  *
     153             :  * Then, we define
     154             :  *
     155             :  * \begin{equation}\label{eq:x_1}
     156             :  *     \vec x_1 = \lambda (\vec x - \vec P) + \vec P
     157             :  * \end{equation}
     158             :  *
     159             :  * where $\lambda$ is a scalar to be determined. We can see that this is valid
     160             :  * because $\vec x - \vec P$ is centered on $\vec P$ and lies along the ray so
     161             :  * $\lambda$ will scale this vector to be the correct length.
     162             :  *
     163             :  * Computing $\lambda$ is a bit complicated because the outer surface can either
     164             :  * be a cube, a sphere, or something in between and the way to solve for
     165             :  * $\lambda$ in the cube case is different than in the sphere case. Therefore we
     166             :  * define $\lambda_c$ and $\lambda_s$ as the scalar factors for the cube and
     167             :  * sphere case, respectively. This allows us to define $\lambda$ as
     168             :  *
     169             :  * \begin{equation}\label{eq:lambda}
     170             :  *     \lambda = (1 - s_1) \lambda_c + s_1 \lambda_s
     171             :  * \end{equation}
     172             :  *
     173             :  * #### Computing cube lambda
     174             :  *
     175             :  * To compute $\lambda_c$ for the cube case, we notice that (in the image)
     176             :  *
     177             :  * \begin{align}
     178             :  *     L &= \vec x_1 \cdot \hat z \\
     179             :  *     &= \left(\lambda_c^{+z}(\vec x - \vec P) + \vec P\right) \cdot \hat z\\
     180             :  *     &= \lambda_c^{+z}(x_z - P_z) + P_z
     181             :  * \end{align}
     182             :  *
     183             :  * If we generalize this to all six unit vectors and solve for $\lambda_c^{\pm
     184             :  * k}$ we get
     185             :  *
     186             :  * \begin{equation}\label{eq:lambda_c_pm}
     187             :  *     \lambda_c^{\pm k} = \frac{\pm L - \vec P \cdot \hat x_k}{(\vec x -
     188             :  * \vec P) \cdot \hat x_k}
     189             :  * \end{equation}
     190             :  *
     191             :  * for $k \in \{x, y, z\}$. This quantity $\lambda_c^{\pm k}$ represents the
     192             :  * factor needed to scale the vector $\vec x - \vec P$ to intersect with the
     193             :  * infinite planes that contain the six faces of the cube.
     194             :  *
     195             :  * Some $\lambda_c^{\pm k}$ will be negative as they point to the opposite
     196             :  * planes. We can discard those. Then for the $\lambda_c^{\pm k}$ that are
     197             :  * positive, we want the one that is smallest in magnitude. This can be written
     198             :  * as
     199             :  *
     200             :  * \begin{equation}\label{eq:lambda_c}
     201             :  *     \lambda_c = \min_{\substack{\lambda_c^{\pm k} > 0}} (\lambda_c^{\pm k})
     202             :  * \end{equation}
     203             :  *
     204             :  * #### Computing sphere lambda
     205             :  *
     206             :  * To compute $\lambda_s$ for the sphere case, again we notice that (in the
     207             :  * image)
     208             :  *
     209             :  * \begin{align}
     210             :  *     R_1^2 &= |\vec x_1|^2 \\
     211             :  *     &= |\lambda_s (\vec x - \vec P) + \vec P|^2 \\
     212             :  *     &= \lambda_s^2 |\vec x - \vec P|^2 + 2 \lambda_s (\vec x - \vec P) \cdot
     213             :  * \vec P + |\vec P|^2
     214             :  * \end{align}
     215             :  *
     216             :  * This is simply a quadratic equation for $\lambda_s$:
     217             :  *
     218             :  * \begin{equation}\label{eq:lambda_s}
     219             :  *     0 = \lambda_s^2 |\vec x - \vec P|^2 + 2 \lambda_s (\vec x - \vec P) \cdot
     220             :  * \vec P + |\vec P|^2 - R_1^2
     221             :  * \end{equation}
     222             :  *
     223             :  * We explicitly don't write the typical form of the solution of a quadratic
     224             :  * equation because that form behaviors poorly numerically if the two terms in
     225             :  * the numerator are close to each other (bad numerical roundoff). Therefore, we
     226             :  * just resolve to compute the solution numerically, and say that we have
     227             :  * $\lambda_s$.
     228             :  *
     229             :  * We have now solved for $\vec x_1$.
     230             :  *
     231             :  * \begin{equation}
     232             :  *     \vec x_1 = \left((1 - s_1) \lambda_c + s_1 \lambda_s \right) (\vec x -
     233             :  * \vec P) + \vec P
     234             :  * \end{equation}
     235             :  *
     236             :  * given the solutions for $\lambda_c$ in Eqn. $\ref{eq:lambda_c}$ and
     237             :  * $\lambda_s$ in Eqn. $\ref{eq:lambda_s}$.
     238             :  *
     239             :  * ## Original radius divided by mapped radius
     240             :  *
     241             :  * Given an already mapped point $\tilde{\vec x}$ and the radial distortion
     242             :  * $\Sigma(\theta, \phi) = \sum_{\ell,m}\lambda_{\ell m}Y_{\ell m}(\theta,
     243             :  * \phi)$, we can figure out the ratio of the original radius $r$ to the mapped
     244             :  * $\tilde{r} = |\tilde{\vec x}|$ by solving
     245             :  *
     246             :  * \begin{equation}
     247             :  * \frac{r}{\tilde{r}} =
     248             :  * \frac{1}{1-G(r)\Sigma(\theta,\phi)}
     249             :  * \end{equation}
     250             :  *
     251             :  * If the axis is `Axis::Interior`, this formula becomes (after simplification
     252             :  * and because the inner surface must be spherical)
     253             :  *
     254             :  * \begin{equation}
     255             :  *    0 = \left(\frac{r}{\tilde{r}}\right)^3 - \left(\frac{r}{\tilde{r}}\right)
     256             :  *    \frac{R_0^3}{\tilde{r}^2\Sigma(\theta,\phi)} +
     257             :  *    \frac{R_0^3}{\tilde{r}^2\Sigma(\theta,\phi)}
     258             :  * \end{equation}
     259             :  *
     260             :  * This is a special case of a cubic root, so we use the method outlined in
     261             :  * \cite NumericalRecipes on pg 228.
     262             :  *
     263             :  * For other axes, after plugging in $f(r,\theta,\phi)/r$ and solving, we get
     264             :  *
     265             :  * \begin{equation}
     266             :  * \frac{r}{\tilde{r}} = \frac{1 + \frac{|\vec x_1 - \vec P|\Sigma(\theta,
     267             :  * \phi)}{\tilde{r}(|\vec x_1 - \vec P| - |\vec x_0 - \vec P|)}}{1 +
     268             :  * \frac{\Sigma(\theta, \phi)}{|\vec x_1 - \vec P| - |\vec x_0 - \vec P|}}
     269             :  * \label{eq:r_over_rtil}
     270             :  * \end{equation}
     271             :  *
     272             :  * \note Since $\vec x_0 - \vec P$ and $\vec x_1 - \vec P$ are not functions of
     273             :  * the radius, we can use $\tilde{\vec x}$ in Eq. $\ref{eq:x_0_vector}$ instead
     274             :  * of $\vec x$.
     275             :  *
     276             :  * \parblock
     277             :  *
     278             :  * \note If \p reverse is true, then the value multiplying $\Sigma$ in the
     279             :  * numerator is now $-|\vec x_0 - \vec P|$ and in the denominator $\Sigma$ picks
     280             :  * up a minus sign factor.
     281             :  *
     282             :  * \endparblock
     283             :  *
     284             :  * ## Gradient
     285             :  *
     286             :  * The cartesian gradient of the transition function is
     287             :  *
     288             :  * \begin{equation}
     289             :  *     \frac{\partial G}{\partial x_i} = \frac{1}{r}\frac{\partial f}{\partial
     290             :  *     \xi^i} - \frac{f \xi_i}{r^3}
     291             :  * \end{equation}
     292             :  *
     293             :  * where
     294             :  *
     295             :  * \begin{equation}
     296             :  * \frac{\partial f}{\partial x_i} = \frac{\frac{\partial
     297             :  * |\vec x_1 - \vec P|}{\partial x_i} - \frac{x_i - P_i}{r}}{|\vec x_1 - \vec P|
     298             :  * - |\vec x_0 - \vec P|} - \frac{\left(|\vec x_1 - \vec P| -
     299             :  * r\right)\left(\frac{\partial |\vec x_1 - \vec P|}{\partial x_i} -
     300             :  * \frac{\partial |\vec x_0 - \vec P|}{\partial x_i} \right)}{\left(|\vec x_1 -
     301             :  * \vec P| - |\vec x_0 - \vec P|\right)^2}.
     302             :  * \end{equation}
     303             :  *
     304             :  * \note If \p reverse is true, the gradient picks up an overall factor of -1.0.
     305             :  *
     306             :  * If the axis is `Axis::Interior`, then the gradient is
     307             :  *
     308             :  * \begin{equation}
     309             :  * \frac{\partial G}{\partial x_i} = \frac{2(x_i-P_i)}{R_0^3}
     310             :  * \end{equation}
     311             :  *
     312             :  * For the other axes, we need to compute the gradients of $\vec x_0$ and $\vec
     313             :  * x_1$.
     314             :  *
     315             :  * ### Gradient of vector to inner surface
     316             :  *
     317             :  * If $\vec P \neq 0$, then we require the inner surface to be a sphere, which
     318             :  * means the gradient is trivially zero. Therefore the following is only for
     319             :  * when $\vec P = 0$.
     320             :  *
     321             :  * The gradient of $|\vec x_0 - \vec P|$ depends on the result of the $\max$ in
     322             :  * the denominator of $\ref{eq:x_0_norm}$. To simplify the expression, let $i
     323             :  * \in \{0,1,2\}$ correspond to the $\max(x_i - P_i)$. Then we can write the
     324             :  * gradient of as
     325             :  *
     326             :  * \begin{align}
     327             :  * \frac{\partial |\vec x_0 - \vec P|}{\partial x_i} &= -\text{sgn}(x_i -
     328             :  * P_i)\frac{R(1-s)\left(r^2 - (x_i - P_i)^2\right)}
     329             :  * {r (x_i - P_i)^2 \sqrt{3}} \\
     330             :  * \frac{\partial |\vec x_0 - \vec P|}{\partial x_{i+1}} &=
     331             :  * \frac{R(1-s)(x_{i+1} - P_{i+1})}{r |x_i - P_i| \sqrt{3}} \\
     332             :  * \frac{\partial |\vec x_0 - \vec P|}{\partial x_{i+2}} &=
     333             :  * \frac{R(1-s)(x_{i+2} - P_{i+2})}{r |x_i - P_i| \sqrt{3}}
     334             :  * \end{align}
     335             :  *
     336             :  * where $i+1$ and $i+2$ are understood to be $\mod 3$. Also since we don't
     337             :  * allow points at the center of the inner surfaces, we can be assured that for
     338             :  * whichever $i$ is max, that $x_i - P_i$ won't be zero.
     339             :  *
     340             :  * ### Gradient of vector to outer surface
     341             :  *
     342             :  * This gradient is much more complicated because of how we have to define
     343             :  * $\lambda$. To start off with, we need to compute
     344             :  *
     345             :  * \begin{align}\label{eq:x_1_grad}
     346             :  *     \frac{\partial}{\partial x_i}|\vec x_1 - \vec P| &=
     347             :  * \frac{\partial}{\partial x_i} (\lambda |\vec x - \vec P|) \\
     348             :  *     &= \frac{\lambda (x_i - P_i)}{|\vec x - \vec P|} + \frac{\partial
     349             :  * \lambda}{\partial x_i}|\vec x - \vec P|
     350             :  * \end{align}
     351             :  *
     352             :  * Since we know $\lambda$ and $\vec x$, that just leaves
     353             :  *
     354             :  * \begin{equation}
     355             :  *     \frac{\partial\lambda}{\partial x_i} = \frac{\partial\lambda_c}{\partial
     356             :  * x_i}(1-s_1) + s_1\frac{\partial\lambda_s}{\partial x_i}
     357             :  * \end{equation}
     358             :  *
     359             :  * #### Gradient of cube lambda
     360             :  *
     361             :  * Taking the gradient of Eqn. $\ref{eq:lambda_c_pm}$ we notice that $L$, $\vec
     362             :  * P$, and $\hat x_k$ are constant, so we only have to worry about $\vec x$
     363             :  *
     364             :  * \begin{equation}\label{eq:tmp_lambda_c_grad}
     365             :  *     \frac{\partial}{\partial x_i}\lambda_c^{\pm k} = -\frac{(\pm L -
     366             :  * \vec P \cdot \hat x_k)(\partial/\partial x_i(\vec x - \vec P) \cdot \hat
     367             :  * x_k)}{((\vec x - \vec P) \cdot \hat x_k)^2}
     368             :  * \end{equation}
     369             :  *
     370             :  * The gradient in the numerator is simple to take so we end up with
     371             :  *
     372             :  * \begin{equation}
     373             :  *     \frac{\partial}{\partial x_i}\lambda_c^{\pm k} = -\frac{(\pm L -
     374             :  * \vec P \cdot \hat x_k)}{( x_k - P_k)^2} \delta_{ik}
     375             :  * \end{equation}
     376             :  *
     377             :  * #### Gradient of sphere lambda
     378             :  *
     379             :  * Taking the gradient of Eqn. $\ref{eq:lambda_s}$ (and using the fact that
     380             :  * $\vec P$ and $R$ are constant), we get
     381             :  *
     382             :  * \begin{equation}
     383             :  *     0 = \lambda_s \frac{\partial \lambda_s}{\partial x_i}|\vec x - \vec P|^2
     384             :  * + \lambda_s^2 (\vec x - \vec P) \cdot \frac{\partial}{\partial x_i}(\vec x -
     385             :  * \vec P) + \frac{\partial\lambda_s}{\partial x_i}(\vec x - \vec P) \cdot \vec
     386             :  * P + \lambda_s \vec P \cdot \frac{\partial}{\partial x_i}(\vec x - \vec P)
     387             :  * \end{equation}
     388             :  *
     389             :  * Taking the simple gradients and moving things around, we get
     390             :  *
     391             :  * \begin{equation}
     392             :  *     \frac{\partial\lambda_s}{\partial x_i} = - \frac{\lambda_s^2 (x_i - P_i)
     393             :  * + \lambda_s P_i}{\lambda_s |\vec x - \vec P|^2 + (\vec x - \vec P) \cdot \vec
     394             :  * P}
     395             :  * \end{equation}
     396             :  *
     397             :  * where $\lambda_s$ can be computed from Eqn. $\ref{eq:lambda_s}$.
     398             :  *
     399             :  * So now we can put it all together and we get
     400             :  *
     401             :  * \begin{equation}
     402             :  *    \frac{\partial\lambda}{\partial x_i} =  -\frac{(\pm L - \vec P \cdot
     403             :  * \hat x_k)}{( x_k - P_k)^2} \delta_{ik}(1 - s_1)
     404             :  *     + s_1 \frac{\lambda_s^2 (x_i - P_i) + \lambda_s P_i}{\lambda_s |\vec x -
     405             :  * \vec P|^2 + (\vec x - \vec P) \cdot \vec P} \end{equation}
     406             :  *
     407             :  * which can then be substituted into Eqn. $\ref{eq:x_1_grad}$ to get the
     408             :  * gradient of $|\vec x_1 - \vec P|$.
     409             :  */
     410           1 : class Wedge final : public ShapeMapTransitionFunction {
     411           0 :   struct Surface {
     412           0 :     std::array<double, 3> center{};
     413           0 :     double radius{};
     414           0 :     double sphericity{};
     415           0 :     double half_cube_length{};
     416             : 
     417           0 :     Surface() = default;
     418           0 :     Surface(const std::array<double, 3>& center_in, double radius_in,
     419             :             double sphericity_in);
     420             : 
     421           0 :     void pup(PUP::er& p);
     422             :   };
     423             : 
     424             :  public:
     425             :   /*!
     426             :    * \brief Class to represent the direction of the wedge relative to the outer
     427             :    * center.
     428             :    *
     429             :    * \details \p Interior means within inner surface.
     430             :    */
     431           0 :   enum class Axis : int {
     432             :     Interior = 4,
     433             :     PlusZ = 3,
     434             :     MinusZ = -3,
     435             :     PlusY = 2,
     436             :     MinusY = -2,
     437             :     PlusX = 1,
     438             :     MinusX = -1,
     439             :     None = 0,
     440             :   };
     441             : 
     442           0 :   friend std::ostream& operator<<(std::ostream& os, Axis axis);
     443             : 
     444             :  private:
     445           0 :   static size_t axis_index(Axis axis);
     446           0 :   static double axis_sgn(Axis axis);
     447             : 
     448             :  public:
     449           0 :   explicit Wedge() = default;
     450             : 
     451             :   /*!
     452             :    * \brief Construct a Wedge transition for a wedge block in a given direction.
     453             :    *
     454             :    * \details Many concentric wedges can be part of the same falloff from 1 at
     455             :    * the inner boundary of the innermost wedge, to 0 at the outer boundary of
     456             :    * the outermost wedge.
     457             :    *
     458             :    * \note If \p inner_center and \p outer_center are different, then
     459             :    * \p inner_sphericity must be 1.0. if the \p axis is `Axis::Interior`, then
     460             :    * \p inner_sphericity must be 1.0 and \p reverse must be false.
     461             :    *
     462             :    * \param inner_center Center of the inner surface
     463             :    * \param inner_radius Inner radius of innermost wedge
     464             :    * \param inner_sphericity Sphericity of innermost surface of innermost wedge
     465             :    * \param outer_center Center of the outer surface
     466             :    * \param outer_radius Outermost radius of outermost wedge
     467             :    * \param outer_sphericity Sphericity of outermost surface of outermost wedge
     468             :    * \param axis The direction that this wedge is in.
     469             :    * \param reverse If true, the function $f$ will be 0 at the inner
     470             :    * boundary and 1 at the outer boundary (useful for deforming star surfaces).
     471             :    * Otherwise, it will be 1 at the inner boundary and 0 at the outer boundary
     472             :    * (useful for deforming black hole excision surfaces).
     473             :    */
     474           1 :   Wedge(const std::array<double, 3>& inner_center, double inner_radius,
     475             :         double inner_sphericity, const std::array<double, 3>& outer_center,
     476             :         double outer_radius, double outer_sphericity, Axis axis,
     477             :         bool reverse = false);
     478             : 
     479           1 :   double operator()(
     480             :       const std::array<double, 3>& source_coords,
     481             :       const std::optional<size_t>& one_over_radius_power) const override;
     482           1 :   DataVector operator()(
     483             :       const std::array<DataVector, 3>& source_coords,
     484             :       const std::optional<size_t>& one_over_radius_power) const override;
     485             : 
     486           1 :   std::optional<double> original_radius_over_radius(
     487             :       const std::array<double, 3>& target_coords,
     488             :       double radial_distortion) const override;
     489             : 
     490           1 :   std::array<double, 3> gradient(
     491             :       const std::array<double, 3>& source_coords) const override;
     492           1 :   std::array<DataVector, 3> gradient(
     493             :       const std::array<DataVector, 3>& source_coords) const override;
     494             : 
     495           0 :   WRAPPED_PUPable_decl_template(Wedge);
     496           0 :   explicit Wedge(CkMigrateMessage* msg);
     497           0 :   void pup(PUP::er& p) override;
     498             : 
     499           0 :   std::unique_ptr<ShapeMapTransitionFunction> get_clone() const override {
     500             :     return std::make_unique<Wedge>(*this);
     501             :   }
     502             : 
     503           0 :   bool operator==(const ShapeMapTransitionFunction& other) const override;
     504           0 :   bool operator!=(const ShapeMapTransitionFunction& other) const override;
     505             : 
     506             :  private:
     507             :   template <typename T>
     508           0 :   T call_impl(const std::array<T, 3>& source_coords,
     509             :               const std::optional<size_t>& one_over_radius_power) const;
     510             : 
     511             :   template <typename T>
     512           0 :   std::array<T, 3> gradient_impl(const std::array<T, 3>& source_coords) const;
     513             : 
     514             :   // This is x_0 - P in the docs
     515             :   template <typename T>
     516           0 :   std::array<T, 3> compute_inner_surface_vector(
     517             :       const std::array<T, 3>& centered_coords,
     518             :       const T& centered_coords_magnitude,
     519             :       const std::optional<Axis>& potential_axis) const;
     520             : 
     521             :   // This is x_1 - P in the docs
     522             :   template <typename T>
     523           0 :   std::array<T, 3> compute_outer_surface_vector(
     524             :       const std::array<T, 3>& centered_coords, const T& lambda) const;
     525             : 
     526             :   template <typename T>
     527           0 :   T lambda_cube(const std::array<T, 3>& centered_coords,
     528             :                 const std::optional<Axis>& potential_axis) const;
     529             : 
     530             :   template <typename T>
     531           0 :   T lambda_sphere(const std::array<T, 3>& centered_coords,
     532             :                   const T& centered_coords_magnitude) const;
     533             : 
     534             :   template <typename T>
     535           0 :   T compute_lambda(const std::array<T, 3>& centered_coords,
     536             :                    const T& centered_coords_magnitude,
     537             :                    const std::optional<Axis>& potential_axis) const;
     538             : 
     539             :   template <typename T>
     540           0 :   std::array<T, 3> lambda_cube_gradient(
     541             :       const T& lambda_cube, const std::array<T, 3>& centered_coords) const;
     542             : 
     543             :   template <typename T>
     544           0 :   std::array<T, 3> lambda_sphere_gradient(
     545             :       const T& lambda_sphere, const std::array<T, 3>& centered_coords,
     546             :       const T& centered_coords_magnitude) const;
     547             : 
     548             :   template <typename T>
     549           0 :   std::array<T, 3> compute_lambda_gradient(
     550             :       const std::array<T, 3>& centered_coords,
     551             :       const T& centered_coords_magnitude) const;
     552             : 
     553             :   template <typename T>
     554           0 :   void check_distances(const T& inner_distance, const T& outer_distance,
     555             :                        const T& centered_coords_magnitude,
     556             :                        const std::array<T, 3>& source_coords,
     557             :                        bool check_bounds) const;
     558             : 
     559           0 :   Surface inner_surface_;
     560           0 :   Surface outer_surface_;
     561           0 :   std::array<double, 3> projection_center_{};
     562           0 :   Axis axis_{};
     563           0 :   bool reverse_{false};
     564             : 
     565           0 :   static constexpr double eps_ = std::numeric_limits<double>::epsilon() * 100;
     566             : };
     567             : }  // namespace domain::CoordinateMaps::ShapeMapTransitionFunctions

Generated by: LCOV version 1.14