SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Systems/Cce/AnalyticSolutions - TeukolskyWave.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 16.7 % 42 7
Test Date: 2026-10-22 17:29:42
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 <complex>
       7              : #include <cstddef>
       8              : #include <limits>
       9              : #include <memory>
      10              : 
      11              : #include "DataStructures/DataBox/Prefixes.hpp"
      12              : #include "DataStructures/SpinWeighted.hpp"
      13              : #include "DataStructures/Tensor/Tensor.hpp"
      14              : #include "Evolution/Systems/Cce/AnalyticSolutions/SphericalMetricData.hpp"
      15              : #include "Evolution/Systems/Cce/AnalyticSolutions/WorldtubeData.hpp"
      16              : #include "Evolution/Systems/Cce/Tags.hpp"
      17              : #include "Options/String.hpp"
      18              : #include "Utilities/Gsl.hpp"
      19              : #include "Utilities/Serialization/CharmPupable.hpp"
      20              : #include "Utilities/TMPL.hpp"
      21              : 
      22              : /// \cond
      23              : class DataVector;
      24              : class ComplexDataVector;
      25              : /// \endcond
      26              : 
      27              : namespace Cce {
      28              : namespace Solutions {
      29              : 
      30              : /*!
      31              :  * \brief Computes the analytic data for a Teukolsky wave solution described in
      32              :  * \cite Barkett2019uae.
      33              :  *
      34              :  * \details This test computes an outgoing perturbative wave solution in
      35              :  * spherical coordinates with wave profile
      36              :  *
      37              :  * \f[
      38              :  * F(u) = A e^{- u^2 / k^2}.
      39              :  * \f]
      40              :  */
      41            1 : struct TeukolskyWave : public SphericalMetricData {
      42            0 :   struct ExtractionRadius {
      43            0 :     using type = double;
      44            0 :     static constexpr Options::String help{
      45              :         "The extraction radius of the spherical solution"};
      46            0 :     static type lower_bound() { return 0.0; }
      47              :   };
      48            0 :   struct Amplitude {
      49            0 :     using type = double;
      50            0 :     static constexpr Options::String help{
      51              :         "The amplitude of the Teukolsky wave."};
      52            0 :     static type lower_bound() { return 0.0; }
      53              :   };
      54            0 :   struct Duration {
      55            0 :     using type = double;
      56            0 :     static constexpr Options::String help{
      57              :         "The characteristic duration of the Gaussian envelope."};
      58            0 :     static type lower_bound() { return 0.0; }
      59              :   };
      60              : 
      61            0 :   static constexpr Options::String help{
      62              :       "An analytic solution derived from the linearized Teukolsky equation"};
      63              : 
      64            0 :   using options = tmpl::list<ExtractionRadius, Amplitude, Duration>;
      65              : 
      66            0 :   WRAPPED_PUPable_decl_template(TeukolskyWave);  // NOLINT
      67              : 
      68            0 :   explicit TeukolskyWave(CkMigrateMessage* msg) : SphericalMetricData(msg) {}
      69              : 
      70              :   // clang doesn't manage to use = default correctly in this case
      71              :   // NOLINTNEXTLINE(modernize-use-equals-default)
      72            0 :   TeukolskyWave() {}
      73              : 
      74            0 :   TeukolskyWave(double extraction_radius, double amplitude, double duration);
      75              : 
      76            0 :   std::unique_ptr<WorldtubeData> get_clone() const override;
      77              : 
      78            0 :   void pup(PUP::er& p) override;
      79              : 
      80              :  private:
      81              :   /*
      82              :    * The A coefficient is calculated as
      83              :    *
      84              :    * \f[
      85              :    * A = 3 (3 k^4 + 4 r^2 u^2 - 2 k^2 r^2 (r + 3 u)) a e^{-u^2/k^2} / (k^4 r^5)
      86              :    * \f]
      87              :    *
      88              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
      89              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
      90              :    */
      91            0 :   double pulse_profile_coefficient_a(double time) const;
      92              : 
      93              :   /*
      94              :    * The B coefficient is calculated as
      95              :    *
      96              :    * \f[
      97              :    * B = 2 (-3 k^6 + 4 r^4 u^3 - 6 k^2 r^3 u (r + u) + 3 k^4 r^2 (r + 2 u))
      98              :    *  * a e^{-u^2/k^2} / (k^6 r^6)
      99              :    * \f]
     100              :    *
     101              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     102              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     103              :    */
     104            0 :   double pulse_profile_coefficient_b(double time) const;
     105              : 
     106              :   /*
     107              :    * The C coefficient is calculated as
     108              :    *
     109              :    * \f[
     110              :    * C = (1/4) (21 k^8 + 16 r^4 u^4 - 16 k^2 r^3 u^2 (3 r + u)
     111              :    * - 6 k^6 r (3 r + 7 u) + 12 k^4 r^2 (r^2 + 2 r u + 3 u^2))
     112              :    *  * a e^{-u^2/k^2} / (k^8 r^5)
     113              :    * \f]
     114              :    *
     115              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     116              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     117              :    */
     118            0 :   double pulse_profile_coefficient_c(double time) const;
     119              : 
     120              :   /*
     121              :    * The time derivative of the A coefficient is calculated as
     122              :    *
     123              :    * \f[
     124              :    * \partial_t A = -6 (4 r^2 u^3 + 3 k^4 (r + u) - 6 k^2 r u (r + u))
     125              :    *  a e^{-u^2/k^2} / (k^6 r^5)
     126              :    * \f]
     127              :    *
     128              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     129              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     130              :    */
     131            0 :   double dt_pulse_profile_coefficient_a(double time) const;
     132              : 
     133              :   /*
     134              :    * The time derivative of the B coefficient is calculated as
     135              :    *
     136              :    * \f[
     137              :    * \partial_t B = 4 (-4 r^4 u^4 + 6 k ^2 r^3 u^2 (2 r + u)
     138              :    * + 3 k^6 (r^2 + u) - 3 k^4 r^2 (r + u) (r + 2u))
     139              :    *  a e^{-u^2/k^2} / (k^8 r^6)
     140              :    * \f]
     141              :    *
     142              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     143              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     144              :    */
     145            0 :   double dt_pulse_profile_coefficient_b(double time) const;
     146              : 
     147              :   /*
     148              :    * The time derivative of the C coefficient is calculated as
     149              :    *
     150              :    * \f[
     151              :    * \partial_t C = (1/2) (-16 r^4 u^5 - 21 k^8 (r + u)
     152              :    * + 16 k^2 r^3 u^3 (5 r + u) + 6 k^6 r (r + u) (2 r + 7 u)
     153              :    * - 12 k^4 r^2 u (4 r^2 + 4 r u + 3 u^2))
     154              :    *  a e^{-u^2/k^2} / (k^10 r^5)
     155              :    * \f]
     156              :    *
     157              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     158              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     159              :    */
     160            0 :   double dt_pulse_profile_coefficient_c(double time) const;
     161              : 
     162              :   /*
     163              :    * The radial derivative of the A coefficient is calculated as
     164              :    *
     165              :    * \f[
     166              :    * \partial_r A + \partial_t A = - 9 (5 k^4 + 4 r^2 u^2 - 2 k^2 r (r + 4 u))
     167              :    * a e^{-u^2/k^2} / (k^4 r^6)
     168              :    * \f]
     169              :    *
     170              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     171              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     172              :    */
     173            0 :   double dr_pulse_profile_coefficient_a(double time) const;
     174              : 
     175              :   /*
     176              :    * The radial derivative of the B coefficient is calculated as
     177              :    *
     178              :    * \f[
     179              :    * \partial_r B + \partial_t B  = 2 (18 k^6 - 8 r^4 u^3 + 6 k^2 r^3 u (2 r + 3
     180              :    * u)
     181              :    * - 3 k^4 r^2 (3 r + 8 u)) a e^{-u^2/k^2} / (k^6 r^7)
     182              :    * \f]
     183              :    *
     184              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     185              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     186              :    */
     187            0 :   double dr_pulse_profile_coefficient_b(double time) const;
     188              : 
     189              :   /*
     190              :    * The radial derivative of the C coefficient is calculated as
     191              :    *
     192              :    * \f[
     193              :    * \partial_r C + \partial_t C  = -(1/4) (105 * k^8 + 16 r^4 u^4
     194              :    * - 16 k^2 r^3 u^2 (3 r + 2 u) - 6 k^6 r (9 r + 28 u)
     195              :    * + 12 k^4 r^2 (r^2 + 4 r u + 9 u^2))
     196              :    *  a e^{-u^2/k^2} / (k^8 r^6)
     197              :    * \f]
     198              :    *
     199              :    * where \f$r\f$ is the extraction radius, \f$u\f$ the retarded time, \f$a\f$
     200              :    * the amplitude of the pulse and \f$k\f$ the duration of the pulse.
     201              :    */
     202            0 :   double dr_pulse_profile_coefficient_c(double time) const;
     203              : 
     204            0 :   static DataVector sin_theta(size_t l_max);
     205              : 
     206            0 :   static DataVector cos_theta(size_t l_max);
     207              : 
     208              :  protected:
     209              :   /// A no-op as the Teukolsky wave solution does not have substantial
     210              :   /// shared computation to prepare before the separate component calculations.
     211            1 :   void prepare_solution(const size_t /*output_l_max*/,
     212              :                         const double /*time*/) const override {}
     213              : 
     214              :   /*!
     215              :    * \brief Compute the spherical coordinate metric from the closed-form
     216              :    * perturbative Teukolsky wave metric.
     217              :    *
     218              :    * \details The specific outgoing wave selected in this analytic solution is
     219              :    * constructed from a (2,0) mode as in \cite Barkett2019uae, and takes the
     220              :    * form
     221              :    *
     222              :    * \f{align*}{
     223              :    * g_{tt} &= -1\\
     224              :    * g_{rr} &= (1 + A f_{rr}) \\
     225              :    * g_{r \theta} &= 2 B f_{r \theta} r\\
     226              :    * g_{\theta \theta} &= (1 + C f_{\theta \theta}^{(C)}
     227              :    * + A f_{\theta \theta}^{(A)}) r^2\\
     228              :    * g_{\phi \phi} &= (1 + C f_{\phi \phi}^{(C)}
     229              :    * + A f_{\phi \phi}^{(A)}) r^2 \sin^2 \theta\\
     230              :    * \f}
     231              :    *
     232              :    * and all other components vanish. The angular factors generated by the
     233              :    * choice of spin-weighted spherical harmonic are
     234              :    *
     235              :    * \f{align*}{
     236              :    * f_{rr} &= 2 - 3 \sin^2 \theta \\
     237              :    * f_{r \theta} &=  -3 \sin \theta \cos \theta \\
     238              :    * f_{\theta \theta}^{(C)} &= 3 \sin^2 \theta \\
     239              :    * f_{\theta \theta}^{(A)} &= -1 \\
     240              :    * f_{\phi \phi}^{(C)} &= - 3 \sin^2 \theta \\
     241              :    * f_{\phi \phi}^{(A)} &= 3 \sin^2 \theta -1,
     242              :    * \f}
     243              :    *
     244              :    * the radial and time dependent factors are
     245              :    *
     246              :    * \f{align*}{
     247              :    * A &= 3 \left(\frac{\partial_u^2 F(u)}{r^3}
     248              :    * + \frac{3 \partial_u F(u)}{r^4} + \frac{3 F(u)}{r^5} \right),\\
     249              :    * B &= - \left(\frac{\partial_u^3 F(u)}{r^2}
     250              :    * + \frac{3 \partial_u^2 F(u)}{r^3} + \frac{6 \partial_uF(u)}{r^4}
     251              :    * + \frac{6 F(u)}{r^5}\right), \\
     252              :    * C &= \frac{1}{4} \left(\frac{\partial_u^4 F(u)}{r}
     253              :    * + \frac{2 \partial_u^3 F(u)}{r^2} + \frac{9 \partial_u^2 F(u)}{r^3}
     254              :    * + \frac{21 \partial_u F(u)}{r^4} + \frac{21 F(u)}{r}\right),
     255              :    * \f}
     256              :    *
     257              :    * and the pulse profile is
     258              :    *
     259              :    * \f[
     260              :    * F(u) = a e^{-u^2 /k^2}.
     261              :    * \f]
     262              :    *
     263              :    * So, the pulse profile factors expand to
     264              :    *
     265              :    * \f{align*}{
     266              :    * A &= \frac{3 a e^{-u^2/k^2}}{k^4 r^5} \left(3 k^4 + 4 r^2 u^2
     267              :    * - 2 k^2 r (r + 3 u)\right),\\
     268              :    * B &= \frac{2 a e^{-u^2/k^2}}{k^6 r^5} \left(-3 k^6 + 4 r^3 u^3
     269              :    * - 6 k^2 r^2 u (r + u) + 3 k^4 r (r + 2 u)\right), \\
     270              :    * C &= \frac{a e^{-u^2/k^2}}{4 k^8 r^5} \left(21 k^8 + 16 r^4 u^4
     271              :    * - 16 k^2 r^3 u^2 (3 r + u) - 6 k^6 r (3 r + 7 u)
     272              :    * + 12 k^4 r^2 (r^2 + 2 r u + 3 u^2)\right),
     273              :    * \f}
     274              :    *
     275              :    * \note The \f$\phi\f$ components are returned in a form for which the
     276              :    * \f$\sin(\theta)\f$ factors are omitted, assuming that derivatives and
     277              :    * Jacobians will be applied similarly omitting those factors (and therefore
     278              :    * improving precision of the tensor expression). If you require the
     279              :    * \f$\sin(\theta)\f$ factors, be sure to put them in by hand in the calling
     280              :    * code.
     281              :    */
     282            1 :   void spherical_metric(
     283              :       gsl::not_null<
     284              :           tnsr::aa<DataVector, 3, ::Frame::Spherical<::Frame::Inertial>>*>
     285              :           spherical_metric,
     286              :       size_t l_max, double time) const override;
     287              : 
     288              :   /*!
     289              :    * \brief Compute the radial derivative of the spherical coordinate metric
     290              :    * from the closed-form perturbative Teukolsky wave metric.
     291              :    *
     292              :    * \details The specific outgoing wave selected in this analytic solution is
     293              :    * constructed from a (2,0) mode as in \cite Barkett2019uae, and takes the
     294              :    * form
     295              :    *
     296              :    * \f{align*}{
     297              :    * \partial_r g_{rr} &= f_{r r} \partial_r A \\
     298              :    * \partial_r g_{r \theta} &= f_{r \theta} (B + r \partial_r B)\\
     299              :    * \partial_r g_{\theta \theta} &= 2 (1 + C f_{\theta \theta}^{(C)}
     300              :    * + A f_{\theta \theta}^{(A)}) r
     301              :    * + (\partial_r C f_{\theta \theta}^{(C)}
     302              :    * + \partial_r A f_{\theta \theta}^{(A)}) r^2 \\
     303              :    * \partial_r g_{\phi \phi} &= 2 (1 + C f_{\phi \phi}^{(C)}
     304              :    * + A f_{\phi \phi}^{(A)}) r \sin^2 \theta
     305              :    * + (\partial_r C f_{\phi \phi}^{(C)}
     306              :    * + \partial_r A f_{\phi \phi}^{(A)}) r^2 \sin^2 \theta\\
     307              :    * \f}
     308              :    *
     309              :    * and all other components vanish. The angular factors \f$f_{a b}\f$ and the
     310              :    * metric component functions \f$A, B,\f$ and \f$C\f$ are defined as in
     311              :    * `TeukolskyWave::spherical_metric()`.
     312              :    * The radial derivatives of the pulse profile functions are obtained by:
     313              :    *
     314              :    * \f{align*}{
     315              :    * \partial_r A + \partial_t A &= \frac{-9 a e^{-u^2/k^2}}{k^4 r^6} \left(
     316              :    *  5 k^4 + 4 r^2 u^2 - 2 k^2 r (r + 4 u)\right), \\
     317              :    * \partial_r B + \partial_t B &= \frac{2 a e^{-u^2/k^2}}{k^6 r^6} \left(
     318              :    *  15 k^6 - 8 r^3 u^3 + 6 k^2 r^2 u (2 r + 3 u)
     319              :    *  - 3 k^4 r (3 r + 8 u)\right), \\
     320              :    * \partial_r C + \partial_t C &= \frac{-a e^{-u^2/k^2}}{4 k^8 r^6} \left(
     321              :    *  105 k^8 + 16 k^4 u^4 - 16 k^2 r^3 u^2 (3 r + 2 u) - 6 k^6 r (9 r + 28 u)
     322              :    *  + 12 k^4 r^2 (r^2 + 4 r u + 9 u^2)\right),
     323              :    * \f}
     324              :    *
     325              :    * and the time derivatives of the pulse profile functions are given in
     326              :    * `TeukolskyWave::dt_spherical_metric()`.
     327              :    *
     328              :    * \note The \f$\phi\f$ components are returned in a form for which the
     329              :    * \f$\sin(\theta)\f$ factors are omitted, assuming that derivatives and
     330              :    * Jacobians will be applied similarly omitting those factors (and therefore
     331              :    * improving precision of the tensor expression). If you require the
     332              :    * \f$\sin(\theta)\f$ factors, be sure to put them in by hand in the calling
     333              :    * code.
     334              :    */
     335            1 :   void dr_spherical_metric(
     336              :       gsl::not_null<
     337              :           tnsr::aa<DataVector, 3, ::Frame::Spherical<::Frame::Inertial>>*>
     338              :           dr_spherical_metric,
     339              :       size_t l_max, double time) const override;
     340              : 
     341              :   /*!
     342              :    * \brief Compute the time derivative of the spherical coordinate metric
     343              :    * from the closed-form perturbative Teukolsky wave metric.
     344              :    *
     345              :    * \details The specific outgoing wave selected in this analytic solution is
     346              :    * constructed from a (2,0) mode as in \cite Barkett2019uae, and takes the
     347              :    * form
     348              :    *
     349              :    * \f{align*}{
     350              :    * \partial_t g_{rr} &= f_{r r} \partial_t A \\
     351              :    * \partial_t g_{r \theta} &= f_{r \theta} r \partial_t B\\
     352              :    * \partial_t g_{\theta \theta} &=
     353              :    * (\partial_t C f_{\theta \theta}^{(C)}
     354              :    * + \partial_t A f_{\theta \theta}^{(A)}) r^2 \\
     355              :    * \partial_t g_{\phi \phi} &= (\partial_t C f_{\phi \phi}^{(C)}
     356              :    * + \partial_t A f_{\phi \phi}^{(A)}) r^2 \sin^2 \theta\\
     357              :    * \f}
     358              :    *
     359              :    * and all other components vanish. The angular factors \f$f_{a b}\f$ and the
     360              :    * metric component functions \f$A, B,\f$ and \f$C\f$ are defined as in
     361              :    * `TeukolskyWave::spherical_metric()`.
     362              :    * The time derivatives of the pulse profile functions are:
     363              :    *
     364              :    * \f{align*}{
     365              :    * \partial_t A &=  \frac{-2 u}{k^2} A + \frac{3 a e^{-u^2/k^2}}{k^4 r^5}
     366              :    *  \left( 8 r^2 u - 6 k^2 r \right), \\
     367              :    * \partial_t B &= \frac{-2 u}{k^2} B + \frac{2 a e^{-u^2/k^2}}{k^6 r^5}
     368              :    *  \left(12 r^3 u^2 - 6 k^2 r^2 (r + 2 u) + 6 k^4 r\right), \\
     369              :    * \partial_t C &= \frac{-2 u}{k^2} C + \frac{-a e^{-u^2/k^2}}{4 k^8 r^5}
     370              :    * \left(64 k^4 u^3 - 16 k^2 r^3 u (6 r +  3 u) - 42 k^6 r
     371              :    *  + 12 k^4 r^2 (2 r + 6 u)\right),
     372              :    * \f}
     373              :    *
     374              :    * \note The \f$\phi\f$ components are returned in a form for which the
     375              :    * \f$\sin(\theta)\f$ factors are omitted, assuming that derivatives and
     376              :    * Jacobians will be applied similarly omitting those factors (and therefore
     377              :    * improving precision of the tensor expression). If you require the
     378              :    * \f$\sin(\theta)\f$ factors, be sure to put them in by hand in the calling
     379              :    * code.
     380              :    */
     381            1 :   void dt_spherical_metric(
     382              :       gsl::not_null<
     383              :           tnsr::aa<DataVector, 3, ::Frame::Spherical<::Frame::Inertial>>*>
     384              :           dt_spherical_metric,
     385              :       size_t l_max, double time) const override;
     386              : 
     387            0 :   using WorldtubeData::variables_impl;
     388              : 
     389            1 :   using SphericalMetricData::variables_impl;
     390              : 
     391              :   /*!
     392              :    * \brief Compute the news associated with the (2,0)-mode Teukolsky wave.
     393              :    *
     394              :    * \details The value of the news is
     395              :    *
     396              :    * \f{align*}{
     397              :    * N = \frac{3 \sin^2 \theta}{4} \partial_u^5 F(u)
     398              :    * \f}
     399              :    *
     400              :    * where \f$F(u)\f$ is the pulse profile, taken to be
     401              :    *
     402              :    * \f[
     403              :    * F(u) = a e^{-u^2 /k^2},
     404              :    * \f]
     405              :    *
     406              :    * So, the news expands to
     407              :    *
     408              :    * \f[
     409              :    * N = -\frac{6 a e^{-u^2/k^2} u}{k^{10}} \left(15 k^4 - 20 k^2 u^2
     410              :    * + 4 u^4\right)
     411              :    * \f]
     412              :    *
     413              :    * in this analytic solution.
     414              :    */
     415            1 :   void variables_impl(
     416              :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, -2>>*> news,
     417              :       size_t l_max, double time,
     418              :       tmpl::type_<Tags::News> /*meta*/) const override;
     419              : 
     420            0 :   double amplitude_ = std::numeric_limits<double>::signaling_NaN();
     421            0 :   double duration_ = std::numeric_limits<double>::signaling_NaN();
     422              : };
     423              : }  // namespace Solutions
     424              : }  // namespace Cce
        

Generated by: LCOV version 2.0-1