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 <string>
10 :
11 : #include "DataStructures/TaggedTuple.hpp"
12 : #include "DataStructures/Tensor/Tensor.hpp"
13 : #include "Options/Context.hpp"
14 : #include "Options/String.hpp"
15 : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp"
16 : #include "PointwiseFunctions/GeneralRelativity/TagsDeclarations.hpp"
17 : #include "Utilities/TMPL.hpp"
18 :
19 : /// \cond
20 : namespace PUP {
21 : class er;
22 : } // namespace PUP
23 : namespace Tags {
24 : template <typename Tag>
25 : struct dt;
26 : } // namespace Tags
27 : /// \endcond
28 :
29 : namespace gr::Solutions {
30 :
31 : /*!
32 : * \brief A perturbative Teukolsky wave (optionally plus Minkowski).
33 : *
34 : * \details This class provides a linearized \f$l=2\f$ Teukolsky wave in
35 : * Cartesian inertial coordinates. The implementation evaluates the spherical
36 : * formulas point-by-point and then transforms to Cartesian coordinates.
37 : *
38 : * This solution does not provide spatial derivatives of the metric, so it
39 : * does not support the full tag list of a typical GR analytic solution.
40 : *
41 : * See Eqs. (5) -- (10) of \cite Teukolsky1982nz for the equations in
42 : * spherical coordinates of the perturbed metric implemented here. Those
43 : * equations contain a freely specifiable radial profile; this implementation
44 : * chooses a Gaussian in \f$r - R_0 \pm t\f$, where \f$R_0\f$ is the
45 : * `Radius` parameter, with `Width` setting the pulse width.
46 : *
47 : * \note The implementation evaluates spherical-coordinate expressions, so it
48 : * must not be used too close to the origin about `Center`, where those
49 : * coordinates are singular. Specifically, evaluating the solution at points
50 : * with \f$r \le 0.1\f$, where \f$r\f$ is the distance from `Center`,
51 : * triggers an error. This cutoff is unrelated to the option `Radius`,
52 : * which sets the location of the Gaussian pulse.
53 : *
54 : * On the \f$z\f$-axis, the spherical coordinate \f$\phi\f$ is not well
55 : * defined. The implementation here is based on an implementation in SpEC that
56 : * just assumed the solution is never evaluated on the axis. Here, the
57 : * z-axis singularity is handled explicitly: on the \f$z\f$-axis
58 : * (cylindrical radius \f$\rho = 0\f$), the Cartesian result is obtained by
59 : * averaging the smooth limit approached from two orthogonal transverse
60 : * directions, so the solution is regular there.
61 : *
62 : * Optionally, the solution can include a flat Minkowski background as well as
63 : * the metric perturbation. Note that the tags for the inverse spatial metric,
64 : * square root of the spatial metric determinant, and extrinsic curvature
65 : * require the flat background to be included. The background can be excluded
66 : * when one wants only the perturbation itself (e.g., to add it on top of a
67 : * different background, such as the metric of a Kerr-Schild black hole).
68 : */
69 1 : class TeukolskyWave : public MarkAsAnalyticSolution {
70 : public:
71 0 : static constexpr size_t volume_dim = 3;
72 :
73 0 : struct Amplitude {
74 0 : using type = double;
75 0 : static constexpr Options::String help{"Amplitude of the perturbation"};
76 : };
77 :
78 0 : struct Mode {
79 0 : using type = int;
80 0 : static constexpr Options::String help{
81 : "Azimuthal mode m of the l=2 Teukolsky wave"};
82 0 : static type lower_bound() { return -2; }
83 0 : static type upper_bound() { return 2; }
84 : };
85 :
86 0 : struct Parity {
87 0 : using type = std::string;
88 0 : static constexpr Options::String help{
89 : "Parity of the perturbation: 'even' or 'odd'"};
90 : };
91 :
92 0 : struct Direction {
93 0 : using type = std::string;
94 0 : static constexpr Options::String help{
95 : "Propagation direction: 'outgoing' or 'ingoing'"};
96 : };
97 :
98 0 : struct Center {
99 0 : using type = std::array<double, 3>;
100 0 : static constexpr Options::String help{
101 : "Center of the Teukolsky wave in inertial coordinates"};
102 : };
103 :
104 0 : struct Radius {
105 0 : using type = double;
106 0 : static constexpr Options::String help{
107 : "Radius of the center of the Gaussian pulse at t=0"};
108 : };
109 :
110 0 : struct Width {
111 0 : using type = double;
112 0 : static constexpr Options::String help{
113 : "Width of the Gaussian pulse profile"};
114 0 : static type lower_bound() { return 0.0; }
115 : };
116 :
117 0 : using options =
118 : tmpl::list<Amplitude, Mode, Parity, Direction, Center, Radius, Width>;
119 0 : static constexpr Options::String help{
120 : "A perturbative Teukolsky wave in Cartesian inertial coordinates"};
121 :
122 : template <typename DataType>
123 0 : using tags = tmpl::list<
124 : gr::Tags::Lapse<DataType>, ::Tags::dt<gr::Tags::Lapse<DataType>>,
125 : gr::Tags::Shift<DataType, volume_dim, Frame::Inertial>,
126 : ::Tags::dt<gr::Tags::Shift<DataType, volume_dim, Frame::Inertial>>,
127 : gr::Tags::SpatialMetric<DataType, volume_dim, Frame::Inertial>,
128 : ::Tags::dt<
129 : gr::Tags::SpatialMetric<DataType, volume_dim, Frame::Inertial>>,
130 : gr::Tags::SqrtDetSpatialMetric<DataType>,
131 : gr::Tags::ExtrinsicCurvature<DataType, volume_dim, Frame::Inertial>,
132 : gr::Tags::InverseSpatialMetric<DataType, volume_dim, Frame::Inertial>>;
133 :
134 0 : TeukolskyWave(double amplitude, int mode, std::string parity,
135 : std::string direction, std::array<double, 3> center,
136 : double radius, double width,
137 : const Options::Context& context = {});
138 :
139 0 : TeukolskyWave(double amplitude, int mode, std::string parity,
140 : std::string direction, std::array<double, 3> center,
141 : double radius, double width, bool include_minkowski_background,
142 : const Options::Context& context = {});
143 :
144 0 : TeukolskyWave() = default;
145 0 : TeukolskyWave(const TeukolskyWave& /*rhs*/) = default;
146 0 : TeukolskyWave& operator=(const TeukolskyWave& /*rhs*/) = default;
147 0 : TeukolskyWave(TeukolskyWave&& /*rhs*/) = default;
148 0 : TeukolskyWave& operator=(TeukolskyWave&& /*rhs*/) = default;
149 0 : ~TeukolskyWave() = default;
150 :
151 0 : explicit TeukolskyWave(CkMigrateMessage* /*msg*/);
152 :
153 : template <typename DataType, typename... RequestedTags>
154 0 : tuples::TaggedTuple<RequestedTags...> variables(
155 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
156 : tmpl::list<RequestedTags...> /*meta*/) const {
157 : static_assert(tmpl2::flat_all_v<
158 : tmpl::list_contains_v<tags<DataType>, RequestedTags>...>,
159 : "At least one of the requested tags is not supported.");
160 : return {
161 : get<RequestedTags>(variables(x, t, tmpl::list<RequestedTags>{}))...};
162 : }
163 :
164 : template <typename RequestedTag, typename DataType>
165 0 : tuples::TaggedTuple<RequestedTag> variable(
166 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x,
167 : const double t) const {
168 : return variables(x, t, tmpl::list<RequestedTag>{});
169 : }
170 :
171 : // NOLINTNEXTLINE(google-runtime-references)
172 0 : void pup(PUP::er& p);
173 :
174 0 : double amplitude() const { return amplitude_; }
175 0 : int mode() const { return mode_; }
176 0 : const std::string& parity() const { return parity_; }
177 0 : const std::string& direction() const { return direction_; }
178 0 : const std::array<double, 3>& center() const { return center_; }
179 0 : double radius() const { return radius_; }
180 0 : double width() const { return width_; }
181 0 : bool include_minkowski_background() const {
182 : return include_minkowski_background_;
183 : }
184 :
185 : private:
186 : template <typename DataType>
187 0 : auto variables(const tnsr::I<DataType, volume_dim, Frame::Inertial>& x,
188 : double t, tmpl::list<gr::Tags::Lapse<DataType>> /*meta*/) const
189 : -> tuples::TaggedTuple<gr::Tags::Lapse<DataType>>;
190 :
191 : template <typename DataType>
192 0 : auto variables(
193 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
194 : tmpl::list<::Tags::dt<gr::Tags::Lapse<DataType>>> /*meta*/) const
195 : -> tuples::TaggedTuple<::Tags::dt<gr::Tags::Lapse<DataType>>>;
196 :
197 : template <typename DataType>
198 0 : auto variables(
199 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
200 : tmpl::list<gr::Tags::Shift<DataType, volume_dim, Frame::Inertial>>
201 : /*meta*/) const
202 : -> tuples::TaggedTuple<
203 : gr::Tags::Shift<DataType, volume_dim, Frame::Inertial>>;
204 :
205 : template <typename DataType>
206 0 : auto variables(const tnsr::I<DataType, volume_dim, Frame::Inertial>& x,
207 : double t,
208 : tmpl::list<::Tags::dt<gr::Tags::Shift<
209 : DataType, volume_dim, Frame::Inertial>>> /*meta*/) const
210 : -> tuples::TaggedTuple<
211 : ::Tags::dt<gr::Tags::Shift<DataType, volume_dim, Frame::Inertial>>>;
212 :
213 : template <typename DataType>
214 0 : auto variables(const tnsr::I<DataType, volume_dim, Frame::Inertial>& x,
215 : double t,
216 : tmpl::list<gr::Tags::SpatialMetric<
217 : DataType, volume_dim, Frame::Inertial>> /*meta*/) const
218 : -> tuples::TaggedTuple<
219 : gr::Tags::SpatialMetric<DataType, volume_dim, Frame::Inertial>>;
220 :
221 : template <typename DataType>
222 0 : auto variables(
223 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
224 : tmpl::list<::Tags::dt<
225 : gr::Tags::SpatialMetric<DataType, volume_dim, Frame::Inertial>>>
226 : /*meta*/) const
227 : -> tuples::TaggedTuple<::Tags::dt<
228 : gr::Tags::SpatialMetric<DataType, volume_dim, Frame::Inertial>>>;
229 :
230 : template <typename DataType>
231 0 : auto variables(
232 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
233 : tmpl::list<gr::Tags::SqrtDetSpatialMetric<DataType>> /*meta*/) const
234 : -> tuples::TaggedTuple<gr::Tags::SqrtDetSpatialMetric<DataType>>;
235 :
236 : template <typename DataType>
237 0 : auto variables(
238 : const tnsr::I<DataType, volume_dim, Frame::Inertial>& x, double t,
239 : tmpl::list<
240 : gr::Tags::ExtrinsicCurvature<DataType, volume_dim, Frame::Inertial>>
241 : /*meta*/) const
242 : -> tuples::TaggedTuple<
243 : gr::Tags::ExtrinsicCurvature<DataType, volume_dim, Frame::Inertial>>;
244 :
245 : template <typename DataType>
246 0 : auto variables(const tnsr::I<DataType, volume_dim, Frame::Inertial>& x,
247 : double t,
248 : tmpl::list<gr::Tags::InverseSpatialMetric<
249 : DataType, volume_dim, Frame::Inertial>> /*meta*/) const
250 : -> tuples::TaggedTuple<gr::Tags::InverseSpatialMetric<
251 : DataType, volume_dim, Frame::Inertial>>;
252 :
253 0 : double amplitude_{std::numeric_limits<double>::signaling_NaN()};
254 0 : int mode_{0};
255 0 : std::string parity_{};
256 0 : std::string direction_{};
257 0 : std::array<double, 3> center_{};
258 0 : double radius_{std::numeric_limits<double>::signaling_NaN()};
259 0 : double width_{std::numeric_limits<double>::signaling_NaN()};
260 0 : bool include_minkowski_background_{false};
261 : };
262 :
263 0 : bool operator==(const TeukolskyWave& lhs, const TeukolskyWave& rhs);
264 0 : bool operator!=(const TeukolskyWave& lhs, const TeukolskyWave& rhs);
265 :
266 : } // namespace gr::Solutions
|