#include "serif/eos/models/polytropic.hpp" #include "serif/utils/misc/finite.hpp" #include "serif/eos/exceptions.hpp" namespace serif::eos::models { using utils::misc::validate_finite; using utils::misc::validate_greater_than; using utils::misc::validate_less_than; using utils::misc::validate_nonnegativity; using namespace dimensions; using namespace relations; Polytrope::Polytrope(const PolytropeParameters& parameters) : Polytrope(parameters.n, parameters.K) {} Polytrope::Polytrope(const double n, const double K): m_polytropic_index(n), m_polytropic_constant(K), m_enthalpy_scale((n + 1.0) * K) { validate_finite(m_polytropic_index, EOSEvaluationErrorCode::outside_domain); validate_greater_than(m_polytropic_index, 1.0, EOSEvaluationErrorCode::outside_domain); validate_finite(m_polytropic_constant, EOSEvaluationErrorCode::outside_domain); validate_greater_than(m_polytropic_constant, 0.0, EOSEvaluationErrorCode::outside_domain); } [[nodiscard]] double Polytrope::polytropic_index() const noexcept { return m_polytropic_index; } [[nodiscard]] double Polytrope::polytropic_constant() const noexcept { return m_polytropic_constant; } [[nodiscard]] double Polytrope::enthalpy_scale() const noexcept { return m_enthalpy_scale; } [[nodiscard]] PressureValue Polytrope::evaluate(PressureFromDensity, const DensityValue density) const { validate_nonnegativity(density.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (density.value() == 0.0) { // P = 0 return PressureValue{0.0}; } // P = K * (ρ)^(1 + 1/n) return PressureValue{ m_polytropic_constant * std::pow(density.value(), 1.0 + 1.0 / m_polytropic_index) }; } [[nodiscard]] SpecificEnthalpyValue Polytrope::evaluate(SpecificEnthalpyFromDensity, const DensityValue density) const { validate_nonnegativity(density.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (density.value() == 0.0) { // h = 0 return SpecificEnthalpyValue{0.0}; } // h = hs * (ρ)^(1/n) return SpecificEnthalpyValue{ m_enthalpy_scale * std::pow(density.value(), 1.0 / m_polytropic_index) }; } [[nodiscard]] DensityValue Polytrope::evaluate(DensityFromSpecificEnthalpy, SpecificEnthalpyValue specific_enthalpy) const { validate_finite(specific_enthalpy.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (specific_enthalpy.value() <= 0.0) { // ρ = 0 return DensityValue{0.0}; } // ρ = (h/hs)^n return DensityValue{std::pow(specific_enthalpy.value() / m_enthalpy_scale, m_polytropic_index)}; } [[nodiscard]] PressureValue Polytrope::evaluate(PressureFromSpecificEnthalpy, SpecificEnthalpyValue specific_enthalpy) const { const DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specific_enthalpy); if (specific_enthalpy.value() <= 0.0) { // P = 0 return PressureValue{0.0}; } // P = ρ * h / (n + 1) return PressureValue{density.value() * specific_enthalpy.value()/ (m_polytropic_index + 1.0)}; } [[nodiscard]] SpecificEnthalpyValue Polytrope::evaluate(SpecificEnthalpyFromPressure, PressureValue pressure) const { validate_nonnegativity(pressure.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (pressure.value() == 0.0) { // h = 0 return SpecificEnthalpyValue{0.0}; } const double indexPlusOne = m_polytropic_index + 1.0; // h = (n+1) * (K^(n/(n+1))) * (P^(1/(n+1))) return SpecificEnthalpyValue{ indexPlusOne * std::pow(m_polytropic_constant, m_polytropic_index / indexPlusOne) * std::pow(pressure.value(), 1.0 / indexPlusOne) }; } [[nodiscard]] PartialDerivative Polytrope::partial_derivative(DensityFromSpecificEnthalpy, WithRespectTo, const SpecificEnthalpyValue specific_enthalpy) const { validate_finite(specific_enthalpy.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (specific_enthalpy.value() < 0.0) { // dρ/dh = 0 return PartialDerivative{0.0}; } if (specific_enthalpy.value() == 0.0) { // dρ/dh = n == 1 -> 1/hs // dρ/dh = else -> 0 return PartialDerivative{ m_polytropic_index == 1.0 ? 1.0 / m_enthalpy_scale : 0.0 }; } // dρ/dh = (n/hs) * (h/hs)^(n-1) return PartialDerivative{ m_polytropic_index / m_enthalpy_scale * std::pow(specific_enthalpy.value() / m_enthalpy_scale, m_polytropic_index - 1.0) }; } [[nodiscard]] PartialDerivative Polytrope::partial_derivative(PressureFromSpecificEnthalpy, WithRespectTo, const SpecificEnthalpyValue specific_enthalpy) const { const DensityValue density = evaluate(DensityFromSpecificEnthalpy{}, specific_enthalpy); // dP/dh = ρ return PartialDerivative{density.value()}; } [[nodiscard]] PartialDerivative Polytrope::partial_derivative(PressureFromDensity, WithRespectTo, const DensityValue density) const { validate_nonnegativity(density.value(), EOSEvaluationErrorCode::invalid_thermodynamic_input); if (density.value() == 0.0) { // dP/dρ = 0 return PartialDerivative{0.0}; } // dP/dρ = K * (1 + 1/n) * (ρ)^(1/n) return PartialDerivative{ m_polytropic_constant * (1.0 + 1.0 / m_polytropic_index) * std::pow(density.value(), 1.0 / m_polytropic_index) }; } }