SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/Hydro/EquationsOfState - Enthalpy.hpp Hit Total Coverage
Commit: 6fc8fdbdf23e4074652c072163d993527a2ee045 Lines: 7 97 7.2 %
Date: 2025-01-17 22:07:03
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 1.14