SpECTRE Documentation Coverage Report
Current view: top level - Domain/CoordinateMaps/TimeDependent - SphericalCompression.hpp Hit Total Coverage
Commit: 37c384043430860f87787999aa7399d01bb3d213 Lines: 2 20 10.0 %
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 <limits>
       9             : #include <memory>
      10             : #include <optional>
      11             : #include <string>
      12             : #include <unordered_map>
      13             : #include <unordered_set>
      14             : 
      15             : #include "DataStructures/Tensor/TypeAliases.hpp"
      16             : #include "Utilities/TypeTraits/RemoveReferenceWrapper.hpp"
      17             : 
      18             : /// \cond
      19             : namespace domain::FunctionsOfTime {
      20             : class FunctionOfTime;
      21             : }  // namespace domain::FunctionsOfTime
      22             : namespace PUP {
      23             : class er;
      24             : }  // namespace PUP
      25             : /// \endcond
      26             : 
      27             : namespace domain::CoordinateMaps::TimeDependent {
      28             : /*!
      29             :  * \ingroup CoordMapsTimeDependentGroup
      30             :  * \brief Time-dependent compression of a finite 3D spherical volume.
      31             :  *
      32             :  * \details Let \f$\xi^i\f$ be the unmapped coordinates, and let \f$\rho\f$ be
      33             :  * the Euclidean radius corresponding to these coordinates with respect to
      34             :  * some center \f$C^i\f$. The transformation implemented by this map is
      35             :  * equivalent to the following transformation: at each point, the mapped
      36             :  * coordinates are the same as the unmapped coordinates, except in
      37             :  * a spherical region \f$\rho \leq \rho_{\rm max}\f$, where instead coordinates
      38             :  * are mapped using a compression that is spherically symmetric about the center
      39             :  * \f$C^i\f$. The amount of compression decreases linearly from a maximum at
      40             :  * \f$\rho = \rho_{\rm min}\f$ to zero at \f$\rho = \rho_{\rm max}\f$. A
      41             :  * scalar domain::FunctionsOfTime::FunctionOfTime \f$\lambda_{00}(t)\f$ controls
      42             :  * the amount of compression.
      43             :  *
      44             :  * The mapped coordinates are a continuous function of the unmapped
      45             :  * coordinates, but the Jacobians are not continuous at \f$\rho_{\rm min}\f$
      46             :  * and \f$\rho_{\rm max}\f$. Therefore, \f$\rho_{\rm min}\f$ and \f$\rho_{\rm
      47             :  * max}\f$ should both be surfaces corresponding to block boundaries. Therefore,
      48             :  * this class implements the transformation described above as follows: the
      49             :  * if the template parameter `InteriorMap` is true, the map is the one
      50             :  * appropriate for \f$\rho < \rho_{\rm min}\f$, while if `InteriorMap` is false,
      51             :  * the map is the one appropriate for \f$\rho_{\rm min} \leq \rho \leq \rho_{\rm
      52             :  * max}\f$. To use this map, add it to the blocks where the transformation is
      53             :  * not the identity, using the appropriate template parameter, depending on
      54             :  * which region the block is in.
      55             :  *
      56             :  * \note This map performs a only a spherical compression. A
      57             :  * generalization of this map that changes the region's shape as well as
      58             :  * its size, by including more terms than the spherically symmetric
      59             :  * term included here, can be found in the
      60             :  * domain::CoordinateMaps::TimeDependent::Shape map.
      61             :  *
      62             :  * \note The quantity stored in the FunctionOfTime is really
      63             :  * the spherical-harmonic coefficient \f$\lambda_{00}(t)\f$.  This is
      64             :  * different from the Shape map, which stores ylm::Spherepack coefficients
      65             :  * \f$a_{lm}(t)\f$ and \f$b_{lm}(t)\f$ instead of \f$\lambda_{lm}(t)\f$.
      66             :  * See domain::CoordinateMaps::TimeDependent::Shape for more details.
      67             :  *
      68             :  * ### Mapped coordinates
      69             :  *
      70             :  * The mapped coordinates
      71             :  * \f$x^i\f$ are related to the unmapped coordinates \f$\xi^i\f$
      72             :  * as follows:
      73             :  * \f{align}{
      74             :  * x^i &= \left\{\begin{array}{ll}\xi^i - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
      75             :  * \frac{\rho^i}{\rho_{\rm min}}, & \rho < \rho_{\rm min}, \\
      76             :  * \xi^i - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
      77             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}} \rho^i, &
      78             :  * \rho_{\rm min} \leq \rho \leq \rho_{\rm max}, \\
      79             :  * \xi^i, & \rho_{\rm max} < \rho,\end{array}\right.
      80             :  * \f}
      81             :  * where \f$\rho^i = \xi^i - C^i\f$ is the Euclidean radial position vector in
      82             :  * the unmapped coordinates with respect to the center \f$C^i\f$, \f$\rho =
      83             :  * \sqrt{\delta_{kl}\left(\xi^k - C^l\right)\left(\xi^l - C^l\right)}\f$ is the
      84             :  * Euclidean magnitude of \f$\rho^i\f$, and \f$\rho_j = \delta_{ij} \rho^i\f$.
      85             :  *
      86             :  * ### Frame velocity
      87             :  *
      88             :  * The frame velocity \f$v^i \equiv dx^i/dt\f$ is then
      89             :  * \f{align}{
      90             :  * v^i &= \left\{\begin{array}{ll} - \frac{\lambda_{00}^\prime(t)}{\sqrt{4\pi}}
      91             :  * \frac{\rho^i}{\rho_{\rm min}}, & \rho < \rho_{\rm min}, \\
      92             :  * - \frac{\lambda_{00}^\prime(t)}{\sqrt{4\pi}}
      93             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}} \rho^i,
      94             :  * & \rho_{\rm min} \leq \rho \leq \rho_{\rm max}, \\
      95             :  * 0, & \rho_{\rm max} < \rho,\end{array}\right.
      96             :  * \f} where \f$\lambda_{00}^\prime(t) \equiv d\lambda_{00}/dt\f$.
      97             :  *
      98             :  * ### Jacobian
      99             :  *
     100             :  * Differentiating the equations for \f$x^i\f$ gives the Jacobian
     101             :  * \f$\partial x^i / \partial \xi^j\f$. Using the result
     102             :  * \f{align}{
     103             :  * \frac{\partial \rho^i}{\partial \xi^j} &= \frac{\partial}{\partial \xi^j}
     104             :  * \left(\xi^i - C^i\right) = \frac{\partial \xi^i}{\partial \xi^j}
     105             :  * = \delta^i_{j}
     106             :  * \f}
     107             :  * and taking the derivatives yields
     108             :  * \f{align}{
     109             :  * \frac{\partial x^i}{\partial \xi^j} &= \left\{\begin{array}{ll}
     110             :  * \delta^i_j \left(1
     111             :  * - \frac{\lambda_{00}(t)}{\sqrt{4\pi}} \frac{1}{\rho_{\rm min}}\right),
     112             :  * & \rho < \rho_{\rm min},\\
     113             :  * \delta^i_j
     114             :  * \left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     115             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}}\right)
     116             :  * - \rho^i \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     117             :  * \frac{\partial}{\partial \xi^j}\left(
     118             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}}\right),
     119             :  * & \rho_{\rm min} \leq \rho < \rho_{\rm max},\\
     120             :  * \delta^i_j, & \rho_{\rm max} < \rho.\end{array}\right.
     121             :  * \f}
     122             :  * Inserting
     123             :  * \f{align}{
     124             :  * \frac{\partial}{\partial \xi^j}\left(
     125             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}}\right)
     126             :  * &= \frac{\rho_{\rm max}}{\rho_{\rm max} - \rho_{\rm min}}
     127             :  * \frac{\partial}{\partial \xi^j}\left(\frac{1}{\rho}\right)
     128             :  * = - \frac{\rho_{\rm max}}{\rho_{\rm max} - \rho_{\rm min}} \frac{1}{\rho^2}
     129             :  * \frac{\partial \rho}{\partial \xi^j}
     130             :  * \f}
     131             :  * and
     132             :  * \f{align}{
     133             :  * \frac{\partial \rho}{\partial \xi^j} &= \frac{\rho_j}{\rho}.
     134             :  * \f}
     135             :  * into the Jacobian yields
     136             :  * \f{align}{
     137             :  * \frac{\partial x^i}{\partial \xi^j} &= \left\{\begin{array}{ll}
     138             :  * \delta^i_j \left(1
     139             :  * - \frac{\lambda_{00}(t)}{\sqrt{4\pi}} \frac{1}{\rho_{\rm min}}\right),
     140             :  * & \rho < \rho_{\rm min},\\
     141             :  * \delta^i_j
     142             :  * \left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     143             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}}\right)
     144             :  * + \rho^i \rho_j \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     145             :  * \frac{\rho_{\rm max}}{\rho_{\rm max} - \rho_{\rm min}}\frac{1}{\rho^3},
     146             :  * & \rho_{\rm min} \leq \rho < \rho_{\rm max},\\
     147             :  * \delta^i_j, & \rho_{\rm max} < \rho.\end{array}\right.
     148             :  * \f}
     149             :  *
     150             :  * ### Inverse Jacobian
     151             :  *
     152             :  * This map finds the inverse Jacobian by first finding the Jacobian and then
     153             :  * numerically inverting it.
     154             :  *
     155             :  * ### Inverse map
     156             :  *
     157             :  * For \f$\lambda_{00}(t)\f$ that satisfy
     158             :  * \f{align}{
     159             :  * \rho_{\rm min} - \rho_{\rm max} < \lambda_{00}(t) / \sqrt{4\pi} <
     160             :  * \rho_{\rm min},
     161             :  * \f}
     162             :  * the map will be invertible and nonsingular. For simplicity, here we
     163             :  * enforce this condition, even though perhaps the map might be generalized to
     164             :  * handle cases that are still invertible but violate this condition. This
     165             :  * avoids the need to specially handle the cases
     166             :  * \f$\lambda_{00}(t) / \sqrt{4\pi} = \rho_{\rm min} - \rho_{\rm max}\f$
     167             :  * and \f$\lambda_{00}(t) / \sqrt{4\pi} = \rho_{\rm min}\f$, both of which
     168             :  * yield a singular map, and it also avoids cases where the map behaves
     169             :  * in undesirable ways (such as a larger \f$\lambda_{00}(t)\f$ leading to
     170             :  * an expansion and a coordinate inversion instead of a compression).
     171             :  *
     172             :  * After
     173             :  * requiring the above inequality to be satisfied, however, the inverse mapping
     174             :  * can be derived as follows. Let \f$r^i \equiv x^i - C^i\f$. In terms of
     175             :  * \f$r^i\f$, the map is \f{align}{ r^i &= \left\{\begin{array}{ll}\rho^i
     176             :  * \left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     177             :  * \frac{1}{\rho_{\rm min}}\right), & \rho < \rho_{\rm min}, \\
     178             :  * \rho^i\left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     179             :  * \frac{\rho_{\rm max} / \rho - 1}{\rho_{\rm max} - \rho_{\rm min}}\right),
     180             :  * & \rho_{\rm min} \leq \rho \leq \rho_{\rm max}, \\
     181             :  * \rho^i, & \rho_{\rm max} < \rho.\end{array}\right.
     182             :  * \f}
     183             :  *
     184             :  * Taking the Euclidean magnitude of both sides and simplifying yields
     185             :  * \f{align}{
     186             :  * \frac{r}{\rho} &= \left\{\begin{array}{ll}
     187             :  * 1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     188             :  * \frac{1}{\rho_{\rm min}}, & \rho < \rho_{\rm min}, \\
     189             :  * 1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     190             :  * \frac{\rho_{\rm max}/\rho - 1}{\rho_{\rm max} - \rho_{\rm min}},
     191             :  * & \rho_{\rm min} \leq \rho \leq \rho_{\rm max}, \\
     192             :  * 1, & \rho_{\rm max} < \rho,\end{array}\right.
     193             :  * \f}
     194             :  * which implies
     195             :  * \f{align}{
     196             :  * r^i = \rho^i \frac{r}{\rho} \Rightarrow \rho^i = r^i \frac{\rho}{r}.
     197             :  * \f}
     198             :  *
     199             :  * Inserting \f$\rho_{\rm min}\f$ or \f$\rho_{\rm max}\f$ then gives the
     200             :  * corresponding bounds in the mapped coordinates: \f{align}{
     201             :  * r_{\rm min} &= \rho_{\rm min} - \frac{\lambda_{00}(t)}{\sqrt{4\pi}},\\
     202             :  * r_{\rm max} &= \rho_{\rm max}.
     203             :  * \f}
     204             :  *
     205             :  * In the regime \f$\rho_{\rm min} \leq \rho < \rho_{\rm max}\f$, rearranging
     206             :  * yields a linear relationship between \f$\rho\f$ and \f$r\f$, which
     207             :  * can then be solved for \f$\rho(r)\f$:
     208             :  * \f{align}{
     209             :  * r &= \rho - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     210             :  * \frac{\rho_{\rm max} - \rho}{\rho_{\rm max} - \rho_{\rm min}}\\
     211             :  * \Rightarrow r &= \rho \left(1 + \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     212             :  * \frac{1}{\rho_{\rm max} - \rho_{\rm min}}\right)
     213             :  * - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     214             :  * \frac{\rho_{\rm max}}{\rho_{\rm max} - \rho_{\rm min}}.
     215             :  * \f}
     216             :  * Solving this linear equation for \f$\rho\f$ yields
     217             :  * \f{align}{
     218             :  * \rho &= \left(r+\frac{\lambda_{00}(t)}{\sqrt{4\pi}}\frac{\rho_{\rm
     219             :  * max}}{\rho_{\rm max}-\rho_{\rm min}}\right)
     220             :  * \left(1 + \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     221             :  * \frac{1}{\rho_{\rm max} - \rho_{\rm min}}\right)^{-1}.
     222             :  * \f}
     223             :  *
     224             :  * Inserting the expressions for \f$\rho\f$ into the equation
     225             :  * \f{align}{
     226             :  * \rho^i = r^i \frac{\rho}{r}
     227             :  * \f}
     228             :  * then gives
     229             :  * \f{align}{
     230             :  * \rho^i &= \left\{\begin{array}{ll}
     231             :  * r^i\left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     232             :  * \frac{1}{\rho_{\rm min}}\right)^{-1},
     233             :  * & r < \rho_{\rm min} - \frac{\lambda_{00}(t)}{\sqrt{4\pi}},\\
     234             :  * r^i
     235             :  * \left(1+\frac{1}{r}\frac{\lambda_{00}(t)}{\sqrt{4\pi}}\frac{\rho_{\rm
     236             :  * max}}{\rho_{\rm max}-\rho_{\rm min}}\right)\left(1 +
     237             :  * \frac{\lambda_{00}(t)}{\sqrt{4\pi}} \frac{1}{\rho_{\rm max} - \rho_{\rm
     238             :  * min}}\right)^{-1}, & \rho_{\rm min} - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     239             :  * \leq r
     240             :  * \leq \rho_{\rm max},\\
     241             :  * r^i, & \rho_{\rm max} < r.\end{array}\right.
     242             :  * \f}
     243             :  * Finally, inserting \f$\rho^i = \xi^i - C^i\f$ yields the inverse map:
     244             :  * \f{align}{
     245             :  * \xi^i &= \left\{\begin{array}{ll}
     246             :  * r^i\left(1 - \frac{\lambda_{00}(t)}{\sqrt{4\pi}}
     247             :  * \frac{1}{\rho_{\rm min}}\right)^{-1} + C^i,
     248             :  * & r < \rho_{\rm min} - \frac{\lambda_{00}(t)}{\sqrt{4\pi}},\\
     249             :  * r^i
     250             :  * \left(1+\frac{1}{r}\frac{\lambda_{00}(t)}{\sqrt{4\pi}}\frac{\rho_{\rm
     251             :  * max}}{\rho_{\rm max}-\rho_{\rm min}}\right)\left(1 +
     252             :  * \frac{\lambda_{00}(t)}{\sqrt{4\pi}} \frac{1}{\rho_{\rm max} - \rho_{\rm
     253             :  * min}}\right)^{-1} + C^i, & \rho_{\rm min} -
     254             :  * \frac{\lambda_{00}(t)}{\sqrt{4\pi}} \leq r
     255             :  * \leq \rho_{\rm max},\\
     256             :  * r^i + C^i = x^i, & \rho_{\rm max} < r.\end{array}\right.
     257             :  * \f}
     258             :  *
     259             :  */
     260             : template <bool InteriorMap>
     261           1 : class SphericalCompression {
     262             :  public:
     263           0 :   static constexpr size_t dim = 3;
     264             : 
     265           0 :   explicit SphericalCompression(std::string function_of_time_name,
     266             :                                 double min_radius, double max_radius,
     267             :                                 const std::array<double, 3>& center);
     268           0 :   SphericalCompression() = default;
     269             : 
     270             :   template <typename T>
     271           0 :   std::array<tt::remove_cvref_wrap_t<T>, 3> operator()(
     272             :       const std::array<T, 3>& source_coords, double time,
     273             :       const std::unordered_map<
     274             :           std::string,
     275             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     276             :           functions_of_time) const;
     277             : 
     278             :   /// The inverse function is only callable with doubles because the inverse
     279             :   /// might fail if called for a point out of range, and it is unclear
     280             :   /// what should happen if the inverse were to succeed for some points in a
     281             :   /// DataVector but fail for other points.
     282           1 :   std::optional<std::array<double, 3>> inverse(
     283             :       const std::array<double, 3>& target_coords, double time,
     284             :       const std::unordered_map<
     285             :           std::string,
     286             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     287             :           functions_of_time) const;
     288             : 
     289             :   template <typename T>
     290           0 :   std::array<tt::remove_cvref_wrap_t<T>, 3> frame_velocity(
     291             :       const std::array<T, 3>& source_coords, double time,
     292             :       const std::unordered_map<
     293             :           std::string,
     294             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     295             :           functions_of_time) const;
     296             : 
     297             :   template <typename T>
     298           0 :   tnsr::Ij<tt::remove_cvref_wrap_t<T>, 3, Frame::NoFrame> jacobian(
     299             :       const std::array<T, 3>& source_coords, double time,
     300             :       const std::unordered_map<
     301             :           std::string,
     302             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     303             :           functions_of_time) const;
     304             : 
     305             :   template <typename T>
     306           0 :   tnsr::Ij<tt::remove_cvref_wrap_t<T>, 3, Frame::NoFrame> inv_jacobian(
     307             :       const std::array<T, 3>& source_coords, double time,
     308             :       const std::unordered_map<
     309             :           std::string,
     310             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     311             :           functions_of_time) const;
     312             : 
     313             :   // NOLINTNEXTLINE(google-runtime-references)
     314           0 :   void pup(PUP::er& p);
     315             : 
     316           0 :   static bool is_identity() { return false; }
     317             : 
     318           0 :   const std::unordered_set<std::string>& function_of_time_names() const {
     319             :     return f_of_t_names_;
     320             :   }
     321             : 
     322             :  private:
     323           0 :   friend bool operator==(const SphericalCompression& lhs,
     324             :                          const SphericalCompression& rhs) {
     325             :     return lhs.f_of_t_name_ == rhs.f_of_t_name_ and
     326             :            lhs.min_radius_ == rhs.min_radius_ and
     327             :            lhs.max_radius_ == rhs.max_radius_ and lhs.center_ == rhs.center_;
     328             :   }
     329           0 :   std::string f_of_t_name_;
     330           0 :   std::unordered_set<std::string> f_of_t_names_;
     331           0 :   double min_radius_ = std::numeric_limits<double>::signaling_NaN();
     332           0 :   double max_radius_ = std::numeric_limits<double>::signaling_NaN();
     333           0 :   std::array<double, 3> center_;
     334             : };
     335             : 
     336             : template <bool InteriorMap>
     337           0 : bool operator!=(const SphericalCompression<InteriorMap>& lhs,
     338             :                 const SphericalCompression<InteriorMap>& rhs) {
     339             :   return not(lhs == rhs);
     340             : }
     341             : }  // namespace domain::CoordinateMaps::TimeDependent

Generated by: LCOV version 1.14