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 <optional> 10 : 11 : #include "DataStructures/Tensor/TypeAliases.hpp" 12 : 13 : /// \cond 14 : namespace PUP { 15 : class er; 16 : } // namespace PUP 17 : /// \endcond 18 : 19 : namespace domain { 20 : namespace CoordinateMaps { 21 : 22 : /*! 23 : * \ingroup CoordinateMapsGroup 24 : * 25 : * \brief Redistributes gridpoints on the sphere. 26 : * \image html EquatorialCompression.png "A sphere with an `aspect_ratio` of 3." 27 : * 28 : * \details A mapping from the sphere to itself which redistributes points 29 : * towards (or away from) a user-specifed axis, indicated by `index_pole_axis_`. 30 : * Once the axis is selected, the map is determined by a single parameter, 31 : * the `aspect_ratio` \f$\alpha\f$, which is the ratio of the distance 32 : * perpendicular to the polar axis to the distance along the polar axis for 33 : * a given point. This parameter name was chosen because points with 34 : * \f$\tan \theta = 1\f$ get mapped to points with \f$\tan \theta' = \alpha\f$. 35 : * In general, gridpoints located at an angle \f$\theta\f$ from the pole are 36 : * mapped to a new angle 37 : * \f$\theta'\f$ satisfying \f$\tan \theta' = \alpha \tan \theta\f$. 38 : * 39 : * For an `aspect_ratio` greater than one, the gridpoints are mapped towards 40 : * the equator, leading to an equatorially compressed grid. For an 41 : * `aspect_ratio` less than one, the gridpoints are mapped towards the poles. 42 : * Note that the aspect ratio must be positive. 43 : * 44 : * Suppose the polar axis were the z-axis, given by `index_pole_axis_ == 2`. 45 : * We can then define the auxiliary variables \f$ r := \sqrt{x^2 + y^2 +z^2}\f$ 46 : * and \f$ \rho := \sqrt{x^2 + y^2 + \alpha^{-2} z^2}\f$. 47 : * 48 : * The map corresponding to this transformation in cartesian coordinates 49 : * is then given by: 50 : * 51 : * \f[\vec{x}'(x,y,z) = 52 : * \frac{r}{\rho}\begin{bmatrix} 53 : * x\\ 54 : * y\\ 55 : * \alpha^{-1} z\\ 56 : * \end{bmatrix}.\f] 57 : * 58 : * The mappings for polar axes along the x and y axes are similarly obtained. 59 : */ 60 1 : class EquatorialCompression { 61 : public: 62 0 : static constexpr size_t dim = 3; 63 0 : explicit EquatorialCompression(double aspect_ratio, 64 : size_t index_pole_axis = 2); 65 0 : EquatorialCompression() = default; 66 0 : ~EquatorialCompression() = default; 67 0 : EquatorialCompression(EquatorialCompression&&) = default; 68 0 : EquatorialCompression(const EquatorialCompression&) = default; 69 0 : EquatorialCompression& operator=(const EquatorialCompression&) = default; 70 0 : EquatorialCompression& operator=(EquatorialCompression&&) = default; 71 : 72 : template <typename T> 73 0 : std::array<T, 3> operator()(const std::array<T, 3>& source_coords) const; 74 : 75 : /// The inverse function is only callable with doubles because the inverse 76 : /// might fail if called for a point out of range, and it is unclear 77 : /// what should happen if the inverse were to succeed for some points in a 78 : /// DataVector but fail for other points. 79 1 : std::optional<std::array<double, 3>> inverse( 80 : const std::array<double, 3>& target_coords) const; 81 : 82 : template <typename T> 83 0 : tnsr::Ij<T, 3, Frame::NoFrame> jacobian( 84 : const std::array<T, 3>& source_coords) const; 85 : 86 : template <typename T> 87 0 : tnsr::Ij<T, 3, Frame::NoFrame> inv_jacobian( 88 : const std::array<T, 3>& source_coords) const; 89 : 90 : // NOLINTNEXTLINE(google-runtime-references) 91 0 : void pup(PUP::er& p); 92 : 93 0 : bool is_identity() const { return is_identity_; } 94 : 95 0 : static constexpr bool supports_hessian{false}; 96 : 97 : private: 98 : template <typename T> 99 0 : std::array<T, 3> angular_distortion(const std::array<T, 3>& coords, 100 : double inverse_alpha) const; 101 : template <typename T> 102 0 : tnsr::Ij<T, 3, Frame::NoFrame> angular_distortion_jacobian( 103 : const std::array<T, 3>& coords, double inverse_alpha) const; 104 0 : friend bool operator==(const EquatorialCompression& lhs, 105 : const EquatorialCompression& rhs); 106 : 107 0 : double aspect_ratio_{std::numeric_limits<double>::signaling_NaN()}; 108 0 : double inverse_aspect_ratio_{std::numeric_limits<double>::signaling_NaN()}; 109 0 : bool is_identity_{false}; 110 0 : size_t index_pole_axis_{}; 111 : }; 112 0 : bool operator!=(const EquatorialCompression& lhs, 113 : const EquatorialCompression& rhs); 114 : } // namespace CoordinateMaps 115 : } // namespace domain