SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/AnalyticData/GrMhd - MagnetizedFmDisk.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 6 44 13.6 %
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 <cstddef>
       7             : #include <limits>
       8             : 
       9             : #include "DataStructures/Tensor/TypeAliases.hpp"
      10             : #include "Options/String.hpp"
      11             : #include "PointwiseFunctions/AnalyticData/AnalyticData.hpp"
      12             : #include "PointwiseFunctions/AnalyticData/GrMhd/AnalyticData.hpp"
      13             : #include "PointwiseFunctions/AnalyticSolutions/RelativisticEuler/FishboneMoncriefDisk.hpp"
      14             : #include "PointwiseFunctions/GeneralRelativity/KerrSchildCoords.hpp"
      15             : #include "PointwiseFunctions/Hydro/EquationsOfState/PolytropicFluid.hpp"
      16             : #include "PointwiseFunctions/Hydro/TagsDeclarations.hpp"
      17             : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
      18             : #include "Utilities/Serialization/CharmPupable.hpp"
      19             : #include "Utilities/TMPL.hpp"
      20             : #include "Utilities/TaggedTuple.hpp"
      21             : 
      22             : /// \cond
      23             : namespace PUP {
      24             : class er;
      25             : }  // namespace PUP
      26             : /// \endcond
      27             : 
      28             : namespace grmhd::AnalyticData {
      29             : 
      30             : /*!
      31             :  * \brief Magnetized fluid disk orbiting a Kerr black hole.
      32             :  *
      33             :  * In the context of simulating accretion disks, this class implements a widely
      34             :  * used (e.g. \cite Gammie2003, \cite Porth2016rfi, \cite White2015omx)
      35             :  * initial setup for the GRMHD variables, consisting of a Fishbone-Moncrief disk
      36             :  * \cite Fishbone1976apj (see also
      37             :  * RelativisticEuler::Solutions::FishboneMoncriefDisk),
      38             :  * threaded by a weak poloidal magnetic field. The magnetic field is constructed
      39             :  * from an axially symmetric toroidal magnetic potential which, in Kerr
      40             :  * ("spherical Kerr-Schild") coordinates, has the form
      41             :  *
      42             :  * \f{align*}
      43             :  * A_\phi(r,\theta) \propto \text{max}(\rho(r,\theta) - \rho_\text{thresh}, 0),
      44             :  * \f}
      45             :  *
      46             :  * where \f$\rho_\text{thresh}\f$ is a user-specified threshold density that
      47             :  * confines the magnetic flux to exist inside of the fluid disk only. A commonly
      48             :  * used value for this parameter is
      49             :  * \f$\rho_\text{thresh} = 0.2\rho_\text{max}\f$, where \f$\rho_\text{max}\f$
      50             :  * is the maximum value of
      51             :  * the rest mass density in the disk. Using this potential, the Eulerian
      52             :  * magnetic field takes the form
      53             :  *
      54             :  * \f{align*}
      55             :  * B^r = \frac{F_{\theta\phi}}{\sqrt{\gamma}},\quad
      56             :  * B^\theta = \frac{F_{\phi r}}{\sqrt{\gamma}},\quad B^\phi = 0,
      57             :  * \f}
      58             :  *
      59             :  * where \f$F_{ij} = \partial_i A_j - \partial_j A_i\f$ are the spatial
      60             :  * components of the Faraday tensor, and \f$\gamma\f$ is the determinant of the
      61             :  * spatial metric. The magnetic field is then normalized so that the
      62             :  * plasma-\f$\beta\f$ parameter, \f$\beta = 2p/b^2\f$, equals some value
      63             :  * specified by the user. Here, \f$p\f$ is the fluid pressure, and
      64             :  *
      65             :  * \f{align*}
      66             :  * b^2 = b^\mu b_\mu = \frac{B_iB^i}{W^2} + (B^iv_i)^2
      67             :  * \f}
      68             :  *
      69             :  * is the norm of the magnetic field in the fluid frame, with \f$v_i\f$ being
      70             :  * the spatial velocity, and \f$W\f$ the Lorentz factor.
      71             :  *
      72             :  * \note When using Kerr-Schild coordinates, the horizon that is at
      73             :  * constant \f$r\f$ is not spherical, but instead spheroidal. This could make
      74             :  * application of boundary condition and computing various fluxes
      75             :  * across the horizon more complicated than they need to be.
      76             :  * Thus, similar to RelativisticEuler::Solutions::FishboneMoncriefDisk
      77             :  * we use Spherical Kerr-Schild coordinates,
      78             :  * see gr::Solutions::SphericalKerrSchild, in which constant \f$r\f$
      79             :  * is spherical. Because we compute variables in Kerr-Schild coordinates,
      80             :  * there is a necessary extra step of transforming them back to
      81             :  * Spherical Kerr-Schild coordinates.
      82             :  *
      83             :  * \warning Spherical Kerr-Schild coordinates and "spherical Kerr-Schild"
      84             :  * coordinates are not same.
      85             :  *
      86             :  */
      87           1 : class MagnetizedFmDisk : public virtual evolution::initial_data::InitialData,
      88             :                          public MarkAsAnalyticData {
      89             :  private:
      90           0 :   using FmDisk = RelativisticEuler::Solutions::FishboneMoncriefDisk;
      91             : 
      92             :  public:
      93             :   /// The rest mass density (in units of the maximum rest mass density in the
      94             :   /// disk) below which the matter in the disk is initially unmagetized.
      95           1 :   struct ThresholdDensity {
      96           0 :     using type = double;
      97           0 :     static constexpr Options::String help = {
      98             :         "Frac. rest mass density below which B-field vanishes."};
      99           0 :     static type lower_bound() { return 0.0; }
     100           0 :     static type upper_bound() { return 1.0; }
     101             :   };
     102             :   /// The maximum-magnetic-pressure-to-maximum-fluid-pressure ratio.
     103           1 :   struct InversePlasmaBeta {
     104           0 :     using type = double;
     105           0 :     static constexpr Options::String help = {
     106             :         "Ratio of max magnetic pressure to max fluid pressure."};
     107           0 :     static type lower_bound() { return 0.0; }
     108             :   };
     109             :   /// Grid resolution used in magnetic field normalization.
     110           1 :   struct BFieldNormGridRes {
     111           0 :     using type = size_t;
     112           0 :     static constexpr Options::String help = {
     113             :         "Grid Resolution for b-field normalization."};
     114           0 :     static type suggested_value() { return 255; }
     115           0 :     static type lower_bound() { return 4; }
     116             :   };
     117             : 
     118             :   // Unlike the other analytic data classes, we cannot get these from the
     119             :   // `AnalyticDataBase` because this case causes clang-tidy to believe that
     120             :   // there is an ambiguous inheritance problem
     121           0 :   static constexpr size_t volume_dim = 3_st;
     122             : 
     123             :   template <typename DataType>
     124           0 :   using tags =
     125             :       tmpl::push_back<typename gr::AnalyticSolution<3>::template tags<DataType>,
     126             :                       hydro::Tags::RestMassDensity<DataType>,
     127             :                       hydro::Tags::ElectronFraction<DataType>,
     128             :                       hydro::Tags::SpecificInternalEnergy<DataType>,
     129             :                       hydro::Tags::Temperature<DataType>,
     130             :                       hydro::Tags::Pressure<DataType>,
     131             :                       hydro::Tags::SpatialVelocity<DataType, 3>,
     132             :                       hydro::Tags::MagneticField<DataType, 3>,
     133             :                       hydro::Tags::DivergenceCleaningField<DataType>,
     134             :                       hydro::Tags::LorentzFactor<DataType>,
     135             :                       hydro::Tags::SpecificEnthalpy<DataType>>;
     136             : 
     137           0 :   using options = tmpl::push_back<FmDisk::options, ThresholdDensity,
     138             :                                   InversePlasmaBeta, BFieldNormGridRes>;
     139             : 
     140           0 :   static constexpr Options::String help = {
     141             :       "Magnetized Fishbone-Moncrief disk."};
     142             : 
     143           0 :   MagnetizedFmDisk() = default;
     144           0 :   MagnetizedFmDisk(const MagnetizedFmDisk& /*rhs*/) = default;
     145           0 :   MagnetizedFmDisk& operator=(const MagnetizedFmDisk& /*rhs*/) = default;
     146           0 :   MagnetizedFmDisk(MagnetizedFmDisk&& /*rhs*/) = default;
     147           0 :   MagnetizedFmDisk& operator=(MagnetizedFmDisk&& /*rhs*/) = default;
     148           0 :   ~MagnetizedFmDisk() override = default;
     149             : 
     150           0 :   MagnetizedFmDisk(
     151             :       double bh_mass, double bh_dimless_spin, double inner_edge_radius,
     152             :       double max_pressure_radius, double polytropic_constant,
     153             :       double polytropic_exponent, double noise, double threshold_density,
     154             :       double inverse_plasma_beta,
     155             :       size_t normalization_grid_res = BFieldNormGridRes::suggested_value());
     156             : 
     157           0 :   auto get_clone() const
     158             :       -> std::unique_ptr<evolution::initial_data::InitialData> override;
     159             : 
     160             :   /// \cond
     161             :   explicit MagnetizedFmDisk(CkMigrateMessage* msg);
     162             :   using PUP::able::register_constructor;
     163             :   WRAPPED_PUPable_decl_template(MagnetizedFmDisk);
     164             :   /// \endcond
     165             : 
     166             :   // Overload the variables function from the base class.
     167           0 :   using equation_of_state_type = typename FmDisk::equation_of_state_type;
     168             : 
     169             :   /// @{
     170             :   /// The variables in Cartesian Kerr-Schild coordinates at `(x, t)`.
     171             :   template <typename DataType, typename... Tags>
     172           1 :   tuples::TaggedTuple<Tags...> variables(const tnsr::I<DataType, 3>& x,
     173             :                                          tmpl::list<Tags...> /*meta*/) const {
     174             :     // Can't store IntermediateVariables as member variable because we
     175             :     // need to be threadsafe.
     176             :     typename FmDisk::IntermediateVariables<DataType> vars(x);
     177             :     return {std::move(get<Tags>([this, &x, &vars]() {
     178             :       if constexpr (std::is_same_v<hydro::Tags::MagneticField<DataType, 3>,
     179             :                                    Tags>) {
     180             :         return variables(x, tmpl::list<Tags>{}, make_not_null(&vars));
     181             :       } else {
     182             :         return fm_disk_.variables(x, tmpl::list<Tags>{}, make_not_null(&vars));
     183             :       }
     184             :     }()))...};
     185             :   }
     186             : 
     187             :   template <typename DataType, typename Tag>
     188           1 :   tuples::TaggedTuple<Tag> variables(const tnsr::I<DataType, 3>& x,
     189             :                                      tmpl::list<Tag> /*meta*/) const {
     190             :     // Can't store IntermediateVariables as member variable because we need to
     191             :     // be threadsafe.
     192             :     typename FmDisk::IntermediateVariables<DataType> vars(x);
     193             :     if constexpr (std::is_same_v<hydro::Tags::MagneticField<DataType, 3>,
     194             :                                  Tag>) {
     195             :       return variables(x, tmpl::list<Tag>{}, make_not_null(&vars));
     196             :     } else {
     197             :       return fm_disk_.variables(x, tmpl::list<Tag>{}, make_not_null(&vars));
     198             :     }
     199             :   }
     200             :   /// @}
     201             : 
     202             :   // NOLINTNEXTLINE(google-runtime-references)
     203           0 :   void pup(PUP::er& /*p*/) override;
     204             : 
     205           0 :   const equation_of_state_type& equation_of_state() const {
     206             :     return fm_disk_.equation_of_state();
     207             :   }
     208             : 
     209             :  private:
     210             :   template <typename DataType>
     211           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     212             :                  tmpl::list<hydro::Tags::MagneticField<DataType, 3>> /*meta*/,
     213             :                  gsl::not_null<FmDisk::IntermediateVariables<DataType>*> vars)
     214             :       const -> tuples::TaggedTuple<hydro::Tags::MagneticField<DataType, 3>>;
     215             : 
     216             :   template <typename DataType>
     217           0 :   tnsr::I<DataType, 3> unnormalized_magnetic_field(
     218             :       const tnsr::I<DataType, 3>& x) const;
     219             : 
     220           0 :   friend bool operator==(const MagnetizedFmDisk& lhs,
     221             :                          const MagnetizedFmDisk& rhs);
     222             : 
     223           0 :   RelativisticEuler::Solutions::FishboneMoncriefDisk fm_disk_{};
     224           0 :   double threshold_density_ = std::numeric_limits<double>::signaling_NaN();
     225           0 :   double inverse_plasma_beta_ = std::numeric_limits<double>::signaling_NaN();
     226           0 :   double b_field_normalization_ = std::numeric_limits<double>::signaling_NaN();
     227           0 :   size_t normalization_grid_res_ = 255;
     228           0 :   gr::KerrSchildCoords kerr_schild_coords_{};
     229             : };
     230             : 
     231           0 : bool operator!=(const MagnetizedFmDisk& lhs, const MagnetizedFmDisk& rhs);
     232             : 
     233             : }  // namespace grmhd::AnalyticData

Generated by: LCOV version 1.14