SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/AnalyticSolutions/GrMhd - BondiMichel.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 7 76 9.2 %
Date: 2024-04-23 20:50:18
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 <pup.h>
       7             : 
       8             : #include "DataStructures/Tensor/TypeAliases.hpp"
       9             : #include "Options/String.hpp"
      10             : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp"
      11             : #include "PointwiseFunctions/AnalyticSolutions/GeneralRelativity/KerrSchild.hpp"
      12             : #include "PointwiseFunctions/AnalyticSolutions/GrMhd/Solutions.hpp"
      13             : #include "PointwiseFunctions/Hydro/EquationsOfState/PolytropicFluid.hpp"  // IWYU pragma: keep
      14             : #include "PointwiseFunctions/Hydro/Tags.hpp"
      15             : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
      16             : #include "Utilities/Requires.hpp"
      17             : #include "Utilities/Serialization/CharmPupable.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : #include "Utilities/TaggedTuple.hpp"
      20             : 
      21             : namespace grmhd::Solutions {
      22             : 
      23             : /*!
      24             :  * \brief Bondi-Michel accretion \cite Michel1972 with superposed magnetic field
      25             :  * in Schwarzschild spacetime in Cartesian Kerr-Schild coordinates.
      26             :  *
      27             :  * An analytic solution to the 3-D GRMHD system. The user specifies the sonic
      28             :  * radius \f$r_c\f$ and sonic rest mass density \f$\rho_c\f$, which are the
      29             :  * radius and rest mass density at the sonic point, the radius at which the
      30             :  * fluid's Eulerian velocity as seen by a distant observer overtakes the local
      31             :  * sound speed \f$c_{s,c}\f$. With a specified polytropic exponent \f$\gamma\f$,
      32             :  * these quantities can be related to the sound speed at infinity
      33             :  * \f$c_{s,\infty}\f$ using the following relations:
      34             :  *
      35             :  * \f{align*}
      36             :  * c_{s,c}^2 &= \frac{M}{2r_c - 3M} \\
      37             :  * c_{s,\infty}^2 &= \gamma - 1 + (c_{s,c}^2 - \gamma + 1)\sqrt{1 + 3c_{s,c}^2}
      38             :  * \f}
      39             :  *
      40             :  * In the case of the interstellar medium, the sound
      41             :  * speed is \f$\approx 10^{-4}\f$, which results in a sonic radius of
      42             :  * \f$\approx 10^8 M\f$ for \f$\gamma \neq 5/3\f$ \cite RezzollaBook.
      43             :  *
      44             :  * The density is found via root-finding, through the
      45             :  * Bernoulli equation. As one approaches the sonic radius, a second root makes
      46             :  * an appearance and one must take care to bracket the correct root. This is
      47             :  * done by using the upper bound
      48             :  * \f$\frac{\dot{M}}{4\pi}\sqrt{\frac{2}{Mr^3}}\f$.
      49             :  *
      50             :  * Additionally specified by the user are the polytropic exponent \f$\gamma\f$,
      51             :  * and the strength parameter of the magnetic field \f$B_0\f$.
      52             :  * In Cartesian Kerr-Schild coordinates \f$(x, y, z)\f$, where
      53             :  * \f$ r = \sqrt{x^2 + y^2 + z^2}\f$, the superposed magnetic field is
      54             :  * \cite Etienne2010ui
      55             :  *
      56             :  * \f{align*}
      57             :  * B^i(\vec{x},t) = \frac{B_0 M^2}{r^3 \sqrt{\gamma}}x^i
      58             :  *  =\frac{B_0 M^2}{r^3 \sqrt{1 + 2M/r}}x^i.
      59             :  * \f}
      60             :  *
      61             :  * The accretion rate is
      62             :  *
      63             :  * \f{align*}{
      64             :  * \dot{M}=4\pi r^2\rho u^r,
      65             :  * \f}
      66             :  *
      67             :  * and at the sonic radius
      68             :  *
      69             :  * \f{align*}{
      70             :  * \dot{M}_c=\sqrt{8}\pi \sqrt{M}r_c^{3/2}\rho_c.
      71             :  * \f}
      72             :  *
      73             :  * The polytropic constant is given by
      74             :  *
      75             :  * \f{align*}{
      76             :  * K=\frac{1}{\gamma\rho_c^{\gamma-1}}
      77             :  * \left[\frac{M(\gamma-1)}{(2r_c-3M)(\gamma-1)-M}\right].
      78             :  * \f}
      79             :  *
      80             :  * The density as a function of the sound speed is
      81             :  *
      82             :  * \f{align*}{
      83             :  * \rho^{\gamma-1}=\frac{(\gamma-1)c_s^2}{\gamma K(\gamma-1-c_s^2)}.
      84             :  * \f}
      85             :  *
      86             :  * #### Horizon quantities, \f$\gamma\ne5/3\f$
      87             :  * The density at the horizon is given by:
      88             :  *
      89             :  * \f{align*}{
      90             :  *  \rho_h\simeq\frac{1}{16}
      91             :  *  \left(\frac{5-3\gamma}{2}\right)^{(3\gamma-5)/[2(\gamma-1)]}
      92             :  *  \frac{\rho_\infty}{c_{s,\infty}^3}.
      93             :  * \f}
      94             :  *
      95             :  * Using the Lorentz invariance of \f$b^2\f$ we evaluate:
      96             :  *
      97             :  * \f{align*}{
      98             :  * b^2=\frac{B^2}{W^2}+(B^i v_i)^2=
      99             :  *  B^r B^r(1-\gamma_{rr}v^r v^r)+B^r B^r v^r v^r
     100             :  * =B^r B^r = \frac{B_0^2 M^4}{r^4},
     101             :  * \f}
     102             :  *
     103             :  * where \f$r\f$ is the Cartesian Kerr-Schild radius, which is equal to the
     104             :  * areal radius for a non-spinning black hole. At the horizon we get
     105             :  *
     106             :  * \f{align*}{
     107             :  * b^2_h=\frac{B^2_0}{16}.
     108             :  * \f}
     109             :  *
     110             :  * Finally, we get
     111             :  *
     112             :  * \f{align*}{
     113             :  * B_0 = 4 \sqrt{b^2_h} = 4\sqrt{\rho_h} \sqrt{\frac{b^2_h}{\rho_h}},
     114             :  * \f}
     115             :  *
     116             :  * where the last equality is useful for comparison to papers that give
     117             :  * \f$b^2_h/\rho_h\f$.
     118             :  *
     119             :  * To help with comparing to other codes the following script can be used to
     120             :  * compute \f$b^2_h/\rho_h\f$:
     121             :  *
     122             :  * \code{.py}
     123             :  * #!/bin/env python
     124             :  *
     125             :  * import numpy as np
     126             :  *
     127             :  * # Input parameters
     128             :  * B_0 = 18
     129             :  * r_c = 8
     130             :  * rho_c = 1 / 16
     131             :  * gamma = 4 / 3
     132             :  * mass = 1
     133             :  *
     134             :  * K = 1 / (gamma * rho_c**(gamma - 1)) * ((gamma - 1) * mass) / (
     135             :  *     (2 * r_c - 3 * mass) * (gamma - 1) - mass)
     136             :  * c_s_c = mass / (2 * r_c - 3 * mass)
     137             :  * c_inf = gamma - 1 + (c_s_c - gamma + 1) * np.sqrt(1. + 3. * c_s_c)
     138             :  * rho_inf = ((gamma - 1) * c_inf / (gamma * K *
     139             :  *                                   (gamma - 1 - c_inf)))**(1. / (gamma - 1.))
     140             :  * rho_h = 1. / 16. * (2.5 - 1.5 * gamma)**(
     141             :  *     (3 * gamma - 5) / (2 * (gamma - 1))) * rho_inf / (c_inf**1.5)
     142             :  *
     143             :  * print("B_0", B_0)
     144             :  * print("r_c: ", r_c)
     145             :  * print("rho_c", rho_c)
     146             :  * print("b_h^2/rho_h: ", B_0**2 / (16. * rho_h))
     147             :  * print("gamma: ", gamma)
     148             :  * \endcode
     149             :  *
     150             :  * #### Horizon quantities, \f$\gamma=5/3\f$
     151             :  * The density at the horizon is given by:
     152             :  *
     153             :  * \f{align*}{
     154             :  * \rho_h\simeq \frac{1}{16}\frac{\rho_\infty}{u_h c_{s,\infty}^3},
     155             :  * \f}
     156             :  *
     157             :  * which gives \cite RezzollaBook
     158             :  *
     159             :  * \f{align*}{
     160             :  * \rho_h\simeq 0.08\frac{\rho_\infty}{c_{s,\infty}^3}.
     161             :  * \f}
     162             :  *
     163             :  * The magnetic field \f$b^2\f$ is the same as the \f$\gamma\ne5/3\f$.
     164             :  */
     165           1 : class BondiMichel : public virtual evolution::initial_data::InitialData,
     166             :                     public AnalyticSolution,
     167             :                     public MarkAsAnalyticSolution {
     168             :  protected:
     169             :   template <typename DataType>
     170             :   struct IntermediateVars;
     171             : 
     172             :  public:
     173           0 :   using equation_of_state_type = EquationsOfState::PolytropicFluid<true>;
     174             : 
     175             :   /// The mass of the black hole.
     176           1 :   struct Mass {
     177           0 :     using type = double;
     178           0 :     static constexpr Options::String help = {"Mass of the black hole."};
     179           0 :     static type lower_bound() { return 0.0; }
     180             :   };
     181             : 
     182             :   /// The radius at which the fluid becomes supersonic.
     183           1 :   struct SonicRadius {
     184           0 :     using type = double;
     185           0 :     static constexpr Options::String help = {
     186             :         "Schwarzschild radius where fluid becomes supersonic."};
     187           0 :     static type lower_bound() { return 0.0; }
     188             :   };
     189             : 
     190             :   /// The rest mass density of the fluid at the sonic radius.
     191           1 :   struct SonicDensity {
     192           0 :     using type = double;
     193           0 :     static constexpr Options::String help = {
     194             :         "The density of the fluid at the sonic radius."};
     195           0 :     static type lower_bound() { return 0.0; }
     196             :   };
     197             : 
     198             :   /// The polytropic exponent for the polytropic fluid.
     199           1 :   struct PolytropicExponent {
     200           0 :     using type = double;
     201           0 :     static constexpr Options::String help = {
     202             :         "The polytropic exponent for the polytropic fluid."};
     203           0 :     static type lower_bound() { return 1.0; }
     204             :   };
     205             : 
     206             :   /// The strength of the radial magnetic field.
     207           1 :   struct MagFieldStrength {
     208           0 :     using type = double;
     209           0 :     static constexpr Options::String help = {
     210             :         "The strength of the radial magnetic field."};
     211             :   };
     212             : 
     213           0 :   using options = tmpl::list<Mass, SonicRadius, SonicDensity,
     214             :                              PolytropicExponent, MagFieldStrength>;
     215           0 :   static constexpr Options::String help = {
     216             :       "Bondi-Michel solution with a radial magnetic field using \n"
     217             :       "the Schwarzschild coordinate system. Quantities prefixed with \n"
     218             :       "`sonic` refer to field quantities evaluated at the radius \n"
     219             :       "where the fluid speed overtakes the sound speed."};
     220             : 
     221           0 :   BondiMichel() = default;
     222           0 :   BondiMichel(const BondiMichel& /*rhs*/) = default;
     223           0 :   BondiMichel& operator=(const BondiMichel& /*rhs*/) = default;
     224           0 :   BondiMichel(BondiMichel&& /*rhs*/) = default;
     225           0 :   BondiMichel& operator=(BondiMichel&& /*rhs*/) = default;
     226           0 :   ~BondiMichel() override = default;
     227             : 
     228           0 :   BondiMichel(double mass, double sonic_radius, double sonic_density,
     229             :               double polytropic_exponent, double mag_field_strength);
     230             : 
     231           0 :   auto get_clone() const
     232             :       -> std::unique_ptr<evolution::initial_data::InitialData> override;
     233             : 
     234             :   /// \cond
     235             :   explicit BondiMichel(CkMigrateMessage* msg);
     236             :   using PUP::able::register_constructor;
     237             :   WRAPPED_PUPable_decl_template(BondiMichel);
     238             :   /// \endcond
     239             : 
     240             :   /// Retrieve a collection of  hydro variables at `(x, t)`
     241             :   template <typename DataType, typename... Tags>
     242           1 :   tuples::TaggedTuple<Tags...> variables(const tnsr::I<DataType, 3>& x,
     243             :                                          const double /*t*/,
     244             :                                          tmpl::list<Tags...> /*meta*/) const {
     245             :     // non-const so we can move out the metric vars. We assume that no variable
     246             :     // is being retrieved more than once, which would cause problems with
     247             :     // TaggedTuple anyway.
     248             :     auto intermediate_vars = IntermediateVars<DataType>{
     249             :         rest_mass_density_at_infinity_,
     250             :         mass_accretion_rate_over_four_pi_,
     251             :         mass_,
     252             :         polytropic_constant_,
     253             :         polytropic_exponent_,
     254             :         bernoulli_constant_squared_minus_one_,
     255             :         sonic_radius_,
     256             :         sonic_density_,
     257             :         x,
     258             :         tmpl2::flat_any_v<
     259             :             not tmpl::list_contains_v<hydro::grmhd_tags<DataType>, Tags>...>,
     260             :         background_spacetime_};
     261             :     return {get<Tags>(variables(x, tmpl::list<Tags>{}, intermediate_vars))...};
     262             :   }
     263             : 
     264             :   template <typename DataType, typename Tag>
     265           0 :   tuples::TaggedTuple<Tag> variables(const tnsr::I<DataType, 3>& x,
     266             :                                      const double /*t*/,  // NOLINT
     267             :                                      tmpl::list<Tag> /*meta*/) const {
     268             :     return variables(
     269             :         x, tmpl::list<Tag>{},
     270             :         IntermediateVars<DataType>{
     271             :             rest_mass_density_at_infinity_, mass_accretion_rate_over_four_pi_,
     272             :             mass_, polytropic_constant_, polytropic_exponent_,
     273             :             bernoulli_constant_squared_minus_one_, sonic_radius_,
     274             :             sonic_density_, x,
     275             :             not tmpl::list_contains_v<hydro::grmhd_tags<DataType>, Tag>,
     276             :             background_spacetime_});
     277             :   }
     278             : 
     279             :   // NOLINTNEXTLINE(google-runtime-references)
     280           0 :   void pup(PUP::er& /*p*/) override;
     281           0 :   const EquationsOfState::PolytropicFluid<true>& equation_of_state() const {
     282             :     return equation_of_state_;
     283             :   }
     284             : 
     285             :  protected:
     286           0 :   friend bool operator==(const BondiMichel& lhs, const BondiMichel& rhs);
     287             : 
     288             :   template <typename DataType>
     289           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     290             :                  tmpl::list<hydro::Tags::RestMassDensity<DataType>> /*meta*/,
     291             :                  const IntermediateVars<DataType>& vars) const
     292             :       -> tuples::TaggedTuple<hydro::Tags::RestMassDensity<DataType>>;
     293             : 
     294             :   template <typename DataType>
     295           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     296             :                  tmpl::list<hydro::Tags::ElectronFraction<DataType>> /*meta*/,
     297             :                  const IntermediateVars<DataType>& vars) const
     298             :       -> tuples::TaggedTuple<hydro::Tags::ElectronFraction<DataType>>;
     299             : 
     300             :   template <typename DataType>
     301           0 :   auto variables(
     302             :       const tnsr::I<DataType, 3>& x,
     303             :       tmpl::list<hydro::Tags::SpecificInternalEnergy<DataType>> /*meta*/,
     304             :       const IntermediateVars<DataType>& vars) const
     305             :       -> tuples::TaggedTuple<hydro::Tags::SpecificInternalEnergy<DataType>>;
     306             : 
     307             :   template <typename DataType>
     308           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     309             :                  tmpl::list<hydro::Tags::Pressure<DataType>> /*meta*/,
     310             :                  const IntermediateVars<DataType>& vars) const
     311             :       -> tuples::TaggedTuple<hydro::Tags::Pressure<DataType>>;
     312             : 
     313             :   template <typename DataType>
     314           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     315             :                  tmpl::list<hydro::Tags::Temperature<DataType>> /*meta*/,
     316             :                  const IntermediateVars<DataType>& vars) const
     317             :       -> tuples::TaggedTuple<hydro::Tags::Temperature<DataType>>;
     318             : 
     319             :   template <typename DataType>
     320           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     321             :                  tmpl::list<hydro::Tags::SpatialVelocity<DataType, 3>> /*meta*/,
     322             :                  const IntermediateVars<DataType>& vars) const
     323             :       -> tuples::TaggedTuple<hydro::Tags::SpatialVelocity<DataType, 3>>;
     324             : 
     325             :   template <typename DataType>
     326           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     327             :                  tmpl::list<hydro::Tags::MagneticField<DataType, 3>> /*meta*/,
     328             :                  const IntermediateVars<DataType>& vars) const
     329             :       -> tuples::TaggedTuple<hydro::Tags::MagneticField<DataType, 3>>;
     330             : 
     331             :   template <typename DataType>
     332           0 :   auto variables(
     333             :       const tnsr::I<DataType, 3>& x,
     334             :       tmpl::list<hydro::Tags::DivergenceCleaningField<DataType>> /*meta*/,
     335             :       const IntermediateVars<DataType>& vars) const
     336             :       -> tuples::TaggedTuple<hydro::Tags::DivergenceCleaningField<DataType>>;
     337             : 
     338             :   template <typename DataType>
     339           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     340             :                  tmpl::list<hydro::Tags::LorentzFactor<DataType>> /*meta*/,
     341             :                  const IntermediateVars<DataType>& vars) const
     342             :       -> tuples::TaggedTuple<hydro::Tags::LorentzFactor<DataType>>;
     343             : 
     344             :   template <typename DataType>
     345           0 :   auto variables(const tnsr::I<DataType, 3>& x,
     346             :                  tmpl::list<hydro::Tags::SpecificEnthalpy<DataType>> /*meta*/,
     347             :                  const IntermediateVars<DataType>& vars) const
     348             :       -> tuples::TaggedTuple<hydro::Tags::SpecificEnthalpy<DataType>>;
     349             : 
     350             :   template <typename DataType, typename Tag,
     351             :             Requires<not tmpl::list_contains_v<
     352             :                 tmpl::push_back<hydro::grmhd_tags<DataType>,
     353             :                                 hydro::Tags::SpecificEnthalpy<DataType>>,
     354             :                 Tag>> = nullptr>
     355           0 :   tuples::TaggedTuple<Tag> variables(
     356             :       const tnsr::I<DataType, 3>& /*x*/, tmpl::list<Tag> /*meta*/,
     357             :       const IntermediateVars<DataType>& vars) const {
     358             :     return {std::move(get<Tag>(vars.kerr_schild_soln))};
     359             :   }
     360             : 
     361             :   template <typename DataType>
     362           0 :   struct IntermediateVars {
     363           0 :     IntermediateVars(double rest_mass_density_at_infinity,
     364             :                      double in_mass_accretion_rate_over_four_pi, double in_mass,
     365             :                      double in_polytropic_constant,
     366             :                      double in_polytropic_exponent,
     367             :                      double in_bernoulli_constant_squared_minus_one,
     368             :                      double in_sonic_radius, double in_sonic_density,
     369             :                      const tnsr::I<DataType, 3>& x, bool need_spacetime,
     370             :                      const gr::Solutions::KerrSchild& background_spacetime);
     371           0 :     DataType radius{};
     372           0 :     DataType rest_mass_density{};
     373           0 :     DataType electron_fraction{};
     374           0 :     double mass_accretion_rate_over_four_pi{};
     375           0 :     double mass{};
     376           0 :     double polytropic_constant{};
     377           0 :     double polytropic_exponent{};
     378           0 :     double bernoulli_constant_squared_minus_one{};
     379           0 :     double sonic_radius{};
     380           0 :     double sonic_density{};
     381           0 :     double bernoulli_root_function(double rest_mass_density_guess,
     382             :                                    double current_radius) const;
     383             :     tuples::tagged_tuple_from_typelist<
     384             :         typename gr::Solutions::KerrSchild::tags<DataType>>
     385           0 :         kerr_schild_soln{};
     386             :   };
     387             : 
     388           0 :   double mass_ = std::numeric_limits<double>::signaling_NaN();
     389           0 :   double sonic_radius_ = std::numeric_limits<double>::signaling_NaN();
     390           0 :   double sonic_density_ = std::numeric_limits<double>::signaling_NaN();
     391           0 :   double polytropic_exponent_ = std::numeric_limits<double>::signaling_NaN();
     392           0 :   double mag_field_strength_ = std::numeric_limits<double>::signaling_NaN();
     393           0 :   double sonic_fluid_speed_squared_ =
     394             :       std::numeric_limits<double>::signaling_NaN();
     395           0 :   double sonic_sound_speed_squared_ =
     396             :       std::numeric_limits<double>::signaling_NaN();
     397           0 :   double polytropic_constant_ = std::numeric_limits<double>::signaling_NaN();
     398           0 :   double mass_accretion_rate_over_four_pi_ =
     399             :       std::numeric_limits<double>::signaling_NaN();
     400           0 :   double bernoulli_constant_squared_minus_one_ =
     401             :       std::numeric_limits<double>::signaling_NaN();
     402           0 :   double rest_mass_density_at_infinity_ =
     403             :       std::numeric_limits<double>::signaling_NaN();
     404           0 :   EquationsOfState::PolytropicFluid<true> equation_of_state_{};
     405           0 :   gr::Solutions::KerrSchild background_spacetime_{};
     406             : };
     407             : 
     408           0 : bool operator!=(const BondiMichel& lhs, const BondiMichel& rhs);
     409             : 
     410             : }  // namespace grmhd::Solutions

Generated by: LCOV version 1.14