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 <optional> 8 : #include <pup.h> 9 : 10 : #include "DataStructures/DataVector.hpp" 11 : #include "Utilities/Serialization/CharmPupable.hpp" 12 : 13 : namespace domain::CoordinateMaps::ShapeMapTransitionFunctions { 14 : 15 : /*! 16 : * \brief Abstract base class for the transition function $G(r,\theta,\phi)$ 17 : * used by the domain::CoordinateMaps::TimeDependent::Shape map. 18 : * 19 : * \details This base class defines the required methods of a transition 20 : * function that is defined as 21 : * 22 : * \begin{equation} 23 : * G(r,\theta,\phi) = \frac{f(r,\theta,\phi)}{r} 24 : * \end{equation} 25 : * 26 : * where $0 <= f(r,\theta,\phi) <= 1$. Different domains may require the shape 27 : * map to fall off towards the boundary in different ways. This behavior is 28 : * controlled by the transition function. It is also needed to find the inverse 29 : * of the shape map. Since the shape map preserves angles, the problem of 30 : * finding its inverse reduces to the 1-dimensional problem of finding the 31 : * original radius from the mapped radius. The mapped radius $\tilde{r}$ is 32 : * related to the original $r$ radius by: 33 : * \begin{equation} 34 : * \label{eq:shape_map_radius} 35 : * \tilde{r} = r \left(1 - G(r,\theta,\phi)\sum_{lm} 36 : * \lambda_{lm}(t)Y_{lm}(\theta,\phi)\right), 37 : * \end{equation} 38 : * Depending on the format of the transition function, it should be possible to 39 : * analytically derive this map's inverse because it preserves angles and shifts 40 : * only the radius of each point. Otherwise the inverse has to be computed 41 : * numerically. 42 : * 43 : * The transition function must also be able to compute the gradient and the 44 : * value of the function divided by the radius. Care must be taken that this 45 : * does not divide by zero. 46 : * 47 : * All member functions with the exception of `original_radius_over_radius` 48 : * exist as overloads for types `double` and `DataVector` so that they work with 49 : * the templated shape map methods calling them. To avoid code duplication these 50 : * can be forwarded to templated implementation methods held by the derived 51 : * classes only. 52 : * 53 : * For an example, see SphereTransition. 54 : * 55 : * #### Design Decisions: 56 : * 57 : * It was decided to make the ShapeMapTransitionFunction an abstract base class 58 : * with overloads for types `double` and `DataVector` corresponding to the 59 : * template parameter `T` of the shape map's methods. The shape map holds a 60 : * `unique_ptr` to this abstract class using a common dynamic dispatch design 61 : * pattern. This approach avoids templating the shape map all together. 62 : * 63 : * An alternative approach would be to directly template the transition 64 : * functions onto the shape map so that no abstract base class is necessary. 65 : * These approaches can also be combined by making the transition function an 66 : * abstract base class but also templating it onto the shape map. In this way 67 : * the shape map does not need to hold a `unique_ptr` but can hold the 68 : * transition function directly as a member. 69 : */ 70 1 : class ShapeMapTransitionFunction : public PUP::able { 71 : public: 72 0 : ShapeMapTransitionFunction() = default; 73 : 74 : /// @{ 75 : /*! 76 : * Evaluate the transition function $G(r,\theta,\phi)$ at the 77 : * Cartesian coordinates `source_coords` and possibly divide by the radius 78 : * $r$. 79 : * 80 : * \details If \p one_over_radius_power has a value, then divide $G$ by $r$ to 81 : * that power. This is done here because the transition function knows how to 82 : * handle points in various regions of the map. 83 : */ 84 1 : virtual double operator()( 85 : const std::array<double, 3>& source_coords, 86 : const std::optional<size_t>& one_over_radius_power) const = 0; 87 1 : virtual DataVector operator()( 88 : const std::array<DataVector, 3>& source_coords, 89 : const std::optional<size_t>& one_over_radius_power) const = 0; 90 : /// @} 91 : 92 : /*! 93 : * \brief The inverse of the transition function 94 : * 95 : * This method returns $r/\tilde{r}$ given the mapped coordinates 96 : * $\tilde{x}^i$ (`target_coords`) and the spherical harmonic expansion 97 : * $\Sigma(t, \theta, \phi) = \sum_{lm} \lambda_{lm}(t)Y_{lm}(\theta, \phi)$ 98 : * (`radial_distortion`). See domain::CoordinateMaps::TimeDependent::Shape for 99 : * details on how this quantity is used to compute the inverse of the Shape 100 : * map. 101 : * 102 : * To derive the expression for this inverse, solve Eq. 103 : * ($\ref{eq:shape_map_radius}$) for $r$ after substituting 104 : * $G(r,\theta,\phi)$. 105 : * 106 : * \param target_coords The mapped Cartesian coordinates $\tilde{x}^i$. 107 : * \param radial_distortion The spherical harmonic expansion 108 : * $\Sigma(t, \theta, \phi)$. 109 : * \return The quantity $r/\tilde{r}$. 110 : */ 111 1 : virtual std::optional<double> original_radius_over_radius( 112 : const std::array<double, 3>& target_coords, 113 : double radial_distortion) const = 0; 114 : 115 : /*! 116 : * Evaluate the gradient of the transition function with respect to the 117 : * Cartesian coordinates x, y and z at the Cartesian coordinates 118 : * `source_coords`. 119 : */ 120 : /// @{ 121 1 : virtual std::array<double, 3> gradient( 122 : const std::array<double, 3>& source_coords) const = 0; 123 1 : virtual std::array<DataVector, 3> gradient( 124 : const std::array<DataVector, 3>& source_coords) const = 0; 125 : /// @} 126 : 127 0 : virtual std::unique_ptr<ShapeMapTransitionFunction> get_clone() const = 0; 128 : 129 0 : virtual bool operator==(const ShapeMapTransitionFunction& other) const = 0; 130 0 : virtual bool operator!=(const ShapeMapTransitionFunction& other) const = 0; 131 : 132 0 : WRAPPED_PUPable_abstract(ShapeMapTransitionFunction); 133 0 : explicit ShapeMapTransitionFunction(CkMigrateMessage* m) : PUP::able(m) {} 134 : }; 135 : } // namespace domain::CoordinateMaps::ShapeMapTransitionFunctions