SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/Hydro/EquationsOfState - EquationOfState.hpp Hit Total Coverage
Commit: a18e59fda1a195609825c55450f7d61ad20a91a4 Lines: 70 107 65.4 %
Date: 2026-06-11 22:10:41
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/sub.hpp>
       7             : #include <boost/preprocessor/list/for_each.hpp>
       8             : #include <boost/preprocessor/punctuation/comma_if.hpp>
       9             : #include <boost/preprocessor/repetition/repeat.hpp>
      10             : #include <boost/preprocessor/tuple/enum.hpp>
      11             : #include <boost/preprocessor/tuple/to_list.hpp>
      12             : 
      13             : #include "DataStructures/DataVector.hpp"
      14             : #include "DataStructures/Tensor/Tensor.hpp"
      15             : #include "PointwiseFunctions/Hydro/Units.hpp"
      16             : #include "Utilities/CallWithDynamicType.hpp"
      17             : #include "Utilities/Serialization/CharmPupable.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : #include "Utilities/TypeTraits.hpp"
      20             : 
      21             : /// \cond
      22             : namespace EquationsOfState {
      23             : template <typename ColdEos>
      24             : class Barotropic2D;
      25             : template <typename ColdEquilEos>
      26             : class Barotropic3D;
      27             : template <bool IsRelativistic>
      28             : class DarkEnergyFluid;
      29             : template <typename EquilEos>
      30             : class Equilibrium3D;
      31             : template <typename ColdEquationOfState>
      32             : class HybridEos;
      33             : template <bool IsRelativistic>
      34             : class IdealFluid;
      35             : template <bool IsRelativistic>
      36             : class PolytropicFluid;
      37             : template <bool IsRelativistic>
      38             : class PiecewisePolytropicFluid;
      39             : class Spectral;
      40             : template <typename LowDensityEoS>
      41             : class Enthalpy;
      42             : template <bool IsRelativistic>
      43             : class Tabulated3D;
      44             : }  // namespace EquationsOfState
      45             : /// \endcond
      46             : 
      47             : /// Contains all equations of state, including base class
      48             : namespace EquationsOfState {
      49             : 
      50             : namespace detail {
      51             : template <bool IsRelativistic, size_t ThermodynamicDim>
      52             : struct DerivedClasses {};
      53             : 
      54             : template <>
      55             : struct DerivedClasses<true, 1> {
      56             :   using type = tmpl::list<PolytropicFluid<true>, PiecewisePolytropicFluid<true>,
      57             :                           Spectral, Enthalpy<PolytropicFluid<true>>,
      58             :                           Enthalpy<Enthalpy<PolytropicFluid<true>>>,
      59             :                           Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>,
      60             :                           Enthalpy<Spectral>, Enthalpy<Enthalpy<Spectral>>,
      61             :                           Enthalpy<Enthalpy<Enthalpy<Spectral>>>>;
      62             : };
      63             : 
      64             : template <>
      65             : struct DerivedClasses<false, 1> {
      66             :   using type =
      67             :       tmpl::list<PolytropicFluid<false>, PiecewisePolytropicFluid<false>>;
      68             : };
      69             : 
      70             : template <>
      71             : struct DerivedClasses<true, 2> {
      72             :   using type = tmpl::list<
      73             :       DarkEnergyFluid<true>, IdealFluid<true>,
      74             :       Barotropic2D<PolytropicFluid<true>>,
      75             :       Barotropic2D<PiecewisePolytropicFluid<true>>, Barotropic2D<Spectral>,
      76             :       Barotropic2D<Enthalpy<PolytropicFluid<true>>>,
      77             :       Barotropic2D<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
      78             :       Barotropic2D<Enthalpy<Spectral>>,
      79             :       Barotropic2D<Enthalpy<Enthalpy<Spectral>>>,
      80             :       Barotropic2D<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>,
      81             :       HybridEos<PolytropicFluid<true>>, HybridEos<Spectral>,
      82             :       HybridEos<Enthalpy<PolytropicFluid<true>>>,
      83             :       HybridEos<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
      84             :       HybridEos<Enthalpy<Spectral>>, HybridEos<Enthalpy<Enthalpy<Spectral>>>,
      85             :       HybridEos<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>>;
      86             : };
      87             : 
      88             : template <>
      89             : struct DerivedClasses<false, 2> {
      90             :   using type =
      91             :       tmpl::list<IdealFluid<false>, Barotropic2D<PolytropicFluid<false>>,
      92             :                  Barotropic2D<PiecewisePolytropicFluid<false>>,
      93             :                  HybridEos<PolytropicFluid<false>>>;
      94             : };
      95             : 
      96             : template <>
      97             : struct DerivedClasses<true, 3> {
      98             :   using type = tmpl::list<
      99             :       Tabulated3D<true>, Barotropic3D<PolytropicFluid<true>>,
     100             :       Barotropic3D<PiecewisePolytropicFluid<true>>, Barotropic3D<Spectral>,
     101             :       Barotropic3D<Enthalpy<PolytropicFluid<true>>>,
     102             :       Barotropic3D<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
     103             :       Barotropic3D<Enthalpy<Spectral>>,
     104             :       Barotropic3D<Enthalpy<Enthalpy<Spectral>>>,
     105             :       Barotropic3D<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>,
     106             :       Equilibrium3D<DarkEnergyFluid<true>>, Equilibrium3D<IdealFluid<true>>,
     107             :       Equilibrium3D<HybridEos<PolytropicFluid<true>>>,
     108             :       Equilibrium3D<HybridEos<Enthalpy<PolytropicFluid<true>>>>,
     109             :       Equilibrium3D<
     110             :           HybridEos<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>>,
     111             :       Equilibrium3D<HybridEos<Enthalpy<Spectral>>>,
     112             :       Equilibrium3D<HybridEos<Enthalpy<Enthalpy<Spectral>>>>,
     113             :       Equilibrium3D<HybridEos<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>>,
     114             :       Equilibrium3D<HybridEos<Spectral>>>;
     115             : };
     116             : 
     117             : template <>
     118             : struct DerivedClasses<false, 3> {
     119             :   using type =
     120             :       tmpl::list<Tabulated3D<false>, Barotropic3D<PolytropicFluid<false>>,
     121             :                  Barotropic3D<PiecewisePolytropicFluid<false>>,
     122             :                  Equilibrium3D<IdealFluid<false>>,
     123             :                  Equilibrium3D<HybridEos<PolytropicFluid<false>>>>;
     124             : };
     125             : 
     126             : }  // namespace detail
     127             : 
     128             : /*!
     129             :  * \ingroup EquationsOfStateGroup
     130             :  * \brief Base class for equations of state depending on whether or not the
     131             :  * system is relativistic, and the number of independent thermodynamic variables
     132             :  * (`ThermodynamicDim`) needed to determine the pressure.
     133             :  *
     134             :  * The template parameter `IsRelativistic` is `true` for relativistic equations
     135             :  * of state and `false` for non-relativistic equations of state.
     136             :  */
     137             : template <bool IsRelativistic, size_t ThermodynamicDim>
     138           1 : class EquationOfState;
     139             : 
     140             : template <typename T>
     141           0 : struct get_eos_base_impl {
     142           0 :   using type = EquationsOfState::EquationOfState<T::is_relativistic,
     143             :                                                  T::thermodynamic_dim>;
     144             : };
     145             : 
     146             : template <bool IsRelativistic, size_t ThermodynamicDim>
     147           0 : struct get_eos_base_impl<
     148             :     EquationsOfState::EquationOfState<IsRelativistic, ThermodynamicDim>> {
     149           0 :   using type =
     150             :       EquationsOfState::EquationOfState<IsRelativistic, ThermodynamicDim>;
     151             : };
     152             : 
     153             : template <typename T>
     154           0 : using get_eos_base = typename get_eos_base_impl<T>::type;
     155             : 
     156             : /*!
     157             :  * \ingroup EquationsOfStateGroup
     158             :  * \brief Base class for equations of state which need one thermodynamic
     159             :  * variable in order to determine the pressure.
     160             :  *
     161             :  * The template parameter `IsRelativistic` is `true` for relativistic equations
     162             :  * of state and `false` for non-relativistic equations of state.
     163             :  */
     164             : template <bool IsRelativistic>
     165           1 : class EquationOfState<IsRelativistic, 1> : public PUP::able {
     166             :  public:
     167           0 :   static constexpr bool is_relativistic = IsRelativistic;
     168           0 :   static constexpr size_t thermodynamic_dim = 1;
     169           0 :   using creatable_classes =
     170             :       typename detail::DerivedClasses<IsRelativistic, 1>::type;
     171             : 
     172           0 :   EquationOfState() = default;
     173           0 :   EquationOfState(const EquationOfState&) = default;
     174           0 :   EquationOfState& operator=(const EquationOfState&) = default;
     175           0 :   EquationOfState(EquationOfState&&) = default;
     176           0 :   EquationOfState& operator=(EquationOfState&&) = default;
     177           0 :   ~EquationOfState() override = default;
     178             : 
     179           0 :   explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
     180             : 
     181           0 :   WRAPPED_PUPable_abstract(EquationOfState);  // NOLINT
     182             : 
     183           0 :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 1>> get_clone()
     184             :       const = 0;
     185             : 
     186           0 :   virtual bool is_equal(
     187             :       const EquationOfState<IsRelativistic, 1>& rhs) const = 0;
     188             : 
     189             :   /// Create a 3D EOS from the 1D EOS
     190             :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
     191           1 :   promote_to_3d_eos() const = 0;
     192             : 
     193             :   /// Create a 2D EOS from the 1D EOS
     194             :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 2>>
     195           1 :   promote_to_2d_eos() const = 0;
     196             : 
     197             :   /// \brief Returns `true` if the EOS is barotropic
     198           1 :   bool is_barotropic() const { return true; }
     199             :   /// @{
     200             :   /*!
     201             :    * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
     202             :    * the rest mass density \f$\rho\f$.
     203             :    */
     204           1 :   virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
     205             :       const Scalar<double>& rest_mass_density,
     206             :       const Scalar<double>& /*temperature*/) const {
     207             :     return make_with_value<Scalar<double>>(rest_mass_density, 0.1);
     208             :   }
     209             : 
     210             :   virtual Scalar<DataVector>
     211           1 :   equilibrium_electron_fraction_from_density_temperature(
     212             :       const Scalar<DataVector>& rest_mass_density,
     213             :       const Scalar<DataVector>& /*temperature*/) const {
     214             :     return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.1);
     215             :   }
     216             :   /// @}
     217             : 
     218             :   /// @{
     219             :   /*!
     220             :    * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$.
     221             :    */
     222           1 :   virtual Scalar<double> pressure_from_density(
     223             :       const Scalar<double>& /*rest_mass_density*/) const = 0;
     224           1 :   virtual Scalar<DataVector> pressure_from_density(
     225             :       const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
     226             :   /// @}
     227             : 
     228             :   /// @{
     229             :   /*!
     230             :    * Computes the rest mass density \f$\rho\f$ from the specific enthalpy
     231             :    * \f$h\f$.
     232             :    */
     233           1 :   virtual Scalar<double> rest_mass_density_from_enthalpy(
     234             :       const Scalar<double>& /*specific_enthalpy*/) const = 0;
     235           1 :   virtual Scalar<DataVector> rest_mass_density_from_enthalpy(
     236             :       const Scalar<DataVector>& /*specific_enthalpy*/) const = 0;
     237             :   /// @}
     238             : 
     239             :   /// @{
     240             :   /*!
     241             :    * Computes the specific entropy \f$s\f$ from the rest mass density
     242             :    * \f$\rho\f$.
     243             :    */
     244           1 :   virtual Scalar<double> specific_entropy_from_density(
     245             :       const Scalar<double>& /*rest_mass_density*/) const {
     246             :     return Scalar<double>{0.0};
     247             :   }
     248           1 :   virtual Scalar<DataVector> specific_entropy_from_density(
     249             :       const Scalar<DataVector>& rest_mass_density) const {
     250             :     return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.0);
     251             :   }
     252             :   /// @}
     253             : 
     254             :   /// @{
     255             :   /*!
     256             :    * Computes the specific entropy \f$s\f$ from the specific internal energy
     257             :    * \f$\epsilon\f$.
     258             :    */
     259           1 :   virtual Scalar<double> specific_entropy_from_specific_internal_energy(
     260             :       const Scalar<double>& /*specific_internal_energy*/) const {
     261             :     return Scalar<double>{0.0};
     262             :   }
     263           1 :   virtual Scalar<DataVector> specific_entropy_from_specific_internal_energy(
     264             :       const Scalar<DataVector>& specific_internal_energy) const {
     265             :     return make_with_value<Scalar<DataVector>>(specific_internal_energy, 0.0);
     266             :   }
     267             :   /// @}
     268             : 
     269             :   /// @{
     270             :   /*!
     271             :    * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
     272             :    * density \f$\rho\f$.
     273             :    */
     274           1 :   virtual Scalar<double> specific_internal_energy_from_density(
     275             :       const Scalar<double>& /*rest_mass_density*/) const = 0;
     276           1 :   virtual Scalar<DataVector> specific_internal_energy_from_density(
     277             :       const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
     278             :   /// @}
     279             : 
     280             :   /// @{
     281             :   /*!
     282             :    * Computes the temperature \f$T\f$ from the rest mass
     283             :    * density \f$\rho\f$.
     284             :    */
     285           1 :   virtual Scalar<double> temperature_from_density(
     286             :       const Scalar<double>& /*rest_mass_density*/) const {
     287             :     return Scalar<double>{0.0};
     288             :   }
     289           1 :   virtual Scalar<DataVector> temperature_from_density(
     290             :       const Scalar<DataVector>& rest_mass_density) const {
     291             :     return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.0);
     292             :   }
     293             :   /// @}
     294             : 
     295             :   /// @{
     296             :   /*!
     297             :    * Computes the temperature \f$\T\f$ from the specific internal energy
     298             :    * \f$\epsilon\f$.
     299             :    */
     300           1 :   virtual Scalar<double> temperature_from_specific_internal_energy(
     301             :       const Scalar<double>& /*specific_internal_energy*/) const {
     302             :     return Scalar<double>{0.0};
     303             :   }
     304           1 :   virtual Scalar<DataVector> temperature_from_specific_internal_energy(
     305             :       const Scalar<DataVector>& specific_internal_energy) const {
     306             :     return make_with_value<Scalar<DataVector>>(specific_internal_energy, 0.0);
     307             :   }
     308             :   /// @}
     309             : 
     310             :   /// @{
     311             :   /*!
     312             :    * Computes \f$\chi=\partial p / \partial \rho\f$ from \f$\rho\f$, where
     313             :    * \f$p\f$ is the pressure and \f$\rho\f$ is the rest mass density.
     314             :    */
     315           1 :   virtual Scalar<double> chi_from_density(
     316             :       const Scalar<double>& /*rest_mass_density*/) const = 0;
     317           1 :   virtual Scalar<DataVector> chi_from_density(
     318             :       const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
     319             :   /// @}
     320             : 
     321             :   /// @{
     322             :   /*!
     323             :    * Computes \f$\kappa p/\rho^2=(p/\rho^2)\partial p / \partial \epsilon\f$
     324             :    * from \f$\rho\f$, where \f$p\f$ is the pressure, \f$\rho\f$ is the rest mass
     325             :    * density, and \f$\epsilon\f$ is the specific internal energy.
     326             :    *
     327             :    * The reason for not returning just
     328             :    * \f$\kappa=\partial p / \partial \epsilon\f$ is to avoid division by zero
     329             :    * for small values of \f$\rho\f$ when assembling the speed of sound with
     330             :    * some equations of state.
     331             :    */
     332           1 :   virtual Scalar<double> kappa_times_p_over_rho_squared_from_density(
     333             :       const Scalar<double>& /*rest_mass_density*/) const = 0;
     334           1 :   virtual Scalar<DataVector> kappa_times_p_over_rho_squared_from_density(
     335             :       const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
     336             : 
     337             :   /// The lower bound of the electron fraction that is valid for this EOS
     338           1 :   virtual double electron_fraction_lower_bound() const { return 0.0; }
     339             : 
     340             :   /// The upper bound of the electron fraction that is valid for this EOS
     341           1 :   virtual double electron_fraction_upper_bound() const { return 1.0; }
     342             : 
     343             :   /// The lower bound of the rest mass density that is valid for this EOS
     344           1 :   virtual double rest_mass_density_lower_bound() const = 0;
     345             : 
     346             :   /// The upper bound of the rest mass density that is valid for this EOS
     347           1 :   virtual double rest_mass_density_upper_bound() const = 0;
     348             : 
     349             :   /// The lower bound of the temperature that is valid for this EOS
     350           1 :   virtual double temperature_lower_bound() const { return 0.0; };
     351             : 
     352             :   /// The upper bound of the temperature that is valid for this EOS
     353           1 :   virtual double temperature_upper_bound() const {
     354             :     return std::numeric_limits<double>::max();
     355             :   };
     356             : 
     357             :   /// The lower bound of the specific internal energy that is valid for this EOS
     358           1 :   virtual double specific_internal_energy_lower_bound() const { return 0.0; };
     359             : 
     360             :   /// The upper bound of the specific internal energy that is valid for this EOS
     361           1 :   virtual double specific_internal_energy_upper_bound() const {
     362             :     return std::numeric_limits<double>::max();
     363             :   };
     364             : 
     365             :   /// The lower bound of the specific enthalpy that is valid for this EOS
     366           1 :   virtual double specific_enthalpy_lower_bound() const = 0;
     367             : 
     368             :   /// The vacuum mass of a baryon for this EOS
     369           1 :   virtual double baryon_mass() const {
     370             :     return hydro::units::geometric::default_baryon_mass;
     371             :   }
     372             : };
     373             : 
     374             : /*!
     375             :  * \ingroup EquationsOfStateGroup
     376             :  * \brief Base class for equations of state which need two independent
     377             :  * thermodynamic variables in order to determine the pressure.
     378             :  *
     379             :  * The template parameter `IsRelativistic` is `true` for relativistic equations
     380             :  * of state and `false` for non-relativistic equations of state.
     381             :  */
     382             : template <bool IsRelativistic>
     383           1 : class EquationOfState<IsRelativistic, 2> : public PUP::able {
     384             :  public:
     385           0 :   static constexpr bool is_relativistic = IsRelativistic;
     386           0 :   static constexpr size_t thermodynamic_dim = 2;
     387           0 :   using creatable_classes =
     388             :       typename detail::DerivedClasses<IsRelativistic, 2>::type;
     389             : 
     390           0 :   EquationOfState() = default;
     391           0 :   EquationOfState(const EquationOfState&) = default;
     392           0 :   EquationOfState& operator=(const EquationOfState&) = default;
     393           0 :   EquationOfState(EquationOfState&&) = default;
     394           0 :   EquationOfState& operator=(EquationOfState&&) = default;
     395           0 :   ~EquationOfState() override = default;
     396             : 
     397           0 :   explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
     398             : 
     399           0 :   WRAPPED_PUPable_abstract(EquationOfState);  // NOLINT
     400             : 
     401           0 :   virtual inline std::unique_ptr<EquationOfState<IsRelativistic, 2>> get_clone()
     402             :       const = 0;
     403             : 
     404           0 :   virtual bool is_equal(
     405             :       const EquationOfState<IsRelativistic, 2>& rhs) const = 0;
     406             : 
     407             :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 2>>
     408           0 :   promote_to_2d_eos() const {
     409             :     return this->get_clone();
     410             :   }
     411             : 
     412             :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
     413           0 :   promote_to_3d_eos() const = 0;
     414             : 
     415             :   /// \brief Returns `true` if the EOS is barotropic
     416           1 :   virtual bool is_barotropic() const = 0;
     417             : 
     418             :   /// \brief Returns `true` if the EOS is in beta-equilibrium
     419           1 :   virtual bool is_equilibrium() const { return true; }
     420             : 
     421             :   /// @{
     422             :   /*!
     423             :    * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
     424             :    * the rest mass density \f$\rho\f$ and the temperature \f$T\f$.
     425             :    */
     426           1 :   virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
     427             :       const Scalar<double>& rest_mass_density,
     428             :       const Scalar<double>& /*temperature*/) const {
     429             :     return make_with_value<Scalar<double>>(rest_mass_density, 0.1);
     430             :   }
     431             : 
     432             :   virtual Scalar<DataVector>
     433           1 :   equilibrium_electron_fraction_from_density_temperature(
     434             :       const Scalar<DataVector>& rest_mass_density,
     435             :       const Scalar<DataVector>& /*temperature*/) const {
     436             :     return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.1);
     437             :   }
     438             :   /// @}
     439             : 
     440             :   /// @{
     441             :   /*!
     442             :    * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$ and the
     443             :    * specific internal energy \f$\epsilon\f$.
     444             :    */
     445           1 :   virtual Scalar<double> pressure_from_density_and_energy(
     446             :       const Scalar<double>& /*rest_mass_density*/,
     447             :       const Scalar<double>& /*specific_internal_energy*/) const = 0;
     448           1 :   virtual Scalar<DataVector> pressure_from_density_and_energy(
     449             :       const Scalar<DataVector>& /*rest_mass_density*/,
     450             :       const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
     451             :   /// @}
     452             : 
     453             :   /// @{
     454             :   /*!
     455             :    * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$ and the
     456             :    * specific enthalpy \f$h\f$.
     457             :    */
     458           1 :   virtual Scalar<double> pressure_from_density_and_enthalpy(
     459             :       const Scalar<double>& /*rest_mass_density*/,
     460             :       const Scalar<double>& /*specific_enthalpy*/) const = 0;
     461           1 :   virtual Scalar<DataVector> pressure_from_density_and_enthalpy(
     462             :       const Scalar<DataVector>& /*rest_mass_density*/,
     463             :       const Scalar<DataVector>& /*specific_enthalpy*/) const = 0;
     464             :   /// @}
     465             : 
     466             :   /// @{
     467             :   /*!
     468             :    * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
     469             :    * and the specific internal energy \f$\epsilon\f$.
     470             :    */
     471           1 :   virtual Scalar<double> specific_entropy_from_density_and_energy(
     472             :       const Scalar<double>& /*rest_mass_density*/,
     473             :       const Scalar<double>& /*specific_internal_energy*/) const = 0;
     474             : 
     475           1 :   virtual Scalar<DataVector> specific_entropy_from_density_and_energy(
     476             :       const Scalar<DataVector>& /*rest_mass_density*/,
     477             :       const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
     478             :   /// @}
     479             : 
     480             :   /// @{
     481             :   /*!
     482             :    * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
     483             :    * and the temperature \f$T\f$.
     484             :    */
     485           1 :   virtual Scalar<double> specific_entropy_from_density_and_temperature(
     486             :       const Scalar<double>& /*rest_mass_density*/,
     487             :       const Scalar<double>& /*temperature*/) const = 0;
     488             : 
     489           1 :   virtual Scalar<DataVector> specific_entropy_from_density_and_temperature(
     490             :       const Scalar<DataVector>& /*rest_mass_density*/,
     491             :       const Scalar<DataVector>& /*temperature*/) const = 0;
     492             :   /// @}
     493             : 
     494             :   /// @{
     495             :   /*!
     496             :    * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
     497             :    * density \f$\rho\f$ and the pressure \f$p\f$.
     498             :    */
     499           1 :   virtual Scalar<double> specific_internal_energy_from_density_and_pressure(
     500             :       const Scalar<double>& /*rest_mass_density*/,
     501             :       const Scalar<double>& /*pressure*/) const = 0;
     502           1 :   virtual Scalar<DataVector> specific_internal_energy_from_density_and_pressure(
     503             :       const Scalar<DataVector>& /*rest_mass_density*/,
     504             :       const Scalar<DataVector>& /*pressure*/) const = 0;
     505             :   /// @}
     506             : 
     507             :   /// @{
     508             :   /*!
     509             :    * Computes the temperature \f$T\f$ from the rest mass
     510             :    * density \f$\rho\f$ and the specific internal energy \f$\epsilon\f$.
     511             :    */
     512           1 :   virtual Scalar<double> temperature_from_density_and_energy(
     513             :       const Scalar<double>& /*rest_mass_density*/,
     514             :       const Scalar<double>& /*specific_internal_energy*/) const = 0;
     515           1 :   virtual Scalar<DataVector> temperature_from_density_and_energy(
     516             :       const Scalar<DataVector>& /*rest_mass_density*/,
     517             :       const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
     518             :   /// @}
     519             : 
     520             :   /// @{
     521             :   /*!
     522             :    * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
     523             :    * density \f$\rho\f$ and the temperature \f$T\f$.
     524             :    */
     525           1 :   virtual Scalar<double> specific_internal_energy_from_density_and_temperature(
     526             :       const Scalar<double>& /*rest_mass_density*/,
     527             :       const Scalar<double>& /*temperature*/) const = 0;
     528             :   virtual Scalar<DataVector>
     529           1 :   specific_internal_energy_from_density_and_temperature(
     530             :       const Scalar<DataVector>& /*rest_mass_density*/,
     531             :       const Scalar<DataVector>& /*temperature*/) const = 0;
     532             :   /// @}
     533             : 
     534             :   /// @{
     535             :   /*!
     536             :    * Computes \f$\chi=\partial p / \partial \rho |_{\epsilon}\f$ from the
     537             :    * \f$\rho\f$ and \f$\epsilon\f$, where \f$p\f$ is the pressure, \f$\rho\f$ is
     538             :    * the rest mass density, and \f$\epsilon\f$ is the specific internal energy.
     539             :    */
     540           1 :   virtual Scalar<double> chi_from_density_and_energy(
     541             :       const Scalar<double>& /*rest_mass_density*/,
     542             :       const Scalar<double>& /*specific_internal_energy*/) const = 0;
     543           1 :   virtual Scalar<DataVector> chi_from_density_and_energy(
     544             :       const Scalar<DataVector>& /*rest_mass_density*/,
     545             :       const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
     546             :   /// @}
     547             : 
     548             :   /// @{
     549             :   /*!
     550             :    * Computes \f$\kappa p/\rho^2=(p/\rho^2)\partial p / \partial \epsilon
     551             :    * |_{\rho}\f$ from \f$\rho\f$ and \f$\epsilon\f$, where \f$p\f$ is the
     552             :    * pressure, \f$\rho\f$ is the rest mass density, and \f$\epsilon\f$ is the
     553             :    * specific internal energy.
     554             :    *
     555             :    * The reason for not returning just
     556             :    * \f$\kappa=\partial p / \partial \epsilon\f$ is to avoid division by zero
     557             :    * for small values of \f$\rho\f$ when assembling the speed of sound with
     558             :    * some equations of state.
     559             :    */
     560           1 :   virtual Scalar<double> kappa_times_p_over_rho_squared_from_density_and_energy(
     561             :       const Scalar<double>& /*rest_mass_density*/,
     562             :       const Scalar<double>& /*specific_internal_energy*/) const = 0;
     563             :   virtual Scalar<DataVector>
     564           1 :   kappa_times_p_over_rho_squared_from_density_and_energy(
     565             :       const Scalar<DataVector>& /*rest_mass_density*/,
     566             :       const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
     567             :   /// @}
     568             : 
     569             :   /// The lower bound of the electron fraction that is valid for this EOS
     570           1 :   virtual double electron_fraction_lower_bound() const { return 0.0; }
     571             : 
     572             :   /// The upper bound of the electron fraction that is valid for this EOS
     573           1 :   virtual double electron_fraction_upper_bound() const { return 1.0; }
     574             : 
     575             :   /// The lower bound of the rest mass density that is valid for this EOS
     576           1 :   virtual double rest_mass_density_lower_bound() const = 0;
     577             : 
     578             :   /// The upper bound of the rest mass density that is valid for this EOS
     579           1 :   virtual double rest_mass_density_upper_bound() const = 0;
     580             : 
     581             :   /// The lower bound of the specific internal energy that is valid for this EOS
     582             :   /// at the given rest mass density \f$\rho\f$
     583           1 :   virtual double specific_internal_energy_lower_bound(
     584             :       const double rest_mass_density) const = 0;
     585             : 
     586             :   /// The upper bound of the specific internal energy that is valid for this EOS
     587             :   /// at the given rest mass density \f$\rho\f$
     588           1 :   virtual double specific_internal_energy_upper_bound(
     589             :       const double rest_mass_density) const = 0;
     590             : 
     591             :   /// The lower bound of the temperature that is valid for this EOS
     592           1 :   virtual double temperature_lower_bound() const { return 0.0; };
     593             : 
     594             :   /// The upper bound of the temperature that is valid for this EOS
     595           1 :   virtual double temperature_upper_bound() const {
     596             :     return std::numeric_limits<double>::max();
     597             :   };
     598             : 
     599             :   /// The lower bound of the specific enthalpy that is valid for this EOS
     600           1 :   virtual double specific_enthalpy_lower_bound() const = 0;
     601             : 
     602             :   /// The vacuum mass of a baryon for this EOS
     603           1 :   virtual double baryon_mass() const {
     604             :     return hydro::units::geometric::default_baryon_mass;
     605             :   }
     606             : };
     607             : 
     608             : /*!
     609             :  * \ingroup EquationsOfStateGroup
     610             :  * \brief Base class for equations of state which need three independent
     611             :  * thermodynamic variables in order to determine the pressure.
     612             :  *
     613             :  * The template parameter `IsRelativistic` is `true` for relativistic equations
     614             :  * of state and `false` for non-relativistic equations of state.
     615             :  */
     616             : template <bool IsRelativistic>
     617             : class EquationOfState<IsRelativistic, 3> : public PUP::able {
     618             :  public:
     619             :   static constexpr bool is_relativistic = IsRelativistic;
     620             :   static constexpr size_t thermodynamic_dim = 3;
     621             :   using creatable_classes =
     622             :       typename detail::DerivedClasses<IsRelativistic, 3>::type;
     623             : 
     624             :   EquationOfState() = default;
     625             :   EquationOfState(const EquationOfState&) = default;
     626             :   EquationOfState& operator=(const EquationOfState&) = default;
     627             :   EquationOfState(EquationOfState&&) = default;
     628             :   EquationOfState& operator=(EquationOfState&&) = default;
     629             :   ~EquationOfState() override = default;
     630             : 
     631             :   explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
     632             : 
     633             :   WRAPPED_PUPable_abstract(EquationOfState);  // NOLINT
     634             : 
     635             :   virtual inline std::unique_ptr<EquationOfState<IsRelativistic, 3>> get_clone()
     636             :       const = 0;
     637             : 
     638             :   virtual bool is_equal(
     639             :       const EquationOfState<IsRelativistic, 3>& rhs) const = 0;
     640             : 
     641             :   virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
     642             :   promote_to_3d_eos() const {
     643             :     return this->get_clone();
     644             :   }
     645             : 
     646             :   /// \brief Returns `true` if the EOS is barotropic
     647             :   virtual bool is_barotropic() const = 0;
     648             : 
     649             :   /// \brief Returns `true` if the EOS is in beta-equilibrium
     650             :   virtual bool is_equilibrium() const = 0;
     651             : 
     652             :   /// @{
     653             :   /*!
     654             :    * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
     655             :    * the rest mass density \f$\rho\f$ and the temperature \f$T\f$.
     656             :    */
     657             :   virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
     658             :       const Scalar<double>& /*rest_mass_density*/,
     659             :       const Scalar<double>& /*temperature*/) const = 0;
     660             : 
     661             :   virtual Scalar<DataVector>
     662             :   equilibrium_electron_fraction_from_density_temperature(
     663             :       const Scalar<DataVector>& /*rest_mass_density*/,
     664             :       const Scalar<DataVector>& /*temperature*/) const = 0;
     665             :   /// @}
     666             : 
     667             :   /// @{
     668             :   /*!
     669             :    * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$, the
     670             :    * specific internal energy \f$\epsilon\f$ and electron fraction \f$Y_e\f$.
     671             :    */
     672             :   virtual Scalar<double> pressure_from_density_and_energy(
     673             :       const Scalar<double>& /*rest_mass_density*/,
     674             :       const Scalar<double>& /*specific_internal_energy*/,
     675             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     676             :   virtual Scalar<DataVector> pressure_from_density_and_energy(
     677             :       const Scalar<DataVector>& /*rest_mass_density*/,
     678             :       const Scalar<DataVector>& /*specific_internal_energy*/,
     679             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     680             :   /// @}
     681             : 
     682             :   /// @{
     683             :   /*!
     684             :    * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$, the
     685             :    * temperature \f$T\f$, and electron fraction \f$Y_e\f$.
     686             :    */
     687             :   virtual Scalar<double> pressure_from_density_and_temperature(
     688             :       const Scalar<double>& /*rest_mass_density*/,
     689             :       const Scalar<double>& /*temperature*/,
     690             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     691             :   virtual Scalar<DataVector> pressure_from_density_and_temperature(
     692             :       const Scalar<DataVector>& /*rest_mass_density*/,
     693             :       const Scalar<DataVector>& /*temperature*/,
     694             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     695             :   /// @}
     696             : 
     697             :   /// @{
     698             :   /*!
     699             :    * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
     700             :    * and the specific internal energy \f$\epsilon\f$ and electron fraction
     701             :    * \f$Y_e\f$.
     702             :    */
     703             :   virtual Scalar<double> specific_entropy_from_density_and_energy(
     704             :       const Scalar<double>& /*rest_mass_density*/,
     705             :       const Scalar<double>& /*specific_internal_energy*/,
     706             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     707             : 
     708             :   virtual Scalar<DataVector> specific_entropy_from_density_and_energy(
     709             :       const Scalar<DataVector>& /*rest_mass_density*/,
     710             :       const Scalar<DataVector>& /*specific_internal_energy*/,
     711             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     712             :   /// @}
     713             : 
     714             :   /// @{
     715             :   /*!
     716             :    * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
     717             :    * and the temperature \f$T\f$ and electron fraction \f$Y_e\f$.
     718             :    */
     719             :   virtual Scalar<double> specific_entropy_from_density_and_temperature(
     720             :       const Scalar<double>& /*rest_mass_density*/,
     721             :       const Scalar<double>& /*temperature*/,
     722             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     723             : 
     724             :   virtual Scalar<DataVector> specific_entropy_from_density_and_temperature(
     725             :       const Scalar<DataVector>& /*rest_mass_density*/,
     726             :       const Scalar<DataVector>& /*temperature*/,
     727             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     728             :   /// @}
     729             : 
     730             :   /// @{
     731             :   /*!
     732             :    * Computes the temperature \f$T\f$ from the rest mass
     733             :    * density \f$\rho\f$, the specific internal energy \f$\epsilon\f$,
     734             :    * and electron fraction \f$Y_e\f$.
     735             :    */
     736             :   virtual Scalar<double> temperature_from_density_and_energy(
     737             :       const Scalar<double>& /*rest_mass_density*/,
     738             :       const Scalar<double>& /*specific_internal_energy*/,
     739             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     740             :   virtual Scalar<DataVector> temperature_from_density_and_energy(
     741             :       const Scalar<DataVector>& /*rest_mass_density*/,
     742             :       const Scalar<DataVector>& /*specific_internal_energy*/,
     743             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     744             :   /// @}
     745             : 
     746             :   /// @{
     747             :   /*!
     748             :    * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
     749             :    * density \f$\rho\f$, the temperature \f$T\f$, and electron fraction
     750             :    * \f$Y_e\f$.
     751             :    */
     752             :   virtual Scalar<double> specific_internal_energy_from_density_and_temperature(
     753             :       const Scalar<double>& /*rest_mass_density*/,
     754             :       const Scalar<double>& /*temperature*/,
     755             :       const Scalar<double>& /*electron_fraction*/
     756             :   ) const = 0;
     757             :   virtual Scalar<DataVector>
     758             :   specific_internal_energy_from_density_and_temperature(
     759             :       const Scalar<DataVector>& /*rest_mass_density*/,
     760             :       const Scalar<DataVector>& /*temperature*/,
     761             :       const Scalar<DataVector>& /*electron_fraction*/
     762             :   ) const = 0;
     763             :   /// @}
     764             : 
     765             :   /// @{
     766             :   /*!
     767             :    * Computes adiabatic sound speed squared
     768             :    * \f[
     769             :    * c_s^2  \equiv \frac{\partial p}{\partial e} |_{s, Y_e} =
     770             :    * \frac{\rho}{h}\frac{\partial p}{\partial \rho} |_{e, Y_e} +
     771             :    * \frac{\partial p}{\partial e}|_{\rho, Y_e}
     772             :    * \f].
     773             :    * With \f$p, e\f$ the pressure and energy density respectively,
     774             :    * \f$s\f$ the entropy density, \f$Y_e\f$ the electron fraction
     775             :    * \f$\rho\f$ the rest-mass density, and \f$h\f$ the enthalpy density.
     776             :    * Note that \f$e\f$ is the total energy density and not the internal energy,
     777             :    * therefore
     778             :    * \f[
     779             :    * \frac{\partial p}{\partial \rho} |_{e, Y_e} \neq \chi \equiv \frac{\partial
     780             :    * p}{\partial \rho} |_{\epsilon, Y_e}
     781             :    * \f]
     782             :    * as defined in the 2-d EoS above. By definition
     783             :    * \f$ e = (1+\epsilon) \rho \f$ so holding \f$e\f$ constant
     784             :    * \f[
     785             :    *  0 = \frac{d e}{d \rho} = \frac{\partial e}{\partial \rho} +
     786             :    *     \frac{\partial e}{\partial \epsilon} \frac{\partial \epsilon}{\rho}.
     787             :    * \f]
     788             :    * (where we have suppressed \f$ Y_e\f$ dependence)
     789             :    * So \f$ \partial \epsilon /  \partial \rho |_{e} = (1 + \epsilon)/\rho \f$
     790             :    * and we can expand
     791             :    * \f[
     792             :    * \frac{\partial p}{\partial \rho} |_{e, Y_e} = \frac{\partial e}{\partial
     793             :    * \rho}_{\epsilon, Y_e} + \frac{(1 + \epsilon)}{\rho} \frac{\partial
     794             :    * e}{\partial \epsilon}|_{\rho, Y_e}
     795             :    * \f]
     796             :    *  Finally, we can rewrite the entire sound speed using only the rest-mass
     797             :    * density, specific internal energy, and electron fraction as variables,
     798             :    * by using \f$ \frac{\partial e}{\partial \epsilon}|_{\rho, Y_e} = 1 \f$
     799             :    * \f[
     800             :    * c_s^2   =
     801             :    * \frac{\rho}{h}\frac{\partial p}{\partial \rho} |_{\epsilon, Y_e} +
     802             :    * \frac{1}{\rho} \frac{\partial p}{\partial \epsilon}|_{\rho, Y_e} \left(
     803             :    * 1 - \frac{(1 + \epsilon)\rho}{h}\right)
     804             :    * \f]
     805             :    * Which reduces to our preferred form
     806             :    * \f[
     807             :    * c_s^2 =
     808             :    * \frac{\rho}{h}(\chi + \kappa)
     809             :    * \f]
     810             :    *
     811             :    * Computed as a function of temperature, rest-mass density and electron
     812             :    * fraction. Note that this will break thermodynamic consistency if the
     813             :    * pressure and internal energy interpolated separately. The precise impact of
     814             :    * this will depend on the EoS and numerical scheme used for the evolution.
     815             :    */
     816             :   virtual Scalar<double> sound_speed_squared_from_density_and_temperature(
     817             :       const Scalar<double>& /*rest_mass_density*/,
     818             :       const Scalar<double>& /*temperature*/,
     819             :       const Scalar<double>& /*electron_fraction*/) const = 0;
     820             :   virtual Scalar<DataVector> sound_speed_squared_from_density_and_temperature(
     821             :       const Scalar<DataVector>& /*rest_mass_density*/,
     822             :       const Scalar<DataVector>& /*temperature*/,
     823             :       const Scalar<DataVector>& /*electron_fraction*/) const = 0;
     824             :   /// @}
     825             : 
     826             :   /// The lower bound of the electron fraction that is valid for this EOS
     827             :   virtual double electron_fraction_lower_bound() const = 0;
     828             : 
     829             :   /// The upper bound of the electron fraction that is valid for this EOS
     830             :   virtual double electron_fraction_upper_bound() const = 0;
     831             : 
     832             :   /// The lower bound of the rest mass density that is valid for this EOS
     833             :   virtual double rest_mass_density_lower_bound() const = 0;
     834             : 
     835             :   /// The upper bound of the rest mass density that is valid for this EOS
     836             :   virtual double rest_mass_density_upper_bound() const = 0;
     837             : 
     838             :   /// The lower bound of the specific internal energy that is valid for this EOS
     839             :   /// at the given rest mass density \f$\rho\f$ and electron fraction \f$Y_e\f$.
     840             :   virtual double specific_internal_energy_lower_bound(
     841             :       const double rest_mass_density, const double electron_fraction) const = 0;
     842             : 
     843             :   /// The upper bound of the specific internal energy that is valid for this EOS
     844             :   /// at the given rest mass density \f$\rho\f$ and electron fraction \f$Y_e\f$.
     845             :   virtual double specific_internal_energy_upper_bound(
     846             :       const double rest_mass_density, const double electron_fraction) const = 0;
     847             : 
     848             :   /// The lower bound of the specific enthalpy that is valid for this EOS
     849             :   virtual double specific_enthalpy_lower_bound() const = 0;
     850             : 
     851             :   /// The lower bound of the temperature that is valid for this EOS
     852             :   virtual double temperature_lower_bound() const = 0;
     853             : 
     854             :   /// The upper bound of the temperature that is valid for this EOS
     855             :   virtual double temperature_upper_bound() const = 0;
     856             : 
     857             :   /// The vacuum mass of a baryon for this EOS
     858             :   virtual double baryon_mass() const {
     859             :     return hydro::units::geometric::default_baryon_mass;
     860             :   }
     861             : };
     862             : 
     863             : /// Compare two equations of state for equality
     864             : template <bool IsRelLhs, bool IsRelRhs, size_t ThermoDimLhs,
     865             :           size_t ThermoDimRhs>
     866           1 : bool operator==(const EquationOfState<IsRelLhs, ThermoDimLhs>& lhs,
     867             :                 const EquationOfState<IsRelRhs, ThermoDimRhs>& rhs) {
     868             :   if constexpr (IsRelLhs == IsRelRhs and ThermoDimLhs == ThermoDimRhs) {
     869             :     return typeid(lhs) == typeid(rhs) and lhs.is_equal(rhs);
     870             :   } else {
     871             :     return false;
     872             :   }
     873             : }
     874             : template <bool IsRelLhs, bool IsRelRhs, size_t ThermoDimLhs,
     875             :           size_t ThermoDimRhs>
     876           0 : bool operator!=(const EquationOfState<IsRelLhs, ThermoDimLhs>& lhs,
     877             :                 const EquationOfState<IsRelRhs, ThermoDimRhs>& rhs) {
     878             :   return not(lhs == rhs);
     879             : }
     880             : }  // namespace EquationsOfState
     881             : 
     882             : /// \cond
     883             : #define EQUATION_OF_STATE_FUNCTIONS_1D                      \
     884             :   (pressure_from_density, rest_mass_density_from_enthalpy,  \
     885             :    specific_internal_energy_from_density, chi_from_density, \
     886             :    kappa_times_p_over_rho_squared_from_density)
     887             : 
     888             : #define EQUATION_OF_STATE_FUNCTIONS_2D                                   \
     889             :   (pressure_from_density_and_energy, pressure_from_density_and_enthalpy, \
     890             :    specific_entropy_from_density_and_energy,                             \
     891             :    specific_entropy_from_density_and_temperature,                        \
     892             :    specific_internal_energy_from_density_and_pressure,                   \
     893             :    temperature_from_density_and_energy,                                  \
     894             :    specific_internal_energy_from_density_and_temperature,                \
     895             :    chi_from_density_and_energy,                                          \
     896             :    kappa_times_p_over_rho_squared_from_density_and_energy)
     897             : 
     898             : #define EQUATION_OF_STATE_FUNCTIONS_3D                                      \
     899             :   (pressure_from_density_and_energy, pressure_from_density_and_temperature, \
     900             :    specific_entropy_from_density_and_energy,                                \
     901             :    specific_entropy_from_density_and_temperature,                           \
     902             :    temperature_from_density_and_energy,                                     \
     903             :    specific_internal_energy_from_density_and_temperature,                   \
     904             :    sound_speed_squared_from_density_and_temperature)
     905             : 
     906             : #define EQUATION_OF_STATE_ARGUMENTS_EXPAND(z, n, type) \
     907             :   BOOST_PP_COMMA_IF(n) const Scalar<type>&
     908             : 
     909             : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS_HELPER(r, DIM,        \
     910             :                                                          FUNCTION_NAME) \
     911             :   Scalar<double> FUNCTION_NAME(BOOST_PP_REPEAT(                         \
     912             :       DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, double)) const override; \
     913             :   Scalar<DataVector> FUNCTION_NAME(BOOST_PP_REPEAT(                     \
     914             :       DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, DataVector)) const override;
     915             : 
     916             : /// \endcond
     917             : 
     918             : /*!
     919             :  * \ingroup EquationsOfStateGroup
     920             :  * \brief Macro used to generate forward declarations of member functions in
     921             :  * derived classes
     922             :  */
     923           1 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS(DERIVED, DIM)            \
     924             :   BOOST_PP_LIST_FOR_EACH(                                                  \
     925             :       EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS_HELPER, DIM,               \
     926             :       BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(                          \
     927             :           BOOST_PP_SUB(DIM, 1),                                            \
     928             :           (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
     929             :            EQUATION_OF_STATE_FUNCTIONS_3D))))                              \
     930             :                                                                            \
     931             :   /* clang-tidy: do not use non-const references */                        \
     932             :   void pup(PUP::er& p) override; /* NOLINT */                              \
     933             :                                                                            \
     934             :   explicit DERIVED(CkMigrateMessage* msg);
     935             : 
     936             : /// \cond
     937             : #define EQUATION_OF_STATE_FORWARD_ARGUMENTS(z, n, unused) \
     938             :   BOOST_PP_COMMA_IF(n) arg##n
     939             : 
     940             : #define EQUATION_OF_STATE_ARGUMENTS_EXPAND_NAMED(z, n, type) \
     941             :   BOOST_PP_COMMA_IF(n) const Scalar<type>& arg##n
     942             : 
     943             : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER(                        \
     944             :     TEMPLATE, DERIVED, DATA_TYPE, DIM, FUNCTION_NAME)                       \
     945             :   TEMPLATE                                                                  \
     946             :   Scalar<DATA_TYPE> DERIVED::FUNCTION_NAME(BOOST_PP_REPEAT(                 \
     947             :       DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND_NAMED, DATA_TYPE)) const {    \
     948             :     return FUNCTION_NAME##_impl(                                            \
     949             :         BOOST_PP_REPEAT(DIM, EQUATION_OF_STATE_FORWARD_ARGUMENTS, UNUSED)); \
     950             :   }
     951             : 
     952             : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER_2(r, ARGS, FUNCTION_NAME) \
     953             :   EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER(                                \
     954             :       BOOST_PP_TUPLE_ELEM(0, ARGS), BOOST_PP_TUPLE_ELEM(1, ARGS),             \
     955             :       BOOST_PP_TUPLE_ELEM(2, ARGS), BOOST_PP_TUPLE_ELEM(3, ARGS),             \
     956             :       FUNCTION_NAME)
     957             : /// \endcond
     958             : 
     959             : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS(TEMPLATE, DERIVED, DATA_TYPE, \
     960           0 :                                              DIM)                          \
     961             :   BOOST_PP_LIST_FOR_EACH(                                                  \
     962             :       EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER_2,                       \
     963             :       (TEMPLATE, DERIVED, DATA_TYPE, DIM),                                 \
     964             :       BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(                          \
     965             :           BOOST_PP_SUB(DIM, 1),                                            \
     966             :           (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
     967             :            EQUATION_OF_STATE_FUNCTIONS_3D))))
     968             : 
     969             : /// \cond
     970             : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS_HELPER(r, DIM,        \
     971             :                                                               FUNCTION_NAME) \
     972             :   template <class DataType>                                                  \
     973             :   Scalar<DataType> FUNCTION_NAME##_impl(BOOST_PP_REPEAT(                     \
     974             :       DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, DataType)) const;
     975             : /// \endcond
     976             : 
     977           0 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS(DIM)                \
     978             :   BOOST_PP_LIST_FOR_EACH(                                                  \
     979             :       EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS_HELPER, DIM,          \
     980             :       BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(                          \
     981             :           BOOST_PP_SUB(DIM, 1),                                            \
     982             :           (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
     983             :            EQUATION_OF_STATE_FUNCTIONS_3D))))

Generated by: LCOV version 1.14