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 within the unit sphere.
26 : * \image html SpecialMobius.png "A sphere with a `mu` of 0.25."
27 : *
28 : * \details A special case of the conformal Mobius transformation that
29 : * maps the unit ball to itself. This map depends on a single
30 : * parameter, `mu` \f$ = \mu\f$, which is the x-coordinate of the preimage
31 : * of the origin under this map. This map has the fixed points \f$x=1\f$ and
32 : * \f$x=-1\f$. The map is singular for \f$\mu=1\f$ but we have found that this
33 : * map is accurate up to 12 decimal places for values of \f$\mu\f$ up to 0.96.
34 : *
35 : * We define the auxiliary variables
36 : * \f[ r := \sqrt{x^2 + y^2 +z^2}\f]
37 : * and
38 : * \f[ \lambda := \frac{1}{1 - 2 x \mu + \mu^2 r^2}\f]
39 : *
40 : * The map corresponding to this transformation in cartesian coordinates
41 : * is then given by:
42 : *
43 : * \f[\vec{x}'(x,y,z) =
44 : * \lambda\begin{bmatrix}
45 : * x(1+\mu^2) - \mu(1+r^2)\\
46 : * y(1-\mu^2)\\
47 : * z(1-\mu^2)\\
48 : * \end{bmatrix}\f]
49 : *
50 : * The inverse map is the same as the forward map with \f$\mu\f$
51 : * replaced by \f$-\mu\f$.
52 : *
53 : * This map is intended to be used only inside the unit sphere. A
54 : * point inside the unit sphere maps to another point inside the unit
55 : * sphere. The map can have undesirable behavior at certain points
56 : * outside the unit sphere: The map is singular at
57 : * \f$(x,y,z) = (1/\mu, 0, 0)\f$ (which is outside the unit sphere
58 : * since \f$|\mu| < 1\f$). Moreover, a point on the \f$x\f$-axis
59 : * arbitrarily close to the singularity maps to an arbitrarily large
60 : * value on the \f$\pm x\f$-axis, where the sign depends on which side
61 : * of the singularity the point is on.
62 : *
63 : * A general Mobius transformation is a function on the complex plane, and
64 : * takes the form \f$ f(z) = \frac{az+b}{cz+d}\f$, where
65 : * \f$z, a, b, c, d \in \mathbb{C}\f$, and \f$ad-bc\neq 0\f$.
66 : *
67 : * The special case used in this map is the function
68 : * \f$ f(z) = \frac{z - \mu}{1 - z\mu}\f$. This has the desired properties:
69 : * - The unit disk in the complex plane is mapped to itself.
70 : *
71 : * - The x-axis is mapped to itself.
72 : *
73 : * - \f$f(\mu) = 0\f$.
74 : *
75 : * The three-dimensional version of this map is obtained by rotating the disk
76 : * in the plane about the x-axis.
77 : *
78 : * This map is useful for performing transformations along the x-axis
79 : * that preserve the unit disk. A concrete example of this is in the BBH
80 : * domain, where two BBHs with a center-of-mass at x=\f$\mu\f$ can be shifted
81 : * such that the new center of mass is now located at x=0. Additionally,
82 : * the spherical shape of the outer wave-zone is preserved and, as a mobius
83 : * map, the spherical coordinate shapes of the black holes is also preserved.
84 : */
85 1 : class SpecialMobius {
86 : public:
87 0 : static constexpr size_t dim = 3;
88 0 : explicit SpecialMobius(double mu);
89 0 : SpecialMobius() = default;
90 0 : ~SpecialMobius() = default;
91 0 : SpecialMobius(SpecialMobius&&) = default;
92 0 : SpecialMobius(const SpecialMobius&) = default;
93 0 : SpecialMobius& operator=(const SpecialMobius&) = default;
94 0 : SpecialMobius& operator=(SpecialMobius&&) = default;
95 :
96 : template <typename T>
97 0 : std::array<T, 3> operator()(const std::array<T, 3>& source_coords) const;
98 :
99 : /// Returns std::nullopt for target_coords outside the unit sphere.
100 : /// The inverse function is only callable with doubles because the inverse
101 : /// might fail if called for a point out of range, and it is unclear
102 : /// what should happen if the inverse were to succeed for some points in a
103 : /// DataVector but fail for other points.
104 1 : std::optional<std::array<double, 3>> inverse(
105 : const std::array<double, 3>& target_coords) const;
106 :
107 : template <typename T>
108 0 : tnsr::Ij<T, 3, Frame::NoFrame> jacobian(
109 : const std::array<T, 3>& source_coords) const;
110 :
111 : template <typename T>
112 0 : tnsr::Ij<T, 3, Frame::NoFrame> inv_jacobian(
113 : const std::array<T, 3>& source_coords) const;
114 :
115 : // NOLINTNEXTLINE(google-runtime-references)
116 0 : void pup(PUP::er& p);
117 :
118 0 : bool is_identity() const { return is_identity_; }
119 :
120 0 : static constexpr bool supports_hessian{true};
121 :
122 : private:
123 : template <typename T>
124 0 : std::array<T, 3> mobius_distortion(const std::array<T, 3>& coords,
125 : double mu) const;
126 : template <typename T>
127 0 : tnsr::Ij<T, 3, Frame::NoFrame> mobius_distortion_jacobian(
128 : const std::array<T, 3>& coords, double mu) const;
129 0 : friend bool operator==(const SpecialMobius& lhs, const SpecialMobius& rhs);
130 :
131 0 : double mu_{std::numeric_limits<double>::signaling_NaN()};
132 0 : bool is_identity_{false};
133 : };
134 0 : bool operator!=(const SpecialMobius& lhs, const SpecialMobius& rhs);
135 : } // namespace CoordinateMaps
136 : } // namespace domain
|