diff --git a/singularity-eos/CMakeLists.txt b/singularity-eos/CMakeLists.txt index 5676c19a22..1e95981544 100644 --- a/singularity-eos/CMakeLists.txt +++ b/singularity-eos/CMakeLists.txt @@ -51,6 +51,7 @@ register_headers( eos/modifiers/ramps_eos.hpp eos/modifiers/shifted_eos.hpp eos/modifiers/eos_unitsystem.hpp + eos/modifiers/minimum_energy.hpp eos/eos_base.hpp eos/eos_eospac.hpp eos/eos_noble_abel.hpp diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index cc40752045..8274006f76 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -642,7 +642,18 @@ class EosBase { PORTABLE_ALWAYS_THROW_OR_ABORT(msg); } - // Default MinInternalEnergyFromDensity behavior is to cause an error + // Default MinInternalEnergyFromDensity behavior is to just return the zero-K isotherm. + // This should be fine for all thermodynamically consistent EOS, but could cause issues + // with EOS that aren't thermodynamically consistent. + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + CRTP copy = *(static_cast(this)); + return copy.InternalEnergyFromDensityTemperature(rho, 0.); + } + + // This error is useful for EOS where the zero-K approximation is invalid for whatever + // reason PORTABLE_FORCEINLINE_FUNCTION void MinInternalEnergyIsNotEnabled(const char *eosname) const { // Construct the error message using char* so it works on device diff --git a/singularity-eos/eos/eos_gruneisen.hpp b/singularity-eos/eos/eos_gruneisen.hpp index 1e8254614a..83b3d276d0 100644 --- a/singularity-eos/eos/eos_gruneisen.hpp +++ b/singularity-eos/eos/eos_gruneisen.hpp @@ -349,8 +349,7 @@ template PORTABLE_INLINE_FUNCTION Real Gruneisen::MinInternalEnergyFromDensity(const Real rho_in, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); - MinInternalEnergyIsNotEnabled("Gruneisen"); - return 0.0; + return EosBase::MinInternalEnergyFromDensity(rho); } template PORTABLE_INLINE_FUNCTION Real Gruneisen::EntropyFromDensityInternalEnergy( diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 3dc5b07d41..74a5c108bd 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -501,12 +501,6 @@ class Helmholtz : public EosBase { thermalqs::pressure | thermalqs::temperature, lambda); return p; } - template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { - MinInternalEnergyIsNotEnabled("Helmholtz"); - return 0.0; - } template PORTABLE_INLINE_FUNCTION Real diff --git a/singularity-eos/eos/eos_jwl.hpp b/singularity-eos/eos/eos_jwl.hpp index 6cf06ad947..4905d35b85 100644 --- a/singularity-eos/eos/eos_jwl.hpp +++ b/singularity-eos/eos/eos_jwl.hpp @@ -67,9 +67,6 @@ class JWL : public EosBase { const Real rho, const Real sie, Indexer_t &&lambda = static_cast(nullptr)) const; template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; - template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(const Real rho, const Real temperature, Indexer_t &&lambda = static_cast(nullptr)) const; @@ -162,12 +159,6 @@ PORTABLE_INLINE_FUNCTION Real JWL::PressureFromDensityInternalEnergy( return ReferencePressure(rho) + _w * rho * (sie - ReferenceEnergy(rho)); } template -PORTABLE_INLINE_FUNCTION Real -JWL::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { - MinInternalEnergyIsNotEnabled("JWL"); - return 0.0; -} -template PORTABLE_INLINE_FUNCTION Real JWL::EntropyFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda) const { EntropyIsNotEnabled("JWL"); diff --git a/singularity-eos/eos/eos_mgusup.hpp b/singularity-eos/eos/eos_mgusup.hpp index 84b999ea1c..3f1784dcdd 100644 --- a/singularity-eos/eos/eos_mgusup.hpp +++ b/singularity-eos/eos/eos_mgusup.hpp @@ -61,9 +61,6 @@ class MGUsup : public EosBase { const Real rho, const Real sie, Indexer_t &&lambda = static_cast(nullptr)) const; template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; - template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(const Real rho, const Real temp, Indexer_t &&lambda = static_cast(nullptr)) const; @@ -312,12 +309,6 @@ PORTABLE_INLINE_FUNCTION Real MGUsup::PressureFromDensityInternalEnergy( return value; } template -PORTABLE_INLINE_FUNCTION Real -MGUsup::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { - MinInternalEnergyIsNotEnabled("MGUsup"); - return 0.0; -} -template PORTABLE_INLINE_FUNCTION Real MGUsup::EntropyFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda) const { Real eta = 1.0 - robust::ratio(_rho0, rho); diff --git a/singularity-eos/eos/eos_noble_abel.hpp b/singularity-eos/eos/eos_noble_abel.hpp index 4a1fdae28f..358860635d 100644 --- a/singularity-eos/eos/eos_noble_abel.hpp +++ b/singularity-eos/eos/eos_noble_abel.hpp @@ -88,12 +88,6 @@ class NobleAbel : public EosBase { return std::max(robust::SMALL(), robust::ratio(_gm1 * rho * (sie - _qq), 1.0 - _bb * rho)); } - template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { - MinInternalEnergyIsNotEnabled("Noble Abel"); - return 0.0; - } template PORTABLE_INLINE_FUNCTION Real diff --git a/singularity-eos/eos/eos_powermg.hpp b/singularity-eos/eos/eos_powermg.hpp index b30516a4f0..5e46c08853 100644 --- a/singularity-eos/eos/eos_powermg.hpp +++ b/singularity-eos/eos/eos_powermg.hpp @@ -62,9 +62,6 @@ class PowerMG : public EosBase { const Real rho, const Real sie, Indexer_t &&lambda = static_cast(nullptr)) const; template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; - template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(const Real rho, const Real temp, Indexer_t &&lambda = static_cast(nullptr)) const; @@ -409,12 +406,6 @@ PORTABLE_INLINE_FUNCTION Real PowerMG::PressureFromDensityInternalEnergy( return value; } template -PORTABLE_INLINE_FUNCTION Real -PowerMG::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { - MinInternalEnergyIsNotEnabled("PowerMG"); - return 0.0; -} -template PORTABLE_INLINE_FUNCTION Real PowerMG::EntropyFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda) const { const Real eta = 1.0 - robust::ratio(_rho0, rho); diff --git a/singularity-eos/eos/eos_sap_polynomial.hpp b/singularity-eos/eos/eos_sap_polynomial.hpp index 8499de7c59..1739aa6ef4 100644 --- a/singularity-eos/eos/eos_sap_polynomial.hpp +++ b/singularity-eos/eos/eos_sap_polynomial.hpp @@ -83,13 +83,6 @@ class SAP_Polynomial : public EosBase { sie * (_b0 + _b1 * mu + _b2e * mu * mu + _b3 * mu * mu * mu); } - template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { - MinInternalEnergyIsNotEnabled("SAP Polynomial"); - return 0.0; - }; - template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(const Real rho, const Real temperature, diff --git a/singularity-eos/eos/eos_stiff.hpp b/singularity-eos/eos/eos_stiff.hpp index d0ca49e096..707ca93210 100644 --- a/singularity-eos/eos/eos_stiff.hpp +++ b/singularity-eos/eos/eos_stiff.hpp @@ -86,13 +86,6 @@ class StiffGas : public EosBase { return std::max(-_Pinf, _gm1 * rho * (sie - _qq) - (_gm1 + 1.0) * _Pinf); } - template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { - MinInternalEnergyIsNotEnabled("StiffGas"); - return 0.0; - }; - template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(const Real rho, const Real temperature, diff --git a/singularity-eos/eos/eos_vinet.hpp b/singularity-eos/eos/eos_vinet.hpp index e7bbf8e809..46a6da1291 100644 --- a/singularity-eos/eos/eos_vinet.hpp +++ b/singularity-eos/eos/eos_vinet.hpp @@ -63,9 +63,6 @@ class Vinet : public EosBase { PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda = static_cast(nullptr)) const; - template - PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( - const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; // Entropy added AEM Dec. 2022 template PORTABLE_INLINE_FUNCTION Real @@ -346,12 +343,6 @@ PORTABLE_INLINE_FUNCTION Real Vinet::PressureFromDensityInternalEnergy( return output[1]; } template -PORTABLE_INLINE_FUNCTION Real -Vinet::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { - MinInternalEnergyIsNotEnabled("Vinet"); - return 0.0; -} -template PORTABLE_INLINE_FUNCTION Real Vinet::EntropyFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda) const { Real temp; diff --git a/singularity-eos/eos/modifiers/minimum_energy.hpp b/singularity-eos/eos/modifiers/minimum_energy.hpp new file mode 100644 index 0000000000..26356b4129 --- /dev/null +++ b/singularity-eos/eos/modifiers/minimum_energy.hpp @@ -0,0 +1,378 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_MINIMUM_ENERGY_ +#define _SINGULARITY_EOS_EOS_MINIMUM_ENERGY_ + +#include "stdio.h" +#include +#include + +#include +#include +#include + +namespace singularity { + +using namespace eos_base; + +template +class MinimumEnergy : public EosBase> { + public: + // Generic functions provided by the base class. These contain + // e.g. the vector overloads that use the scalar versions declared + // here We explicitly list, rather than using the macro because we + // overload some methods. + + // TODO(JMM): The modifier EOS's should probably call the specific + // sub-functions of the class they modify so that they can leverage, + // e.g., an especially performant or special version of these + using EosBase>::TemperatureFromDensityInternalEnergy; + using EosBase>::InternalEnergyFromDensityTemperature; + using EosBase>::PressureFromDensityTemperature; + using EosBase>::PressureFromDensityInternalEnergy; + using EosBase>::MinInternalEnergyFromDensity; + using EosBase>::EntropyFromDensityTemperature; + using EosBase>::EntropyFromDensityInternalEnergy; + using EosBase>::SpecificHeatFromDensityTemperature; + using EosBase>::SpecificHeatFromDensityInternalEnergy; + using EosBase>::BulkModulusFromDensityTemperature; + using EosBase>::BulkModulusFromDensityInternalEnergy; + using EosBase>::GruneisenParamFromDensityTemperature; + using EosBase>::GruneisenParamFromDensityInternalEnergy; + using EosBase>::FillEos; + + using BaseType = T; + + // give me std::format or fmt::format... + static std::string EosType() { + return std::string("MinimumEnergy<") + T::EosType() + std::string(">"); + } + + static std::string EosPyType() { return std::string("MinimumEnergy") + T::EosPyType(); } + + MinimumEnergy() = default; + + auto GetOnDevice() { return MinimumEnergy(t_.GetOnDevice()); } + inline void Finalize() { t_.Finalize(); } + + template + PORTABLE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.TemperatureFromDensityInternalEnergy(rho, std::max(sie, min_sie), lambda); + } + template + PORTABLE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.InternalEnergyFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.PressureFromDensityInternalEnergy(rho, std::max(sie, min_sie), lambda); + } + template + PORTABLE_FUNCTION Real + MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda = nullptr) const { + return t_.MinInternalEnergyFromDensity(rho, lambda); + } + template + PORTABLE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.EntropyFromDensityInternalEnergy(rho, std::max(sie, min_sie), lambda); + } + template + PORTABLE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.SpecificHeatFromDensityInternalEnergy(rho, std::max(sie, min_sie), lambda); + } + template + PORTABLE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.BulkModulusFromDensityInternalEnergy(rho, std::max(sie, min_sie), lambda); + } + template + PORTABLE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda = nullptr) const { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + return t_.GruneisenParamFromDensityInternalEnergy(rho, std::max(sie, min_sie), + lambda); + } + template + PORTABLE_FUNCTION Real PressureFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.PressureFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION Real EntropyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.EntropyFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.SpecificHeatFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.BulkModulusFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda = nullptr) const { + return t_.GruneisenParamFromDensityTemperature(rho, temperature, lambda); + } + template + PORTABLE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, + Real &cv, Real &bmod, const unsigned long output, + Indexer_t &&lambda = nullptr) const { + if (output & thermalqs::specific_internal_energy) { + t_.FillEos(rho, temp, energy, press, cv, bmod, output, lambda); + } else { + const Real min_sie = t_.MinInternalEnergyFromDensity(rho); + t_.FillEos(rho, temp, std::max(energy, min_sie), press, cv, bmod, output, lambda); + } + } + + // vector implementations + inline void choose_max_sie(const Real *sies, const Real *sie_use, const int num) const { + // This code makes the assumption that `sie_use` is first populated with the + // apprioriate minimum values + static auto const name = singularity::mfuncname::member_func_name( + typeid(MinimumEnergy).name(), __func__); + static auto const cname = name.c_str(); + portableFor( + cname, 0, num, + PORTABLE_LAMBDA(const int i) { sie_use[i] = std::max(sies[i], sie_use[i]); }); + } + + template + inline void TemperatureFromDensityInternalEnergy( + const Real *rhos, const Real *sies, Real *temperatures, Real *scratch, + const int num, LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.TemperatureFromDensityInternalEnergy(rhos, sie_used, temperatures, &scratch[num], + num, std::forward(lambdas), + std::forward(transform)); + } + + template + inline void PressureFromDensityTemperature(const Real *rhos, const Real *temperatures, + Real *pressures, Real *scratch, + const int num, LambdaIndexer &&lambdas, + Transform &&transform = Transform()) const { + t_.PressureFromDensityTemperature(rhos, temperatures, pressures, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void + PressureFromDensityInternalEnergy(const Real *rhos, const Real *sies, Real *pressures, + Real *scratch, const int num, LambdaIndexer &&lambdas, + Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.PressureFromDensityInternalEnergy(rhos, sie_used, pressures, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void MinInternalEnergyFromDensity(const Real *rhos, Real *sies, Real *scratch, + const int num, LambdaIndexer &&lambdas, + Transform &&transform = Transform()) const { + t_.MinInternalEnergyFromDensity(rhos, sies, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void SpecificHeatFromDensityTemperature( + const Real *rhos, const Real *temperatures, Real *cvs, Real *scratch, const int num, + LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + t_.SpecificHeatFromDensityTemperature(rhos, temperatures, cvs, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void SpecificHeatFromDensityInternalEnergy( + const Real *rhos, const Real *sies, Real *cvs, Real *scratch, const int num, + LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.SpecificHeatFromDensityInternalEnergy(rhos, sie_used, cvs, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void BulkModulusFromDensityTemperature( + const Real *rhos, const Real *temperatures, Real *bmods, Real *scratch, + const int num, LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + t_.BulkModulusFromDensityTemperature(rhos, temperatures, bmods, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void BulkModulusFromDensityInternalEnergy( + const Real *rhos, const Real *sies, Real *bmods, Real *scratch, const int num, + LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.BulkModulusFromDensityInternalEnergy(rhos, sie_used, bmods, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void GruneisenParamFromDensityTemperature( + const Real *rhos, const Real *temperatures, Real *gm1s, Real *scratch, + const int num, LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + t_.GruneisenParamFromDensityTemperature(rhos, temperatures, gm1s, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void GruneisenParamFromDensityInternalEnergy( + const Real *rhos, const Real *sies, Real *gm1s, Real *scratch, const int num, + LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.GruneisenParamFromDensityInternalEnergy(rhos, sie_used, gm1s, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void InternalEnergyFromDensityTemperature( + const Real *rhos, const Real *temperatures, Real *sies, Real *scratch, + const int num, LambdaIndexer &&lambdas, Transform &&transform = Transform()) const { + t_.InternalEnergyFromDensityTemperature(rhos, temperatures, sies, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void EntropyFromDensityTemperature(const Real *rhos, const Real *temperatures, + Real *entropies, Real *scratch, const int num, + LambdaIndexer &&lambdas, + Transform &&transform = Transform()) const { + t_.EntropyFromDensityTemperature(rhos, temperatures, entropies, scratch, num, + std::forward(lambdas), + std::forward(transform)); + } + + template + inline void + EntropyFromDensityInternalEnergy(const Real *rhos, const Real *sies, Real *entropies, + Real *scratch, const int num, LambdaIndexer &&lambdas, + Transform &&transform = Transform()) const { + Real *sie_used = scratch; + // First populate sies with minimum energies + t_.MinInternalEnergyFromDensity(rhos, sie_used, num, lambdas); + // Chose the maximum between the input and the minimum energy + choose_max_sie(sies, sie_used, num); + t_.EntropyFromDensityInternalEnergy(rhos, sies, entropies, &scratch[num], num, + std::forward(lambdas), + std::forward(transform)); + } + + PORTABLE_INLINE_FUNCTION + int nlambda() const noexcept { return t_.nlambda(); } + + static constexpr unsigned long PreferredInput() { return T::PreferredInput(); } + + static inline unsigned long scratch_size(std::string method, unsigned int nelements) { + constexpr char suffix[] = "FromDensityInternalEnergy"; + if (method.rfind(suffix) == method.length() - sizeof(suffix) + 1) { + return T::scratch_size(method, nelements) + (sizeof(Real) * nelements); + } + return T::scratch_size(method, nelements); + } + + static inline unsigned long max_scratch_size(unsigned int nelements) { + unsigned long m = T::max_scratch_size(nelements); + for (auto &&meth : + {"TemperatureFromDensityInternalEnergy", "PressureFromDensityInternalEnergy", + "SpecificHeatFromDensityInternalEnergy", "BulkModulusFromDensityInternalEnergy", + "GruneisenParamFromDensityInternalEnergy"}) { + m = std::max(m, scratch_size(meth, nelements)); + } + return m; + } + + PORTABLE_FUNCTION void PrintParams() const { t_.PrintParams(); } + template + PORTABLE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { + t_.DensityEnergyFromPressureTemperature(press, temp, lambda, rho, sie); + } + + template + PORTABLE_FUNCTION void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, + Real &press, Real &cv, Real &bmod, + Real &dpde, Real &dvdt, + Indexer_t &&lambda = nullptr) const { + t_.ValuesAtReferenceState(rho, temp, sie, press, cv, bmod, dpde, dvdt, lambda); + } + + PORTABLE_FORCEINLINE_FUNCTION Real MinimumDensity() const { + return t_.MinimumDensity(); + } + PORTABLE_FORCEINLINE_FUNCTION Real MinimumTemperature() const { + return t_.MinimumTemperature(); + } + + inline constexpr bool IsModified() const { return true; } + + inline constexpr T UnmodifyOnce() { return t_; } + + inline constexpr decltype(auto) GetUnmodifiedObject() { + return t_.GetUnmodifiedObject(); + } + + private: + T t_; +}; + +} // namespace singularity + +#endif // _SINGULARITY_EOS_EOS_SHIFTED_EOS_