SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/AnalyticData/SelfForce/Scalar - CircularOrbit.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 1 49 2.0 %
Date: 2025-12-05 05:03:31
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 <array>
       7             : #include <cstddef>
       8             : #include <limits>
       9             : #include <optional>
      10             : #include <pup.h>
      11             : #include <vector>
      12             : 
      13             : #include "DataStructures/DataBox/Prefixes.hpp"
      14             : #include "DataStructures/Tensor/Tensor.hpp"
      15             : #include "Elliptic/Systems/SelfForce/Scalar/Tags.hpp"
      16             : #include "NumericalAlgorithms/LinearOperators/PartialDerivatives.hpp"
      17             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      18             : #include "Options/Auto.hpp"
      19             : #include "Options/String.hpp"
      20             : #include "PointwiseFunctions/InitialDataUtilities/Background.hpp"
      21             : #include "PointwiseFunctions/InitialDataUtilities/InitialGuess.hpp"
      22             : #include "Utilities/Gsl.hpp"
      23             : #include "Utilities/TMPL.hpp"
      24             : #include "Utilities/TaggedTuple.hpp"
      25             : 
      26           0 : namespace ScalarSelfForce::AnalyticData {
      27             : 
      28             : /*!
      29             :  * \brief Scalar self force for a scalar charge on a circular equatorial orbit.
      30             :  *
      31             :  * This class implements Eq. (2.9) in \cite Osburn:2022bby . It does so by
      32             :  * defining the background fields $\alpha$, $\beta$, and $\gamma_i$ in the
      33             :  * general form of the equations
      34             :  * \begin{equation}
      35             :  * -\partial_i F^i + \beta \Psi_m + \gamma_i F^i = S_m
      36             :  * \text{.}
      37             :  * \end{equation}
      38             :  * with the flux
      39             :  * \begin{equation}
      40             :  * F^i = \{\partial_{r_\star}, \alpha \partial_{\cos\theta}\} \Psi_m
      41             :  * \text{.}
      42             :  * \end{equation}
      43             :  * Note that we use $\cos\theta$ as angular coordinate but \cite Osburn:2022bby
      44             :  * uses $\theta$. We also multiply Eq. (2.9) by the factor $\Sigma^2 / (r^2 +
      45             :  * a^2)^2$ so we can easily write it in first-order flux form. The resulting
      46             :  * factors in the equation are:
      47             :  *
      48             :  * \begin{align}
      49             :  * &\alpha = \frac{\Delta}{(r^2 + a^2)^2} \sin^2\theta \\
      50             :  * &\beta = \left(-m^2\Omega^2 \Sigma^2 + 4a m^2 \Omega M r + \Delta \left[
      51             :  *   \frac{m^2}{\sin^2\theta} + \frac{2M}{r}(1-\frac{a^2}{Mr}) + \frac{2iam}{r}
      52             :  *   \right]\right) \frac{1}{(r^2 + a^2)^2} \\
      53             :  * &\gamma_{r_\star} = -\frac{2iam}{r^2+a^2} + \frac{2a^2}{r}
      54             :  *   \frac{\alpha}{\sin^2\theta} \\
      55             :  * &\gamma_{\cos\theta} = 0
      56             :  * \end{align}
      57             :  *
      58             :  * This class also provides the effective source $S_m^\mathrm{eff} = \Delta_m
      59             :  * \Psi_m^P$ and the singular field $\Psi_m^P$ in the regularized region (see
      60             :  * `ScalarSelfForce::FirstOrderSystem` and Sec. III in \cite Osburn:2022bby ).
      61             :  * The effective source is computed using the scalar EffectiveSource code by
      62             :  * Wardell et. al. (https://github.com/barrywardell/EffectiveSource and
      63             :  * \cite Wardell:2011gb ). It is then transformed to correspond to the m-mode
      64             :  * decomposition used in \cite Osburn:2022bby Eq. (2.8) as:
      65             :  * \begin{align}
      66             :  *   &\Psi_m^P = \frac{r}{2 \pi} e^{-i m \Delta\phi} \Phi_m^\mathrm{Wardell} \\
      67             :  *   &S_m^\mathrm{eff} = \frac{r}{2 \pi} e^{-i m \Delta\phi}
      68             :  *     \frac{\Delta\,(r^2 + a^2\cos^2\theta)}{(r^2 + a^2)^2}
      69             :  *     S_m^\mathrm{Wardell}
      70             :  *   \text{,}
      71             :  * \end{align}
      72             :  * where $\Delta\phi = \frac{a}{r_+ - r_-} \ln(\frac{r-r_+}{r-r_-})$ (Eq. (2.7)
      73             :  * in \cite Osburn:2022bby ).
      74             :  *
      75             :  * \par Hyperboloidal slicing
      76             :  * Transforming to a hyperboloidal time coordinate $s = t - h(r_*)$ can simplify
      77             :  * the solution a lot because the slice will only intersect a finite number of
      78             :  * wave fronts. In frequency domain this transformation means that partial
      79             :  * derivatives transform as:
      80             :  * \begin{align}
      81             :  *   &\partial_{r_*} \rightarrow \partial_{r_*} + i m\Omega H(r_*) \\
      82             :  *   &\partial_{r_*}^2 \rightarrow \partial_{r_*}^2 +
      83             :  *     2 i m\Omega H(r_*) \partial_{r_*} + i m\Omega H'(r_*)
      84             :  *     -m^2\Omega^2 H(r_*)^2
      85             :  * \end{align}
      86             :  * where $H(r_*) = h'(r_*)$ is the boost function that asymptotes to
      87             :  * $H(r_* \rightarrow \pm \infty) = \pm 1$.
      88             :  * This maps to the following additional terms in $\beta$ and $\gamma_{r_*}$:
      89             :  * \begin{align}
      90             :  *   &\beta \rightarrow \beta + i m\Omega \gamma_{r_*} H(r_*)
      91             :  *     - i m\Omega H'(r_*) + m^2\Omega^2 H(r_*)^2 \\
      92             :  *   &\gamma_{r_*} \rightarrow \gamma_{r_*} - 2 i m\Omega H(r_*)
      93             :  * \end{align}
      94             :  * For the boost function we choose here a simple sigmoid so that it is exactly
      95             :  * zero in a finite region around the puncture where we apply the effective
      96             :  * source, and transitions to -1 and 1 outside of this region. We choose
      97             :  * the $C^1$ continuous `smoothstep<1>` for this. Reasonable transition points
      98             :  * are from the boundaries of the effective source region to about $20M$
      99             :  * away from it, though this hasn't been tested very much yet. We may also want
     100             :  * to try jumping from $H=0$ to $H=\pm 1$ discontinuously at the boundary of the
     101             :  * effective source region, which is supported by the DG scheme (see
     102             :  * `fluxes_computer::is_discontinuous` in
     103             :  * `elliptic::protocols::FirstOrderSystem`), so (1) we don't have to resolve the
     104             :  * transition, and (2) we can more easily support the 2nd order self-force
     105             :  * source.
     106             :  */
     107           1 : class CircularOrbit : public elliptic::analytic_data::Background,
     108             :                       public elliptic::analytic_data::InitialGuess {
     109             :  public:
     110           0 :   struct BlackHoleMass {
     111           0 :     static constexpr Options::String help =
     112             :         "Kerr mass parameter 'M' of the black hole";
     113           0 :     using type = double;
     114             :   };
     115           0 :   struct BlackHoleSpin {
     116           0 :     static constexpr Options::String help =
     117             :         "Kerr dimensionless spin parameter 'chi' of the black hole";
     118           0 :     using type = double;
     119             :   };
     120           0 :   struct OrbitalRadius {
     121           0 :     static constexpr Options::String help =
     122             :         "Radius 'r_0' of the circular orbit";
     123           0 :     using type = double;
     124             :   };
     125           0 :   struct MModeNumber {
     126           0 :     static constexpr Options::String help =
     127             :         "Mode number 'm' of the scalar field";
     128           0 :     using type = int;
     129             :   };
     130           0 :   struct HyperboloidalSlicingTransitions {
     131           0 :     static constexpr Options::String help =
     132             :         "Enable hyperboloidal slicing by specifying the transition points for "
     133             :         "the boost function. The boost function transitions from -1 to zero "
     134             :         "between the first two points and from zero to 1 between the last "
     135             :         "two points. The effective source can only be evaluated where the "
     136             :         "boost function is zero, so the regularized region must be between "
     137             :         "the second and third points.";
     138           0 :     using type = Options::Auto<std::array<double, 4>, Options::AutoLabel::None>;
     139             :   };
     140           0 :   using options = tmpl::list<BlackHoleMass, BlackHoleSpin, OrbitalRadius,
     141             :                              MModeNumber, HyperboloidalSlicingTransitions>;
     142           0 :   static constexpr Options::String help =
     143             :       "Quasicircular orbit of a scalar point charge in Kerr spacetime";
     144             : 
     145           0 :   CircularOrbit() = default;
     146           0 :   CircularOrbit(const CircularOrbit&) = default;
     147           0 :   CircularOrbit& operator=(const CircularOrbit&) = default;
     148           0 :   CircularOrbit(CircularOrbit&&) = default;
     149           0 :   CircularOrbit& operator=(CircularOrbit&&) = default;
     150           0 :   ~CircularOrbit() override = default;
     151             : 
     152           0 :   CircularOrbit(
     153             :       double black_hole_mass, double black_hole_spin, double orbital_radius,
     154             :       int m_mode_number,
     155             :       std::optional<std::array<double, 4>> hyperboloidal_slicing_transitions);
     156             : 
     157           0 :   explicit CircularOrbit(CkMigrateMessage* m);
     158             :   using PUP::able::register_constructor;
     159           0 :   WRAPPED_PUPable_decl_template(CircularOrbit);
     160             : 
     161           0 :   tnsr::I<double, 2> puncture_position() const;
     162           0 :   double black_hole_mass() const { return black_hole_mass_; }
     163           0 :   double black_hole_spin() const { return black_hole_spin_; }
     164           0 :   double orbital_radius() const { return orbital_radius_; }
     165           0 :   int m_mode_number() const { return m_mode_number_; }
     166           0 :   std::optional<std::array<double, 4>> hyperboloidal_slicing_transitions()
     167             :       const {
     168             :     return hyperboloidal_slicing_transitions_;
     169             :   }
     170             : 
     171           0 :   using background_tags = tmpl::list<Tags::Alpha, Tags::Beta, Tags::Gamma>;
     172           0 :   using source_tags = tmpl::list<
     173             :       ::Tags::FixedSource<Tags::MMode>, Tags::SingularField,
     174             :       ::Tags::deriv<Tags::SingularField, tmpl::size_t<2>, Frame::Inertial>,
     175             :       Tags::BoyerLindquistRadius>;
     176             : 
     177             :   // Background
     178           0 :   tuples::tagged_tuple_from_typelist<background_tags> variables(
     179             :       const tnsr::I<DataVector, 2>& x, background_tags /*meta*/) const;
     180             : 
     181             :   // Initial guess
     182           0 :   static tuples::TaggedTuple<Tags::MMode> variables(
     183             :       const tnsr::I<DataVector, 2>& x, tmpl::list<Tags::MMode> /*meta*/);
     184             : 
     185             :   // Fixed sources
     186           0 :   tuples::tagged_tuple_from_typelist<source_tags> variables(
     187             :       const tnsr::I<DataVector, 2>& x, source_tags /*meta*/) const;
     188             : 
     189             :   template <typename... RequestedTags>
     190           0 :   tuples::TaggedTuple<RequestedTags...> variables(
     191             :       const tnsr::I<DataVector, 2>& x, const Mesh<2>& /*mesh*/,
     192             :       const InverseJacobian<DataVector, 2, Frame::ElementLogical,
     193             :                             Frame::Inertial>& /*inv_jacobian*/,
     194             :       tmpl::list<RequestedTags...> /*meta*/) const {
     195             :     return variables(x, tmpl::list<RequestedTags...>{});
     196             :   }
     197             : 
     198             :   // NOLINTNEXTLINE
     199           0 :   void pup(PUP::er& p) override;
     200             : 
     201             :  private:
     202           0 :   friend bool operator==(const CircularOrbit& lhs, const CircularOrbit& rhs);
     203             : 
     204           0 :   double black_hole_mass_{std::numeric_limits<double>::signaling_NaN()};
     205           0 :   double black_hole_spin_{std::numeric_limits<double>::signaling_NaN()};
     206           0 :   double orbital_radius_{std::numeric_limits<double>::signaling_NaN()};
     207           0 :   int m_mode_number_{};
     208           0 :   std::optional<std::array<double, 4>> hyperboloidal_slicing_transitions_{};
     209             : };
     210             : 
     211           0 : bool operator!=(const CircularOrbit& lhs, const CircularOrbit& rhs);
     212             : 
     213             : }  // namespace ScalarSelfForce::AnalyticData

Generated by: LCOV version 1.14