SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/Hydro/EquationsOfState - HybridEos.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 20.9 % 43 9
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 <boost/preprocessor/arithmetic/dec.hpp>
       7              : #include <boost/preprocessor/arithmetic/inc.hpp>
       8              : #include <boost/preprocessor/control/expr_iif.hpp>
       9              : #include <boost/preprocessor/list/adt.hpp>
      10              : #include <boost/preprocessor/repetition/for.hpp>
      11              : #include <boost/preprocessor/repetition/repeat.hpp>
      12              : #include <boost/preprocessor/tuple/to_list.hpp>
      13              : #include <cstddef>
      14              : #include <limits>
      15              : #include <pup.h>
      16              : 
      17              : #include "DataStructures/Tensor/TypeAliases.hpp"
      18              : #include "Options/String.hpp"
      19              : #include "PointwiseFunctions/Hydro/EquationsOfState/EquationOfState.hpp"
      20              : #include "PointwiseFunctions/Hydro/Units.hpp"
      21              : #include "Utilities/Serialization/CharmPupable.hpp"
      22              : #include "Utilities/TMPL.hpp"
      23              : 
      24              : /// \cond
      25              : class DataVector;
      26              : /// \endcond
      27              : 
      28              : namespace EquationsOfState {
      29              : /*!
      30              :  * \ingroup EquationsOfStateGroup
      31              :  *
      32              :  * \brief Hybrid equation of state combining a barotropic EOS for cold
      33              :  * (zero-temperature) part with a simple thermal part
      34              :  *
      35              :  * The hybrid equation of state:
      36              :  *
      37              :  * \f[
      38              :  * p = p_{cold}(\rho) + \rho (\Gamma_{th}-1) (\epsilon - \epsilon_{cold}(\rho))
      39              :  * \f]
      40              :  *
      41              :  * where \f$p\f$ is the pressure, \f$\rho\f$ is the rest mass density,
      42              :  * \f$\epsilon\f$ is the specific internal energy, \f$p_{cold}\f$ and
      43              :  * \f$\epsilon_{cold}\f$ are the pressure and specific internal energy evaluated
      44              :  * using the cold EOS, and \f$\Gamma_{th}\f$ is the adiabatic index for the
      45              :  * thermal part.
      46              :  *
      47              :  * The temperature \f$T\f$ is defined as
      48              :  *
      49              :  * \f[
      50              :  * T = (\Gamma_{th} - 1) (\epsilon - \epsilon_{cold})
      51              :  * \f]
      52              :  *
      53              :  * This is the amount of internal energy above that of the cold EOS.
      54              :  *
      55              :  * For a hybrid EOS with the cold EOS being a polytrope we have
      56              :  *
      57              :  * \f{align}
      58              :  * p &= \kappa \rho^\Gamma + \rho T
      59              :  *     =\kappa\rho^\Gamma+\rho
      60              :  *     (\Gamma-1)\left(\epsilon-\frac{K\rho^{\Gamma-1}}{\Gamma-1}\right), \\
      61              :  * T&=(\Gamma-1)\left(\epsilon-\frac{K\rho^{\Gamma-1}}{\Gamma-1}\right), \\
      62              :  * \epsilon &= \frac{1}{(\Gamma-1)}\frac{p}{\rho}
      63              :  * \f}
      64              :  */
      65              : template <typename ColdEquationOfState>
      66            1 : class HybridEos
      67              :     : public EquationOfState<ColdEquationOfState::is_relativistic, 2> {
      68              :  public:
      69            0 :   static constexpr size_t thermodynamic_dim = 2;
      70            0 :   static constexpr bool is_relativistic = ColdEquationOfState::is_relativistic;
      71              : 
      72            0 :   struct ColdEos {
      73            0 :     using type = ColdEquationOfState;
      74            0 :     static constexpr Options::String help = {"Cold equation of state"};
      75            0 :     static std::string name() {
      76              :       return pretty_type::short_name<ColdEquationOfState>();
      77              :     }
      78              :   };
      79              : 
      80            0 :   struct ThermalAdiabaticIndex {
      81            0 :     using type = double;
      82            0 :     static constexpr Options::String help = {"Adiabatic index Gamma_th"};
      83              :   };
      84              : 
      85            0 :   struct MinTemperature {
      86            0 :     using type = double;
      87            0 :     static type lower_bound() { return 0.0; }
      88            0 :     static constexpr Options::String help = {
      89              :         "Minimum temperature. "
      90              :         "This value must be non-negative."};
      91              :   };
      92              : 
      93            0 :   static constexpr Options::String help = {
      94              :       "A hybrid equation of state combining a cold EOS with a simple thermal "
      95              :       "part.  The pressure is related to the rest mass density by "
      96              :       " p = p_cold(rho) + rho * (Gamma_th - 1) * (epsilon - "
      97              :       "epsilon_cold(rho)), where p is the pressure, rho is the rest mass "
      98              :       "density, epsilon is the specific internal energy, p_cold and "
      99              :       "epsilon_cold are the pressure and specific internal energy evaluated "
     100              :       "using the cold EOS and Gamma_th is the adiabatic index for the thermal "
     101              :       "part."};
     102              : 
     103            0 :   using options = tmpl::list<ColdEos, ThermalAdiabaticIndex, MinTemperature>;
     104              : 
     105            0 :   HybridEos() = default;
     106            0 :   HybridEos(const HybridEos&) = default;
     107            0 :   HybridEos& operator=(const HybridEos&) = default;
     108            0 :   HybridEos(HybridEos&&) = default;
     109            0 :   HybridEos& operator=(HybridEos&&) = default;
     110            0 :   ~HybridEos() override = default;
     111              : 
     112            0 :   HybridEos(ColdEquationOfState cold_eos, double thermal_adiabatic_index,
     113              :             double min_temperature = 0.0);
     114              : 
     115              :   EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS(HybridEos, 2)
     116              : 
     117            0 :   WRAPPED_PUPable_decl_base_template(  // NOLINT
     118              :       SINGLE_ARG(EquationOfState<is_relativistic, 2>), HybridEos);
     119              : 
     120            0 :   std::unique_ptr<EquationOfState<is_relativistic, 2>> get_clone()
     121              :       const override;
     122              : 
     123            0 :   std::unique_ptr<EquationOfState<is_relativistic, 3>> promote_to_3d_eos()
     124              :       const override;
     125              : 
     126              :   /// \brief Returns `true` if the EOS is barotropic
     127            1 :   bool is_barotropic() const override { return false; }
     128              : 
     129            0 :   bool operator==(const HybridEos<ColdEquationOfState>& rhs) const;
     130              : 
     131            0 :   bool operator!=(const HybridEos<ColdEquationOfState>& rhs) const;
     132              : 
     133            0 :   bool is_equal(const EquationOfState<is_relativistic, 2>& rhs) const override;
     134              : 
     135            0 :   static std::string name() {
     136              :     return "HybridEos(" + pretty_type::name<ColdEquationOfState>() + ")";
     137              :   }
     138              : 
     139              :   /// The lower bound of the rest mass density that is valid for this EOS
     140            1 :   double rest_mass_density_lower_bound() const override {
     141              :     return cold_eos_.rest_mass_density_lower_bound();
     142              :   }
     143              : 
     144              :   /// The upper bound of the rest mass density that is valid for this EOS
     145            1 :   double rest_mass_density_upper_bound() const override {
     146              :     return cold_eos_.rest_mass_density_upper_bound();
     147              :   }
     148              : 
     149              :   /// The lower bound of the specific internal energy that is valid for this EOS
     150              :   /// at the given rest mass density \f$\rho\f$
     151            1 :   double specific_internal_energy_lower_bound(
     152              :       const double rest_mass_density) const override {
     153              :     return get(cold_eos_.specific_internal_energy_from_density(
     154              :                Scalar<double>{rest_mass_density})) +
     155              :            (min_temperature_) / (thermal_adiabatic_index_ - 1.0);
     156              :   }
     157              : 
     158              :   /// The upper bound of the specific internal energy that is valid for this EOS
     159              :   /// at the given rest mass density \f$\rho\f$
     160            1 :   double specific_internal_energy_upper_bound(
     161              :       const double /*rest_mass_density*/) const override {
     162              :     return std::numeric_limits<double>::max();
     163              :   }
     164              : 
     165              :   /// The lower bound of the specific enthalpy that is valid for this EOS
     166            1 :   double specific_enthalpy_lower_bound() const override {
     167              :     return cold_eos_.specific_enthalpy_lower_bound() +
     168              :            (thermal_adiabatic_index_ * min_temperature_) /
     169              :                (thermal_adiabatic_index_ - 1.0);
     170              :   }
     171              : 
     172              :   /// The lower bound of the temperature that is valid for this EOS.
     173              :   /// Non-zero lower bound could be set to impose floor on the specific
     174              :   /// internal energy.
     175            1 :   double temperature_lower_bound() const override { return min_temperature_; }
     176              : 
     177              :   /// The vacuum baryon mass for this EoS
     178            1 :   double baryon_mass() const override { return cold_eos_.baryon_mass(); }
     179              : 
     180              :  private:
     181              :   EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS(2)
     182              : 
     183            0 :   double specific_entropy_from_density_and_thermal_energy(
     184              :       double density, double energy) const;
     185              : 
     186            0 :   ColdEquationOfState cold_eos_;
     187            0 :   double thermal_adiabatic_index_ =
     188              :       std::numeric_limits<double>::signaling_NaN();
     189            0 :   double min_temperature_ = std::numeric_limits<double>::signaling_NaN();
     190              : };
     191              : 
     192              : /// \cond
     193              : template <typename ColdEquationOfState>
     194              : PUP::able::PUP_ID EquationsOfState::HybridEos<ColdEquationOfState>::my_PUP_ID =
     195              :     0;
     196              : /// \endcond
     197              : }  // namespace EquationsOfState
        

Generated by: LCOV version 2.0-1