SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/Hydro/EquationsOfState - Enthalpy.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 7.2 % 97 7
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 <limits>
      14              : #include <pup.h>
      15              : #include <vector>
      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/Math.hpp"
      22              : #include "Utilities/Serialization/CharmPupable.hpp"
      23              : #include "Utilities/TMPL.hpp"
      24              : 
      25              : /// \cond
      26              : class DataVector;
      27              : 
      28              : /// \endcond
      29              : 
      30              : namespace EquationsOfState {
      31              : 
      32              : /*!
      33              :  * \ingroup EquationsOfStateGroup
      34              :  * \brief An equation of state given by parametrized enthalpy
      35              :  *
      36              :  * This equation of state is determined as a function of \f$x =
      37              :  * \ln(\rho/\rho_0)\f$ where \f$\rho\f$ is the rest mass density and
      38              :  * \f$\rho_0\f$ is the provided reference density.
      39              :  * The pseudo-enthalpy \f$h \equiv (p + rho  + u)/rho\f$
      40              :  * is expanded as
      41              :  *
      42              :  * \f{equation}
      43              :  * h(x) = \sum_i a_i x^i + \sum_j b_j \sin(jkx) + c_j \cos(jkx)
      44              :  * \f}
      45              :  *
      46              :  * This form allows for convenient calculation of thermodynamic
      47              :  * quantities for a cold equation of state. For example
      48              :  *
      49              :  * \f{equation}
      50              :  * h(x) = \frac{d e} {d \rho} |_{x = \log(\rho/\rho_0)}
      51              :  * \f}
      52              :  *
      53              :  * where \f$e\f$ is the total energy density.  At the same time \f$ dx =
      54              :  * d\rho/\rho \f$ so \f$ \rho_0 e^x dx = d \rho \f$ Therefore,
      55              :  *
      56              :  * \f{equation}
      57              :  * e(x) - e(x_0) = \int_{x_0}^x h(x') e^{x'} dx '
      58              :  * \f}
      59              :  *
      60              :  * This can be computed analytically because
      61              :  *
      62              :  * \f{equation}
      63              :  *  \int a_i \frac{x^i}{i!} e^{x} dx = \sum_{j \leq i} a_i (-1)^{i-j}
      64              :  * \frac{(x)^{j}}{j!}
      65              :  * + C \f}
      66              :  *
      67              :  * and
      68              :  *
      69              :  * \f{equation}
      70              :  * \int b_j \sin(j k x) e^x dx = b_j e^x \frac{\sin(jkx) - j k \cos(jkx)}{j^2
      71              :  * k^2 + 1} \f}
      72              :  *
      73              :  * \f{equation}
      74              :  * \int c_j \cos(j k x) e^x dx = b_j e^x \frac{\cos(jkx) + j k \sin(jkx)}{j^2
      75              :  * k^2 + 1} \f}
      76              :  *
      77              :  * From this most other thermodynamic quantities can be computed
      78              :  * analytically
      79              :  *
      80              :  * The internal energy density
      81              :  * \f{equation}
      82              :  * \epsilon(x)\rho(x) = e(x)  - \rho(x)
      83              :  * \f}
      84              :  *
      85              :  * The pressure
      86              :  * \f{equation}
      87              :  * p(x) = \rho(x) h(x) - e(x)
      88              :  * \f}
      89              :  *
      90              :  * The derivative of the pressure with respect to the rest mass density
      91              :  * \f{equation}
      92              :  * \chi(x) = \frac{dp}{d\rho} |_{x = x(\rho)} = \frac{dh}{dx}
      93              :  * \f}
      94              :  *
      95              :  * Below the minimum density, a spectral parameterization
      96              :  * is used.
      97              :  *
      98              :  *
      99              :  *
     100              :  */
     101              : template <typename LowDensityEoS>
     102            1 : class Enthalpy : public EquationOfState<true, 1> {
     103              :  private:
     104            0 :   struct Coefficients {
     105            0 :     std::vector<double> polynomial_coefficients;
     106            0 :     std::vector<double> sin_coefficients;
     107            0 :     std::vector<double> cos_coefficients;
     108            0 :     double trig_scale;
     109            0 :     double reference_density;
     110            0 :     bool has_exponential_prefactor;
     111            0 :     double exponential_external_constant;
     112            0 :     Coefficients() = default;
     113            0 :     ~Coefficients() = default;
     114            0 :     Coefficients(const Coefficients& coefficients) = default;
     115            0 :     Coefficients(std::vector<double> in_polynomial_coefficients,
     116              :                  std::vector<double> in_sin_coefficients,
     117              :                  std::vector<double> in_cos_coefficients, double in_trig_scale,
     118              :                  double in_reference_density,
     119              :                  double in_exponential_constant =
     120              :                      std::numeric_limits<double>::quiet_NaN());
     121            0 :     bool operator==(const Coefficients& rhs) const;
     122              : 
     123            0 :     Enthalpy<LowDensityEoS>::Coefficients compute_exponential_integral(
     124              :         const std::pair<double, double>& initial_condition,
     125              :         const double minimum_density);
     126            0 :     Enthalpy<LowDensityEoS>::Coefficients compute_derivative();
     127            0 :     void pup(PUP::er& p);
     128              :   };
     129              : 
     130              :  public:
     131            0 :   static constexpr size_t thermodynamic_dim = 1;
     132            0 :   static constexpr bool is_relativistic = true;
     133              : 
     134            0 :   static std::string name() {
     135              :     return "Enthalpy(" + pretty_type::name<LowDensityEoS>() + ")";
     136              :   }
     137              : 
     138            0 :   struct ReferenceDensity {
     139            0 :     using type = double;
     140            0 :     static constexpr Options::String help = {"Reference density rho_0"};
     141            0 :     static double lower_bound() { return 0.0; }
     142              :   };
     143              : 
     144            0 :   struct MinimumDensity {
     145            0 :     using type = double;
     146            0 :     static constexpr Options::String help = {
     147              :         "Minimum valid density rho_min,"
     148              :         " for this parametrization"};
     149            0 :     static double lower_bound() { return 0.0; }
     150              :   };
     151            0 :   struct MaximumDensity {
     152            0 :     using type = double;
     153            0 :     static constexpr Options::String help = {"Maximum density for this EoS"};
     154            0 :     static double lower_bound() { return 0.0; }
     155              :   };
     156              : 
     157            0 :   struct PolynomialCoefficients {
     158            0 :     using type = std::vector<double>;
     159            0 :     static constexpr Options::String help = {"Polynomial coefficients a_i"};
     160              :   };
     161              : 
     162            0 :   struct TrigScaling {
     163            0 :     using type = double;
     164            0 :     static constexpr Options::String help = {
     165              :         "Fundamental wavenumber of trig "
     166              :         "functions, k"};
     167            0 :     static double lower_bound() { return 0.0; }
     168              :   };
     169              : 
     170            0 :   struct SinCoefficients {
     171            0 :     using type = std::vector<double>;
     172            0 :     static constexpr Options::String help = {"Sine coefficients b_j"};
     173              :   };
     174            0 :   struct CosCoefficients {
     175            0 :     using type = std::vector<double>;
     176            0 :     static constexpr Options::String help = {"Cosine coefficients c_j"};
     177              :   };
     178            0 :   struct StitchedLowDensityEoS {
     179            0 :     using type = LowDensityEoS;
     180            0 :     static std::string name() {
     181              :       return pretty_type::short_name<LowDensityEoS>();
     182              :     }
     183            0 :     static constexpr Options::String help = {
     184              :         "Low density EoS stitched at the MinimumDensity"};
     185              :   };
     186              : 
     187            0 :   struct TransitionDeltaEpsilon {
     188            0 :     using type = double;
     189            0 :     static constexpr Options::String help = {
     190              :         "the change in internal energy across the low-"
     191              :         "to-high-density transition, generically 0.0"};
     192            0 :     static double lower_bound() { return 0.0; }
     193              :   };
     194              : 
     195            0 :   static constexpr Options::String help = {
     196              :       "An EoS with a parametrized value h(log(rho/rho_0)) with h the specific "
     197              :       "enthalpy and rho the baryon rest mass density.  The enthalpy is "
     198              :       "expanded as a sum of polynomial terms and trigonometric corrections. "
     199              :       "let x = log(rho/rho_0) in"
     200              :       "h(x) = \\sum_i a_ix^i + \\sum_j b_jsin(k * j * x) + c_jcos(k * j * x) "
     201              :       "Note that rho(x)(1+epsilon(x)) = int_0^x e^x' h((x') dx' can be "
     202              :       "computed "
     203              :       "analytically, and therefore so can "
     204              :       "P(x) = rho(x) * (h(x) - (1 + epsilon(x))) "};
     205              : 
     206            0 :   using options =
     207              :       tmpl::list<ReferenceDensity, MaximumDensity, MinimumDensity, TrigScaling,
     208              :                  PolynomialCoefficients, SinCoefficients, CosCoefficients,
     209              :                  StitchedLowDensityEoS, TransitionDeltaEpsilon>;
     210              : 
     211            0 :   Enthalpy() = default;
     212            0 :   Enthalpy(const Enthalpy&) = default;
     213            0 :   Enthalpy& operator=(const Enthalpy&) = default;
     214            0 :   Enthalpy(Enthalpy&&) = default;
     215            0 :   Enthalpy& operator=(Enthalpy&&) = default;
     216            0 :   ~Enthalpy() override = default;
     217              : 
     218            0 :   Enthalpy(double reference_density, double max_density, double min_density,
     219              :            double trig_scale,
     220              :            const std::vector<double>& polynomial_coefficients,
     221              :            const std::vector<double>& sin_coefficients,
     222              :            const std::vector<double>& cos_coefficients,
     223              :            const LowDensityEoS& low_density_eos,
     224              :            const double transition_delta_epsilon);
     225              : 
     226            0 :   std::unique_ptr<EquationOfState<true, 1>> get_clone() const override;
     227              : 
     228            0 :   std::unique_ptr<EquationOfState<true, 3>> promote_to_3d_eos() const override;
     229              : 
     230            0 :   std::unique_ptr<EquationOfState<true, 2>> promote_to_2d_eos() const override;
     231              : 
     232            0 :   bool is_equal(const EquationOfState<true, 1>& rhs) const override;
     233              : 
     234            0 :   bool operator==(const Enthalpy<LowDensityEoS>& rhs) const;
     235              : 
     236            0 :   bool operator!=(const Enthalpy<LowDensityEoS>& rhs) const;
     237              : 
     238              :   EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS(Enthalpy, 1)
     239              : 
     240            0 :   WRAPPED_PUPable_decl_base_template(  // NOLINT
     241              :       SINGLE_ARG(EquationOfState<true, 1>), Enthalpy);
     242              : 
     243              :   /// The lower bound of the rest mass density that is valid for this EOS
     244            1 :   double rest_mass_density_lower_bound() const override { return 0.0; }
     245              : 
     246              :   /// The upper bound of the rest mass density that is valid for this EOS
     247            1 :   double rest_mass_density_upper_bound() const override {
     248              :     return std::numeric_limits<double>::max();
     249              :   }
     250              : 
     251              :   /// The lower bound of the specific enthalpy that is valid for this EOS
     252            1 :   double specific_enthalpy_lower_bound() const override { return 1.0; }
     253              : 
     254              :   /// The lower bound of the specific internal energy that is valid for this EOS
     255            1 :   double specific_internal_energy_lower_bound() const override { return 0.0; }
     256              : 
     257              :   /// The upper bound of the specific internal energy that is valid for this EOS
     258            1 :   double specific_internal_energy_upper_bound() const override {
     259              :     return std::numeric_limits<double>::max();
     260              :   }
     261              : 
     262              :   /// The vacuum baryon mass for this EoS
     263            1 :   double baryon_mass() const override { return low_density_eos_.baryon_mass(); }
     264              : 
     265              :  private:
     266              :   EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS(1)
     267              : 
     268              :   SPECTRE_ALWAYS_INLINE
     269            0 :   bool in_low_density_domain(const double rest_mass_density) const {
     270              :     return rest_mass_density < minimum_density_;
     271              :   }
     272              : 
     273            0 :   double x_from_density(const double rest_mass_density) const;
     274            0 :   double density_from_x(const double x) const;
     275            0 :   double energy_density_from_log_density(const double x,
     276              :                                          const double rest_mass_density) const;
     277            0 :   static double evaluate_coefficients(
     278              :       const Enthalpy::Coefficients& coefficients, const double x,
     279              :       const double exponential_prefactor =
     280              :           std::numeric_limits<double>::signaling_NaN());
     281            0 :   static Enthalpy::Coefficients compute_pressure_coefficients(
     282              :       const typename Enthalpy::Coefficients& enthalpy,
     283              :       const typename Enthalpy::Coefficients& energy_density);
     284              : 
     285            0 :   double chi_from_density(const double rest_mass_density) const;
     286            0 :   double specific_internal_energy_from_density(
     287              :       const double rest_mass_density) const;
     288            0 :   double specific_enthalpy_from_density(const double rest_mass_density) const;
     289            0 :   double pressure_from_density(const double rest_mass_density) const;
     290            0 :   double pressure_from_log_density(const double x,
     291              :                                    const double rest_mass_density) const;
     292            0 :   double rest_mass_density_from_enthalpy(const double specific_enthalpy) const;
     293              : 
     294            0 :   double reference_density_ = std::numeric_limits<double>::signaling_NaN();
     295            0 :   double minimum_density_ = std::numeric_limits<double>::signaling_NaN();
     296            0 :   double maximum_density_ = std::numeric_limits<double>::signaling_NaN();
     297            0 :   double minimum_enthalpy_ = std::numeric_limits<double>::signaling_NaN();
     298              : 
     299            0 :   LowDensityEoS low_density_eos_;
     300            0 :   Coefficients coefficients_;
     301            0 :   Coefficients exponential_integral_coefficients_;
     302            0 :   Coefficients derivative_coefficients_;
     303            0 :   Coefficients pressure_coefficients_;
     304              : };
     305              : 
     306              : }  // namespace EquationsOfState
        

Generated by: LCOV version 2.0-1