From 53bc81a03b68e99798ba6a4b1b6a16b47ff1001d Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 14 Aug 2024 16:32:17 -0600 Subject: [PATCH 01/48] temporarily switch to spiner serialization branch --- utils/spiner | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/spiner b/utils/spiner index 0d0d7474f3..bd57161576 160000 --- a/utils/spiner +++ b/utils/spiner @@ -1 +1 @@ -Subproject commit 0d0d7474f34cdc168c141185cc692b65ee8ad0c0 +Subproject commit bd57161576a62a13341dada183f2b336a3e99b08 From bc4b50af77e28f7f333cb62d962f411b7b2148c5 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 14 Aug 2024 18:26:19 -0600 Subject: [PATCH 02/48] It works for analytic EOSs and modifiers and the variant --- singularity-eos/eos/eos_base.hpp | 44 +++++++++++++ singularity-eos/eos/eos_variant.hpp | 41 ++++++++++++ .../eos/modifiers/eos_unitsystem.hpp | 7 +++ singularity-eos/eos/modifiers/ramps_eos.hpp | 4 ++ .../eos/modifiers/relativistic_eos.hpp | 7 +++ singularity-eos/eos/modifiers/scaled_eos.hpp | 7 +++ singularity-eos/eos/modifiers/shifted_eos.hpp | 7 +++ test/test_eos_ideal.cpp | 62 +++++++++++++++++++ test/test_eos_modifiers.cpp | 52 +++++++++++++++- 9 files changed, 228 insertions(+), 3 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index cc40752045..67328cb626 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -83,6 +83,12 @@ char *StrCat(char *destination, const char *source) { using EosBase::EntropyFromDensityInternalEnergy; \ using EosBase::EntropyIsNotEnabled; \ using EosBase::MinInternalEnergyIsNotEnabled; \ + using EosBase::DynamicMemorySizeInBytes; \ + using EosBase::DumpDynamicMemory; \ + using EosBase::SetDynamicMemory; \ + using EosBase::SerializedSizeInBytes; \ + using EosBase::Serialize; \ + using EosBase::DeSerialize; \ using EosBase::IsModified; \ using EosBase::UnmodifyOnce; \ using EosBase::GetUnmodifiedObject; @@ -657,6 +663,44 @@ class EosBase { PORTABLE_ALWAYS_THROW_OR_ABORT(msg); } + // Serialization + // JMM: These must be special-cased. + std::size_t DynamicMemorySizeInBytes() const { return 0; } + std::size_t DumpDynamicMemory(char *dst) const { return 0; } + std::size_t SetDynamicMemory(char *src) { return 0; } + // JMM: These are generic and do not need to be special-cased. + // TODO(JMM): Should this machinery actually be available for "bare" + // EOS's outside the variant? + // TODO(JMM): Should I try to reduce the amount of duplicated code + // between here and the variant? Is this a rare case where multiple + // inheritence or mixins would be useful? Probably more trouble than + // its work for ~20 LOC... + std::size_t SerializedSizeInBytes() const { + // sizeof(*this) apparently returns the size of JUST the base + // class. + return DynamicMemorySizeInBytes() + sizeof(CRTP); + } + std::size_t Serialize(char *dst) const { + memcpy(dst, this, sizeof(CRTP)); + if (DynamicMemorySizeInBytes() > 0) { + DumpDynamicMemory(dst + sizeof(CRTP)); + } + return SerializedSizeInBytes(); + } + auto Serialize() const { + std::size_t size = SerializedSizeInBytes(); + char *dst = (char *)malloc(size); + Serialize(dst); + return std::make_pair(size, dst); + } + std::size_t DeSerialize(char *src) { + memcpy(this, src, sizeof(CRTP)); + if (DynamicMemorySizeInBytes() > 0) { + SetDynamicMemory(src + sizeof(CRTP)); + } + return SerializedSizeInBytes(); + } + // Tooling for modifiers inline constexpr bool IsModified() const { return false; } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 1a98dfdcc8..36fc79a45c 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1013,6 +1013,47 @@ class Variant { eos_); } + // Serialization + // JMM: This must be implemented separately for Variant vs the base + // class/individual EOS's so that the variant state is properly + // carried. Otherwise de-serialization would need to specify a type. + std::size_t DynamicMemorySizeInBytes() const { + return mpark::visit([](const auto &eos) { return eos.DynamicMemorySizeInBytes(); }, + eos_); + } + std::size_t DumpDynamicMemory(char *dst) const { + return mpark::visit([dst](const auto &eos) { return eos.DumpDynamicMemory(dst); }, + eos_); + } + std::size_t SetDynamicMemory(char *src) { + return mpark::visit([src](auto &eos) { return eos.SetDynamicMemory(src); }, eos_); + } + std::size_t SerializedSizeInBytes() const { + return sizeof(*this) + DynamicMemorySizeInBytes(); + } + std::size_t Serialize(char *dst) const { + memcpy(dst, this, sizeof(*this)); + std::size_t offst = sizeof(*this); + if (DynamicMemorySizeInBytes() > 0) { + offst += DumpDynamicMemory(dst + offst); + } + return offst; + } + auto Serialize() const { + std::size_t size = SerializedSizeInBytes(); + char *dst = (char *)malloc(size); + Serialize(dst); + return std::make_pair(size, dst); + } + std::size_t DeSerialize(char *src) { + memcpy(this, src, sizeof(*this)); + std::size_t offst = sizeof(*this); + if (DynamicMemorySizeInBytes() > 0) { + offst += SetDynamicMemory(src + sizeof(*this)); + } + return offst; + } + // Tooling for modifiers inline constexpr bool IsModified() const { return mpark::visit([](const auto &eos) { return eos.IsModified(); }, eos_); diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index 5d513fd543..c5ad576598 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -65,6 +65,9 @@ class UnitSystem : public EosBase> { using EosBase>::GruneisenParamFromDensityTemperature; using EosBase>::GruneisenParamFromDensityInternalEnergy; using EosBase>::FillEos; + using EosBase>::SerializedSizeInBytes; + using EosBase>::Serialize; + using EosBase>::DeSerialize; using BaseType = T; @@ -445,6 +448,10 @@ class UnitSystem : public EosBase> { return t_.GetUnmodifiedObject(); } + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } + std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + private: T t_; diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index d9c46048c8..e90a4e7038 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -452,6 +452,10 @@ class BilinearRampEOS : public EosBase> { return t_.GetUnmodifiedObject(); } + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } + std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + private: T t_; Real r0_; diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index 47726b8c6e..fc3a3ab4a4 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -57,6 +57,9 @@ class RelativisticEOS : public EosBase> { using EosBase>::GruneisenParamFromDensityTemperature; using EosBase>::GruneisenParamFromDensityInternalEnergy; using EosBase>::FillEos; + using EosBase>::SerializedSizeInBytes; + using EosBase>::Serialize; + using EosBase>::DeSerialize; using BaseType = T; @@ -201,6 +204,10 @@ class RelativisticEOS : public EosBase> { return t_.GetUnmodifiedObject(); } + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } + std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + private: T t_; Real cl_, cl2_; diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 930e5baa83..70b7e784e1 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -57,6 +57,9 @@ class ScaledEOS : public EosBase> { using EosBase>::GruneisenParamFromDensityTemperature; using EosBase>::GruneisenParamFromDensityInternalEnergy; using EosBase>::FillEos; + using EosBase>::SerializedSizeInBytes; + using EosBase>::Serialize; + using EosBase>::DeSerialize; using BaseType = T; @@ -361,6 +364,10 @@ class ScaledEOS : public EosBase> { return t_.GetUnmodifiedObject(); } + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } + std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + private: T t_; double scale_; diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index d36a243135..ff8366a5f5 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -57,6 +57,9 @@ class ShiftedEOS : public EosBase> { using EosBase>::GruneisenParamFromDensityTemperature; using EosBase>::GruneisenParamFromDensityInternalEnergy; using EosBase>::FillEos; + using EosBase>::SerializedSizeInBytes; + using EosBase>::Serialize; + using EosBase>::DeSerialize; using BaseType = T; @@ -374,6 +377,10 @@ class ShiftedEOS : public EosBase> { return t_.GetUnmodifiedObject(); } + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } + std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + private: T t_; double shift_; diff --git a/test/test_eos_ideal.cpp b/test/test_eos_ideal.cpp index 211ef6b3ba..0c9ec78675 100644 --- a/test/test_eos_ideal.cpp +++ b/test/test_eos_ideal.cpp @@ -137,3 +137,65 @@ SCENARIO("Ideal gas vector Evaluate call", "[IdealGas][Evaluate]") { PORTABLE_FREE(sie); } } + +struct Dummy {}; +SCENARIO("Ideal gas serialization", "[IdealGas][Serialization]") { + GIVEN("An ideal gas object on host and a variant on host") { + constexpr Real Cv = 2.0; + constexpr Real gm1 = 0.5; + IdealGas eos_bare(gm1, Cv); + EOS eos_variant = IdealGas(gm1, Cv); + + THEN("They both report zero dynamic memory size") { + REQUIRE(eos_bare.DynamicMemorySizeInBytes() == 0); + REQUIRE(eos_variant.DynamicMemorySizeInBytes() == 0); + } + + THEN("They both report sizes larger than a trivial struct, such that the eos variant " + "size >= eos_bare size") { + REQUIRE(eos_bare.SerializedSizeInBytes() > sizeof(Dummy)); + REQUIRE(eos_variant.SerializedSizeInBytes() > sizeof(Dummy)); + REQUIRE(eos_variant.SerializedSizeInBytes() >= eos_bare.SerializedSizeInBytes()); + } + + WHEN("We serialize each") { + auto [size_bare, data_bare] = eos_bare.Serialize(); + auto [size_var, data_var] = eos_variant.Serialize(); + + THEN("The reported sizes are what we expect") { + REQUIRE(size_bare == eos_bare.SerializedSizeInBytes()); + REQUIRE(size_var == eos_variant.SerializedSizeInBytes()); + } + + THEN("We can de-serialize new objects from them") { + IdealGas new_bare; + new_bare.DeSerialize(data_bare); + + EOS new_variant; + new_variant.DeSerialize(data_var); + + AND_THEN("The bare eos has the right Cv and Gruneisen params") { + REQUIRE(new_bare.SpecificHeatFromDensityTemperature(1.0, 1.0) == Cv); + REQUIRE(new_bare.GruneisenParamFromDensityTemperature(1.0, 1.0) == gm1); + } + + AND_THEN("The variant has the right type") { + REQUIRE(new_variant.IsType()); + } + + AND_THEN("The bare eos has the right Cv and Gruneisen params") { + REQUIRE(new_variant.SpecificHeatFromDensityTemperature(1.0, 1.0) == Cv); + REQUIRE(new_variant.GruneisenParamFromDensityTemperature(1.0, 1.0) == gm1); + } + } + + // cleanup + free(data_bare); + free(data_var); + } + + // cleanup + eos_bare.Finalize(); + eos_variant.Finalize(); + } +} diff --git a/test/test_eos_modifiers.cpp b/test/test_eos_modifiers.cpp index 09c52ecdfc..cabccc25f6 100644 --- a/test/test_eos_modifiers.cpp +++ b/test/test_eos_modifiers.cpp @@ -12,6 +12,8 @@ // publicly and display publicly, and to permit others to do so. //------------------------------------------------------------------------------ +#include + #include #include #include @@ -290,13 +292,57 @@ SCENARIO("EOS Unit System", "[EOSBuilder][UnitSystem][IdealGas]") { eos = Modify(eos, eos_units_init::length_time_units_init_tag, time_unit, mass_unit, length_unit, temp_unit); THEN("Units cancel out for an ideal gas") { - Real rho = 1e3; - Real sie = 1e3; + constexpr Real rho = 1e3; + constexpr Real sie = 1e3; + constexpr Real Ptrue = gm1 * rho * sie; Real P = eos.PressureFromDensityInternalEnergy(rho, sie); - Real Ptrue = gm1 * rho * sie; REQUIRE(std::abs(P - Ptrue) / Ptrue < 1e-3); } } } } } + +SCENARIO("Serialization of modified EOSs preserves their properties", + "[ScaledEOS][IdealGas][Serialization]") { + GIVEN("A scaled ideal gas object") { + constexpr Real Cv = 2.0; + constexpr Real gm1 = 0.5; + constexpr Real scale = 2.0; + + constexpr Real rho_test = 1.0; + constexpr Real sie_test = 1.0; + constexpr Real temp_test = sie_test / (Cv * scale); // = 1./4. + constexpr Real EPS = 10 * std::numeric_limits::epsilon(); + + ScaledEOS eos(IdealGas(gm1, Cv), scale); + REQUIRE(isClose(eos.TemperatureFromDensityInternalEnergy(rho_test, sie_test), + temp_test, EPS)); + + THEN("The size of the object is larger than just the ideal gas by itself") { + REQUIRE(eos.SerializedSizeInBytes() > sizeof(IdealGas)); + } + + WHEN("We serialize the EOS") { + auto [size, data] = eos.Serialize(); + REQUIRE(size == eos.SerializedSizeInBytes()); + REQUIRE(size > 0); + REQUIRE(data != nullptr); + + THEN("We can de-serialize the EOS") { + ScaledEOS eos_new; + eos_new.DeSerialize(data); + + AND_THEN("The de-serialized EOS still evaluates properly") { + REQUIRE( + isClose(eos_new.TemperatureFromDensityInternalEnergy(rho_test, sie_test), + temp_test, EPS)); + } + } + + free(data); + } + + eos.Finalize(); + } +} From 073dbe5090bda0dffe562dcde538e59b8d4fe6c3 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 09:48:53 -0600 Subject: [PATCH 03/48] add CheckParams as official part of API --- singularity-eos/eos/eos_carnahan_starling.hpp | 6 +++--- singularity-eos/eos/eos_davis.hpp | 13 ++++++++++++- singularity-eos/eos/eos_eospac.hpp | 3 +++ singularity-eos/eos/eos_gruneisen.hpp | 5 +++++ singularity-eos/eos/eos_helmholtz.hpp | 4 ++++ singularity-eos/eos/eos_ideal.hpp | 6 +++--- singularity-eos/eos/eos_jwl.hpp | 9 ++++++--- singularity-eos/eos/eos_mgusup.hpp | 7 +++---- singularity-eos/eos/eos_noble_abel.hpp | 6 +++--- singularity-eos/eos/eos_powermg.hpp | 18 ++++++++---------- singularity-eos/eos/eos_sap_polynomial.hpp | 4 ++-- singularity-eos/eos/eos_spiner.hpp | 8 ++++++++ singularity-eos/eos/eos_stellar_collapse.hpp | 4 ++++ singularity-eos/eos/eos_stiff.hpp | 6 +++--- singularity-eos/eos/eos_variant.hpp | 5 +++++ singularity-eos/eos/eos_vinet.hpp | 6 +++--- .../eos/modifiers/eos_unitsystem.hpp | 12 +++++++++++- singularity-eos/eos/modifiers/ramps_eos.hpp | 16 ++++++++++++---- .../eos/modifiers/relativistic_eos.hpp | 13 ++++++++++++- singularity-eos/eos/modifiers/scaled_eos.hpp | 13 ++++++++++++- singularity-eos/eos/modifiers/shifted_eos.hpp | 10 +++++++++- 21 files changed, 131 insertions(+), 43 deletions(-) diff --git a/singularity-eos/eos/eos_carnahan_starling.hpp b/singularity-eos/eos/eos_carnahan_starling.hpp index b54bdb5242..e77e844332 100644 --- a/singularity-eos/eos/eos_carnahan_starling.hpp +++ b/singularity-eos/eos/eos_carnahan_starling.hpp @@ -47,7 +47,7 @@ class CarnahanStarling : public EosBase { (PartialRhoZedFromDensity(_rho0) + ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)), _dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) { - checkParams(); + CheckParams(); } PORTABLE_INLINE_FUNCTION CarnahanStarling(Real gm1, Real Cv, Real bb, Real qq, Real qp, Real T0, Real P0) @@ -58,7 +58,7 @@ class CarnahanStarling : public EosBase { (PartialRhoZedFromDensity(_rho0) + ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)), _dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) { - checkParams(); + CheckParams(); } CarnahanStarling GetOnDevice() { return *this; } template @@ -67,7 +67,7 @@ class CarnahanStarling : public EosBase { Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), (sie - _qq) / _Cv); } - PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_INLINE_FUNCTION void CheckParams() const { PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive"); PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); PORTABLE_ALWAYS_REQUIRE(_bb >= 0, "Covolume must be positive"); diff --git a/singularity-eos/eos/eos_davis.hpp b/singularity-eos/eos/eos_davis.hpp index fb34c2a229..f81bca867d 100644 --- a/singularity-eos/eos/eos_davis.hpp +++ b/singularity-eos/eos/eos_davis.hpp @@ -37,8 +37,15 @@ class DavisReactants : public EosBase { const Real A, const Real B, const Real C, const Real G0, const Real Z, const Real alpha, const Real Cv0) : _rho0(rho0), _e0(e0), _P0(P0), _T0(T0), _A(A), _B(B), _C(C), _G0(G0), _Z(Z), - _alpha(alpha), _Cv0(Cv0) {} + _alpha(alpha), _Cv0(Cv0) { + CheckParams(); + } DavisReactants GetOnDevice() { return *this; } + PORTABLE_INLINE_FUNCTION + void CheckParams() const { + PORTABLE_REQUIRE(rho0 >= 0, "Density must be positive"); + PORTABLE_REQUIRE(T0 >= 0, "Temperature must be positive"); + } template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, @@ -193,6 +200,10 @@ class DavisProducts : public EosBase { DavisProducts(const Real a, const Real b, const Real k, const Real n, const Real vc, const Real pc, const Real Cv) : _a(a), _b(b), _k(k), _n(n), _vc(vc), _pc(pc), _Cv(Cv) {} + PORTABLE_INLINE_FUNCTION + void CheckParams() const { + // TODO(JMM): Stub. + } DavisProducts GetOnDevice() { return *this; } template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 343d72690b..698cc22316 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -140,6 +140,9 @@ class EOSPAC : public EosBase { bool apply_smoothing = false, eospacSplit apply_splitting = eospacSplit::none, bool linear_interp = false); + PORTABLE_INLINE_FUNCTION void CheckParams() const { + // TODO(JMM): STUB + } inline EOSPAC GetOnDevice() { return *this; } SG_PIF_NOWARN template diff --git a/singularity-eos/eos/eos_gruneisen.hpp b/singularity-eos/eos/eos_gruneisen.hpp index f5ff57c958..3ac2f9dd8c 100644 --- a/singularity-eos/eos/eos_gruneisen.hpp +++ b/singularity-eos/eos/eos_gruneisen.hpp @@ -63,6 +63,11 @@ class Gruneisen : public EosBase { _Cv(Cv), _rho_max(RHOMAX_SAFETY * ComputeRhoMax(s1, s2, s3, rho0)) {} static PORTABLE_INLINE_FUNCTION Real ComputeRhoMax(const Real s1, const Real s2, const Real s3, const Real rho0); + PORTABLE_INLINE_FUNCTION + void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(_T0 >= 0, "Non-negative reference temperature"); + PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Non-negative reference density"); + } PORTABLE_INLINE_FUNCTION Real MaxStableDensityAtTemperature(const Real temperature) const; Gruneisen GetOnDevice() { return *this; } diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 3dc5b07d41..c5d8ea6c80 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -416,6 +416,10 @@ class Helmholtz : public EosBase { : electrons_(filename), options_(rad, gas, coul, ion, ele, verbose, newton_raphson) {} + PORTABLE_INLINE_FUNCTION void CheckParams() const { + // TODO(JMM): Stub + } + PORTABLE_INLINE_FUNCTION int nlambda() const noexcept { return 3; } static constexpr unsigned long PreferredInput() { return thermalqs::density | thermalqs::temperature; diff --git a/singularity-eos/eos/eos_ideal.hpp b/singularity-eos/eos/eos_ideal.hpp index 489c3a6553..352cf03c14 100644 --- a/singularity-eos/eos/eos_ideal.hpp +++ b/singularity-eos/eos/eos_ideal.hpp @@ -42,13 +42,13 @@ class IdealGas : public EosBase { : _Cv(Cv), _gm1(gm1), _rho0(_P0 / (_gm1 * _Cv * _T0)), _sie0(_Cv * _T0), _bmod0((_gm1 + 1) * _gm1 * _rho0 * _Cv * _T0), _dpde0(_gm1 * _rho0), _dvdt0(1. / (_rho0 * _T0)), _EntropyT0(_T0), _EntropyRho0(_rho0) { - checkParams(); + CheckParams(); } PORTABLE_INLINE_FUNCTION IdealGas(Real gm1, Real Cv, Real EntropyT0, Real EntropyRho0) : _Cv(Cv), _gm1(gm1), _rho0(_P0 / (_gm1 * _Cv * _T0)), _sie0(_Cv * _T0), _bmod0((_gm1 + 1) * _gm1 * _rho0 * _Cv * _T0), _dpde0(_gm1 * _rho0), _dvdt0(1. / (_rho0 * _T0)), _EntropyT0(EntropyT0), _EntropyRho0(EntropyRho0) { - checkParams(); + CheckParams(); } IdealGas GetOnDevice() { return *this; } @@ -58,7 +58,7 @@ class IdealGas : public EosBase { Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, sie / _Cv); } - PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_INLINE_FUNCTION void CheckParams() const { // Portable_require seems to do the opposite of what it should. Conditions // reflect this and the code should be changed when ports-of-call changes PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive"); diff --git a/singularity-eos/eos/eos_jwl.hpp b/singularity-eos/eos/eos_jwl.hpp index 6cf06ad947..1931541630 100644 --- a/singularity-eos/eos/eos_jwl.hpp +++ b/singularity-eos/eos/eos_jwl.hpp @@ -45,9 +45,12 @@ class JWL : public EosBase { _c1(robust::ratio(A, rho0 * R1)), _c2(robust::ratio(B, rho0 * R2)) { assert(R1 > 0.0); assert(R2 > 0.0); - assert(w > 0.0); - assert(rho0 > 0.0); - assert(Cv > 0.0); + CheckParams(); + } + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(_w > 0.0, "w > 0"); + PORTABLE_ALWAYS_REQUIRE(_rho0 > 0.0, "Positive reference density"); + PORTABLE_ALWAYS_REQUIRE(_Cv > 0.0, "Positive specific heat"); } JWL GetOnDevice() { return *this; } template diff --git a/singularity-eos/eos/eos_mgusup.hpp b/singularity-eos/eos/eos_mgusup.hpp index ab42dbe7c4..8fae069056 100644 --- a/singularity-eos/eos/eos_mgusup.hpp +++ b/singularity-eos/eos/eos_mgusup.hpp @@ -40,8 +40,9 @@ class MGUsup : public EosBase { MGUsup(const Real rho0, const Real T0, const Real Cs, const Real s, const Real G0, const Real Cv0, const Real E0, const Real S0) : _rho0(rho0), _T0(T0), _Cs(Cs), _s(s), _G0(G0), _Cv0(Cv0), _E0(E0), _S0(S0) { - _CheckMGUsup(); + CheckParams(); } + PORTABLE_INLINE_FUNCTION void CheckParams() const; MGUsup GetOnDevice() { return *this; } template @@ -156,11 +157,9 @@ class MGUsup : public EosBase { static constexpr const unsigned long _preferred_input = thermalqs::density | thermalqs::specific_internal_energy; Real _rho0, _T0, _Cs, _s, _G0, _Cv0, _E0, _S0; - void _CheckMGUsup(); }; -inline void MGUsup::_CheckMGUsup() { - +PORTABLE_INLINE_FUNCTION void MGUsup::CheckParams() const { if (_rho0 < 0.0) { PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter rho0 < 0"); } diff --git a/singularity-eos/eos/eos_noble_abel.hpp b/singularity-eos/eos/eos_noble_abel.hpp index 898f1b8a3d..a39816996b 100644 --- a/singularity-eos/eos/eos_noble_abel.hpp +++ b/singularity-eos/eos/eos_noble_abel.hpp @@ -44,7 +44,7 @@ class NobleAbel : public EosBase { _bmod0(robust::ratio(_rho0 * Cv * _T0 * gm1 * (gm1 + 1.0), (1.0 - bb * _rho0) * (1.0 - bb * _rho0))), _dpde0(robust::ratio(_rho0 * gm1, 1.0 - bb * _rho0)) { - checkParams(); + CheckParams(); } PORTABLE_INLINE_FUNCTION NobleAbel(Real gm1, Real Cv, Real bb, Real qq, Real qp, Real T0, Real P0) @@ -54,7 +54,7 @@ class NobleAbel : public EosBase { _bmod0(robust::ratio(_rho0 * Cv * T0 * gm1 * (gm1 + 1.0), (1.0 - bb * _rho0) * (1.0 - bb * _rho0))), _dpde0(robust::ratio(_rho0 * gm1, 1.0 - bb * _rho0)) { - checkParams(); + CheckParams(); } NobleAbel GetOnDevice() { return *this; } template @@ -63,7 +63,7 @@ class NobleAbel : public EosBase { Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), (sie - _qq) / _Cv); } - PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_INLINE_FUNCTION void CheckParams() const { PORTABLE_ALWAYS_REQUIRE(_Cv > 0, "Heat capacity must be positive"); PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); PORTABLE_ALWAYS_REQUIRE(_bb >= 0, "Covolume must be positive"); diff --git a/singularity-eos/eos/eos_powermg.hpp b/singularity-eos/eos/eos_powermg.hpp index d73a994a5a..3b17e8aae9 100644 --- a/singularity-eos/eos/eos_powermg.hpp +++ b/singularity-eos/eos/eos_powermg.hpp @@ -41,9 +41,15 @@ class PowerMG : public EosBase { const Real S0, const Real Pmin, const Real *expconsts) : _rho0(rho0), _T0(T0), _G0(G0), _Cv0(Cv0), _E0(E0), _S0(S0), _Pmin(Pmin) { _InitializePowerMG(expconsts); - _CheckPowerMG(); + CheckParams(); + if (_Pmin >= 0.0) { + _Pmin = -1000 * _K0toK40[0]; + PORTABLE_WARN("PowerMG model parameter Pmin not set or positive. Reset to default " + "(-1000*K0)"); + } } + PORTABLE_INLINE_FUNCTION void CheckParams() const; PowerMG GetOnDevice() { return *this; } template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( @@ -164,7 +170,6 @@ class PowerMG : public EosBase { static constexpr const int PressureCoeffsK0toK40Size = 41; int _M; Real _K0toK40[PressureCoeffsK0toK40Size]; - void _CheckPowerMG(); void _InitializePowerMG(const Real *expcoeffs); PORTABLE_INLINE_FUNCTION Real _HugPressureFromDensity(const Real rho) const; PORTABLE_INLINE_FUNCTION Real _HugTemperatureFromDensity(const Real rho) const; @@ -175,7 +180,7 @@ class PowerMG : public EosBase { _compBulkModulusFromDensityInternalEnergy(const Real rho, const Real sie) const; }; -inline void PowerMG::_CheckPowerMG() { +PORTABLE_INLINE_FUNCTION void PowerMG::CheckParams() const { if (_rho0 < 0.0) { PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter rho0 < 0"); @@ -189,13 +194,6 @@ inline void PowerMG::_CheckPowerMG() { if (_K0toK40[0] < 0.0) { PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter K0 < 0"); } - if (_Pmin >= 0.0) { - _Pmin = -1000 * _K0toK40[0]; -#ifndef NDEBUG - PORTABLE_WARN( - "PowerMG model parameter Pmin not set or positive. Reset to default (-1000*K0)"); -#endif // NDEBUG - } } inline void PowerMG::_InitializePowerMG(const Real *K0toK40input) { diff --git a/singularity-eos/eos/eos_sap_polynomial.hpp b/singularity-eos/eos/eos_sap_polynomial.hpp index 8499de7c59..29681300e8 100644 --- a/singularity-eos/eos/eos_sap_polynomial.hpp +++ b/singularity-eos/eos/eos_sap_polynomial.hpp @@ -42,11 +42,11 @@ class SAP_Polynomial : public EosBase { const Real b2c, const Real b2e, const Real b3) : _rho0(rho0), _a0(a0), _a1(a1), _a2c(a2c), _a2e(a2e), _a3(a3), _b0(b0), _b1(b1), _b2c(b2c), _b2e(b2e), _b3(b3) { - checkParams(); + CheckParams(); } SAP_Polynomial GetOnDevice() { return *this; } - PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_INLINE_FUNCTION void CheckParams() const { PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Reference density must be non-negative"); } template diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 8b1d57343c..9e0fa253e8 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -105,6 +105,10 @@ class SpinerEOSDependsRhoT : public EosBase { inline SpinerEOSDependsRhoT GetOnDevice(); + PORTABLE_INLINE_FUNCTION void CheckParams() const { + // TODO(JMM): STUB + } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, @@ -358,6 +362,10 @@ class SpinerEOSDependsRhoSie : public EosBase { bool reproducibility_mode = false); inline SpinerEOSDependsRhoSie GetOnDevice(); + PORTABLE_INLINE_FUNCTION void CheckParams() const { + // TODO(JMM): STUB + } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index 1bbf1dfc9a..2498cc79df 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -96,6 +96,10 @@ class StellarCollapse : public EosBase { PORTABLE_INLINE_FUNCTION StellarCollapse() : memoryStatus_(DataStatus::Deallocated) {} + PORTABLE_INLINE_FUNCTION void CheckParams() const { + // TODO(JMM): STUB + } + inline StellarCollapse GetOnDevice(); template diff --git a/singularity-eos/eos/eos_stiff.hpp b/singularity-eos/eos/eos_stiff.hpp index d0ca49e096..4a64aeffc5 100644 --- a/singularity-eos/eos/eos_stiff.hpp +++ b/singularity-eos/eos/eos_stiff.hpp @@ -44,7 +44,7 @@ class StiffGas : public EosBase { _sie0(robust::ratio(_P0 + (gm1 + 1.0) * Pinf, _P0 + Pinf) * Cv * _T0 + qq), _bmod0(gm1 * (gm1 + 1.0) * robust::ratio(_P0 + Pinf, gm1 * Cv * _T0) * Cv * _T0), _dpde0(_rho0 * _gm1) { - checkParams(); + CheckParams(); } PORTABLE_INLINE_FUNCTION StiffGas(Real gm1, Real Cv, Real Pinf, Real qq, Real qp, Real T0, Real P0) @@ -54,7 +54,7 @@ class StiffGas : public EosBase { _sie0(robust::ratio(P0 + (gm1 + 1.0) * Pinf, P0 + Pinf) * Cv * T0 + qq), _bmod0(gm1 * (gm1 + 1.0) * robust::ratio(P0 + Pinf, gm1 * Cv * T0) * Cv * T0), _dpde0(_rho0 * _gm1) { - checkParams(); + CheckParams(); } StiffGas GetOnDevice() { return *this; } template @@ -63,7 +63,7 @@ class StiffGas : public EosBase { Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(rho * (sie - _qq) - _Pinf, rho * _Cv)); } - PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_INLINE_FUNCTION void CheckParams() const { PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive"); PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 36fc79a45c..769e9cfabb 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -74,6 +74,11 @@ class Variant { } // Place member functions here + PORTABLE_INLINE_FUNCTION + void CheckParams() const { + mpark::visit([](auto &eos) { return eos.CheckParams(); }); + } + template constexpr void Evaluate(Functor_t &f) const { return mpark::visit([&f](const auto &eos) { return eos.Evaluate(f); }, eos_); diff --git a/singularity-eos/eos/eos_vinet.hpp b/singularity-eos/eos/eos_vinet.hpp index e7bbf8e809..4a1babcca8 100644 --- a/singularity-eos/eos/eos_vinet.hpp +++ b/singularity-eos/eos/eos_vinet.hpp @@ -42,7 +42,7 @@ class Vinet : public EosBase { Vinet(const Real rho0, const Real T0, const Real B0, const Real BP0, const Real A0, const Real Cv0, const Real E0, const Real S0, const Real *expconsts) : _rho0(rho0), _T0(T0), _B0(B0), _BP0(BP0), _A0(A0), _Cv0(Cv0), _E0(E0), _S0(S0) { - CheckVinet(); + CheckParams(); InitializeVinet(expconsts); } @@ -163,13 +163,13 @@ class Vinet : public EosBase { static constexpr const int PressureCoeffsd2tod40Size = 39; static constexpr const int VinetInternalParametersSize = PressureCoeffsd2tod40Size + 4; Real _VIP[VinetInternalParametersSize], _d2tod40[PressureCoeffsd2tod40Size]; - void CheckVinet(); + PORTABLE_INLINE_FUNCTION void CheckParams() const; void InitializeVinet(const Real *expcoeffs); PORTABLE_INLINE_FUNCTION void Vinet_F_DT_func(const Real rho, const Real T, Real *output) const; }; -inline void Vinet::CheckVinet() { +PORTABLE_INLINE_FUNCTION void Vinet::CheckParams() const { if (_rho0 < 0.0) { PORTABLE_ALWAYS_THROW_OR_ABORT("Required Vinet model parameter rho0 < 0"); diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index c5ad576598..ed9506ed5a 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -96,7 +97,9 @@ class UnitSystem : public EosBase> { inv_dpdr_unit_(rho_unit / press_unit_), inv_dtdr_unit_(rho_unit / temp_unit), inv_dtde_unit_(sie_unit / temp_unit) // obviously this is also Cv , - inv_cv_unit_(temp_unit / sie_unit), inv_bmod_unit_(1 / press_unit_) {} + inv_cv_unit_(temp_unit / sie_unit), inv_bmod_unit_(1 / press_unit_) { + CheckParams(); + } UnitSystem(T &&t, eos_units_init::LengthTimeUnitsInit, const Real time_unit, const Real mass_unit, const Real length_unit, const Real temp_unit) : UnitSystem(std::forward(t), eos_units_init::thermal_units_init_tag, @@ -107,6 +110,13 @@ class UnitSystem : public EosBase> { sie_unit, temp_unit) {} UnitSystem() = default; + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(rho_unit_ > 0, "Nonzero density unit"); + PORTABLE_ALWAYS_REQUIRE(sie_unit_ > 0, "Nonzero energy unit"); + PORTABLE_ALWAYS_REQUIRE(temp_unit_ > 0, "Nonzero temperature unit"); + t_.CheckParams(); + } + auto GetOnDevice() { return UnitSystem(t_.GetOnDevice(), eos_units_init::thermal_units_init_tag, rho_unit_, sie_unit_, temp_unit_); diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index e90a4e7038..28338614f6 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -83,15 +84,22 @@ class BilinearRampEOS : public EosBase> { : t_(std::forward(t)), r0_(r0), a_(a), b_(b), c_(c), rmid_(r0 * (a - b * c) / (a - b)), Pmid_(a * (rmid_ / r0 - 1.0)) { // add input parameter checks to ensure validity of the ramp - assert(r0 > 0.0); - assert(a > 0.0); - assert(b >= 0); - assert(a != b); + CheckParams(); } BilinearRampEOS() = default; using BaseType = T; + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(r0_ > 0.0, "Reference density > 0"); + PORTABLE_ALWAYS_REQUIRE(a_ > 0.0, "Ramp a coefficient > 0"); + PORTABLE_ALWAYS_REQUIRE(b_ >= 0, "Non-negative ramp b coefficient"); + PORTABLE_ALWAYS_REQUIRE(a_ != b_, "Ramp a and b coefficients may not be the same"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(rmid_), "Mid density must be well defined"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(Pmid_), "Mid pressure must be well defined"); + t_.CheckParams(); + } + // give me std::format or fmt::format... static std::string EosType() { return std::string("BilinearRampEOS<") + T::EosType() + std::string(">"); diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index fc3a3ab4a4..fd03d03f9a 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -75,9 +76,19 @@ class RelativisticEOS : public EosBase> { : t_(std::forward(t)), cl_(cl) // speed of light, units arbitrary , cl2_(cl * cl) // speed of light squared - {} + { + CheckParams(); + } RelativisticEOS() = default; + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(cl_ > 0, "Positive speed of light"); + PORTABLE_ALWAYS_REQUIRE(cl2_ > 0, "Positive speed of light squared"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(cl_), "Well defined speed of light"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(cl2_), "Well defined speed of light squared"); + t_.CheckParams(); + } + auto GetOnDevice() { return RelativisticEOS(t_.GetOnDevice(), cl_); } inline void Finalize() { t_.Finalize(); } diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 70b7e784e1..0163e20933 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -72,9 +73,19 @@ class ScaledEOS : public EosBase> { // move semantics ensures dynamic memory comes along for the ride ScaledEOS(T &&t, const Real scale) - : t_(std::forward(t)), scale_(scale), inv_scale_(1. / scale) {} + : t_(std::forward(t)), scale_(scale), inv_scale_(1. / scale) { + CheckParams(); + } ScaledEOS() = default; + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(std::abs(scale_) > 0, "Scale must not be zero."); + PORTABLE_ALWAYS_REQUIRE(std::abs(inv_scale_) > 0, "Inverse scale must not be zero."); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(scale_), "Scale must be well defined."); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(inv_scale_), + "Inverse scale must be well defined."); + t_.CheckParams(); + } auto GetOnDevice() { return ScaledEOS(t_.GetOnDevice(), scale_); } inline void Finalize() { t_.Finalize(); } diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index ff8366a5f5..5111fd2a5a 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -71,9 +72,16 @@ class ShiftedEOS : public EosBase> { static std::string EosPyType() { return std::string("Shifted") + T::EosPyType(); } // move semantics ensures dynamic memory comes along for the ride - ShiftedEOS(T &&t, const Real shift) : t_(std::forward(t)), shift_(shift) {} + ShiftedEOS(T &&t, const Real shift) : t_(std::forward(t)), shift_(shift) { + CheckParams(); + } ShiftedEOS() = default; + PORTABLE_INLINE_FUNCTION void CheckParams() const { + PORTABLE_ALWAYS_REQUIRE(!std::isnan(shift_), "Shift must be a number"); + t_.CheckParams(); + } + auto GetOnDevice() { return ShiftedEOS(t_.GetOnDevice(), shift_); } inline void Finalize() { t_.Finalize(); } From c9ac614849704095e4457a9b70cc59759ef63c86 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 09:52:10 -0600 Subject: [PATCH 04/48] CheckParams docs --- doc/sphinx/src/using-eos.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index adabdbeb33..d8ab5b7b98 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -552,6 +552,18 @@ might look something like this: .. _eos methods reference section: +CheckParams +------------ + +You may check whether or not an equation of state object is +constructed self-consistently and ready for use by calling + +.. cpp:function:: void CheckParams() const; + +which raise an error and/or print an equation of state specific error +message if something has gone wrong. Most EOS constructors and ways of +building an EOS call ``CheckParams`` by default. + Equation of State Methods Reference ------------------------------------ From b11a8de211b31865e3a1d3ace93ec19a8f372b6b Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 10:05:49 -0600 Subject: [PATCH 05/48] got a little paranoid about CRTP --- singularity-eos/eos/eos_base.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 67328cb626..0ce045d890 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -678,11 +678,15 @@ class EosBase { std::size_t SerializedSizeInBytes() const { // sizeof(*this) apparently returns the size of JUST the base // class. - return DynamicMemorySizeInBytes() + sizeof(CRTP); + const CRTP *pcrtp = static_cast(this); + std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); + return dyn_size + sizeof(CRTP); } std::size_t Serialize(char *dst) const { - memcpy(dst, this, sizeof(CRTP)); - if (DynamicMemorySizeInBytes() > 0) { + const CRTP *pcrtp = static_cast(this); + memcpy(dst, pcrtp, sizeof(CRTP)); + std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); + if (dyn_size > 0) { DumpDynamicMemory(dst + sizeof(CRTP)); } return SerializedSizeInBytes(); @@ -694,7 +698,7 @@ class EosBase { return std::make_pair(size, dst); } std::size_t DeSerialize(char *src) { - memcpy(this, src, sizeof(CRTP)); + memcpy(static_cast(this), src, sizeof(CRTP)); if (DynamicMemorySizeInBytes() > 0) { SetDynamicMemory(src + sizeof(CRTP)); } From 8424317ca6fa08a5a4eecd901f72762c3b024c2f Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 14:50:53 -0600 Subject: [PATCH 06/48] serialization routines implemented in stellar collapse, with some nice machinery for looping over databoxes --- singularity-eos/eos/eos_stellar_collapse.hpp | 117 +++++++++---------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index 2498cc79df..e802502cbd 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -86,6 +86,12 @@ class StellarCollapse : public EosBase { using EosBase::GruneisenParamFromDensityTemperature; using EosBase::GruneisenParamFromDensityInternalEnergy; using EosBase::FillEos; + using EosBase::SerializedSizeInBytes; + using EosBase::Serialize; + using EosBase::DeSerialize; + using EosBase::IsModified; + using EosBase::UnmodifyOnce; + using EosBase::GetUnmodifiedObject; inline StellarCollapse(const std::string &filename, bool use_sp5 = false, bool filter_bmod = true); @@ -223,6 +229,10 @@ class StellarCollapse : public EosBase { inline static void dataBoxToFastLogs(DataBox &db, DataBox &scratch, bool dependent_var_log); + std::size_t DynamicMemorySizeInBytes() const; + std::size_t DumpDynamicMemory(char *dst) const; + std::size_t SetDynamicMemory(char *src); + private: class LogT { public: @@ -356,6 +366,14 @@ class StellarCollapse : public EosBase { // Bounds of dependent variables. Needed for root finding. DataBox eCold_, eHot_; + // TODO(JMM): Pointers here? or reference_wrapper? IMO the pointers are more clear +#define DBLIST \ + &lP_, &lE_, &dPdRho_, &dPdE_, &dEdT_, &lBMod_, &entropy_, &Xa_, &Xh_, &Xn_, &Xp_, \ + &Abar_, &Zbar_, &mu_e_, &mu_n_, &mu_p_, &muhat_, &munu_, &eCold_, &eHot_ + auto GetDataBoxPointers_() const { return std::vector{DBLIST}; } + auto GetDataBoxPointers_() { return std::vector{DBLIST}; } +#undef DBLIST + // Independent variable bounds int numRho_, numT_, numYe_; Real lRhoMin_, lRhoMax_; @@ -453,73 +471,54 @@ inline void StellarCollapse::Save(const std::string &filename) { } inline StellarCollapse StellarCollapse::GetOnDevice() { - StellarCollapse other; - other.lP_ = Spiner::getOnDeviceDataBox(lP_); - other.lE_ = Spiner::getOnDeviceDataBox(lE_); - other.dPdRho_ = Spiner::getOnDeviceDataBox(dPdRho_); - other.dPdE_ = Spiner::getOnDeviceDataBox(dPdE_); - other.dEdT_ = Spiner::getOnDeviceDataBox(dEdT_); - other.entropy_ = Spiner::getOnDeviceDataBox(entropy_); - other.Xa_ = Spiner::getOnDeviceDataBox(Xa_); - other.Xh_ = Spiner::getOnDeviceDataBox(Xh_); - other.Xn_ = Spiner::getOnDeviceDataBox(Xn_); - other.Xp_ = Spiner::getOnDeviceDataBox(Xp_); - other.Abar_ = Spiner::getOnDeviceDataBox(Abar_); - other.Zbar_ = Spiner::getOnDeviceDataBox(Zbar_); - other.lBMod_ = Spiner::getOnDeviceDataBox(lBMod_); - other.eCold_ = Spiner::getOnDeviceDataBox(eCold_); - other.eHot_ = Spiner::getOnDeviceDataBox(eHot_); - other.mu_e_ = Spiner::getOnDeviceDataBox(mu_e_); - other.mu_n_ = Spiner::getOnDeviceDataBox(mu_n_); - other.mu_p_ = Spiner::getOnDeviceDataBox(mu_p_); - other.muhat_ = Spiner::getOnDeviceDataBox(muhat_); - other.munu_ = Spiner::getOnDeviceDataBox(munu_); + // trivially copy all but dynamic memory + StellarCollapse other = *this; + // set dynamic memory + auto other_dbs = other.GetDataBoxPointers_(); + auto my_dbs = GetDataBoxPointers_(); + int idb = 0; + for (DataBox *pother_db : other_dbs) { + DataBox *pmy_db = my_dbs[idb++]; + *pother_db = Spiner::getOnDeviceDataBox(*pmy_db); + } + // set memory status other.memoryStatus_ = DataStatus::OnDevice; - other.numRho_ = numRho_; - other.numT_ = numT_; - other.numYe_ = numYe_; - other.lTMin_ = lTMin_; - other.lTMax_ = lTMax_; - other.YeMin_ = YeMin_; - other.YeMax_ = YeMax_; - other.sieMin_ = sieMin_; - other.sieMax_ = sieMax_; - other.lEOffset_ = lEOffset_; - other.sieNormal_ = sieNormal_; - other.PNormal_ = PNormal_; - other.SNormal_ = SNormal_; - other.CvNormal_ = CvNormal_; - other.bModNormal_ = bModNormal_; - other.dPdENormal_ = dPdENormal_; - other.dVdTNormal_ = dVdTNormal_; - other.status_ = status_; return other; } inline void StellarCollapse::Finalize() { - lP_.finalize(); - lE_.finalize(); - dPdRho_.finalize(); - dPdE_.finalize(); - dEdT_.finalize(); - entropy_.finalize(); - Xa_.finalize(); - Xh_.finalize(); - Xn_.finalize(); - Xp_.finalize(); - Abar_.finalize(); - Zbar_.finalize(); - lBMod_.finalize(); - eCold_.finalize(); - eHot_.finalize(); - mu_e_.finalize(); - mu_n_.finalize(); - mu_p_.finalize(); - muhat_.finalize(); - munu_.finalize(); + for (DataBox *pdb : GetDataBoxPointers_()) { + pdb->finalize(); + } memoryStatus_ = DataStatus::Deallocated; } +inline std::size_t StellarCollapse::DynamicMemorySizeInBytes() const { + std::size_t out = 0; + for (const DataBox *pdb : GetDataBoxPointers_()) { + out += pdb->sizeBytes(); + } + return out; +} + +inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) const { + std::size_t offst = 0; + for (const DataBox *pdb : GetDataBoxPointers_()) { + std::size_t size = pdb->sizeBytes(); + memcpy(dst + offst, pdb->data(), size); + offst += size; + } + return offst; +} + +inline std::size_t StellarCollapse::SetDynamicMemory(char *src) { + std::size_t offst = 0; + for (DataBox *pdb : GetDataBoxPointers_()) { + offst += pdb->setPointer(src + offst); + } + return offst; +} + template PORTABLE_INLINE_FUNCTION Real StellarCollapse::TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, Indexer_t &&lambda) const { From f84ed1dff42a3aa2cdd43755b690dc69119a2ef7 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 15:48:04 -0600 Subject: [PATCH 07/48] stellar collapse EOS has serialization now --- singularity-eos/base/constants.hpp | 2 +- singularity-eos/eos/eos_ideal.hpp | 1 + singularity-eos/eos/eos_stellar_collapse.hpp | 21 ++- singularity-eos/eos/eos_variant.hpp | 2 +- test/test_eos_stellar_collapse.cpp | 171 +++++++++++-------- 5 files changed, 126 insertions(+), 71 deletions(-) diff --git a/singularity-eos/base/constants.hpp b/singularity-eos/base/constants.hpp index 303361534a..48a458a7af 100644 --- a/singularity-eos/base/constants.hpp +++ b/singularity-eos/base/constants.hpp @@ -32,7 +32,7 @@ constexpr unsigned long all_values = (1 << 7) - 1; } // namespace thermalqs constexpr size_t MAX_NUM_LAMBDAS = 3; -enum class DataStatus { Deallocated = 0, OnDevice = 1, OnHost = 2 }; +enum class DataStatus { Deallocated = 0, OnDevice = 1, OnHost = 2, UnManaged = 3 }; enum class TableStatus { OnTable = 0, OffBottom = 1, OffTop = 2 }; constexpr Real ROOM_TEMPERATURE = 293; // K constexpr Real ATMOSPHERIC_PRESSURE = 1e6; diff --git a/singularity-eos/eos/eos_ideal.hpp b/singularity-eos/eos/eos_ideal.hpp index 352cf03c14..d395928404 100644 --- a/singularity-eos/eos/eos_ideal.hpp +++ b/singularity-eos/eos/eos_ideal.hpp @@ -67,6 +67,7 @@ class IdealGas : public EosBase { "Entropy reference temperature must be positive"); PORTABLE_ALWAYS_REQUIRE(_EntropyRho0 >= 0, "Entropy reference density must be positive"); + return; } template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index e802502cbd..cf9517bfd0 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -30,6 +30,7 @@ // ports-of-call #include +#include // singularity-eos #include @@ -103,7 +104,24 @@ class StellarCollapse : public EosBase { StellarCollapse() : memoryStatus_(DataStatus::Deallocated) {} PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): STUB + PORTABLE_ALWAYS_REQUIRE(numRho_ > 0, "Table must be finite"); + PORTABLE_ALWAYS_REQUIRE(numT_ > 0, "Table must be finite"); + PORTABLE_ALWAYS_REQUIRE(numYe_ > 0, "Table must be finite"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(lRhoMin_) && !std::isnan(lRhoMax_), + "Density bounds must be well defined"); + PORTABLE_ALWAYS_REQUIRE(lRhoMax_ > lRhoMin_, "Density bounds must be ordered"); + PORTABLE_ALWAYS_REQUIRE(!std::isnan(lTMin_) && !std::isnan(lTMax_), + "Density bounds must be well defined"); + PORTABLE_ALWAYS_REQUIRE(lTMax_ > lTMin_, "Temperature bounds must be ordered"); + PORTABLE_ALWAYS_REQUIRE(!(std::isnan(YeMin_) || std::isnan(YeMax_)), + "Ye bounds must be well defined"); + PORTABLE_ALWAYS_REQUIRE(YeMin_ >= 0.0, "Ye must be positive"); + PORTABLE_ALWAYS_REQUIRE(YeMax_ <= 1.0, "Ye must be a fraction"); + PORTABLE_ALWAYS_REQUIRE(YeMax_ > YeMin_, "Ye bounds must be ordered"); + PORTABLE_ALWAYS_REQUIRE(!(std::isnan(sieMin_) || std::isnan(sieMax_)), + "Energy bounds must be well defined"); + PORTABLE_ALWAYS_REQUIRE(sieMax_ > sieMin_, "Energy bounds must be ordered"); + return; } inline StellarCollapse GetOnDevice(); @@ -516,6 +534,7 @@ inline std::size_t StellarCollapse::SetDynamicMemory(char *src) { for (DataBox *pdb : GetDataBoxPointers_()) { offst += pdb->setPointer(src + offst); } + memoryStatus_ = DataStatus::UnManaged; return offst; } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 769e9cfabb..cef8d8e10a 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -76,7 +76,7 @@ class Variant { // Place member functions here PORTABLE_INLINE_FUNCTION void CheckParams() const { - mpark::visit([](auto &eos) { return eos.CheckParams(); }); + return mpark::visit([](auto &eos) { return eos.CheckParams(); }, eos_); } template diff --git a/test/test_eos_stellar_collapse.cpp b/test/test_eos_stellar_collapse.cpp index e496900128..009d6eae40 100644 --- a/test/test_eos_stellar_collapse.cpp +++ b/test/test_eos_stellar_collapse.cpp @@ -37,6 +37,75 @@ #ifdef SPINER_USE_HDF #ifdef SINGULARITY_TEST_STELLAR_COLLAPSE +template +void CompareStellarCollapse(EOS_t sc, EOS_t sc2) { + Real yemin = sc.YeMin(); + Real yemax = sc.YeMax(); + Real tmin = sc.TMin(); + Real tmax = sc.TMax(); + Real ltmin = std::log10(tmin); + Real ltmax = std::log10(tmax); + Real lrhomin = std::log10(sc.rhoMin()); + Real lrhomax = std::log10(sc.rhoMax()); + REQUIRE(yemin == sc2.YeMin()); + REQUIRE(yemax == sc2.YeMax()); + REQUIRE(sc.TMin() == sc2.TMin()); + REQUIRE(sc.TMax() == sc2.TMax()); + REQUIRE(isClose(lrhomin, std::log10(sc2.rhoMin()), 1e-12)); + REQUIRE(isClose(lrhomax, std::log10(sc2.rhoMax()), 1e-12)); + + auto sc1_d = sc.GetOnDevice(); + auto sc2_d = sc2.GetOnDevice(); + + int nwrong_h = 0; +#ifdef PORTABILITY_STRATEGY_KOKKOS + using atomic_view = Kokkos::MemoryTraits; + Kokkos::View nwrong_d("wrong"); +#else + PortableMDArray nwrong_d(&nwrong_h, 1); +#endif + + const int N = 123; + constexpr Real gamma = 1.4; + const Real dY = (yemax - yemin) / (N + 1); + const Real dlT = (ltmax - ltmin) / (N + 1); + const Real dlR = (lrhomax - lrhomin) / (N + 1); + portableFor( + "fill eos", 0, N, 0, N, 0, N, + PORTABLE_LAMBDA(const int &k, const int &j, const int &i) { + Real lambda[2]; + Real Ye = yemin + k * dY; + Real lT = ltmin + j * dlT; + Real lR = lrhomin + i * dlR; + Real T = std::pow(10., lT); + Real R = std::pow(10., lR); + Real e1, e2, p1, p2, cv1, cv2, b1, b2, s1, s2; + unsigned long output = (singularity::thermalqs::pressure | + singularity::thermalqs::specific_internal_energy | + singularity::thermalqs::specific_heat | + singularity::thermalqs::bulk_modulus); + lambda[0] = Ye; + + sc1_d.FillEos(R, T, e1, p1, cv1, b1, output, lambda); + sc2_d.FillEos(R, T, e2, p2, cv2, b2, output, lambda); + // Fill entropy. Will need to change later. + s1 = sc1_d.EntropyFromDensityTemperature(R, T, lambda); + s2 = p2 * std::pow(R, -gamma); // ideal + if (!isClose(e1, e2)) nwrong_d() += 1; + if (!isClose(p1, p2)) nwrong_d() += 1; + if (!isClose(cv1, cv2)) nwrong_d() += 1; + if (!isClose(b1, b2)) nwrong_d() += 1; + if (!isClose(s1, s2)) nwrong_d() += 1; + }); +#ifdef PORTABILITY_STRATEGY_KOKKOS + Kokkos::deep_copy(nwrong_h, nwrong_d); +#endif + REQUIRE(nwrong_h == 0); + + sc1_d.Finalize(); + sc2_d.Finalize(); +} + SCENARIO("Test 3D reinterpolation to fast log grid", "[StellarCollapse]") { WHEN("We generate a 3D DataBox of a 2D power law times a line") { using singularity::StellarCollapse; @@ -91,8 +160,6 @@ SCENARIO("Test 3D reinterpolation to fast log grid", "[StellarCollapse]") { singularity::FastMath::log10(std::pow(10, g0.max())), 1e-12)); } - AND_THEN("The re-interpolated fast log is a sane number") {} - AND_THEN("The fast-log table approximately interpolates the power law") { const Real x2 = 0.5; const Real x1 = 100; @@ -220,77 +287,45 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { AND_THEN("We can load the sp5 file") { StellarCollapse sc2(savename, true); AND_THEN("The two stellar collapse EOS's agree") { + CompareStellarCollapse(sc, sc2); + } + sc2.Finalize(); + } + } - Real yemin = sc.YeMin(); - Real yemax = sc.YeMax(); - Real tmin = sc.TMin(); - Real tmax = sc.TMax(); - Real ltmin = std::log10(tmin); - Real ltmax = std::log10(tmax); - Real lrhomin = std::log10(sc.rhoMin()); - Real lrhomax = std::log10(sc.rhoMax()); - REQUIRE(yemin == sc2.YeMin()); - REQUIRE(yemax == sc2.YeMax()); - REQUIRE(sc.TMin() == sc2.TMin()); - REQUIRE(sc.TMax() == sc2.TMax()); - REQUIRE(isClose(lrhomin, std::log10(sc2.rhoMin()), 1e-12)); - REQUIRE(isClose(lrhomax, std::log10(sc2.rhoMax()), 1e-12)); - - auto sc1_d = sc.GetOnDevice(); - auto sc2_d = sc2.GetOnDevice(); - - int nwrong_h = 0; -#ifdef PORTABILITY_STRATEGY_KOKKOS - using atomic_view = Kokkos::MemoryTraits; - Kokkos::View nwrong_d("wrong"); -#else - PortableMDArray nwrong_d(&nwrong_h, 1); -#endif - - const int N = 123; - constexpr Real gamma = 1.4; - const Real dY = (yemax - yemin) / (N + 1); - const Real dlT = (ltmax - ltmin) / (N + 1); - const Real dlR = (lrhomax - lrhomin) / (N + 1); - portableFor( - "fill eos", 0, N, 0, N, 0, N, - PORTABLE_LAMBDA(const int &k, const int &j, const int &i) { - Real lambda[2]; - Real Ye = yemin + k * dY; - Real lT = ltmin + j * dlT; - Real lR = lrhomin + i * dlR; - Real T = std::pow(10., lT); - Real R = std::pow(10., lR); - Real e1, e2, p1, p2, cv1, cv2, b1, b2, s1, s2; - unsigned long output = - (singularity::thermalqs::pressure | - singularity::thermalqs::specific_internal_energy | - singularity::thermalqs::specific_heat | - singularity::thermalqs::bulk_modulus); - lambda[0] = Ye; - - sc1_d.FillEos(R, T, e1, p1, cv1, b1, output, lambda); - sc2_d.FillEos(R, T, e2, p2, cv2, b2, output, lambda); - // Fill entropy. Will need to change later. - s1 = sc1_d.EntropyFromDensityTemperature(R, T, lambda); - s2 = p2 * std::pow(R, -gamma); // ideal - if (!isClose(e1, e2)) nwrong_d() += 1; - if (!isClose(p1, p2)) nwrong_d() += 1; - if (!isClose(cv1, cv2)) nwrong_d() += 1; - if (!isClose(b1, b2)) nwrong_d() += 1; - if (!isClose(s1, s2)) nwrong_d() += 1; - }); -#ifdef PORTABILITY_STRATEGY_KOKKOS - Kokkos::deep_copy(nwrong_h, nwrong_d); -#endif - REQUIRE(nwrong_h == 0); + WHEN("We serialize the StellarCollapse EOS") { + auto [size, data] = sc.Serialize(); + REQUIRE(size > 0); + THEN("We can de-serialize it into a new object") { + StellarCollapse sc2; + std::size_t read_size = sc2.DeSerialize(data); + REQUIRE(read_size == size); + sc2.CheckParams(); + AND_THEN("The two stellar collapse EOS's agree") { + CompareStellarCollapse(sc, sc2); + } + } + free(data); + } - sc1_d.Finalize(); - sc2_d.Finalize(); + WHEN("We serialize a variant that owns a StellarCollapse EOS") { + using EOS = singularity::Variant; + EOS e1 = sc; + auto [size, data] = e1.Serialize(); + REQUIRE(size > 0); + THEN("We can de-serialize it into a new object") { + EOS e2; + std::size_t read_size = e2.DeSerialize(data); + REQUIRE(read_size == size); + e2.CheckParams(); + AND_THEN("The two stellar collapse EOS's agree") { + StellarCollapse sc2 = e2.get(); + CompareStellarCollapse(sc, sc2); } - sc2.Finalize(); } + free(data); } + sc.Finalize(); } } From 36d92111569ab636db98def2d60bec7d5b136397 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 15:55:38 -0600 Subject: [PATCH 08/48] SpinerEOSDependsRhoT check params --- singularity-eos/eos/eos_spiner.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 9e0fa253e8..3b5c6008a2 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -31,6 +31,7 @@ // ports-of-call #include +#include // base #include @@ -94,6 +95,12 @@ class SpinerEOSDependsRhoT : public EosBase { using EosBase::GruneisenParamFromDensityInternalEnergy; using EosBase::FillEos; using EosBase::EntropyIsNotEnabled; + using EosBase::SerializedSizeInBytes; + using EosBase::Serialize; + using EosBase::DeSerialize; + using EosBase::IsModified; + using EosBase::UnmodifyOnce; + using EosBase::GetUnmodifiedObject; inline SpinerEOSDependsRhoT(const std::string &filename, int matid, bool reproduciblity_mode = false); @@ -106,7 +113,16 @@ class SpinerEOSDependsRhoT : public EosBase { inline SpinerEOSDependsRhoT GetOnDevice(); PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): STUB + PORTAbLE_ALWAYS_REQUIRE(numRho_ > 0, "Finite number of density points"); + PORTAbLE_ALWAYS_REQUIRE(numT_ > 0, "Finite number of temperature points"); + PORTABLE_ALWAYS_REQUIRE(!(std::isnan(lRhoMin_) || std::isnan(lRhoMax_)), + "Density bounds well defined"); + PORTABLE_ALWAYS_REQUIRE(lRhoMax_ > lRhoMin_, "Density bounds ordered"); + PORTABLE_ALWAYS_REQUIRE(rhoMax_ > 0, "Max density must be positive"); + PORTABLE_ALWAYS_REQUIRE(!(std::isnan(lTMin_) || std::isnan(lTMax_)), + "Temperature bounds well defined"); + PORTABLE_ALWAYS_REQUIRE(lTMax_ > lTMin_, "Temperature bounds ordered"); + PORTABLE_ALWAYS_REQUIRE(TMax_ > 0, "Max temperature must be positive"); } template From e6289d8933acefbf1f2b0106a4618d1673fcf648 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 16:10:30 -0600 Subject: [PATCH 09/48] add GetDataBoxPointers_ to SpinerEOSDependsRhoT --- singularity-eos/eos/eos_spiner.hpp | 105 +++++++------------ singularity-eos/eos/eos_stellar_collapse.hpp | 7 +- 2 files changed, 40 insertions(+), 72 deletions(-) diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 3b5c6008a2..b8d2912590 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -125,6 +125,10 @@ class SpinerEOSDependsRhoT : public EosBase { PORTABLE_ALWAYS_REQUIRE(TMax_ > 0, "Max temperature must be positive"); } + std::size_t DynamicMemorySizeInBytes() const; + std::size_t DumpDynamicMemory(char *dst) const; + std::size_t SetDynamicMemory(char *src); + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, @@ -297,13 +301,25 @@ class SpinerEOSDependsRhoT : public EosBase { static constexpr const unsigned long _preferred_input = thermalqs::density | thermalqs::temperature; // static constexpr const char _eos_type[] {"SpinerEOSDependsRhoT"}; - static constexpr const int numDataBoxes_ = 12; + + // TODO(JMM): Could unify declarations and macro below by using + // reference_wrapper instead of pointers... worth it? DataBox P_, sie_, bMod_, dPdRho_, dPdE_, dTdRho_, dTdE_, dEdRho_, dEdT_; DataBox PMax_, sielTMax_, dEdTMax_, gm1Max_; DataBox lTColdCrit_; DataBox PCold_, sieCold_, bModCold_; DataBox dPdRhoCold_, dPdECold_, dTdRhoCold_, dTdECold_, dEdTCold_; DataBox rho_at_pmin_; + + // TODO(JMM): Pointers here? or reference_wrapper? IMO the pointers are more clear +#define DBLIST \ + &P_, &sie_, &bMod_, &dPdRho_, &dPdE_, &dTdRho_, &dTdE_, &dEdRho_, &dEdT_, &PMax_, \ + &sielTMax_, &dEdTMax_, &gm1Max_, &lTColdCrit_, &PCold_, &sieCold_, &bModCold_, \ + &dPdRhoCold_, &dPdECold_, &dTdRhoCold_, &dTdECold_, &dEdTCold_, &rho_at_pmin_; + auto GetDataBoxPointers_() const { return std::vector{DBLIST}; } + auto GetDataBoxPointers_() { return std::vector{DBLIST}; } +#undef DBLIST + int numRho_, numT_; Real lRhoMin_, lRhoMax_, rhoMax_; Real lRhoMinSearch_; @@ -634,6 +650,8 @@ inline SpinerEOSDependsRhoT::SpinerEOSDependsRhoT(const std::string &filename, i if (status != H5_SUCCESS) { EOS_ERROR("SpinerDependsRHoT: HDF5 error\n"); // TODO: make this better } + + CheckParams(); } inline SpinerEOSDependsRhoT::SpinerEOSDependsRhoT(const std::string &filename, @@ -665,83 +683,30 @@ inline SpinerEOSDependsRhoT::SpinerEOSDependsRhoT(const std::string &filename, if (status != H5_SUCCESS) { EOS_ERROR("SpinerDependsRhoT: HDF5 error\n"); } + + CheckParams(); } inline SpinerEOSDependsRhoT SpinerEOSDependsRhoT::GetOnDevice() { - SpinerEOSDependsRhoT other; - other.P_ = Spiner::getOnDeviceDataBox(P_); - other.sie_ = Spiner::getOnDeviceDataBox(sie_); - other.bMod_ = Spiner::getOnDeviceDataBox(bMod_); - other.dPdRho_ = Spiner::getOnDeviceDataBox(dPdRho_); - other.dPdE_ = Spiner::getOnDeviceDataBox(dPdE_); - other.dTdRho_ = Spiner::getOnDeviceDataBox(dTdRho_); - other.dTdE_ = Spiner::getOnDeviceDataBox(dTdE_); - other.dEdRho_ = Spiner::getOnDeviceDataBox(dEdRho_); - other.dEdT_ = Spiner::getOnDeviceDataBox(dEdT_); - other.PMax_ = Spiner::getOnDeviceDataBox(PMax_); - other.sielTMax_ = Spiner::getOnDeviceDataBox(sielTMax_); - other.dEdTMax_ = Spiner::getOnDeviceDataBox(dEdTMax_); - other.gm1Max_ = Spiner::getOnDeviceDataBox(gm1Max_); - other.PCold_ = Spiner::getOnDeviceDataBox(PCold_); - other.sieCold_ = Spiner::getOnDeviceDataBox(sieCold_); - other.bModCold_ = Spiner::getOnDeviceDataBox(bModCold_); - other.dPdRhoCold_ = Spiner::getOnDeviceDataBox(dPdRhoCold_); - other.dPdECold_ = Spiner::getOnDeviceDataBox(dPdECold_); - other.dTdRhoCold_ = Spiner::getOnDeviceDataBox(dTdRhoCold_); - other.dTdECold_ = Spiner::getOnDeviceDataBox(dTdECold_); - other.dEdTCold_ = Spiner::getOnDeviceDataBox(dEdTCold_); - other.lTColdCrit_ = Spiner::getOnDeviceDataBox(lTColdCrit_); - other.rho_at_pmin_ = Spiner::getOnDeviceDataBox(rho_at_pmin_); - other.lRhoMin_ = lRhoMin_; - other.lRhoMax_ = lRhoMax_; - other.rhoMax_ = rhoMax_; - other.lRhoMinSearch_ = lRhoMinSearch_; - other.lTMin_ = lTMin_; - other.lTMax_ = lTMax_; - other.TMax_ = TMax_; - other.lRhoOffset_ = lRhoOffset_; - other.lTOffset_ = lTOffset_; - other.rhoNormal_ = rhoNormal_; - other.TNormal_ = TNormal_; - other.sieNormal_ = sieNormal_; - other.PNormal_ = PNormal_; - other.CvNormal_ = CvNormal_; - other.bModNormal_ = bModNormal_; - other.dPdENormal_ = dPdENormal_; - other.dVdTNormal_ = dVdTNormal_; - other.numRho_ = numRho_; - other.numT_ = numT_; - other.matid_ = matid_; - other.reproducible_ = reproducible_; - other.status_ = status_; + SpinerEOSDependsRhoT other = *this; // trivial copy + // now do databoxes + int idb = 0; + auto pmy_dbs = GetDataBoxPointers_(); + for (DataBox *pother_db : other.GetDataBoxPointers_()) { + DataBox *pmy_db = pmy_dbs[idb++]; + *pother_db = Spiner::getOnDeviceDataBox(*pmy_db); + } + // and memory status other.memoryStatus_ = DataStatus::OnDevice; return other; } void SpinerEOSDependsRhoT::Finalize() { - P_.finalize(); - sie_.finalize(); - bMod_.finalize(); - dPdRho_.finalize(); - dPdE_.finalize(); - dTdRho_.finalize(); - dTdE_.finalize(); - dEdRho_.finalize(); - dEdT_.finalize(); - PMax_.finalize(); - sielTMax_.finalize(); - dEdTMax_.finalize(); - gm1Max_.finalize(); - PCold_.finalize(); - sieCold_.finalize(); - bModCold_.finalize(); - dPdRhoCold_.finalize(); - dPdECold_.finalize(); - dTdRhoCold_.finalize(); - dEdTCold_.finalize(); - dTdECold_.finalize(); - lTColdCrit_.finalize(); - rho_at_pmin_.finalize(); + if (memoryStatus_ != DataStatus::UnManaged) { + for (DataBox *pdb : GetDataBoxPointers_()) { + pdb->finalize(); + } + } memoryStatus_ = DataStatus::Deallocated; } diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index cf9517bfd0..155e0aa0e4 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -445,6 +445,7 @@ inline StellarCollapse::StellarCollapse(const std::string &filename, bool use_sp LoadFromStellarCollapseFile_(filename, filter_bmod); } setNormalValues_(); + CheckParams(); } // Saves to an SP5 file @@ -505,8 +506,10 @@ inline StellarCollapse StellarCollapse::GetOnDevice() { } inline void StellarCollapse::Finalize() { - for (DataBox *pdb : GetDataBoxPointers_()) { - pdb->finalize(); + if (memoryStatus_ != DataStatus::UnManaged) { + for (DataBox *pdb : GetDataBoxPointers_()) { + pdb->finalize(); + } } memoryStatus_ = DataStatus::Deallocated; } From 44822df3a1d0c6fc9b8df0029bf89bc03159b73e Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 16:55:58 -0600 Subject: [PATCH 10/48] copy paste feels bad --- singularity-eos/eos/eos_spiner.hpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index b8d2912590..ac5516282d 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -710,6 +710,34 @@ void SpinerEOSDependsRhoT::Finalize() { memoryStatus_ = DataStatus::Deallocated; } +inline std::size_t SpinerEOSDependsRhoT::DynamicMemorySizeInBytes() const { + std::size_t out = 0; + for (const DataBox *pdb : GetDataBoxPointers_()) { + out += pdb->sizeBytes(); + } + return out; +} + +inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) const { + std::size_t offst = 0; + for (const DataBox *pdb : GetDataBoxPointers_()) { + std::size_t size = pdb->sizeBytes(); + memcpy(dst + offst, pdb->data(), size); + offst += size; + } + return offst; +} + +inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src) { + std::size_t offst = 0; + for (DataBox *pdb : GetDataBoxPointers_()) { + offst += pdb->setPointer(src + offst); + } + memoryStatus_ = DataStatus::UnManaged; + return offst; +} + + inline herr_t SpinerEOSDependsRhoT::loadDataboxes_(const std::string &matid_str, hid_t file, hid_t lTGroup, hid_t coldGroup) { From d438ce257b9c1f6b3645895c23aa1f7ffa208c4a Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 17:51:38 -0600 Subject: [PATCH 11/48] spiner EOS compiles now --- singularity-eos/eos/eos_spiner.hpp | 33 ++++-------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index ac5516282d..a2c16a3e40 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -76,32 +76,7 @@ class SpinerEOSDependsRhoT : public EosBase { struct Lambda { enum Index { lRho = 0, lT = 1 }; }; - // 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. - 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 EosBase::EntropyIsNotEnabled; - using EosBase::SerializedSizeInBytes; - using EosBase::Serialize; - using EosBase::DeSerialize; - using EosBase::IsModified; - using EosBase::UnmodifyOnce; - using EosBase::GetUnmodifiedObject; - + SG_ADD_BASE_CLASS_USINGS(SpinerEOSDependsRhoT); inline SpinerEOSDependsRhoT(const std::string &filename, int matid, bool reproduciblity_mode = false); inline SpinerEOSDependsRhoT(const std::string &filename, @@ -113,8 +88,8 @@ class SpinerEOSDependsRhoT : public EosBase { inline SpinerEOSDependsRhoT GetOnDevice(); PORTABLE_INLINE_FUNCTION void CheckParams() const { - PORTAbLE_ALWAYS_REQUIRE(numRho_ > 0, "Finite number of density points"); - PORTAbLE_ALWAYS_REQUIRE(numT_ > 0, "Finite number of temperature points"); + PORTABLE_ALWAYS_REQUIRE(numRho_ > 0, "Finite number of density points"); + PORTABLE_ALWAYS_REQUIRE(numT_ > 0, "Finite number of temperature points"); PORTABLE_ALWAYS_REQUIRE(!(std::isnan(lRhoMin_) || std::isnan(lRhoMax_)), "Density bounds well defined"); PORTABLE_ALWAYS_REQUIRE(lRhoMax_ > lRhoMin_, "Density bounds ordered"); @@ -315,7 +290,7 @@ class SpinerEOSDependsRhoT : public EosBase { #define DBLIST \ &P_, &sie_, &bMod_, &dPdRho_, &dPdE_, &dTdRho_, &dTdE_, &dEdRho_, &dEdT_, &PMax_, \ &sielTMax_, &dEdTMax_, &gm1Max_, &lTColdCrit_, &PCold_, &sieCold_, &bModCold_, \ - &dPdRhoCold_, &dPdECold_, &dTdRhoCold_, &dTdECold_, &dEdTCold_, &rho_at_pmin_; + &dPdRhoCold_, &dPdECold_, &dTdRhoCold_, &dTdECold_, &dEdTCold_, &rho_at_pmin_ auto GetDataBoxPointers_() const { return std::vector{DBLIST}; } auto GetDataBoxPointers_() { return std::vector{DBLIST}; } #undef DBLIST From f7bb9fca82ecc06a7deb44159f329c59be9ac6d9 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 18:07:49 -0600 Subject: [PATCH 12/48] cleaned up base class and modifiers a little bit --- singularity-eos/eos/eos_base.hpp | 27 +++++---------- singularity-eos/eos/eos_spiner.hpp | 22 +----------- singularity-eos/eos/eos_stellar_collapse.hpp | 25 +------------- .../eos/modifiers/eos_unitsystem.hpp | 34 ++----------------- singularity-eos/eos/modifiers/ramps_eos.hpp | 7 +--- .../eos/modifiers/relativistic_eos.hpp | 34 ++----------------- singularity-eos/eos/modifiers/scaled_eos.hpp | 34 ++----------------- singularity-eos/eos/modifiers/shifted_eos.hpp | 34 ++----------------- 8 files changed, 20 insertions(+), 197 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 0ce045d890..cb134439ff 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -61,8 +61,8 @@ char *StrCat(char *destination, const char *source) { } // namespace impl // This Macro adds the `using` statements that allow for the base class -// vector functionality to overload the scalar implementations in the derived -// classes +// VECTOR functionality to overload the scalar implementations in the derived +// classes. Do not add functions here that are not overloads of derived class features. // TODO(JMM): Should we have more macros that capture just some of these? #define SG_ADD_BASE_CLASS_USINGS(EOSDERIVED) \ using EosBase::TemperatureFromDensityInternalEnergy; \ @@ -76,22 +76,9 @@ char *StrCat(char *destination, const char *source) { using EosBase::BulkModulusFromDensityInternalEnergy; \ using EosBase::GruneisenParamFromDensityTemperature; \ using EosBase::GruneisenParamFromDensityInternalEnergy; \ - using EosBase::MinimumDensity; \ - using EosBase::MinimumTemperature; \ using EosBase::FillEos; \ using EosBase::EntropyFromDensityTemperature; \ - using EosBase::EntropyFromDensityInternalEnergy; \ - using EosBase::EntropyIsNotEnabled; \ - using EosBase::MinInternalEnergyIsNotEnabled; \ - using EosBase::DynamicMemorySizeInBytes; \ - using EosBase::DumpDynamicMemory; \ - using EosBase::SetDynamicMemory; \ - using EosBase::SerializedSizeInBytes; \ - using EosBase::Serialize; \ - using EosBase::DeSerialize; \ - using EosBase::IsModified; \ - using EosBase::UnmodifyOnce; \ - using EosBase::GetUnmodifiedObject; + using EosBase::EntropyFromDensityInternalEnergy; class Factor { Real value_ = 1.0; @@ -706,12 +693,16 @@ class EosBase { } // Tooling for modifiers - inline constexpr bool IsModified() const { return false; } + static inline constexpr bool IsModified() { return false; } inline constexpr decltype(auto) UnmodifyOnce() { return *static_cast(this); } inline constexpr decltype(auto) GetUnmodifiedObject() { - return *static_cast(this); + if constexpr (CRTP::IsModified()) { + return static_cast(this)->UnmodifyOnce().GetUnmodifiedObject(); + } else { + return *static_cast(this); + } } }; } // namespace eos_base diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index a2c16a3e40..eab7cb09c7 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -340,26 +340,7 @@ class SpinerEOSDependsRhoSie : public EosBase { struct SP5Tables { DataBox P, bMod, dPdRho, dPdE, dTdRho, dTdE, dEdRho; }; - // 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. - 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 EosBase::EntropyIsNotEnabled; - + SG_ADD_BASE_CLASS_USINGS(SpinerEOSDependsRhoSie); PORTABLE_INLINE_FUNCTION SpinerEOSDependsRhoSie() : memoryStatus_(DataStatus::Deallocated) {} inline SpinerEOSDependsRhoSie(const std::string &filename, int matid, @@ -712,7 +693,6 @@ inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src) { return offst; } - inline herr_t SpinerEOSDependsRhoT::loadDataboxes_(const std::string &matid_str, hid_t file, hid_t lTGroup, hid_t coldGroup) { diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index 155e0aa0e4..6a0ebf1401 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -69,30 +69,7 @@ class StellarCollapse : public EosBase { enum Index { Ye = 0, lT = 1 }; }; - // 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. - 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 EosBase::SerializedSizeInBytes; - using EosBase::Serialize; - using EosBase::DeSerialize; - using EosBase::IsModified; - using EosBase::UnmodifyOnce; - using EosBase::GetUnmodifiedObject; + SG_ADD_BASE_CLASS_USINGS(StellarCollapse); inline StellarCollapse(const std::string &filename, bool use_sp5 = false, bool filter_bmod = true); diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index ed9506ed5a..a9fb296e8b 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -44,32 +44,7 @@ static struct LengthTimeUnitsInit { template class UnitSystem : 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 EosBase>::SerializedSizeInBytes; - using EosBase>::Serialize; - using EosBase>::DeSerialize; - + SG_ADD_BASE_CLASS_USINGS(UnitSystem); using BaseType = T; // give me std::format or fmt::format... @@ -450,14 +425,9 @@ class UnitSystem : public EosBase> { printf("Units = %e %e %e %e\n", rho_unit_, sie_unit_, temp_unit_, press_unit_); } - inline constexpr bool IsModified() const { return true; } - + static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } - inline constexpr decltype(auto) GetUnmodifiedObject() { - return t_.GetUnmodifiedObject(); - } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index 28338614f6..4895029d98 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -452,14 +452,9 @@ class BilinearRampEOS : public EosBase> { t_.ValuesAtReferenceState(rho, temp, sie, press, cv, bmod, dpde, dvdt, lambda); } - inline constexpr bool IsModified() const { return true; } - + static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } - inline constexpr decltype(auto) GetUnmodifiedObject() { - return t_.GetUnmodifiedObject(); - } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index fd03d03f9a..87a965c8ea 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -36,32 +36,7 @@ using namespace eos_base; template class RelativisticEOS : 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 EosBase>::SerializedSizeInBytes; - using EosBase>::Serialize; - using EosBase>::DeSerialize; - + SG_ADD_BASE_CLASS_USINGS(RelativisticEOS); using BaseType = T; // give me std::format or fmt::format... @@ -207,14 +182,9 @@ class RelativisticEOS : public EosBase> { t_.ValuesAtReferenceState(rho, temp, sie, press, cv, bmod, dpde, dvdt, lambda); } - inline constexpr bool IsModified() const { return true; } - + static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } - inline constexpr decltype(auto) GetUnmodifiedObject() { - return t_.GetUnmodifiedObject(); - } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 0163e20933..3487a7a6bd 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -36,32 +36,7 @@ using namespace eos_base; template class ScaledEOS : 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 EosBase>::SerializedSizeInBytes; - using EosBase>::Serialize; - using EosBase>::DeSerialize; - + SG_ADD_BASE_CLASS_USINGS(ScaledEOS); using BaseType = T; // give me std::format or fmt::format... @@ -367,14 +342,9 @@ class ScaledEOS : public EosBase> { return t_.MinimumTemperature(); } - inline constexpr bool IsModified() const { return true; } - + static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } - inline constexpr decltype(auto) GetUnmodifiedObject() { - return t_.GetUnmodifiedObject(); - } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 5111fd2a5a..07de42b3d0 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -36,32 +36,7 @@ using namespace eos_base; template class ShiftedEOS : 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 EosBase>::SerializedSizeInBytes; - using EosBase>::Serialize; - using EosBase>::DeSerialize; - + SG_ADD_BASE_CLASS_USINGS(ShiftedEOS); using BaseType = T; // give me std::format or fmt::format... @@ -377,14 +352,9 @@ class ShiftedEOS : public EosBase> { return t_.MinimumTemperature(); } - inline constexpr bool IsModified() const { return true; } - + static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } - inline constexpr decltype(auto) GetUnmodifiedObject() { - return t_.GetUnmodifiedObject(); - } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } From 8dab3381e91614bb06d1fd2816725715b3c892fe Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 18:13:18 -0600 Subject: [PATCH 13/48] table bounds -> table utils. Jeff was right. --- sesame2spiner/io_eospac.hpp | 2 +- singularity-eos/CMakeLists.txt | 2 +- .../{spiner_table_bounds.hpp => spiner_table_utils.hpp} | 7 ++++--- test/test_bounds.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) rename singularity-eos/base/{spiner_table_bounds.hpp => spiner_table_utils.hpp} (98%) diff --git a/sesame2spiner/io_eospac.hpp b/sesame2spiner/io_eospac.hpp index dcbfce18eb..454d44ec0f 100644 --- a/sesame2spiner/io_eospac.hpp +++ b/sesame2spiner/io_eospac.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/singularity-eos/CMakeLists.txt b/singularity-eos/CMakeLists.txt index 0096902e09..b3d6e17235 100644 --- a/singularity-eos/CMakeLists.txt +++ b/singularity-eos/CMakeLists.txt @@ -27,7 +27,7 @@ register_headers( base/fast-math/logs.hpp base/robust_utils.hpp base/root-finding-1d/root_finding.hpp - base/spiner_table_bounds.hpp + base/spiner_table_utils.hpp base/variadic_utils.hpp base/math_utils.hpp base/constants.hpp diff --git a/singularity-eos/base/spiner_table_bounds.hpp b/singularity-eos/base/spiner_table_utils.hpp similarity index 98% rename from singularity-eos/base/spiner_table_bounds.hpp rename to singularity-eos/base/spiner_table_utils.hpp index 80d3dbd080..25933dcc08 100644 --- a/singularity-eos/base/spiner_table_bounds.hpp +++ b/singularity-eos/base/spiner_table_utils.hpp @@ -12,8 +12,8 @@ // publicly and display publicly, and to permit others to do so. //------------------------------------------------------------------------------ -#ifndef SINGULARITY_EOS_BASE_TABLE_BOUNDS_HPP_ -#define SINGULARITY_EOS_BASE_TABLE_BOUNDS_HPP_ +#ifndef SINGULARITY_EOS_BASE_TABLE_UTILS_HPP_ +#define SINGULARITY_EOS_BASE_TABLE_UTILS_HPP_ #ifdef SINGULARITY_USE_SPINER #include @@ -279,8 +279,9 @@ class Bounds { private: Real linmin_, linmax_; }; + } // namespace table_utils } // namespace singularity #endif // SINGULARITY_USE_SPINER -#endif // SINGULARITY_EOS_BASE_TABLE_BOUNDS_HPP_ +#endif // SINGULARITY_EOS_BASE_TABLE_UTILS_HPP_ diff --git a/test/test_bounds.cpp b/test/test_bounds.cpp index 6dcd06c637..c291df0610 100644 --- a/test/test_bounds.cpp +++ b/test/test_bounds.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #ifndef CATCH_CONFIG_FAST_COMPILE #define CATCH_CONFIG_FAST_COMPILE From 2abb8b8cdce321f596379332c1db78994c8fe036 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 20 Aug 2024 18:59:11 -0600 Subject: [PATCH 14/48] thread SpinerTricks through a few models --- singularity-eos/base/spiner_table_utils.hpp | 54 ++++++++++++ singularity-eos/eos/eos_helmholtz.hpp | 87 ++++++++------------ singularity-eos/eos/eos_spiner.hpp | 46 ++--------- singularity-eos/eos/eos_stellar_collapse.hpp | 44 ++-------- 4 files changed, 105 insertions(+), 126 deletions(-) diff --git a/singularity-eos/base/spiner_table_utils.hpp b/singularity-eos/base/spiner_table_utils.hpp index 25933dcc08..5a01c17fc4 100644 --- a/singularity-eos/base/spiner_table_utils.hpp +++ b/singularity-eos/base/spiner_table_utils.hpp @@ -25,7 +25,10 @@ #include #include +#include #include + +#include #include namespace singularity { @@ -280,6 +283,57 @@ class Bounds { Real linmin_, linmax_; }; +// JMM: Making this a struct with static methods, rather than a +// namespace, saves a few "friend" declarations +template +struct SpinerTricks { + static auto GetOnDevice(EOS *peos_h) { + // trivially copy all but dynamic memory + EOS eos_d = *peos_h; + auto pdbs_d = eos_d.GetDataBoxPointers_(); + auto pdbs_h = peos_h->GetDataBoxPointers_(); + int idb = 0; + for (auto *pdb_d : pdbs_d) { + auto *pdb_h = pdbs_h[idb++]; + *pdb_d = pdb_h->getOnDevice(); + } + // set memory status + eos_d.memoryStatus_ = DataStatus::OnDevice; + return eos_d; + } + static void Finalize(EOS *peos) { + if (peos->memoryStatus_ != DataStatus::UnManaged) { + for (auto *pdb : peos->GetDataBoxPointers_()) { + pdb->finalize(); + } + } + peos->memoryStatus_ = DataStatus::Deallocated; + } + static std::size_t DynamicMemorySizeInBytes(const EOS *peos) { + std::size_t out = 0; + for (const auto *pdb : peos->GetDataBoxPointers_()) { + out += pdb->sizeBytes(); + } + return out; + } + static std::size_t DumpDynamicMemory(char *dst, const EOS *peos) { + std::size_t offst = 0; + for (const auto *pdb : peos->GetDataBoxPointers_()) { + std::size_t size = pdb->sizeBytes(); + memcpy(dst + offst, pdb->data(), size); + offst += size; + } + return offst; + } + static std::size_t SetDynamicMemory(char *src, EOS *peos) { + std::size_t offst = 0; + for (auto *pdb : peos->GetDataBoxPointers_()) { + offst += pdb->setPointer(src + offst); + } + peos->memoryStatus_ = DataStatus::UnManaged; + return offst; + } +}; } // namespace table_utils } // namespace singularity diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index c5d8ea6c80..18b0f689a9 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -34,6 +34,7 @@ #include #include #include +#include // ports of call #include @@ -45,6 +46,7 @@ #include #include #include +#include #include // spiner @@ -203,6 +205,9 @@ inline void SetTablesFromFile(std::ifstream &file, int n1, Real r1min, Real r1ma } // namespace HelmUtils class HelmElectrons { + friend class table_utils::SpinerTricks; + using SpinerTricks = table_utils::SpinerTricks; + public: // may change with time using DataBox = HelmUtils::DataBox; @@ -214,6 +219,16 @@ class HelmElectrons { inline HelmElectrons GetOnDevice(); inline void Finalize(); + std::size_t DynamicMemorySizeInBytes() const { + return SpinerTricks::DynamicMemorySizeInBytes(this); + } + std::size_t DumpDynamicMemory(char *dst) const { + return SpinerTricks::DumpDynamicMemory(dst, this); + } + std::size_t SetDynamicMemory(char *src) { + return SpinerTricks::SetDynamicMemory(src, this); + } + PORTABLE_INLINE_FUNCTION void GetFromDensityTemperature(Real rho, Real lT, Real Ye, Real Ytot, Real De, Real lDe, Real pele[NDERIV], Real eele[NDERIV], Real sele[NDERIV], @@ -259,6 +274,15 @@ class HelmElectrons { // number density DataBox xf_, xfd_, xft_, xfdt_; +#define DBLIST \ + &rho_, &T_, &f_, &fd_, &ft_, &fdd_, &ftt_, &fdt_, &fddt_, &fdtt_, &fddtt_, &dpdf_, \ + &dpdfd_, &dpdft_, &dpdfdt_, &ef_, &efd_, &eft_, &efdt_, &xf_, &xfd_, &xft_, &xfdt_ + auto GetDataBoxPointers_() const { return std::vector{DBLIST}; } + auto GetDataBoxPointers_() { return std::vector{DBLIST}; } +#undef DBLIST + + DataStatus memoryStatus_ = DataStatus::Deallocated; + static constexpr std::size_t NTEMP = 101; static constexpr std::size_t NRHO = 271; @@ -455,6 +479,13 @@ class Helmholtz : public EosBase { coul_.Finalize(); electrons_.Finalize(); } + std::size_t DynamicMemorySizeInBytes() const { + return electrons_.DynamicMemorySizeInBytes(); + } + std::size_t DumpDynamicMemory(char *dst) const { + return electrons_.DumpDynamicMemory(dst); + } + std::size_t SetDynamicMemory(char *src) { return electrons_.SetDynamicMemory(src); } PORTABLE_INLINE_FUNCTION void GetMassFractions(const Real rho, const Real temp, const Real ytot, Real &xni, @@ -884,63 +915,15 @@ inline void HelmElectrons::InitDataFile_(const std::string &filename) { for (int i = 0; i < NTEMP; ++i) { T_(i) = math_utils::pow10(lTRange.x(i)); } + + memoryStatus_ = DataStatus::OnHost; } inline HelmElectrons HelmElectrons::GetOnDevice() { - HelmElectrons other; - other.rho_ = Spiner::getOnDeviceDataBox(rho_); - other.T_ = Spiner::getOnDeviceDataBox(T_); - other.f_ = Spiner::getOnDeviceDataBox(f_); - other.fd_ = Spiner::getOnDeviceDataBox(fd_); - other.ft_ = Spiner::getOnDeviceDataBox(ft_); - other.fdd_ = Spiner::getOnDeviceDataBox(fdd_); - other.ftt_ = Spiner::getOnDeviceDataBox(ftt_); - other.fdt_ = Spiner::getOnDeviceDataBox(fdt_); - other.fdd_ = Spiner::getOnDeviceDataBox(fdd_); - other.fddt_ = Spiner::getOnDeviceDataBox(fddt_); - other.fdtt_ = Spiner::getOnDeviceDataBox(fdtt_); - other.fddtt_ = Spiner::getOnDeviceDataBox(fddtt_); - other.dpdf_ = Spiner::getOnDeviceDataBox(dpdf_); - other.dpdfd_ = Spiner::getOnDeviceDataBox(dpdfd_); - other.dpdft_ = Spiner::getOnDeviceDataBox(dpdft_); - other.dpdfdt_ = Spiner::getOnDeviceDataBox(dpdfdt_); - other.ef_ = Spiner::getOnDeviceDataBox(ef_); - other.efd_ = Spiner::getOnDeviceDataBox(efd_); - other.eft_ = Spiner::getOnDeviceDataBox(eft_); - other.efdt_ = Spiner::getOnDeviceDataBox(efdt_); - other.xf_ = Spiner::getOnDeviceDataBox(xf_); - other.xfd_ = Spiner::getOnDeviceDataBox(xfd_); - other.xft_ = Spiner::getOnDeviceDataBox(xft_); - other.xfdt_ = Spiner::getOnDeviceDataBox(xfdt_); - return other; + return SpinerTricks::GetOnDevice(this); } -inline void HelmElectrons::Finalize() { - rho_.finalize(); - T_.finalize(); - f_.finalize(); - fd_.finalize(); - ft_.finalize(); - fdd_.finalize(); - ftt_.finalize(); - fdt_.finalize(); - fdd_.finalize(); - fddt_.finalize(); - fdtt_.finalize(); - fddtt_.finalize(); - dpdf_.finalize(); - dpdfd_.finalize(); - dpdft_.finalize(); - dpdfdt_.finalize(); - ef_.finalize(); - efd_.finalize(); - eft_.finalize(); - efdt_.finalize(); - xf_.finalize(); - xfd_.finalize(); - xft_.finalize(); - xfdt_.finalize(); -} +inline void HelmElectrons::Finalize() { SpinerTricks::Finalize(this); } PORTABLE_INLINE_FUNCTION void HelmElectrons::GetFromDensityTemperature(Real rho, Real lT, Real Ye, Real Ytot, diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index eab7cb09c7..b13ac4d810 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,9 @@ using namespace eos_base; we use log-linear extrapolation. */ class SpinerEOSDependsRhoT : public EosBase { + friend class table_utils::SpinerTricks; + using SpinerTricks = table_utils::SpinerTricks; + public: static constexpr int NGRIDS = 3; using Grid_t = Spiner::PiecewiseGrid1D; @@ -644,53 +648,21 @@ inline SpinerEOSDependsRhoT::SpinerEOSDependsRhoT(const std::string &filename, } inline SpinerEOSDependsRhoT SpinerEOSDependsRhoT::GetOnDevice() { - SpinerEOSDependsRhoT other = *this; // trivial copy - // now do databoxes - int idb = 0; - auto pmy_dbs = GetDataBoxPointers_(); - for (DataBox *pother_db : other.GetDataBoxPointers_()) { - DataBox *pmy_db = pmy_dbs[idb++]; - *pother_db = Spiner::getOnDeviceDataBox(*pmy_db); - } - // and memory status - other.memoryStatus_ = DataStatus::OnDevice; - return other; + return SpinerTricks::GetOnDevice(this); } -void SpinerEOSDependsRhoT::Finalize() { - if (memoryStatus_ != DataStatus::UnManaged) { - for (DataBox *pdb : GetDataBoxPointers_()) { - pdb->finalize(); - } - } - memoryStatus_ = DataStatus::Deallocated; -} +void SpinerEOSDependsRhoT::Finalize() { SpinerTricks::Finalize(this); } inline std::size_t SpinerEOSDependsRhoT::DynamicMemorySizeInBytes() const { - std::size_t out = 0; - for (const DataBox *pdb : GetDataBoxPointers_()) { - out += pdb->sizeBytes(); - } - return out; + return SpinerTricks::DynamicMemorySizeInBytes(this); } inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) const { - std::size_t offst = 0; - for (const DataBox *pdb : GetDataBoxPointers_()) { - std::size_t size = pdb->sizeBytes(); - memcpy(dst + offst, pdb->data(), size); - offst += size; - } - return offst; + return SpinerTricks::DumpDynamicMemory(dst, this); } inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src) { - std::size_t offst = 0; - for (DataBox *pdb : GetDataBoxPointers_()) { - offst += pdb->setPointer(src + offst); - } - memoryStatus_ = DataStatus::UnManaged; - return offst; + return SpinerTricks::SetDynamicMemory(src, this); } inline herr_t SpinerEOSDependsRhoT::loadDataboxes_(const std::string &matid_str, diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index 6a0ebf1401..e5a0368144 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,7 @@ using namespace eos_base; // and introduce extrapolation as needed. class StellarCollapse : public EosBase { public: + friend class table_utils::SpinerTricks; using DataBox = Spiner::DataBox; using Grid_t = Spiner::RegularGrid1D; @@ -467,55 +469,23 @@ inline void StellarCollapse::Save(const std::string &filename) { } inline StellarCollapse StellarCollapse::GetOnDevice() { - // trivially copy all but dynamic memory - StellarCollapse other = *this; - // set dynamic memory - auto other_dbs = other.GetDataBoxPointers_(); - auto my_dbs = GetDataBoxPointers_(); - int idb = 0; - for (DataBox *pother_db : other_dbs) { - DataBox *pmy_db = my_dbs[idb++]; - *pother_db = Spiner::getOnDeviceDataBox(*pmy_db); - } - // set memory status - other.memoryStatus_ = DataStatus::OnDevice; - return other; + return table_utils::SpinerTricks::GetOnDevice(this); } inline void StellarCollapse::Finalize() { - if (memoryStatus_ != DataStatus::UnManaged) { - for (DataBox *pdb : GetDataBoxPointers_()) { - pdb->finalize(); - } - } - memoryStatus_ = DataStatus::Deallocated; + table_utils::SpinerTricks::Finalize(this); } inline std::size_t StellarCollapse::DynamicMemorySizeInBytes() const { - std::size_t out = 0; - for (const DataBox *pdb : GetDataBoxPointers_()) { - out += pdb->sizeBytes(); - } - return out; + return table_utils::SpinerTricks::DynamicMemorySizeInBytes(this); } inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) const { - std::size_t offst = 0; - for (const DataBox *pdb : GetDataBoxPointers_()) { - std::size_t size = pdb->sizeBytes(); - memcpy(dst + offst, pdb->data(), size); - offst += size; - } - return offst; + return table_utils::SpinerTricks::DumpDynamicMemory(dst, this); } inline std::size_t StellarCollapse::SetDynamicMemory(char *src) { - std::size_t offst = 0; - for (DataBox *pdb : GetDataBoxPointers_()) { - offst += pdb->setPointer(src + offst); - } - memoryStatus_ = DataStatus::UnManaged; - return offst; + return table_utils::SpinerTricks::SetDynamicMemory(src, this); } template From d8adfa3053491d69459bc1c8bd071d0f54e37fd6 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 21 Aug 2024 12:03:57 -0600 Subject: [PATCH 15/48] add test for spiner tricks --- singularity-eos/base/spiner_table_utils.hpp | 14 +++ test/CMakeLists.txt | 1 + test/test_spiner_tricks.cpp | 130 ++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 test/test_spiner_tricks.cpp diff --git a/singularity-eos/base/spiner_table_utils.hpp b/singularity-eos/base/spiner_table_utils.hpp index 5a01c17fc4..601e95c324 100644 --- a/singularity-eos/base/spiner_table_utils.hpp +++ b/singularity-eos/base/spiner_table_utils.hpp @@ -333,6 +333,20 @@ struct SpinerTricks { peos->memoryStatus_ = DataStatus::UnManaged; return offst; } + static bool DataBoxesPointToSameMemory(const EOS &eos_a, const EOS &eos_b) { + const auto pdbs_a = eos_a.GetDataBoxPointers_(); + const auto pdbs_b = eos_b.GetDataBoxPointers_(); + int idb = 0; + for (const auto *pdb_a : pdbs_a) { + const auto &db_a = *pdb_a; + const auto &db_b = *(pdbs_b[idb++]); + if (&(db_a(0)) != &(db_b(0))) return false; + } + return true; + } + static bool DataBoxesPointToDifferentMemory(const EOS &eos_a, const EOS &eos_b) { + return !DataBoxesPointToSameMemory(eos_a, eos_b); + } }; } // namespace table_utils } // namespace singularity diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0a127feb6..6297703ebc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable( eos_tabulated_unit_tests catch2_define.cpp eos_unit_test_helpers.hpp + test_spiner_tricks.cpp test_eos_helmholtz.cpp test_eos_tabulated.cpp test_eos_stellar_collapse.cpp diff --git a/test/test_spiner_tricks.cpp b/test/test_spiner_tricks.cpp new file mode 100644 index 0000000000..314f645f4f --- /dev/null +++ b/test/test_spiner_tricks.cpp @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// © 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. +//------------------------------------------------------------------------------ + +#ifdef SINGULARITY_USE_SPINER + +#include +#include + +#include +#include +#include + +#include +#include + +#ifndef CATCH_CONFIG_FAST_COMPILE +#define CATCH_CONFIG_FAST_COMPILE +#include +#endif + +using namespace singularity; +class DummyEOS; +using STricks = table_utils::SpinerTricks; + +class DummyEOS { + public: + friend class table_utils::SpinerTricks; + using Grid_t = Spiner::RegularGrid1D; + using DataBox = Spiner::DataBox; + + DummyEOS() = default; + DummyEOS(int N) : N_(N), a_(N), b_(N), memoryStatus_(DataStatus::OnHost) { + for (int i = 0; i < N; ++i) { + a_(i) = i; + b_(i) = i + N; + } + } + void Finalize() { STricks::Finalize(this); } + DummyEOS GetOnDevice() { return STricks::GetOnDevice(this); } + std::size_t DynamicMemorySizeInBytes() const { + return STricks::DynamicMemorySizeInBytes(this); + } + std::size_t DumpDynamicMemory(char *dst) const { + return STricks::DumpDynamicMemory(dst, this); + } + std::size_t SetDynamicMemory(char *src) { return STricks::SetDynamicMemory(src, this); } + + // Public so we can inspect in unit tests + int N_ = -1; + DataBox a_, b_; + DataStatus memoryStatus_ = DataStatus::Deallocated; + + // Private so we can ensure class friendship is working + private: +#define DBLIST &a_, &b_ + std::vector GetDataBoxPointers_() const { + return std::vector{DBLIST}; + } + std::vector GetDataBoxPointers_() { return std::vector{DBLIST}; } +#undef DBLIST +}; + +constexpr int N = 5; +SCENARIO("The SpinerTricks tool can copy databoxes to device and finalize them", + "[SpinerTricks]") { + WHEN("We initialize a host-side DummyEOS") { + DummyEOS eos_h(N); + REQUIRE(eos_h.memoryStatus_ == DataStatus::OnHost); + THEN("We can copy it to device") { + DummyEOS eos_d = eos_h.GetOnDevice(); + REQUIRE(eos_d.memoryStatus_ == DataStatus::OnDevice); + AND_THEN("The device-side memory is correct") { + int nwrong = 0; + portableReduce( + "Check Dummy EOS", 0, N, + PORTABLE_LAMBDA(const int i, int &nw) { + nw += (eos_d.a_(i) != i) + (eos_d.b_(i) != i + N); + }, + nwrong); + REQUIRE(nwrong == 0); + } + eos_d.Finalize(); + REQUIRE(eos_d.memoryStatus_ == DataStatus::Deallocated); + } + + eos_h.Finalize(); + REQUIRE(eos_h.memoryStatus_ == DataStatus::Deallocated); + } +} + +SCENARIO("The SpinerTricks tool can serialize dynamic memory", "[SpinerTricks]") { + GIVEN("A DummyEOS") { + DummyEOS eos1(N); + std::size_t size = eos1.DynamicMemorySizeInBytes(); + REQUIRE(eos1.memoryStatus_ == DataStatus::OnHost); + REQUIRE(size == 2 * N * sizeof(std::size_t)); + THEN("We can serialize it") { + char *data = (char *)malloc(size); + eos1.DumpDynamicMemory(data); + WHEN("We can de-serialize it twice") { + DummyEOS eos2(N), eos3(N); + eos2.SetDynamicMemory(data); + eos3.SetDynamicMemory(data); + THEN("The data is different from the original object") { + REQUIRE(STricks::DataBoxesPointToDifferentMemory(eos1, eos2)); + REQUIRE(STricks::DataBoxesPointToDifferentMemory(eos1, eos3)); + AND_THEN("The serialized objects point to the same underlying memory as each " + "other") { + REQUIRE(STricks::DataBoxesPointToSameMemory(eos2, eos3)); + } + } + } + free(data); + } + eos1.Finalize(); + } +} + +#endif // SINGULARITY_USE_SPINER From 3699b42fa7d732229a27862c4edbeabb74bc7429 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 21 Aug 2024 15:52:04 -0600 Subject: [PATCH 16/48] Add some sanity checks to base class. Fix bug in base class. Add tests that catch issues related to CRTP. --- singularity-eos/eos/eos_base.hpp | 22 +++++++++++++++------- test/test_eos_stellar_collapse.cpp | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index cb134439ff..f9c9688052 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -671,25 +671,33 @@ class EosBase { } std::size_t Serialize(char *dst) const { const CRTP *pcrtp = static_cast(this); + std::size_t offst = 0; memcpy(dst, pcrtp, sizeof(CRTP)); + offst += sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); if (dyn_size > 0) { - DumpDynamicMemory(dst + sizeof(CRTP)); + offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } - return SerializedSizeInBytes(); + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization succesful"); + return offst; } auto Serialize() const { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); - Serialize(dst); + std::size_t size_new = Serialize(dst); + PORTABLE_REQUIRE(size_new == size, "Serialization succesful"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src) { - memcpy(static_cast(this), src, sizeof(CRTP)); - if (DynamicMemorySizeInBytes() > 0) { - SetDynamicMemory(src + sizeof(CRTP)); + CRTP *pcrtp = static_cast(this); + std::size_t offst = 0; + memcpy(pcrtp, src, sizeof(CRTP)); + offst += sizeof(CRTP); + if (pcrtp->DynamicMemorySizeInBytes() > 0) { + offst += pcrtp->SetDynamicMemory(src + sizeof(CRTP)); } - return SerializedSizeInBytes(); + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Deserialization succesful"); + return offst; } // Tooling for modifiers diff --git a/test/test_eos_stellar_collapse.cpp b/test/test_eos_stellar_collapse.cpp index 009d6eae40..4eb4930db9 100644 --- a/test/test_eos_stellar_collapse.cpp +++ b/test/test_eos_stellar_collapse.cpp @@ -37,6 +37,9 @@ #ifdef SPINER_USE_HDF #ifdef SINGULARITY_TEST_STELLAR_COLLAPSE + +#include + template void CompareStellarCollapse(EOS_t sc, EOS_t sc2) { Real yemin = sc.YeMin(); @@ -294,22 +297,37 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { } WHEN("We serialize the StellarCollapse EOS") { + using Tricks = singularity::table_utils::SpinerTricks; auto [size, data] = sc.Serialize(); REQUIRE(size > 0); THEN("We can de-serialize it into a new object") { StellarCollapse sc2; std::size_t read_size = sc2.DeSerialize(data); REQUIRE(read_size == size); + REQUIRE(size > sizeof(StellarCollapse)); sc2.CheckParams(); + AND_THEN("The new eos uses different memory than the original") { + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc, sc2)); + } AND_THEN("The two stellar collapse EOS's agree") { CompareStellarCollapse(sc, sc2); } + AND_THEN("We can de-serialize into two objects") { + StellarCollapse sc3; + std::size_t read_size_2 = sc3.DeSerialize(data); + REQUIRE(read_size_2 == size); + sc3.CheckParams(); + AND_THEN("The two de-serialized objects use the same memory") { + REQUIRE(Tricks::DataBoxesPointToSameMemory(sc2, sc3)); + } + } } free(data); } WHEN("We serialize a variant that owns a StellarCollapse EOS") { using EOS = singularity::Variant; + using Tricks = singularity::table_utils::SpinerTricks; EOS e1 = sc; auto [size, data] = e1.Serialize(); REQUIRE(size > 0); @@ -321,6 +339,7 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { AND_THEN("The two stellar collapse EOS's agree") { StellarCollapse sc2 = e2.get(); CompareStellarCollapse(sc, sc2); + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc, sc2)); } } free(data); From 1505a33ea141dc0ecfdac86d93a9904573b56cf7 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 21 Aug 2024 16:12:24 -0600 Subject: [PATCH 17/48] add helmholtz tests --- singularity-eos/eos/eos_helmholtz.hpp | 14 +++++++++---- test/test_eos_helmholtz.cpp | 30 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 18b0f689a9..3e00c0fcb5 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -214,10 +214,18 @@ class HelmElectrons { static constexpr std::size_t NDERIV = HelmUtils::NDERIV; HelmElectrons() = default; - inline HelmElectrons(const std::string &filename) { InitDataFile_(filename); } + inline HelmElectrons(const std::string &filename) { + InitDataFile_(filename); + CheckParams(); + } inline HelmElectrons GetOnDevice(); inline void Finalize(); + inline void CheckParams() const { + // better than nothing... + PORTABLE_ALWAYS_REQUIRE(rho_.size() == NRHO, "Density grid correct"); + PORTABLE_ALWAYS_REQUIRE(T_.size() == NTEMP, "Temperature grid correct"); + } std::size_t DynamicMemorySizeInBytes() const { return SpinerTricks::DynamicMemorySizeInBytes(this); @@ -440,9 +448,7 @@ class Helmholtz : public EosBase { : electrons_(filename), options_(rad, gas, coul, ion, ele, verbose, newton_raphson) {} - PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): Stub - } + PORTABLE_INLINE_FUNCTION void CheckParams() const { electrons_.CheckParams(); } PORTABLE_INLINE_FUNCTION int nlambda() const noexcept { return 3; } static constexpr unsigned long PreferredInput() { diff --git a/test/test_eos_helmholtz.cpp b/test/test_eos_helmholtz.cpp index c12af5f866..2691659c8d 100644 --- a/test/test_eos_helmholtz.cpp +++ b/test/test_eos_helmholtz.cpp @@ -45,6 +45,16 @@ SCENARIO("Helmholtz equation of state - Table interpolation (tgiven)", "[Helmhol Helmholtz eos = host_eos.GetOnDevice(); THEN("We loaded the file!") { REQUIRE(true); } + Helmholtz host_eos_2; + auto [size, data] = host_eos.Serialize(); + auto read_size = host_eos_2.DeSerialize(data); + THEN("We can serialize!") { + host_eos_2.CheckParams(); + REQUIRE(size == read_size); + REQUIRE(size > sizeof(Helmholtz)); + } + Helmholtz eos_2 = host_eos_2.GetOnDevice(); + /* Compare test values. Difference should be less than 1e-10 */ #ifdef PORTABILITY_STRATEGY_KOKKOS int nwrong = 1; // != 0 @@ -116,6 +126,22 @@ SCENARIO("Helmholtz equation of state - Table interpolation (tgiven)", "[Helmhol Real gruen = eos.GruneisenParamFromDensityTemperature(rho_in[i], temp_in[j], lambda); + if (!isClose(ein, ein_ref[k], 1e-10)) nwrong += 1; + if (!isClose(press, press_ref[k], 1e-10)) nwrong += 1; + if (!isClose(cv, cv_ref[k], 1e-6)) nwrong += 1; + if (!isClose(bulkmod, bulkmod_ref[k], 1e-8)) nwrong += 1; + if (!isClose(gruen, gruen_ref[k], 1e-6)) nwrong += 1; + + ein = eos_2.InternalEnergyFromDensityTemperature(rho_in[i], temp_in[j], + lambda); + press = eos_2.PressureFromDensityTemperature(rho_in[i], temp_in[j], lambda); + cv = + eos_2.SpecificHeatFromDensityTemperature(rho_in[i], temp_in[j], lambda); + bulkmod = + eos_2.BulkModulusFromDensityTemperature(rho_in[i], temp_in[j], lambda); + gruen = eos_2.GruneisenParamFromDensityTemperature(rho_in[i], temp_in[j], + lambda); + if (!isClose(ein, ein_ref[k], 1e-10)) nwrong += 1; if (!isClose(press, press_ref[k], 1e-10)) nwrong += 1; if (!isClose(cv, cv_ref[k], 1e-6)) nwrong += 1; @@ -127,6 +153,8 @@ SCENARIO("Helmholtz equation of state - Table interpolation (tgiven)", "[Helmhol }, nwrong); REQUIRE(nwrong == 0); + eos.Finalize(); + host_eos.Finalize(); } } @@ -198,6 +226,8 @@ SCENARIO("Helmholtz equation of state - Root finding (egiven)", "[HelmholtzEOS]" }, nwrong); REQUIRE(nwrong == 0); + eos.Finalize(); + host_eos.Finalize(); } } From 0f0c5bb6316e483302c832de924f33574f0fb35f Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Wed, 21 Aug 2024 18:55:45 -0600 Subject: [PATCH 18/48] eospac serialization. Still need to test. Time for Darwin. --- CMakeLists.txt | 6 + singularity-eos/eos/eos_base.hpp | 6 +- singularity-eos/eos/eos_eospac.hpp | 73 ++++++++- singularity-eos/eos/eos_helmholtz.hpp | 4 +- singularity-eos/eos/eos_spiner.hpp | 148 ++++++++++-------- singularity-eos/eos/eos_stellar_collapse.hpp | 4 +- singularity-eos/eos/eos_variant.hpp | 10 +- .../eos/modifiers/eos_unitsystem.hpp | 4 +- singularity-eos/eos/modifiers/ramps_eos.hpp | 4 +- .../eos/modifiers/relativistic_eos.hpp | 4 +- singularity-eos/eos/modifiers/scaled_eos.hpp | 4 +- singularity-eos/eos/modifiers/shifted_eos.hpp | 4 +- 12 files changed, 190 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51973cb148..95d8753fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,9 @@ cmake_dependent_option( option(SINGULARITY_USE_FORTRAN "Enable fortran bindings" ON) option(SINGULARITY_USE_KOKKOS "Use Kokkos for portability" OFF) option(SINGULARITY_USE_EOSPAC "Enable eospac backend" OFF) +option(SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY + "Support shared memory with EOSPAC backend. Requires EOSPAC version 6.5.7." + OFF) # TODO This should be dependent option (or fortran option) option(SINGULARITY_BUILD_CLOSURE "Mixed Cell Closure" ON) @@ -271,6 +274,9 @@ endif() if(SINGULARITY_USE_SPINER_WITH_HDF5) target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_USE_SPINER_WITH_HDF5) endif() +if (SINGULARITY_USE_EOSPAC AND SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY) +endif() # ------------------------------------------------------------------------------# # Handle dependencies diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index f9c9688052..76055e8507 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -654,7 +654,7 @@ class EosBase { // JMM: These must be special-cased. std::size_t DynamicMemorySizeInBytes() const { return 0; } std::size_t DumpDynamicMemory(char *dst) const { return 0; } - std::size_t SetDynamicMemory(char *src) { return 0; } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { return 0; } // JMM: These are generic and do not need to be special-cased. // TODO(JMM): Should this machinery actually be available for "bare" // EOS's outside the variant? @@ -688,13 +688,13 @@ class EosBase { PORTABLE_REQUIRE(size_new == size, "Serialization succesful"); return std::make_pair(size, dst); } - std::size_t DeSerialize(char *src) { + std::size_t DeSerialize(char *src, bool node_root = true) { CRTP *pcrtp = static_cast(this); std::size_t offst = 0; memcpy(pcrtp, src, sizeof(CRTP)); offst += sizeof(CRTP); if (pcrtp->DynamicMemorySizeInBytes() > 0) { - offst += pcrtp->SetDynamicMemory(src + sizeof(CRTP)); + offst += pcrtp->SetDynamicMemory(src + sizeof(CRTP), node_root); } PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Deserialization succesful"); return offst; diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 698cc22316..7ac29d0f9c 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -141,9 +141,14 @@ class EOSPAC : public EosBase { eospacSplit apply_splitting = eospacSplit::none, bool linear_interp = false); PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): STUB + // TODO(JMM): I really don't know what to put here... } inline EOSPAC GetOnDevice() { return *this; } + + std::size_t DynamicMemorySizeInBytes() const; + std::size_t DumpDynamicMemory(char *dst) const; + std::size_t SetDynamicMemory(char *src, bool node_root = true); + SG_PIF_NOWARN template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( @@ -1122,7 +1127,6 @@ class EOSPAC : public EosBase { EOS_INTEGER PofRE_table_; EOS_INTEGER EcofD_table_; EOS_INTEGER tablehandle[NT]; - EOS_INTEGER EOS_Info_table_; static constexpr Real temp_ref_ = 293; Real rho_ref_ = 1; Real sie_ref_ = 1; @@ -1133,6 +1137,9 @@ class EOSPAC : public EosBase { Real dvdt_ref_ = 1; Real rho_min_ = 0; Real temp_min_ = 0; + // TODO(JMM): Is the fact that EOS_INTEGER isn't a size_t a + // problem? Could it ever realistically overflow? + EOS_INTEGER shared_size_, packed_size_; static inline std::map &scratch_nbuffers() { static std::map nbuffers = { @@ -1169,7 +1176,7 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, NT, matid, tableType, tablehandle, std::vector({"EOS_Pt_DT", "EOS_T_DUt", "EOS_Ut_DT", "EOS_D_PtT", "EOS_T_DPt", "EOS_Pt_DUt", "EOS_Uc_D"}), - Verbosity::Quiet, invert_at_setup = invert_at_setup, insert_data = insert_data, + Verbosity::Debug, invert_at_setup = invert_at_setup, insert_data = insert_data, monotonicity = monotonicity, apply_smoothing = apply_smoothing, apply_splitting = apply_splitting, linear_interp = linear_interp); PofRT_table_ = tablehandle[0]; @@ -1180,9 +1187,23 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, PofRE_table_ = tablehandle[5]; EcofD_table_ = tablehandle[6]; + // Shared memory info + { + EOS_INTEGER NTABLES[] = {NT}; + EOS_INTEGER error_code = EOS_OK; +#ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY + eos_GetSharedPackedTablesSize(NTABLES, tablehandle, &packed_size_, &shared_size_, + &error_code); +#else + eos_GetPackedTablesSize(NTABLES, tablehandle, &packed_size_, &error_code); + shared_size_ = 0; +#endif // SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY + eosCheckError(error_code, "Get shared memory info", Verbosity::Debug); + } + // Set reference states and table bounds SesameMetadata m; - eosGetMetadata(matid, m, Verbosity::Quiet); + eosGetMetadata(matid, m, Verbosity::Debug); rho_ref_ = m.normalDensity; rho_min_ = m.rhoMin; temp_min_ = m.TMin; @@ -1211,6 +1232,50 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, robust::ratio(dpde_ref_ * cv_ref_, rho_ref_ * rho_ref_ * pressureFromSesame(DPDR)); } +std::size_t EOSPAC::DynamicMemorySizeInBytes() const { + // JMM: We need both of these because EOSPAC allows the size in + // shared memory to differ from the size required to reconstruct + // an object. This is generically true for spiner too, but we just + // deliberately waste a little space. + return std::max(shared_size_, packed_size_); +} + +std::size_t EOSPAC::DumpDynamicMemory(char *dst) const { + static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); + EOS_INTEGER NTABLES[] = {NT}; + EOS_INTEGER error_code = EOS_OK; + // TODO(JMM): Is casting to EOS_CHAR* safe here? I really hope so. + eos_GetPackedTables(NTABLES, tablehandle, (EOS_CHAR *)dst, &error_code); + eosCheckError(error_code, "eos_GetPackedTables", Verbosity::Debug); + return DynamicMemorySizeInBytes(); +} + +std::size_t EOSPAC::SetDynamicMemory(char *src, bool node_root) { + static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); + EOS_INTEGER NTABLES[] = {NT}; + EOS_INTEGER error_code = EOS_OK; +#ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY + // Because EOSPAC uses BOTH packed and shared pointers, reads from + // one, and writes to the other, we need to do an additional + // internal memcopy + std::vector packed_data(packed_size); + memcpy(packed_data.data(), src, packed_size); + // JMM: EOS_BOOLEAN is an enum with EOS_FALSE=0 and EOS_TRUE=1. + eos_SetSharedPackedTables(NTABLES, &packed_size, packed_data.data(), (EOS_CHAR *)src, + node_root, tablehandle, &error_code); +#else + eos_SetPackedTables(NTABLES, &packed_size, (EOS_CHAR *)src, tablehandle, &error_code); +#endif // SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY + eosCheckError(error_code, "eos_SetSharedPackedTables", Verbosity::Debug); + PofRT_table_ = tablehandle[0]; // these get re-set + TofRE_table_ = tablehandle[1]; + EofRT_table_ = tablehandle[2]; + RofPT_table_ = tablehandle[3]; + TofRP_table_ = tablehandle[4]; + PofRE_table_ = tablehandle[5]; + EcofD_table_ = tablehandle[6]; +} + SG_PIF_NOWARN template PORTABLE_INLINE_FUNCTION Real EOSPAC::TemperatureFromDensityInternalEnergy( diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 3e00c0fcb5..2451a8c7ae 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -491,7 +491,9 @@ class Helmholtz : public EosBase { std::size_t DumpDynamicMemory(char *dst) const { return electrons_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return electrons_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return electrons_.SetDynamicMemory(src); + } PORTABLE_INLINE_FUNCTION void GetMassFractions(const Real rho, const Real temp, const Real ytot, Real &xni, diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index b13ac4d810..0ee4dac16b 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -106,7 +106,7 @@ class SpinerEOSDependsRhoT : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src); + std::size_t SetDynamicMemory(char *src, bool node_root = true); template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( @@ -343,7 +343,20 @@ class SpinerEOSDependsRhoSie : public EosBase { using DataBox = SpinerEOSDependsRhoT::DataBox; struct SP5Tables { DataBox P, bMod, dPdRho, dPdE, dTdRho, dTdE, dEdRho; + +#define DBLIST &P, &bMod, &dPdRho, &dPdE, &dTdRho, &dTdE, &dEdRho + std::vector GetDataBoxPointers_() const { + return std::vector{DBLIST}; + } + std::vector GetDataBoxPointers_() { + return std::vector{DBLIST}; + } +#undef DBLIST + DataStatus memoryStatus_ = DataStatus::Deallocated; + ; }; + using STricks = table_utils::SpinerTricks; + SG_ADD_BASE_CLASS_USINGS(SpinerEOSDependsRhoSie); PORTABLE_INLINE_FUNCTION SpinerEOSDependsRhoSie() : memoryStatus_(DataStatus::Deallocated) {} @@ -355,9 +368,17 @@ class SpinerEOSDependsRhoSie : public EosBase { inline SpinerEOSDependsRhoSie GetOnDevice(); PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): STUB + PORTABLE_ALWAYS_REQUIRE(numRho_ > 0, "Finite number of density points"); + PORTABLE_ALWAYS_REQUIRE(!(std::isnan(lRhoMin_) || std::isnan(lRhoMax_)), + "Density bounds well defined"); + PORTABLE_ALWAYS_REQUIRE(lRhoMax_ > lRhoMin_, "Density bounds ordered"); + PORTABLE_ALWAYS_REQUIRE(rhoMax_ > 0, "Max density must be positive"); } + std::size_t DynamicMemorySizeInBytes() const; + std::size_t DumpDynamicMemory(char *dst) const; + std::size_t SetDynamicMemory(char *src, bool node_root = true); + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( const Real rho, const Real sie, @@ -661,7 +682,7 @@ inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) const { return SpinerTricks::DumpDynamicMemory(dst, this); } -inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src) { +inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src, bool node_root) { return SpinerTricks::SetDynamicMemory(src, this); } @@ -1599,70 +1620,73 @@ inline void SpinerEOSDependsRhoSie::calcBMod_(SP5Tables &tables) { } inline SpinerEOSDependsRhoSie SpinerEOSDependsRhoSie::GetOnDevice() { - SpinerEOSDependsRhoSie other; - using Spiner::getOnDeviceDataBox; - other.sie_ = getOnDeviceDataBox(sie_); - other.T_ = getOnDeviceDataBox(T_); - other.dependsRhoT_.P = getOnDeviceDataBox(dependsRhoT_.P); - other.dependsRhoT_.bMod = getOnDeviceDataBox(dependsRhoT_.bMod); - other.dependsRhoT_.dPdRho = getOnDeviceDataBox(dependsRhoT_.dPdRho); - other.dependsRhoT_.dPdE = getOnDeviceDataBox(dependsRhoT_.dPdE); - other.dependsRhoT_.dTdRho = getOnDeviceDataBox(dependsRhoT_.dTdRho); - other.dependsRhoT_.dTdE = getOnDeviceDataBox(dependsRhoT_.dTdE); - other.dependsRhoT_.dEdRho = getOnDeviceDataBox(dependsRhoT_.dEdRho); - other.dependsRhoSie_.P = getOnDeviceDataBox(dependsRhoSie_.P); - other.dependsRhoSie_.bMod = getOnDeviceDataBox(dependsRhoSie_.bMod); - other.dependsRhoSie_.dPdRho = getOnDeviceDataBox(dependsRhoSie_.dPdRho); - other.dependsRhoSie_.dPdE = getOnDeviceDataBox(dependsRhoSie_.dPdE); - other.dependsRhoSie_.dTdRho = getOnDeviceDataBox(dependsRhoSie_.dTdRho); - other.dependsRhoSie_.dTdE = getOnDeviceDataBox(dependsRhoSie_.dTdE); - other.dependsRhoSie_.dEdRho = getOnDeviceDataBox(dependsRhoSie_.dEdRho); - other.numRho_ = numRho_; - other.lRhoMin_ = lRhoMin_; - other.lRhoMax_ = lRhoMax_; - other.rhoMax_ = rhoMax_; - other.PlRhoMax_ = getOnDeviceDataBox(PlRhoMax_); - other.dPdRhoMax_ = getOnDeviceDataBox(dPdRhoMax_); - other.lRhoOffset_ = lRhoOffset_; - other.lTOffset_ = lTOffset_; - other.lEOffset_ = lEOffset_; - other.rhoNormal_ = rhoNormal_; - other.TNormal_ = TNormal_; - other.sieNormal_ = sieNormal_; - other.PNormal_ = PNormal_; - other.CvNormal_ = CvNormal_; - other.bModNormal_ = bModNormal_; - other.dPdENormal_ = dPdENormal_; - other.dVdTNormal_ = dVdTNormal_; - other.matid_ = matid_; - other.reproducible_ = reproducible_; - other.status_ = status_; + SpinerEOSDependsRhoSie other = *this; // static memory + // dynamic memory + other.sie_ = sie_.getOnDevice(); + other.T_ = T_.getOnDevice(); + other.PlRhoMax_ = PlRhoMax_.getOnDevice(); + other.dPdRhoMax_ = dPdRhoMax_.getOnDevice(); + other.dependsRhoT_ = STricks::GetOnDevice(&dependsRhoT_); + other.dependsRhoSie_ = STricks::GetOnDevice(&dependsRhoSie_); + // memory status other.memoryStatus_ = DataStatus::OnDevice; return other; } void SpinerEOSDependsRhoSie::Finalize() { - sie_.finalize(); - T_.finalize(); - dependsRhoT_.P.finalize(); - dependsRhoT_.bMod.finalize(); - dependsRhoT_.dPdRho.finalize(); - dependsRhoT_.dPdE.finalize(); - dependsRhoT_.dTdRho.finalize(); - dependsRhoT_.dTdE.finalize(); - dependsRhoT_.dEdRho.finalize(); - dependsRhoSie_.P.finalize(); - dependsRhoSie_.bMod.finalize(); - dependsRhoSie_.dPdRho.finalize(); - dependsRhoSie_.dPdE.finalize(); - dependsRhoSie_.dTdRho.finalize(); - dependsRhoSie_.dTdE.finalize(); - dependsRhoSie_.dEdRho.finalize(); - if (memoryStatus_ == DataStatus::OnDevice) { // these are slices on host - PlRhoMax_.finalize(); - dPdRhoMax_.finalize(); - } - memoryStatus_ = DataStatus::Deallocated; + if (memoryStatus_ != DataStatus::UnManaged) { + sie_.finalize(); + T_.finalize(); + STricks::Finalize(&dependsRhoT_); + STricks::Finalize(&dependsRhoSie_); + if (memoryStatus_ == DataStatus::OnDevice) { // these are slices on host + PlRhoMax_.finalize(); + dPdRhoMax_.finalize(); + } + memoryStatus_ = DataStatus::Deallocated; + } +} + +inline std::size_t SpinerEOSDependsRhoSie::DynamicMemorySizeInBytes() const { + return (sie_.sizeBytes() + T_.sizeBytes() + + STricks::DynamicMemorySizeInBytes(&dependsRhoT_) + + STricks::DynamicMemorySizeInBytes(&dependsRhoSie_) + PlRhoMax_.sizeBytes() + + dPdRhoMax_.sizeBytes()); +} + +inline std::size_t SpinerEOSDependsRhoSie::DumpDynamicMemory(char *dst) const { + std::size_t offst = 0; + // sie, T + memcpy(dst + offst, sie_.data(), sie_.sizeBytes()); + offst += sie_.sizeBytes(); + memcpy(dst + offst, T_.data(), T_.sizeBytes()); + offst += T_.sizeBytes(); + // dependsRhoT, dependsRhoSie + offst += STricks::DumpDynamicMemory(dst + offst, &dependsRhoT_); + offst += STricks::DumpDynamicMemory(dst + offst, &dependsRhoSie_); + // maxima + memcpy(dst + offst, PlRhoMax_.data(), PlRhoMax_.sizeBytes()); + offst += PlRhoMax_.sizeBytes(); + memcpy(dst + offst, dPdRhoMax_.data(), dPdRhoMax_.sizeBytes()); + offst += dPdRhoMax_.sizeBytes(); + PORTABLE_REQUIRE(offst == DynamicMemorySizeInBytes(), "all dynamic memory covered"); + return offst; +} + +inline std::size_t SpinerEOSDependsRhoSie::SetDynamicMemory(char *src, bool node_root) { + std::size_t offst = 0; + // sie, T + offst += sie_.setPointer(src + offst); + offst += T_.setPointer(src + offst); + // dependsRhoT, dependsRhoSie + offst += STricks::SetDynamicMemory(src + offst, &dependsRhoT_); + offst += STricks::SetDynamicMemory(src + offst, &dependsRhoSie_); + // maxima + offst += PlRhoMax_.setPointer(src + offst); + offst += dPdRhoMax_.setPointer(src + offst); + memoryStatus_ = DataStatus::UnManaged; + PORTABLE_REQUIRE(offst == DynamicMemorySizeInBytes(), "all dynamic memory covered"); + return offst; } template diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index e5a0368144..8a62f362dc 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -228,7 +228,7 @@ class StellarCollapse : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src); + std::size_t SetDynamicMemory(char *src, bool node_root = true); private: class LogT { @@ -484,7 +484,7 @@ inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) const { return table_utils::SpinerTricks::DumpDynamicMemory(dst, this); } -inline std::size_t StellarCollapse::SetDynamicMemory(char *src) { +inline std::size_t StellarCollapse::SetDynamicMemory(char *src, bool node_root) { return table_utils::SpinerTricks::SetDynamicMemory(src, this); } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index cef8d8e10a..14a7a9a9f0 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1030,8 +1030,10 @@ class Variant { return mpark::visit([dst](const auto &eos) { return eos.DumpDynamicMemory(dst); }, eos_); } - std::size_t SetDynamicMemory(char *src) { - return mpark::visit([src](auto &eos) { return eos.SetDynamicMemory(src); }, eos_); + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return mpark::visit( + [src, node_root](auto &eos) { return eos.SetDynamicMemory(src, node_root); }, + eos_); } std::size_t SerializedSizeInBytes() const { return sizeof(*this) + DynamicMemorySizeInBytes(); @@ -1050,11 +1052,11 @@ class Variant { Serialize(dst); return std::make_pair(size, dst); } - std::size_t DeSerialize(char *src) { + std::size_t DeSerialize(char *src, bool node_root = true) { memcpy(this, src, sizeof(*this)); std::size_t offst = sizeof(*this); if (DynamicMemorySizeInBytes() > 0) { - offst += SetDynamicMemory(src + sizeof(*this)); + offst += SetDynamicMemory(src + sizeof(*this), node_root); } return offst; } diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index a9fb296e8b..1f1054ebf3 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -430,7 +430,9 @@ class UnitSystem : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return t_.SetDynamicMemory(src, node_root); + } private: T t_; diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index 4895029d98..050d55ad9b 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -457,7 +457,9 @@ class BilinearRampEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return t_.SetDynamicMemory(src, node_root); + } private: T t_; diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index 87a965c8ea..f53b99aca9 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -187,7 +187,9 @@ class RelativisticEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return t_.SetDynamicMemory(src, node_root); + } private: T t_; diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 3487a7a6bd..1210f0f0c7 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -347,7 +347,9 @@ class ScaledEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return t_.SetDynamicMemory(src, node_root); + } private: T t_; diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 07de42b3d0..26e298f37f 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -357,7 +357,9 @@ class ShiftedEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src) { return t_.SetDynamicMemory(src); } + std::size_t SetDynamicMemory(char *src, bool node_root = true) { + return t_.SetDynamicMemory(src, node_root); + } private: T t_; From 93f302ca3ea6ec54cee3117e418d671a2ed954ed Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Thu, 22 Aug 2024 09:43:46 -0600 Subject: [PATCH 19/48] Redesign with shared mem settings in plac --- singularity-eos/base/constants.hpp | 10 ++++++++++ singularity-eos/eos/eos_base.hpp | 17 +++++++++++++---- singularity-eos/eos/eos_eospac.hpp | 19 ++++++++++--------- singularity-eos/eos/eos_helmholtz.hpp | 9 ++++++--- singularity-eos/eos/eos_spiner.hpp | 15 ++++++++++----- singularity-eos/eos/eos_stellar_collapse.hpp | 7 +++++-- singularity-eos/eos/eos_variant.hpp | 18 ++++++++++++------ .../eos/modifiers/eos_unitsystem.hpp | 5 +++-- singularity-eos/eos/modifiers/ramps_eos.hpp | 5 +++-- .../eos/modifiers/relativistic_eos.hpp | 5 +++-- singularity-eos/eos/modifiers/scaled_eos.hpp | 5 +++-- singularity-eos/eos/modifiers/shifted_eos.hpp | 5 +++-- 12 files changed, 81 insertions(+), 39 deletions(-) diff --git a/singularity-eos/base/constants.hpp b/singularity-eos/base/constants.hpp index 48a458a7af..30e43808e9 100644 --- a/singularity-eos/base/constants.hpp +++ b/singularity-eos/base/constants.hpp @@ -37,6 +37,16 @@ enum class TableStatus { OnTable = 0, OffBottom = 1, OffTop = 2 }; constexpr Real ROOM_TEMPERATURE = 293; // K constexpr Real ATMOSPHERIC_PRESSURE = 1e6; +struct SharedMemSettings { + SharedMemSettings() = default; + SharedMemSettings(char *data_, bool is_root_node_) + : data(data_), is_root_node(is_root_node_) {} + bool CopyNeeded() const { return (data != nullptr) && is_root_node; } + char *data = nullptr; + bool is_root_node = false; // default true or false? +}; +const SharedMemSettings DEFAULT_SHMEM_STNGS = SharedMemSettings(); + } // namespace singularity #endif // SINGULARITY_EOS_BASE_CONSTANTS_HPP_ diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 76055e8507..e9df4a8bc2 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -20,6 +20,7 @@ #include #include +#include #include namespace singularity { @@ -654,7 +655,10 @@ class EosBase { // JMM: These must be special-cased. std::size_t DynamicMemorySizeInBytes() const { return 0; } std::size_t DumpDynamicMemory(char *dst) const { return 0; } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { return 0; } + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return 0; + } // JMM: These are generic and do not need to be special-cased. // TODO(JMM): Should this machinery actually be available for "bare" // EOS's outside the variant? @@ -688,13 +692,18 @@ class EosBase { PORTABLE_REQUIRE(size_new == size, "Serialization succesful"); return std::make_pair(size, dst); } - std::size_t DeSerialize(char *src, bool node_root = true) { + std::size_t DeSerialize(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { CRTP *pcrtp = static_cast(this); std::size_t offst = 0; memcpy(pcrtp, src, sizeof(CRTP)); offst += sizeof(CRTP); - if (pcrtp->DynamicMemorySizeInBytes() > 0) { - offst += pcrtp->SetDynamicMemory(src + sizeof(CRTP), node_root); + std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); + if (dyn_size > 0) { + if (stngs.CopyNeeded()) { + memcpy(stngs.data, src + offst, dyn_size); + } + offst += pcrtp->SetDynamicMemory(src + offst, stngs); } PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Deserialization succesful"); return offst; diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 7ac29d0f9c..8610503225 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -147,7 +147,8 @@ class EOSPAC : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src, bool node_root = true); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); SG_PIF_NOWARN template @@ -1233,6 +1234,7 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, } std::size_t EOSPAC::DynamicMemorySizeInBytes() const { + printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG // JMM: We need both of these because EOSPAC allows the size in // shared memory to differ from the size required to reconstruct // an object. This is generically true for spiner too, but we just @@ -1250,19 +1252,18 @@ std::size_t EOSPAC::DumpDynamicMemory(char *dst) const { return DynamicMemorySizeInBytes(); } -std::size_t EOSPAC::SetDynamicMemory(char *src, bool node_root) { +std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; #ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY - // Because EOSPAC uses BOTH packed and shared pointers, reads from - // one, and writes to the other, we need to do an additional - // internal memcopy - std::vector packed_data(packed_size); - memcpy(packed_data.data(), src, packed_size); + PORTABLE_ALWAYS_REQUIRE( + stngs.data != nullptr, + "EOSPAC with shared memory active requires a shared memory pointer"); // JMM: EOS_BOOLEAN is an enum with EOS_FALSE=0 and EOS_TRUE=1. - eos_SetSharedPackedTables(NTABLES, &packed_size, packed_data.data(), (EOS_CHAR *)src, - node_root, tablehandle, &error_code); + eos_SetSharedPackedTables(NTABLES, &packed_size, (EOS_CHAR *)src, + (EOS_CHAR *)stngs.data, stngs.is_node_root, tablehandle, + &error_code); #else eos_SetPackedTables(NTABLES, &packed_size, (EOS_CHAR *)src, tablehandle, &error_code); #endif // SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 2451a8c7ae..acea25d750 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -233,8 +233,10 @@ class HelmElectrons { std::size_t DumpDynamicMemory(char *dst) const { return SpinerTricks::DumpDynamicMemory(dst, this); } - std::size_t SetDynamicMemory(char *src) { - return SpinerTricks::SetDynamicMemory(src, this); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return SpinerTricks::SetDynamicMemory((stngs.data == nullptr) ? src : stngs.data, + this); } PORTABLE_INLINE_FUNCTION @@ -491,7 +493,8 @@ class Helmholtz : public EosBase { std::size_t DumpDynamicMemory(char *dst) const { return electrons_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return electrons_.SetDynamicMemory(src); } diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 0ee4dac16b..e41cdf20e7 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -106,7 +106,8 @@ class SpinerEOSDependsRhoT : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src, bool node_root = true); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( @@ -377,7 +378,8 @@ class SpinerEOSDependsRhoSie : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src, bool node_root = true); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( @@ -682,8 +684,9 @@ inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) const { return SpinerTricks::DumpDynamicMemory(dst, this); } -inline std::size_t SpinerEOSDependsRhoT::SetDynamicMemory(char *src, bool node_root) { - return SpinerTricks::SetDynamicMemory(src, this); +inline std::size_t +SpinerEOSDependsRhoT::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { + return SpinerTricks::SetDynamicMemory((stngs.data == nullptr) ? src : stngs.data, this); } inline herr_t SpinerEOSDependsRhoT::loadDataboxes_(const std::string &matid_str, @@ -1673,7 +1676,9 @@ inline std::size_t SpinerEOSDependsRhoSie::DumpDynamicMemory(char *dst) const { return offst; } -inline std::size_t SpinerEOSDependsRhoSie::SetDynamicMemory(char *src, bool node_root) { +inline std::size_t +SpinerEOSDependsRhoSie::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { + if (stngs.data != nullptr) src = stngs.data; std::size_t offst = 0; // sie, T offst += sie_.setPointer(src + offst); diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index 8a62f362dc..a2878935e7 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -228,7 +228,8 @@ class StellarCollapse : public EosBase { std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; - std::size_t SetDynamicMemory(char *src, bool node_root = true); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); private: class LogT { @@ -484,7 +485,9 @@ inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) const { return table_utils::SpinerTricks::DumpDynamicMemory(dst, this); } -inline std::size_t StellarCollapse::SetDynamicMemory(char *src, bool node_root) { +inline std::size_t StellarCollapse::SetDynamicMemory(char *src, + const SharedMemSettings &stngs) { + if (stngs.data != nullptr) src = stngs.data; return table_utils::SpinerTricks::SetDynamicMemory(src, this); } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 14a7a9a9f0..5b50327850 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1030,10 +1031,10 @@ class Variant { return mpark::visit([dst](const auto &eos) { return eos.DumpDynamicMemory(dst); }, eos_); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return mpark::visit( - [src, node_root](auto &eos) { return eos.SetDynamicMemory(src, node_root); }, - eos_); + [src, stngs](auto &eos) { return eos.SetDynamicMemory(src, stngs); }, eos_); } std::size_t SerializedSizeInBytes() const { return sizeof(*this) + DynamicMemorySizeInBytes(); @@ -1052,11 +1053,16 @@ class Variant { Serialize(dst); return std::make_pair(size, dst); } - std::size_t DeSerialize(char *src, bool node_root = true) { + std::size_t DeSerialize(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { memcpy(this, src, sizeof(*this)); std::size_t offst = sizeof(*this); - if (DynamicMemorySizeInBytes() > 0) { - offst += SetDynamicMemory(src + sizeof(*this), node_root); + std::size_t dyn_size = DynamicMemorySizeInBytes(); + if (dyn_size > 0) { + if (stngs.CopyNeeded()) { + memcpy(stngs.data, src + offst, dyn_size); + } + offst += SetDynamicMemory(src + offst, stngs); } return offst; } diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index 1f1054ebf3..b16618d570 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -430,8 +430,9 @@ class UnitSystem : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { - return t_.SetDynamicMemory(src, node_root); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return t_.SetDynamicMemory(src, stngs); } private: diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index 050d55ad9b..e1c77594da 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -457,8 +457,9 @@ class BilinearRampEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { - return t_.SetDynamicMemory(src, node_root); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return t_.SetDynamicMemory(src, stngs); } private: diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index f53b99aca9..cf33db1018 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -187,8 +187,9 @@ class RelativisticEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { - return t_.SetDynamicMemory(src, node_root); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return t_.SetDynamicMemory(src, stngs); } private: diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 1210f0f0c7..f4f60a885c 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -347,8 +347,9 @@ class ScaledEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { - return t_.SetDynamicMemory(src, node_root); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return t_.SetDynamicMemory(src, stngs); } private: diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 26e298f37f..6d313175ab 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -357,8 +357,9 @@ class ShiftedEOS : public EosBase> { std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, bool node_root = true) { - return t_.SetDynamicMemory(src, node_root); + std::size_t SetDynamicMemory(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + return t_.SetDynamicMemory(src, stngs); } private: From 1fbf4481d245f1206301aef8235ec864149a9264 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Thu, 22 Aug 2024 16:57:14 -0600 Subject: [PATCH 20/48] completed testing shared memory routines for stellar collapse --- singularity-eos/eos/eos_base.hpp | 6 +- singularity-eos/eos/eos_eospac.hpp | 12 ++-- singularity-eos/eos/eos_variant.hpp | 6 +- .../eos/modifiers/eos_unitsystem.hpp | 1 + singularity-eos/eos/modifiers/ramps_eos.hpp | 1 + .../eos/modifiers/relativistic_eos.hpp | 1 + singularity-eos/eos/modifiers/scaled_eos.hpp | 1 + singularity-eos/eos/modifiers/shifted_eos.hpp | 1 + test/test_eos_stellar_collapse.cpp | 68 ++++++++++++++++++- 9 files changed, 89 insertions(+), 8 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index e9df4a8bc2..8e3124d430 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -659,6 +659,7 @@ class EosBase { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return 0; } + constexpr bool StaticMemoryIsThis() const { return true; } // JMM: These are generic and do not need to be special-cased. // TODO(JMM): Should this machinery actually be available for "bare" // EOS's outside the variant? @@ -682,7 +683,7 @@ class EosBase { if (dyn_size > 0) { offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization succesful"); + PORTABLE_REQUIRE((offst == SerializedSizeInBytes()), "Serialization succesful"); return offst; } auto Serialize() const { @@ -700,7 +701,8 @@ class EosBase { offst += sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); if (dyn_size > 0) { - if (stngs.CopyNeeded()) { + const bool sizes_same = pcrtp->StaticMemoryIsThis(); + if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); } offst += pcrtp->SetDynamicMemory(src + offst, stngs); diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 8610503225..53e6a6aaab 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -145,10 +145,12 @@ class EOSPAC : public EosBase { } inline EOSPAC GetOnDevice() { return *this; } + std::size_t SerializedSizeInBytes() const; // shadow/overload base class std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst) const; std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); + constexpr bool StaticMemoryIsThis() const { return false; } SG_PIF_NOWARN template @@ -1233,23 +1235,24 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, robust::ratio(dpde_ref_ * cv_ref_, rho_ref_ * rho_ref_ * pressureFromSesame(DPDR)); } -std::size_t EOSPAC::DynamicMemorySizeInBytes() const { +// shadow/overload base class +std::size_t EOSPAC::SerializedSizeInBytes() const { printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG // JMM: We need both of these because EOSPAC allows the size in // shared memory to differ from the size required to reconstruct // an object. This is generically true for spiner too, but we just // deliberately waste a little space. - return std::max(shared_size_, packed_size_); + return sizeof(this) + std::max(shared_size_, packed_size_); } +std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return shared_size_; } std::size_t EOSPAC::DumpDynamicMemory(char *dst) const { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; - // TODO(JMM): Is casting to EOS_CHAR* safe here? I really hope so. eos_GetPackedTables(NTABLES, tablehandle, (EOS_CHAR *)dst, &error_code); eosCheckError(error_code, "eos_GetPackedTables", Verbosity::Debug); - return DynamicMemorySizeInBytes(); + return packed_size_; // JMM: Note this is NOT shared memory size } std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { @@ -1275,6 +1278,7 @@ std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) TofRP_table_ = tablehandle[4]; PofRE_table_ = tablehandle[5]; EcofD_table_ = tablehandle[6]; + return std::max(shared_size_, packed_size_); } SG_PIF_NOWARN diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 5b50327850..0f4fae3d42 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1039,6 +1039,9 @@ class Variant { std::size_t SerializedSizeInBytes() const { return sizeof(*this) + DynamicMemorySizeInBytes(); } + constexpr std::size_t StaticMemoryIsThis() const { + return mpark::visit([](auto &eos) { return eos.StaticMemoryIsThis(); }, eos_); + } std::size_t Serialize(char *dst) const { memcpy(dst, this, sizeof(*this)); std::size_t offst = sizeof(*this); @@ -1059,7 +1062,8 @@ class Variant { std::size_t offst = sizeof(*this); std::size_t dyn_size = DynamicMemorySizeInBytes(); if (dyn_size > 0) { - if (stngs.CopyNeeded()) { + const bool sizes_same = StaticMemoryIsThis(); + if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); } offst += SetDynamicMemory(src + offst, stngs); diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index b16618d570..1f3284a3aa 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -434,6 +434,7 @@ class UnitSystem : public EosBase> { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); } + constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } private: T t_; diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index e1c77594da..ef8f4b672c 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -461,6 +461,7 @@ class BilinearRampEOS : public EosBase> { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); } + constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } private: T t_; diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index cf33db1018..f9ff8edcc5 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -191,6 +191,7 @@ class RelativisticEOS : public EosBase> { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); } + constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } private: T t_; diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index f4f60a885c..6aae804890 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -351,6 +351,7 @@ class ScaledEOS : public EosBase> { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); } + constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } private: T t_; diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 6d313175ab..e55cb47e7b 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -361,6 +361,7 @@ class ShiftedEOS : public EosBase> { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); } + constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } private: T t_; diff --git a/test/test_eos_stellar_collapse.cpp b/test/test_eos_stellar_collapse.cpp index 4eb4930db9..148e5e8c8d 100644 --- a/test/test_eos_stellar_collapse.cpp +++ b/test/test_eos_stellar_collapse.cpp @@ -321,6 +321,43 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { REQUIRE(Tricks::DataBoxesPointToSameMemory(sc2, sc3)); } } + THEN("We can de-serialize it into a new object AROUND a new allocation") { + using singularity::SharedMemSettings; + // mockup of shared data + char *shared_data = (char *)malloc(size); + SharedMemSettings settings(shared_data, true); + StellarCollapse sc3; + std::size_t read_size = sc3.DeSerialize(data, settings); + REQUIRE(read_size == size); + REQUIRE(read_size > sizeof(StellarCollapse)); + sc3.CheckParams(); + AND_THEN("The new eos uses different memory than the original") { + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc, sc3)); + } + AND_THEN( + "The new eos uses different memory than the one de-serialized aorund " + "the non-shared memory") { + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc2, sc3)); + } + AND_THEN("The two stellar collapse EOS's agree") { + CompareStellarCollapse(sc, sc3); + } + AND_THEN("We can de-serialize from shared memory around one more object") { + SharedMemSettings settings2(shared_data, false); + StellarCollapse sc4; + std::size_t read_size_2 = sc4.DeSerialize(data, settings); + REQUIRE(read_size_2 == size); + REQUIRE(read_size_2 > sizeof(StellarCollapse)); + sc4.CheckParams(); + AND_THEN("The two shared-mem objects use the same memory") { + REQUIRE(Tricks::DataBoxesPointToSameMemory(sc3, sc4)); + } + AND_THEN("The two stellar collapse EOS's agree") { + CompareStellarCollapse(sc, sc4); + } + } + free(shared_data); + } } free(data); } @@ -341,10 +378,39 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { CompareStellarCollapse(sc, sc2); REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc, sc2)); } + AND_THEN("We can de-serialize it twice into shared memory") { + using singularity::SharedMemSettings; + + std::size_t dyn_size = e1.DynamicMemorySizeInBytes(); + char *shared_data = (char *)malloc(dyn_size); + EOS e3, e4; + + std::size_t read_size_e3 = + e3.DeSerialize(data, SharedMemSettings(shared_data, true)); + REQUIRE(read_size_e3 == size); + e3.CheckParams(); + + std::size_t read_size_e4 = + e4.DeSerialize(data, SharedMemSettings(shared_data, false)); + REQUIRE(read_size_e4 == size); + e4.CheckParams(); + + AND_THEN("They all agree") { + StellarCollapse sc2 = e2.get(); + StellarCollapse sc3 = e3.get(); + StellarCollapse sc4 = e4.get(); + CompareStellarCollapse(sc, sc3); + CompareStellarCollapse(sc, sc4); + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc, sc3)); + REQUIRE(Tricks::DataBoxesPointToDifferentMemory(sc2, sc3)); + REQUIRE(Tricks::DataBoxesPointToSameMemory(sc3, sc4)); + } + + free(shared_data); + } } free(data); } - sc.Finalize(); } } From 0e302d8abafe41fd66e706dec18732bf204dc449 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 10:37:12 -0600 Subject: [PATCH 21/48] change spinereosdependsrhosie to work like dependsrhot --- singularity-eos/eos/eos_spiner.hpp | 89 +++++++----------------------- 1 file changed, 20 insertions(+), 69 deletions(-) diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index e41cdf20e7..982bda1f69 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -339,24 +339,15 @@ class SpinerEOSDependsRhoT : public EosBase { mitigated by Ye and (1-Ye) to control how important each term is. */ class SpinerEOSDependsRhoSie : public EosBase { + friend class table_utils::SpinerTricks; + public: using Grid_t = SpinerEOSDependsRhoT::Grid_t; using DataBox = SpinerEOSDependsRhoT::DataBox; struct SP5Tables { DataBox P, bMod, dPdRho, dPdE, dTdRho, dTdE, dEdRho; - -#define DBLIST &P, &bMod, &dPdRho, &dPdE, &dTdRho, &dTdE, &dEdRho - std::vector GetDataBoxPointers_() const { - return std::vector{DBLIST}; - } - std::vector GetDataBoxPointers_() { - return std::vector{DBLIST}; - } -#undef DBLIST - DataStatus memoryStatus_ = DataStatus::Deallocated; - ; }; - using STricks = table_utils::SpinerTricks; + using STricks = table_utils::SpinerTricks; SG_ADD_BASE_CLASS_USINGS(SpinerEOSDependsRhoSie); PORTABLE_INLINE_FUNCTION SpinerEOSDependsRhoSie() @@ -531,6 +522,18 @@ class SpinerEOSDependsRhoSie : public EosBase { Real lRhoOffset_, lTOffset_, lEOffset_; // offsets must be non-negative +#define DBLIST \ + &sie_, &T_, &(dependsRhoT_.P), &(dependsRhoT_.bMod), &(dependsRhoT_.dPdRho), \ + &(dependsRhoT_.dPdE), &(dependsRhoT_.dTdRho), &(dependsRhoT_.dTdE), \ + &(dependsRhoT_.dEdRho), &(dependsRhoSie_.P), &(dependsRhoSie_.bMod), \ + &(dependsRhoSie_.dPdRho), &(dependsRhoSie_.dPdE), &(dependsRhoSie_.dTdRho), \ + &(dependsRhoSie_.dTdE), &(dependsRhoSie_.dEdRho), &PlRhoMax_, &dPdRhoMax_ + std::vector GetDataBoxPointers_() const { + return std::vector{DBLIST}; + } + std::vector GetDataBoxPointers_() { return std::vector{DBLIST}; } +#undef DBLIST + static constexpr unsigned long _preferred_input = thermalqs::density | thermalqs::temperature; // static constexpr const char _eos_type[] = "SpinerEOSDependsRhoSie"; @@ -1623,75 +1626,23 @@ inline void SpinerEOSDependsRhoSie::calcBMod_(SP5Tables &tables) { } inline SpinerEOSDependsRhoSie SpinerEOSDependsRhoSie::GetOnDevice() { - SpinerEOSDependsRhoSie other = *this; // static memory - // dynamic memory - other.sie_ = sie_.getOnDevice(); - other.T_ = T_.getOnDevice(); - other.PlRhoMax_ = PlRhoMax_.getOnDevice(); - other.dPdRhoMax_ = dPdRhoMax_.getOnDevice(); - other.dependsRhoT_ = STricks::GetOnDevice(&dependsRhoT_); - other.dependsRhoSie_ = STricks::GetOnDevice(&dependsRhoSie_); - // memory status - other.memoryStatus_ = DataStatus::OnDevice; - return other; + return STricks::GetOnDevice(this); } -void SpinerEOSDependsRhoSie::Finalize() { - if (memoryStatus_ != DataStatus::UnManaged) { - sie_.finalize(); - T_.finalize(); - STricks::Finalize(&dependsRhoT_); - STricks::Finalize(&dependsRhoSie_); - if (memoryStatus_ == DataStatus::OnDevice) { // these are slices on host - PlRhoMax_.finalize(); - dPdRhoMax_.finalize(); - } - memoryStatus_ = DataStatus::Deallocated; - } -} +void SpinerEOSDependsRhoSie::Finalize() { STricks::Finalize(this); } inline std::size_t SpinerEOSDependsRhoSie::DynamicMemorySizeInBytes() const { - return (sie_.sizeBytes() + T_.sizeBytes() + - STricks::DynamicMemorySizeInBytes(&dependsRhoT_) + - STricks::DynamicMemorySizeInBytes(&dependsRhoSie_) + PlRhoMax_.sizeBytes() + - dPdRhoMax_.sizeBytes()); + return STricks::DynamicMemorySizeInBytes(this); } inline std::size_t SpinerEOSDependsRhoSie::DumpDynamicMemory(char *dst) const { - std::size_t offst = 0; - // sie, T - memcpy(dst + offst, sie_.data(), sie_.sizeBytes()); - offst += sie_.sizeBytes(); - memcpy(dst + offst, T_.data(), T_.sizeBytes()); - offst += T_.sizeBytes(); - // dependsRhoT, dependsRhoSie - offst += STricks::DumpDynamicMemory(dst + offst, &dependsRhoT_); - offst += STricks::DumpDynamicMemory(dst + offst, &dependsRhoSie_); - // maxima - memcpy(dst + offst, PlRhoMax_.data(), PlRhoMax_.sizeBytes()); - offst += PlRhoMax_.sizeBytes(); - memcpy(dst + offst, dPdRhoMax_.data(), dPdRhoMax_.sizeBytes()); - offst += dPdRhoMax_.sizeBytes(); - PORTABLE_REQUIRE(offst == DynamicMemorySizeInBytes(), "all dynamic memory covered"); - return offst; + return STricks::DumpDynamicMemory(dst, this); } inline std::size_t SpinerEOSDependsRhoSie::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { if (stngs.data != nullptr) src = stngs.data; - std::size_t offst = 0; - // sie, T - offst += sie_.setPointer(src + offst); - offst += T_.setPointer(src + offst); - // dependsRhoT, dependsRhoSie - offst += STricks::SetDynamicMemory(src + offst, &dependsRhoT_); - offst += STricks::SetDynamicMemory(src + offst, &dependsRhoSie_); - // maxima - offst += PlRhoMax_.setPointer(src + offst); - offst += dPdRhoMax_.setPointer(src + offst); - memoryStatus_ = DataStatus::UnManaged; - PORTABLE_REQUIRE(offst == DynamicMemorySizeInBytes(), "all dynamic memory covered"); - return offst; + return STricks::SetDynamicMemory(src, this); } template From 528294c4e037290c69866b72827d1395acc8bc7c Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 10:37:24 -0600 Subject: [PATCH 22/48] add test for tabulated EOS... now to make sure it works --- test/test_eos_tabulated.cpp | 103 ++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/test/test_eos_tabulated.cpp b/test/test_eos_tabulated.cpp index f80d373d0a..40147663c6 100644 --- a/test/test_eos_tabulated.cpp +++ b/test/test_eos_tabulated.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ #include #ifdef SPINER_USE_HDF +#include using singularity::SpinerEOSDependsRhoSie; using singularity::SpinerEOSDependsRhoT; #endif @@ -62,7 +64,7 @@ constexpr Real ev2k = 1.160451812e4; #ifdef SINGULARITY_USE_EOSPAC using EOS = singularity::Variant; -SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS],[DependsRhoT][EOSPAC]") { +SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS][DependsRhoT][EOSPAC]") { GIVEN("SpinerEOS and EOSPAC EOS for steel can be initialized with matid") { EOS steelEOS_host_polymorphic = SpinerEOSDependsRhoT(eosName, steelID); @@ -124,6 +126,7 @@ SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS],[DependsRhoT][EOSPAC]") steelEOS_host_polymorphic.Finalize(); // host and device must be // finalized separately. steelEOS.Finalize(); // cleans up memory on device. + eospac.Finalize(); } GIVEN("SpinerEOS and EOSPAC for air can be initialized with matid") { @@ -179,6 +182,7 @@ SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS],[DependsRhoT][EOSPAC]") } airEOS_host.Finalize(); airEOS.Finalize(); + eospac.Finalize(); } GIVEN("EOS initialized with matid") { @@ -199,6 +203,7 @@ SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS],[DependsRhoT][EOSPAC]") REQUIRE(isClose(cv, cv_pac)); } eos_spiner.Finalize(); + eos_eospac.Finalize(); } GIVEN("EOS initialized with matid") { @@ -216,11 +221,11 @@ SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS],[DependsRhoT][EOSPAC]") REQUIRE(isClose(rho, rho_pac)); } eos_spiner.Finalize(); + eos_eospac.FInalize(); } } -// Disabling these tests for now as the DependsRhoSie code is not well-maintained -SCENARIO("SpinerEOS depends on rho and sie", "[SpinerEOS],[DependsRhoSie]") { +SCENARIO("SpinerEOS depends on rho and sie", "[SpinerEOS][DependsRhoSie]") { GIVEN("SpinerEOSes for steel can be initialised with matid") { SpinerEOSDependsRhoSie steelEOS_host(eosName, steelID); @@ -257,6 +262,98 @@ SCENARIO("SpinerEOS depends on rho and sie", "[SpinerEOS],[DependsRhoSie]") { steelEOS.Finalize(); // cleans up device memory } } + +SCENARIO("SpinerEOS and EOSPA Serialization", + "[SpinerEOS][DependsRhoT][DependsRhoSie][EOSPAC][Serialization]") { + GIVEN("Eoses initialized with matid") { + SpinerEOSDependsRhoT rhoT_orig = SpinerEOSDependsRhoT(eosName, steelID); + SpinerEOSDependsRhoSie rhoSie_orig = SpinerEOSDependsRhoSie(eosName, steelID); + EOS eospac_orig = EOSPAC(steelID); + THEN("They report dynamic vs static memory correctly") { + REQUIRE(rhoT_orig.StaticMemoryIsThis()); + REQUIRE(rhoSie_orig.StaticMemoryIsThis()); + REQUIRE(!eospac_orig.StaticMemoryIsThis()); + REQUIRE(eospac_orig.SerializedSizeInBytes() > + eospac_orig.DynamicMemorySizeInBytes()); + } + WHEN("We serialize") { + auto [rhoT_size, rhotT_data] = rhoT_orig.Serialize(); + REQUIRE(rhoT_size == rhoT_orig.SerializedSizeInBytes()); + + auto [rhoSie_size, rhoSie_data] = rhoSie_orig.Serialize(); + REQUIRE(rhoSie_size == rhoSie_orig.SerializedSizeInBytes()); + + auto [eospac_size, eospac_data] = eospac_orig.Serialize(); + REQUIRE(eospac_size == eospac_orig.SerializedSizeInBytes()); + + const std::size_t rhoT_shared_size = rhoT_orig.DynamicMemorySizeInBytes(); + REQUIRE(rhoT_size > rhoT_shared_size); + + const std::size_t rhoSie_shared_size = rhoSie_orig.DynamicMemorySizeInBytes(); + REQUIRE(rhoSie_size > rhoSie_shared_size); + + const std::size_t eospac_shared_size = eospac_orig.DynamicMemorySizeInBytes(); + REQUIRE(eospac_size > eospac_shared_size); + + eospac_orig.Finalize(); + THEN("We can deserialize into shared memory") { + using singularity::SharedMemSettings; + using RhoTTricks = singularity::table_utils::SpinerTricks; + using RhoSieTricks = + singularity::table_utils::SpinerTricks; + + rhoT_shared_data = (char *)malloc(rhoT_shared_size); + rhoSie_shared_data = (char *)malloc(rhoSie_shared_size); + eospac_shared_data = (char *)malloc(eospac_shared_size); + + SpinerEOSDependsRhoT eos_rhoT; + std::size_t read_size_rhoT = + eos_rhoT.DeSerialize(rhoT_data, SharedMemSettings(rhoT_shared_data, true)); + REQUIRE(read_size_rhoT == rhoT_size); + REQUIRE(RhoTTricks::DataBoxesPointToDifferentMemory(rhoT_orig, eos_rhoT)); + + SpinerEOSDependsRhoSie eos_rhoSie; + std::size_t read_size_rhoSie = eos_rhoSie.DeSerialize( + rhoSie_data, SharedMemSettings(rhoSie_shared_data, true)); + REQUIRE(read_size_rhoSie == rhoSie_size); + REQUIRE(RhoSieTricks::DataBoxesPointToDifferentMemory(rhoSie_orig, eos_rhoSie)); + + EOS eos_eospac = EOSPAC(); + std::size_t read_size_eospac = eos_rhoSie.DeSerialize( + rhoSie_data, SharedMemSettings(rhoSie_shared_data, true)); + REQUIRE(read_size_eospac = eospac_size); + + AND_THEN("EOS lookups work") { + constexpr Real rho_trial = 1; + constexpr Real sie_trial = 1e12; + const Real P_eospac = + eos_eospac.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + const Real P_spiner_orig = + rhoT_orig.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + const Real P_spiner_rhoT = + eos_rhoT.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + const Real P_spiner_rhoSie = + eos_rhoSie.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + REQUIRE(isClose(P_eospac, P_spiner_orig)); + REQUIRE(isClose(P_eospac, P_spiner_rhoT)); + REQUIRE(isClose(P_eospac, P_spiner_rhoSie)); + } + + eos_eospac.Finalize(); + free(rhoT_shared_data); + free(rhoSie_shared_data); + free(eospac_shared_data); + } + free(rhoT_data); + free(rhoSie_data); + free(eospac_data) + } + + rhoT_orig.Finalize(); + rhoSie_orig.Finalize(); + } +} + #endif // SINGULARITY_USE_EOSPAC #endif // SINGULARITY_TEST_SESAME #endif // SPINER_USE_HDF From 27745331db81c7c2253d49b9391318fdf5cd025f Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 15:22:28 -0600 Subject: [PATCH 23/48] the code finally compiles on darwin --- singularity-eos/eos/eos_base.hpp | 10 ++++----- singularity-eos/eos/eos_eospac.hpp | 14 ++++++------ singularity-eos/eos/eos_helmholtz.hpp | 4 ++-- singularity-eos/eos/eos_spiner.hpp | 8 +++---- singularity-eos/eos/eos_stellar_collapse.hpp | 4 ++-- singularity-eos/eos/eos_variant.hpp | 10 ++++----- singularity-eos/eos/eos_vinet.hpp | 2 +- .../eos/modifiers/eos_unitsystem.hpp | 2 +- singularity-eos/eos/modifiers/ramps_eos.hpp | 2 +- .../eos/modifiers/relativistic_eos.hpp | 2 +- singularity-eos/eos/modifiers/scaled_eos.hpp | 2 +- singularity-eos/eos/modifiers/shifted_eos.hpp | 2 +- test/test_eos_tabulated.cpp | 22 +++++++++---------- 13 files changed, 42 insertions(+), 42 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 8e3124d430..6f65c5c8c7 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -654,7 +654,7 @@ class EosBase { // Serialization // JMM: These must be special-cased. std::size_t DynamicMemorySizeInBytes() const { return 0; } - std::size_t DumpDynamicMemory(char *dst) const { return 0; } + std::size_t DumpDynamicMemory(char *dst) { return 0; } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return 0; @@ -674,8 +674,8 @@ class EosBase { std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); return dyn_size + sizeof(CRTP); } - std::size_t Serialize(char *dst) const { - const CRTP *pcrtp = static_cast(this); + std::size_t Serialize(char *dst) { + CRTP *pcrtp = static_cast(this); std::size_t offst = 0; memcpy(dst, pcrtp, sizeof(CRTP)); offst += sizeof(CRTP); @@ -686,7 +686,7 @@ class EosBase { PORTABLE_REQUIRE((offst == SerializedSizeInBytes()), "Serialization succesful"); return offst; } - auto Serialize() const { + auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t size_new = Serialize(dst); @@ -718,7 +718,7 @@ class EosBase { inline constexpr decltype(auto) GetUnmodifiedObject() { if constexpr (CRTP::IsModified()) { - return static_cast(this)->UnmodifyOnce().GetUnmodifiedObject(); + return ((static_cast(this))->UnmodifyOnce()).GetUnmodifiedObject(); } else { return *static_cast(this); } diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 53e6a6aaab..6bbc53e98e 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -147,7 +147,7 @@ class EOSPAC : public EosBase { std::size_t SerializedSizeInBytes() const; // shadow/overload base class std::size_t DynamicMemorySizeInBytes() const; - std::size_t DumpDynamicMemory(char *dst) const; + std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); constexpr bool StaticMemoryIsThis() const { return false; } @@ -1236,7 +1236,7 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, } // shadow/overload base class -std::size_t EOSPAC::SerializedSizeInBytes() const { +inline std::size_t EOSPAC::SerializedSizeInBytes() const { printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG // JMM: We need both of these because EOSPAC allows the size in // shared memory to differ from the size required to reconstruct @@ -1244,9 +1244,9 @@ std::size_t EOSPAC::SerializedSizeInBytes() const { // deliberately waste a little space. return sizeof(this) + std::max(shared_size_, packed_size_); } -std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return shared_size_; } +inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return shared_size_; } -std::size_t EOSPAC::DumpDynamicMemory(char *dst) const { +inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; @@ -1255,7 +1255,7 @@ std::size_t EOSPAC::DumpDynamicMemory(char *dst) const { return packed_size_; // JMM: Note this is NOT shared memory size } -std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { +inline std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; @@ -1264,11 +1264,11 @@ std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) stngs.data != nullptr, "EOSPAC with shared memory active requires a shared memory pointer"); // JMM: EOS_BOOLEAN is an enum with EOS_FALSE=0 and EOS_TRUE=1. - eos_SetSharedPackedTables(NTABLES, &packed_size, (EOS_CHAR *)src, + eos_SetSharedPackedTables(NTABLES, &packed_size_, (EOS_CHAR *)src, (EOS_CHAR *)stngs.data, stngs.is_node_root, tablehandle, &error_code); #else - eos_SetPackedTables(NTABLES, &packed_size, (EOS_CHAR *)src, tablehandle, &error_code); + eos_SetPackedTables(NTABLES, &packed_size_, (EOS_CHAR *)src, tablehandle, &error_code); #endif // SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY eosCheckError(error_code, "eos_SetSharedPackedTables", Verbosity::Debug); PofRT_table_ = tablehandle[0]; // these get re-set diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index acea25d750..1017603d2d 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -230,7 +230,7 @@ class HelmElectrons { std::size_t DynamicMemorySizeInBytes() const { return SpinerTricks::DynamicMemorySizeInBytes(this); } - std::size_t DumpDynamicMemory(char *dst) const { + std::size_t DumpDynamicMemory(char *dst) { return SpinerTricks::DumpDynamicMemory(dst, this); } std::size_t SetDynamicMemory(char *src, @@ -490,7 +490,7 @@ class Helmholtz : public EosBase { std::size_t DynamicMemorySizeInBytes() const { return electrons_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { + std::size_t DumpDynamicMemory(char *dst) { return electrons_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 982bda1f69..f7d22ed9a2 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -105,7 +105,7 @@ class SpinerEOSDependsRhoT : public EosBase { } std::size_t DynamicMemorySizeInBytes() const; - std::size_t DumpDynamicMemory(char *dst) const; + std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); @@ -368,7 +368,7 @@ class SpinerEOSDependsRhoSie : public EosBase { } std::size_t DynamicMemorySizeInBytes() const; - std::size_t DumpDynamicMemory(char *dst) const; + std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); @@ -683,7 +683,7 @@ inline std::size_t SpinerEOSDependsRhoT::DynamicMemorySizeInBytes() const { return SpinerTricks::DynamicMemorySizeInBytes(this); } -inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) const { +inline std::size_t SpinerEOSDependsRhoT::DumpDynamicMemory(char *dst) { return SpinerTricks::DumpDynamicMemory(dst, this); } @@ -1635,7 +1635,7 @@ inline std::size_t SpinerEOSDependsRhoSie::DynamicMemorySizeInBytes() const { return STricks::DynamicMemorySizeInBytes(this); } -inline std::size_t SpinerEOSDependsRhoSie::DumpDynamicMemory(char *dst) const { +inline std::size_t SpinerEOSDependsRhoSie::DumpDynamicMemory(char *dst) { return STricks::DumpDynamicMemory(dst, this); } diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index a2878935e7..9d2c88d49d 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -227,7 +227,7 @@ class StellarCollapse : public EosBase { bool dependent_var_log); std::size_t DynamicMemorySizeInBytes() const; - std::size_t DumpDynamicMemory(char *dst) const; + std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); @@ -481,7 +481,7 @@ inline std::size_t StellarCollapse::DynamicMemorySizeInBytes() const { return table_utils::SpinerTricks::DynamicMemorySizeInBytes(this); } -inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) const { +inline std::size_t StellarCollapse::DumpDynamicMemory(char *dst) { return table_utils::SpinerTricks::DumpDynamicMemory(dst, this); } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 0f4fae3d42..5a95a55ba1 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -50,7 +50,7 @@ class Variant { PORTABLE_FUNCTION Variant(EOSChoice &&choice) : eos_(std::move(std::forward(choice))) {} - Variant() noexcept = default; + Variant() = default; template 0) { @@ -1050,7 +1050,7 @@ class Variant { } return offst; } - auto Serialize() const { + auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); Serialize(dst); diff --git a/singularity-eos/eos/eos_vinet.hpp b/singularity-eos/eos/eos_vinet.hpp index 4a1babcca8..3b5e0204b6 100644 --- a/singularity-eos/eos/eos_vinet.hpp +++ b/singularity-eos/eos/eos_vinet.hpp @@ -45,6 +45,7 @@ class Vinet : public EosBase { CheckParams(); InitializeVinet(expconsts); } + PORTABLE_INLINE_FUNCTION void CheckParams() const; Vinet GetOnDevice() { return *this; } template @@ -163,7 +164,6 @@ class Vinet : public EosBase { static constexpr const int PressureCoeffsd2tod40Size = 39; static constexpr const int VinetInternalParametersSize = PressureCoeffsd2tod40Size + 4; Real _VIP[VinetInternalParametersSize], _d2tod40[PressureCoeffsd2tod40Size]; - PORTABLE_INLINE_FUNCTION void CheckParams() const; void InitializeVinet(const Real *expcoeffs); PORTABLE_INLINE_FUNCTION void Vinet_F_DT_func(const Real rho, const Real T, Real *output) const; diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index 1f3284a3aa..fddc90f528 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -429,7 +429,7 @@ class UnitSystem : public EosBase> { inline constexpr T UnmodifyOnce() { return t_; } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index ef8f4b672c..985e6eb741 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -456,7 +456,7 @@ class BilinearRampEOS : public EosBase> { inline constexpr T UnmodifyOnce() { return t_; } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index f9ff8edcc5..5c203413c2 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -186,7 +186,7 @@ class RelativisticEOS : public EosBase> { inline constexpr T UnmodifyOnce() { return t_; } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 6aae804890..3e9e285ad2 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -346,7 +346,7 @@ class ScaledEOS : public EosBase> { inline constexpr T UnmodifyOnce() { return t_; } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index e55cb47e7b..9441fff19a 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -356,7 +356,7 @@ class ShiftedEOS : public EosBase> { inline constexpr T UnmodifyOnce() { return t_; } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) const { return t_.DumpDynamicMemory(dst); } + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return t_.SetDynamicMemory(src, stngs); diff --git a/test/test_eos_tabulated.cpp b/test/test_eos_tabulated.cpp index 40147663c6..33bfdb3382 100644 --- a/test/test_eos_tabulated.cpp +++ b/test/test_eos_tabulated.cpp @@ -221,7 +221,7 @@ SCENARIO("SpinerEOS depends on Rho and T", "[SpinerEOS][DependsRhoT][EOSPAC]") { REQUIRE(isClose(rho, rho_pac)); } eos_spiner.Finalize(); - eos_eospac.FInalize(); + eos_eospac.Finalize(); } } @@ -277,7 +277,7 @@ SCENARIO("SpinerEOS and EOSPA Serialization", eospac_orig.DynamicMemorySizeInBytes()); } WHEN("We serialize") { - auto [rhoT_size, rhotT_data] = rhoT_orig.Serialize(); + auto [rhoT_size, rhoT_data] = rhoT_orig.Serialize(); REQUIRE(rhoT_size == rhoT_orig.SerializedSizeInBytes()); auto [rhoSie_size, rhoSie_data] = rhoSie_orig.Serialize(); @@ -302,9 +302,9 @@ SCENARIO("SpinerEOS and EOSPA Serialization", using RhoSieTricks = singularity::table_utils::SpinerTricks; - rhoT_shared_data = (char *)malloc(rhoT_shared_size); - rhoSie_shared_data = (char *)malloc(rhoSie_shared_size); - eospac_shared_data = (char *)malloc(eospac_shared_size); + char *rhoT_shared_data = (char *)malloc(rhoT_shared_size); + char *rhoSie_shared_data = (char *)malloc(rhoSie_shared_size); + char *eospac_shared_data = (char *)malloc(eospac_shared_size); SpinerEOSDependsRhoT eos_rhoT; std::size_t read_size_rhoT = @@ -321,19 +321,19 @@ SCENARIO("SpinerEOS and EOSPA Serialization", EOS eos_eospac = EOSPAC(); std::size_t read_size_eospac = eos_rhoSie.DeSerialize( rhoSie_data, SharedMemSettings(rhoSie_shared_data, true)); - REQUIRE(read_size_eospac = eospac_size); + REQUIRE(read_size_eospac == eospac_size); AND_THEN("EOS lookups work") { constexpr Real rho_trial = 1; constexpr Real sie_trial = 1e12; const Real P_eospac = - eos_eospac.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + eos_eospac.PressureFromDensityInternalEnergy(rho_trial, sie_trial); const Real P_spiner_orig = - rhoT_orig.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + rhoT_orig.PressureFromDensityInternalEnergy(rho_trial, sie_trial); const Real P_spiner_rhoT = - eos_rhoT.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + eos_rhoT.PressureFromDensityInternalEnergy(rho_trial, sie_trial); const Real P_spiner_rhoSie = - eos_rhoSie.InternalEnergyFromDensityPressure(rho_trial, sie_trial); + eos_rhoSie.PressureFromDensityInternalEnergy(rho_trial, sie_trial); REQUIRE(isClose(P_eospac, P_spiner_orig)); REQUIRE(isClose(P_eospac, P_spiner_rhoT)); REQUIRE(isClose(P_eospac, P_spiner_rhoSie)); @@ -346,7 +346,7 @@ SCENARIO("SpinerEOS and EOSPA Serialization", } free(rhoT_data); free(rhoSie_data); - free(eospac_data) + free(eospac_data); } rhoT_orig.Finalize(); From dab97595218c0fbc57387d956b504492dc2476b0 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 15:22:57 -0600 Subject: [PATCH 24/48] formatting --- singularity-eos/eos/eos_helmholtz.hpp | 4 +--- singularity-eos/eos/eos_variant.hpp | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 1017603d2d..e5fbb0be78 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -490,9 +490,7 @@ class Helmholtz : public EosBase { std::size_t DynamicMemorySizeInBytes() const { return electrons_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { - return electrons_.DumpDynamicMemory(dst); - } + std::size_t DumpDynamicMemory(char *dst) { return electrons_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return electrons_.SetDynamicMemory(src); diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 5a95a55ba1..19fb14744e 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1028,8 +1028,7 @@ class Variant { eos_); } std::size_t DumpDynamicMemory(char *dst) { - return mpark::visit([dst](auto &eos) { return eos.DumpDynamicMemory(dst); }, - eos_); + return mpark::visit([dst](auto &eos) { return eos.DumpDynamicMemory(dst); }, eos_); } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { From ba098418e42aab9e61125ed8447ea83d8a1e1ae3 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 15:37:46 -0600 Subject: [PATCH 25/48] tweaks --- singularity-eos/eos/eos_base.hpp | 7 +++++-- test/test_eos_tabulated.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 6f65c5c8c7..c34d5aa644 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -676,6 +676,7 @@ class EosBase { } std::size_t Serialize(char *dst) { CRTP *pcrtp = static_cast(this); + std::size_t tot_size = pcrtp->SerializedSizeInBytes(); std::size_t offst = 0; memcpy(dst, pcrtp, sizeof(CRTP)); offst += sizeof(CRTP); @@ -687,7 +688,8 @@ class EosBase { return offst; } auto Serialize() { - std::size_t size = SerializedSizeInBytes(); + CRTP *pcrtp = static_cast(this); + std::size_t size = pcrtp->SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t size_new = Serialize(dst); PORTABLE_REQUIRE(size_new == size, "Serialization succesful"); @@ -700,6 +702,7 @@ class EosBase { memcpy(pcrtp, src, sizeof(CRTP)); offst += sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); + std::size_t tot_size = pcrtp->SerializedSizeInBytes(); if (dyn_size > 0) { const bool sizes_same = pcrtp->StaticMemoryIsThis(); if (stngs.CopyNeeded() && sizes_same) { @@ -707,7 +710,7 @@ class EosBase { } offst += pcrtp->SetDynamicMemory(src + offst, stngs); } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Deserialization succesful"); + PORTABLE_REQUIRE(offst == tot_size, "Deserialization succesful"); return offst; } diff --git a/test/test_eos_tabulated.cpp b/test/test_eos_tabulated.cpp index 33bfdb3382..7f8c615537 100644 --- a/test/test_eos_tabulated.cpp +++ b/test/test_eos_tabulated.cpp @@ -263,7 +263,7 @@ SCENARIO("SpinerEOS depends on rho and sie", "[SpinerEOS][DependsRhoSie]") { } } -SCENARIO("SpinerEOS and EOSPA Serialization", +SCENARIO("SpinerEOS and EOSPAC Serialization", "[SpinerEOS][DependsRhoT][DependsRhoSie][EOSPAC][Serialization]") { GIVEN("Eoses initialized with matid") { SpinerEOSDependsRhoT rhoT_orig = SpinerEOSDependsRhoT(eosName, steelID); From 215936857f1b39958c72ead8616090b818e85c3f Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 16:06:10 -0600 Subject: [PATCH 26/48] added hidden static size --- singularity-eos/eos/eos_base.hpp | 4 +++- singularity-eos/eos/eos_eospac.hpp | 6 +++--- singularity-eos/eos/eos_variant.hpp | 6 +++++- singularity-eos/eos/modifiers/eos_unitsystem.hpp | 1 + singularity-eos/eos/modifiers/ramps_eos.hpp | 1 + singularity-eos/eos/modifiers/relativistic_eos.hpp | 1 + singularity-eos/eos/modifiers/scaled_eos.hpp | 1 + singularity-eos/eos/modifiers/shifted_eos.hpp | 1 + 8 files changed, 16 insertions(+), 5 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index c34d5aa644..e84081a893 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -659,6 +659,7 @@ class EosBase { const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return 0; } + std::size_t HiddenStaticSizeInBytes() const { return 0; } constexpr bool StaticMemoryIsThis() const { return true; } // JMM: These are generic and do not need to be special-cased. // TODO(JMM): Should this machinery actually be available for "bare" @@ -672,7 +673,8 @@ class EosBase { // class. const CRTP *pcrtp = static_cast(this); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); - return dyn_size + sizeof(CRTP); + std::size_t implicit_size = pcrtp->HiddenStaticSizeInBytes(); + return dyn_size + implicit_size + sizeof(CRTP); } std::size_t Serialize(char *dst) { CRTP *pcrtp = static_cast(this); diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 6bbc53e98e..15c7bab00a 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -145,7 +145,7 @@ class EOSPAC : public EosBase { } inline EOSPAC GetOnDevice() { return *this; } - std::size_t SerializedSizeInBytes() const; // shadow/overload base class + std::size_t HiddenStaticSizeInBytes() const; std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, @@ -1236,13 +1236,13 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, } // shadow/overload base class -inline std::size_t EOSPAC::SerializedSizeInBytes() const { +inline std::size_t EOSPAC::HiddenStaticSizeInBytes() const { printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG // JMM: We need both of these because EOSPAC allows the size in // shared memory to differ from the size required to reconstruct // an object. This is generically true for spiner too, but we just // deliberately waste a little space. - return sizeof(this) + std::max(shared_size_, packed_size_); + return std::max(shared_size_, packed_size_); } inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return shared_size_; } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 19fb14744e..5e616a1f9e 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1027,6 +1027,10 @@ class Variant { return mpark::visit([](const auto &eos) { return eos.DynamicMemorySizeInBytes(); }, eos_); } + std::size_t HiddenStaticSizeInBytes() const { + return mpark::visit([](const auto &eos) { return eos.HiddenStaticSizeInBytes(); }, + eos_); + } std::size_t DumpDynamicMemory(char *dst) { return mpark::visit([dst](auto &eos) { return eos.DumpDynamicMemory(dst); }, eos_); } @@ -1036,7 +1040,7 @@ class Variant { [src, stngs](auto &eos) { return eos.SetDynamicMemory(src, stngs); }, eos_); } std::size_t SerializedSizeInBytes() const { - return sizeof(*this) + DynamicMemorySizeInBytes(); + return sizeof(*this) + DynamicMemorySizeInBytes() + HiddenStaticSizeInBytes(); } constexpr std::size_t StaticMemoryIsThis() const { return mpark::visit([](auto &eos) { return eos.StaticMemoryIsThis(); }, eos_); diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index fddc90f528..b091b9780d 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -428,6 +428,7 @@ class UnitSystem : public EosBase> { static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } + std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index 985e6eb741..d977be9dea 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -455,6 +455,7 @@ class BilinearRampEOS : public EosBase> { static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } + std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index 5c203413c2..a69c2901a4 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -185,6 +185,7 @@ class RelativisticEOS : public EosBase> { static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } + std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 3e9e285ad2..aabc0a428f 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -345,6 +345,7 @@ class ScaledEOS : public EosBase> { static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } + std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 9441fff19a..90fdbd33da 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -355,6 +355,7 @@ class ShiftedEOS : public EosBase> { static inline constexpr bool IsModified() { return true; } inline constexpr T UnmodifyOnce() { return t_; } + std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } std::size_t SetDynamicMemory(char *src, From bfc8ed5e014cf05749d70b06d5aa78e4f40c41b4 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Fri, 23 Aug 2024 16:33:27 -0600 Subject: [PATCH 27/48] trying to debug eospac --- singularity-eos/eos/eos_base.hpp | 6 ++++-- singularity-eos/eos/eos_variant.hpp | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index e84081a893..134e3c8fae 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -683,7 +683,8 @@ class EosBase { memcpy(dst, pcrtp, sizeof(CRTP)); offst += sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); - if (dyn_size > 0) { + std::size_t hidden_size = HiddenStaticSizeInBytes(); + if (dyn_size + hidden_size > 0) { offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } PORTABLE_REQUIRE((offst == SerializedSizeInBytes()), "Serialization succesful"); @@ -704,8 +705,9 @@ class EosBase { memcpy(pcrtp, src, sizeof(CRTP)); offst += sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); + std::size_t hidden_size = HiddenStaticSizeInBytes(); std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - if (dyn_size > 0) { + if (dyn_size + hidden_size > 0) { const bool sizes_same = pcrtp->StaticMemoryIsThis(); if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 5e616a1f9e..a4316515ef 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1048,7 +1048,9 @@ class Variant { std::size_t Serialize(char *dst) { memcpy(dst, this, sizeof(*this)); std::size_t offst = sizeof(*this); - if (DynamicMemorySizeInBytes() > 0) { + std::size_t dyn_size = DynamicMemorySizeInBytes(); + std::size_t hidden_size = HiddenStaticSizeInBytes(); + if (dyn_size + hidden_size > 0) { offst += DumpDynamicMemory(dst + offst); } return offst; @@ -1064,7 +1066,8 @@ class Variant { memcpy(this, src, sizeof(*this)); std::size_t offst = sizeof(*this); std::size_t dyn_size = DynamicMemorySizeInBytes(); - if (dyn_size > 0) { + std::size_t hidden_size = HiddenStaticSizeInBytes(); + if (dyn_size + hidden_size > 0) { const bool sizes_same = StaticMemoryIsThis(); if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); From d89aec3fbe107f3a5746b35614756c367cdefd9c Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Sat, 24 Aug 2024 15:26:11 -0600 Subject: [PATCH 28/48] Give up and expose shared memory and dynamic memory as different concepts --- singularity-eos/eos/eos_base.hpp | 63 +++++++++++-------- singularity-eos/eos/eos_eospac.hpp | 22 +++---- singularity-eos/eos/eos_variant.hpp | 29 ++++----- .../eos/modifiers/eos_unitsystem.hpp | 12 +--- singularity-eos/eos/modifiers/ramps_eos.hpp | 12 +--- .../eos/modifiers/relativistic_eos.hpp | 12 +--- singularity-eos/eos/modifiers/scaled_eos.hpp | 12 +--- singularity-eos/eos/modifiers/shifted_eos.hpp | 12 +--- test/test_eos_stellar_collapse.cpp | 4 +- 9 files changed, 67 insertions(+), 111 deletions(-) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 134e3c8fae..dc0c8ac9e1 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -81,6 +81,25 @@ char *StrCat(char *destination, const char *source) { using EosBase::EntropyFromDensityTemperature; \ using EosBase::EntropyFromDensityInternalEnergy; +// This macro adds several methods that most modifiers will +// want. Not ALL modifiers will want these methods as written here, +// so use this macro with care. +// TODO(JMM): Find a better solution. Multiple inheritence and mixins +// dont' seem to work as desired here. +#define SG_ADD_MODIFIER_METHODS(T, t_) \ + static inline constexpr bool IsModified() { return true; } \ + inline constexpr T UnmodifyOnce() { return t_; } \ + std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } \ + std::size_t SharedMemorySizeInBytes() const { return t_.SharedMemorySizeInBytes(); } \ + std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } \ + std::size_t SetDynamicMemory(char *src, \ + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { \ + return t_.SetDynamicMemory(src, stngs); \ + } \ + constexpr bool AllDynamicMemoryIsShareable() const { \ + return t_.AllDynamicMemoryIsShareable(); \ + } + class Factor { Real value_ = 1.0; bool is_set_ = false; @@ -652,42 +671,36 @@ class EosBase { } // Serialization - // JMM: These must be special-cased. + // JMM: These must frequently be special-cased. std::size_t DynamicMemorySizeInBytes() const { return 0; } std::size_t DumpDynamicMemory(char *dst) { return 0; } std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { return 0; } - std::size_t HiddenStaticSizeInBytes() const { return 0; } - constexpr bool StaticMemoryIsThis() const { return true; } - // JMM: These are generic and do not need to be special-cased. - // TODO(JMM): Should this machinery actually be available for "bare" - // EOS's outside the variant? - // TODO(JMM): Should I try to reduce the amount of duplicated code - // between here and the variant? Is this a rare case where multiple - // inheritence or mixins would be useful? Probably more trouble than - // its work for ~20 LOC... + // JMM: These usually don't need to be special cased. + std::size_t SharedMemorySizeInBytes() const { + const CRTP *pcrtp = static_cast(this); + return pcrtp->DynamicMemorySizeInBytes(); + } + constexpr bool AllDynamicMemoryIsShareable() const { return true; } + // JMM: These are generic and never need to be special-cased. std::size_t SerializedSizeInBytes() const { - // sizeof(*this) apparently returns the size of JUST the base - // class. + // sizeof(*this) returns the size of JUST the base class. const CRTP *pcrtp = static_cast(this); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); - std::size_t implicit_size = pcrtp->HiddenStaticSizeInBytes(); - return dyn_size + implicit_size + sizeof(CRTP); + return dyn_size + sizeof(CRTP); } std::size_t Serialize(char *dst) { CRTP *pcrtp = static_cast(this); - std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - std::size_t offst = 0; memcpy(dst, pcrtp, sizeof(CRTP)); - offst += sizeof(CRTP); + std::size_t offst = sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); - std::size_t hidden_size = HiddenStaticSizeInBytes(); - if (dyn_size + hidden_size > 0) { + if (dyn_size > 0) { offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } - PORTABLE_REQUIRE((offst == SerializedSizeInBytes()), "Serialization succesful"); + const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); + PORTABLE_REQUIRE(offst == tot_size, "Serialization succesful"); return offst; } auto Serialize() { @@ -701,19 +714,17 @@ class EosBase { std::size_t DeSerialize(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { CRTP *pcrtp = static_cast(this); - std::size_t offst = 0; memcpy(pcrtp, src, sizeof(CRTP)); - offst += sizeof(CRTP); + std::size_t offst = sizeof(CRTP); std::size_t dyn_size = pcrtp->DynamicMemorySizeInBytes(); - std::size_t hidden_size = HiddenStaticSizeInBytes(); - std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - if (dyn_size + hidden_size > 0) { - const bool sizes_same = pcrtp->StaticMemoryIsThis(); + if (dyn_size > 0) { + const bool sizes_same = pcrtp->AllDynamicMemoryIsShareable(); if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); } offst += pcrtp->SetDynamicMemory(src + offst, stngs); } + const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); PORTABLE_REQUIRE(offst == tot_size, "Deserialization succesful"); return offst; } diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 15c7bab00a..ea769975ee 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -145,12 +145,12 @@ class EOSPAC : public EosBase { } inline EOSPAC GetOnDevice() { return *this; } - std::size_t HiddenStaticSizeInBytes() const; std::size_t DynamicMemorySizeInBytes() const; std::size_t DumpDynamicMemory(char *dst); std::size_t SetDynamicMemory(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS); - constexpr bool StaticMemoryIsThis() const { return false; } + std::size_t SharedMemorySizeInBytes() const; + constexpr bool AllDynamicMemoryIsShareable() const { return false; } SG_PIF_NOWARN template @@ -1235,18 +1235,9 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, robust::ratio(dpde_ref_ * cv_ref_, rho_ref_ * rho_ref_ * pressureFromSesame(DPDR)); } -// shadow/overload base class -inline std::size_t EOSPAC::HiddenStaticSizeInBytes() const { - printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG - // JMM: We need both of these because EOSPAC allows the size in - // shared memory to differ from the size required to reconstruct - // an object. This is generically true for spiner too, but we just - // deliberately waste a little space. - return std::max(shared_size_, packed_size_); -} -inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return shared_size_; } - +inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return packed_size_; } inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { + printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; @@ -1254,9 +1245,9 @@ inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { eosCheckError(error_code, "eos_GetPackedTables", Verbosity::Debug); return packed_size_; // JMM: Note this is NOT shared memory size } - inline std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); + printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; #ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY @@ -1278,8 +1269,9 @@ inline std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings & TofRP_table_ = tablehandle[4]; PofRE_table_ = tablehandle[5]; EcofD_table_ = tablehandle[6]; - return std::max(shared_size_, packed_size_); + return packed_size_; } +inline std::size_t EOSPAC::SharedMemorySizeInBytes() const { return shared_size_; } SG_PIF_NOWARN template diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index a4316515ef..ab8b90ba9b 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1027,10 +1027,6 @@ class Variant { return mpark::visit([](const auto &eos) { return eos.DynamicMemorySizeInBytes(); }, eos_); } - std::size_t HiddenStaticSizeInBytes() const { - return mpark::visit([](const auto &eos) { return eos.HiddenStaticSizeInBytes(); }, - eos_); - } std::size_t DumpDynamicMemory(char *dst) { return mpark::visit([dst](auto &eos) { return eos.DumpDynamicMemory(dst); }, eos_); } @@ -1039,26 +1035,32 @@ class Variant { return mpark::visit( [src, stngs](auto &eos) { return eos.SetDynamicMemory(src, stngs); }, eos_); } - std::size_t SerializedSizeInBytes() const { - return sizeof(*this) + DynamicMemorySizeInBytes() + HiddenStaticSizeInBytes(); + std::size_t SharedMemorySizeInBytes() const { + return mpark::visit([](const auto &eos) { return eos.SharedMemorySizeInBytes(); }, + eos_); } - constexpr std::size_t StaticMemoryIsThis() const { - return mpark::visit([](auto &eos) { return eos.StaticMemoryIsThis(); }, eos_); + constexpr bool AllDynamicMemoryIsShareable() const { + return mpark::visit([](const auto &eos) { return eos.AllDynamicMemoryIsShareable(); }, + eos_); + } + std::size_t SerializedSizeInBytes() const { + return sizeof(*this) + DynamicMemorySizeInBytes(); } std::size_t Serialize(char *dst) { memcpy(dst, this, sizeof(*this)); std::size_t offst = sizeof(*this); std::size_t dyn_size = DynamicMemorySizeInBytes(); - std::size_t hidden_size = HiddenStaticSizeInBytes(); - if (dyn_size + hidden_size > 0) { + if (dyn_size > 0) { offst += DumpDynamicMemory(dst + offst); } + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization succesful"); return offst; } auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); - Serialize(dst); + std::size_t new_size = Serialize(dst); + PORTABLE_REQUIRE(size == new_size, "Serialization succesful"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, @@ -1066,9 +1068,8 @@ class Variant { memcpy(this, src, sizeof(*this)); std::size_t offst = sizeof(*this); std::size_t dyn_size = DynamicMemorySizeInBytes(); - std::size_t hidden_size = HiddenStaticSizeInBytes(); - if (dyn_size + hidden_size > 0) { - const bool sizes_same = StaticMemoryIsThis(); + if (dyn_size > 0) { + const bool sizes_same = AllDynamicMemoryIsShareable(); if (stngs.CopyNeeded() && sizes_same) { memcpy(stngs.data, src + offst, dyn_size); } diff --git a/singularity-eos/eos/modifiers/eos_unitsystem.hpp b/singularity-eos/eos/modifiers/eos_unitsystem.hpp index b091b9780d..cb98a373ae 100644 --- a/singularity-eos/eos/modifiers/eos_unitsystem.hpp +++ b/singularity-eos/eos/modifiers/eos_unitsystem.hpp @@ -425,17 +425,7 @@ class UnitSystem : public EosBase> { printf("Units = %e %e %e %e\n", rho_unit_, sie_unit_, temp_unit_, press_unit_); } - static inline constexpr bool IsModified() { return true; } - inline constexpr T UnmodifyOnce() { return t_; } - - std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { - return t_.SetDynamicMemory(src, stngs); - } - constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } + SG_ADD_MODIFIER_METHODS(T, t_); private: T t_; diff --git a/singularity-eos/eos/modifiers/ramps_eos.hpp b/singularity-eos/eos/modifiers/ramps_eos.hpp index d977be9dea..a0ce08db2e 100644 --- a/singularity-eos/eos/modifiers/ramps_eos.hpp +++ b/singularity-eos/eos/modifiers/ramps_eos.hpp @@ -452,17 +452,7 @@ class BilinearRampEOS : public EosBase> { t_.ValuesAtReferenceState(rho, temp, sie, press, cv, bmod, dpde, dvdt, lambda); } - static inline constexpr bool IsModified() { return true; } - inline constexpr T UnmodifyOnce() { return t_; } - - std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { - return t_.SetDynamicMemory(src, stngs); - } - constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } + SG_ADD_MODIFIER_METHODS(T, t_); private: T t_; diff --git a/singularity-eos/eos/modifiers/relativistic_eos.hpp b/singularity-eos/eos/modifiers/relativistic_eos.hpp index a69c2901a4..0fd296d78d 100644 --- a/singularity-eos/eos/modifiers/relativistic_eos.hpp +++ b/singularity-eos/eos/modifiers/relativistic_eos.hpp @@ -182,17 +182,7 @@ class RelativisticEOS : public EosBase> { t_.ValuesAtReferenceState(rho, temp, sie, press, cv, bmod, dpde, dvdt, lambda); } - static inline constexpr bool IsModified() { return true; } - inline constexpr T UnmodifyOnce() { return t_; } - - std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { - return t_.SetDynamicMemory(src, stngs); - } - constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } + SG_ADD_MODIFIER_METHODS(T, t_); private: T t_; diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index aabc0a428f..2c0dd871ab 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -342,17 +342,7 @@ class ScaledEOS : public EosBase> { return t_.MinimumTemperature(); } - static inline constexpr bool IsModified() { return true; } - inline constexpr T UnmodifyOnce() { return t_; } - - std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { - return t_.SetDynamicMemory(src, stngs); - } - constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } + SG_ADD_MODIFIER_METHODS(T, t_); private: T t_; diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 90fdbd33da..411a89b333 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -352,17 +352,7 @@ class ShiftedEOS : public EosBase> { return t_.MinimumTemperature(); } - static inline constexpr bool IsModified() { return true; } - inline constexpr T UnmodifyOnce() { return t_; } - - std::size_t HiddenStaticSizeInBytes() const { return t_.HiddenStaticSizeInBytes(); } - std::size_t DynamicMemorySizeInBytes() const { return t_.DynamicMemorySizeInBytes(); } - std::size_t DumpDynamicMemory(char *dst) { return t_.DumpDynamicMemory(dst); } - std::size_t SetDynamicMemory(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { - return t_.SetDynamicMemory(src, stngs); - } - constexpr bool StaticMemoryIsThis() const { return t_.StaticMemoryIsThis(); } + SG_ADD_MODIFIER_METHODS(T, t_); private: T t_; diff --git a/test/test_eos_stellar_collapse.cpp b/test/test_eos_stellar_collapse.cpp index 148e5e8c8d..8b0a9fcfe1 100644 --- a/test/test_eos_stellar_collapse.cpp +++ b/test/test_eos_stellar_collapse.cpp @@ -324,7 +324,9 @@ SCENARIO("Stellar Collapse EOS", "[StellarCollapse]") { THEN("We can de-serialize it into a new object AROUND a new allocation") { using singularity::SharedMemSettings; // mockup of shared data - char *shared_data = (char *)malloc(size); + std::size_t shared_size = sc.SharedMemorySizeInBytes(); + REQUIRE(shared_size == sc.DynamicMemorySizeInBytes()); + char *shared_data = (char *)malloc(shared_size); SharedMemSettings settings(shared_data, true); StellarCollapse sc3; std::size_t read_size = sc3.DeSerialize(data, settings); From 50dc6f32e03052d8fef734bee6a1a56bdf9d94f6 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Sat, 24 Aug 2024 17:08:44 -0600 Subject: [PATCH 29/48] document --- CMakeLists.txt | 4 +- doc/sphinx/src/building.rst | 1 + doc/sphinx/src/using-eos.rst | 190 +++++++++++++++++++++++++++-- singularity-eos/base/constants.hpp | 8 +- 4 files changed, 190 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95d8753fe9..a1762fc0eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ cmake_dependent_option( option(SINGULARITY_USE_FORTRAN "Enable fortran bindings" ON) option(SINGULARITY_USE_KOKKOS "Use Kokkos for portability" OFF) option(SINGULARITY_USE_EOSPAC "Enable eospac backend" OFF) -option(SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY +option(SINGULARITY_EOSPAC_ENABLE_SHMEM "Support shared memory with EOSPAC backend. Requires EOSPAC version 6.5.7." OFF) @@ -274,7 +274,7 @@ endif() if(SINGULARITY_USE_SPINER_WITH_HDF5) target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_USE_SPINER_WITH_HDF5) endif() -if (SINGULARITY_USE_EOSPAC AND SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY) +if (SINGULARITY_USE_EOSPAC AND SINGULARITY_EOSPAC_ENABLE_SHMEM) target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY) endif() diff --git a/doc/sphinx/src/building.rst b/doc/sphinx/src/building.rst index a716f931ef..d5b4839b4c 100644 --- a/doc/sphinx/src/building.rst +++ b/doc/sphinx/src/building.rst @@ -105,6 +105,7 @@ The main CMake options to configure building are in the following table: ``SINGULARITY_USE_FORTRAN`` ON Enable Fortran API for equation of state. ``SINGULARITY_USE_KOKKOS`` OFF Uses Kokkos as the portability backend. Currently only Kokkos is supported for GPUs. ``SINGULARITY_USE_EOSPAC`` OFF Link against EOSPAC. Needed for sesame2spiner and some tests. + ``SINGULARITY_EOSPAC_ENABLE_SHMEM`` OFF Enable shared memory support in EOSPAC backend. ``SINGULARITY_BUILD_CLOSURE`` OFF Build the mixed cell closure models ``SINGULARITY_BUILD_TESTS`` OFF Build test infrastructure. ``SINGULARITY_BUILD_PYTHON`` OFF Build Python bindings. diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index d8ab5b7b98..dd74f4959a 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -19,13 +19,14 @@ The parallelism model ---------------------- For the most part, ``singularity-eos`` tries to be agnostic to how you -parallelize your code on-node. (It knows nothing at all about -distributed memory parallelism.) An ``EOS`` object can be copied into -any parallel code block by value (see below) and scalar calls do not -attempt any internal multi-threading, meaning ``EOS`` objects are not -thread-safe, but are compatible with thread safety, assuming the user -calls them appropriately. The main complication is ``lambda`` arrays, -which are discussed below. +parallelize your code on-node. It knows nothing at all about +distributed memory parallelism, with one exception, discussed +below. An ``EOS`` object can be copied into any parallel code block by +value (see below) and scalar calls do not attempt any internal +multi-threading, meaning ``EOS`` objects are not thread-safe, but are +compatible with thread safety, assuming the user calls them +appropriately. The main complication is ``lambda`` arrays, which are +discussed below. The vector ``EOS`` method overloads are a bit different. These are thread-parallel operations launched by ``singularity-EOS``. They run @@ -39,6 +40,164 @@ A more generic version of the vector calls exists in the ``Evaluate`` method, which allows the user to specify arbitrary parallel dispatch models by writing their own loops. See the relevant section below. +Serialization and shared memory +-------------------------------- + +While ``singularity-eos`` makes a best effort to be agnostic to +parallelism, it exposes several methods that are useful in a +distributed memory environment. In particular, there are two use-cases +the library seeks to support: + +#. To avoid stressing a filesystem, it may desirable to load a table from one thread (e.g., MPI rank) and broadcast this data to all other ranks. +#. To save memory it may be desirable to place tabulated data, which is read-only after it has been loaded from file, into shared memory on a given node, even if al other data is thread local in a distributed-memory environment. This is possible via, e.g., `MPI Windows`_. + +Therefore exposes several methods that can be used in this +context. The function + +.. cpp:function:: std::size_t EOS::SerializedSizeInBytes() const; + +returns the amount of memory required in bytes to hold a serialized +EOS object. The return value will depend on the underlying equation of +state model currently contained in the object. The function + +.. cpp:function:: std::size_t EOS::SharedMemorySizeInBytes() const; + +returns the amount of data (in bytes) that a given object can place into shared memory. Again, the return value depends on the model the object currently represents. + +.. note:: + + Many models may not be able to utilize shared memory at all. This + holds for most analytic models, for example. The ``EOSPAC`` backend + will only utilize shared memory if ``EOSPAC`` is sufficiently recent + to support it and if ``singularity-eos`` is built with serialization + support for ``EOSPAC`` (enabled with + ``-DSINGULARITY_EOSPAC_ENABLE_SHMEM=ON``). + +The function + +.. cpp:function:: std::size_t EOS::Serialize(char *dst); + +fills the ``dst`` pointer with the memory required for serialization +and returns the number of bytes written to ``dst``. The function + +.. cpp:function:: std::pair EOS::Serialize(); + +allocates a ``char*`` pointer to contain serialized data and fills +it. The pair is the pointer and its size. The function + +.. code-block:: cpp + + std::size_t EOS::DeSerialize(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_SETTINGS) + +Sets an EOS object based on the serialized representation contained in +``src``. It returns the number of bytes read from ``src``. Optionally, +``DeSerialize`` may also write the data that can be shared to a +pointer contained in ``SharedMemSettings``. If you do this, you must +pass this pointer in, but designate only one thread per shared memory +domain (frequently a node or socket) to actually write to this +data. ``SharedMemSettings`` is a struct containing a ``data`` pointer +and a ``is_domain_root`` boolean: + +.. code-block:: cpp + + struct SharedMemSettings { + SharedMemSettings(); + SharedMemSettings(char *data_, bool is_domain_root_) + : data(data_), is_domain_root(is_domain_root_) {} + char *data; + bool is_domain_root; + }; + +The ``data`` pointer should point to a shared memory allocation. The +``is_domain_root`` boolean should be true for exactly one thread per +shared memory domain. + +For example you might call ``DeSerialize`` as + +.. code-block:: cpp + + std::size_t read_size = eos.DeSerialize(packed_data, + singularity::SharedMemSettings(shared_data, + my_rank % NTHREADS == 0)); + assert(read_size == write_size); // for safety + +.. warning:: + + Note that for equation of state models that have dynamically + allocated memory, ``singularity-eos`` reserves the right to point + directly at data in ``src``, so it **cannot** be freed until you + would call ``eos.Finalize()``. If the ``SharedMemSettings`` are + utilized to request data be written to a shared memory pointer, + however, you can free the ``src`` pointer, so long as you don't free + the shared memory pointer. + +Putting everything together, a full sequence with MPI might look like this: + +.. code-block:: cpp + + singularity::EOS eos; + std::size_t packed_size, shared_size; + char *packed_data; + if (rank == 0) { // load eos object + eos = singularity::StellarCollapse(filename); + packed_size = eos.SerializedSizeInBytes(); + shared_size = eos.SharedMemorySizeInBytes(); + } + + // Send sizes + MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&shared_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + + // Allocate data needed + packed_data = (char*)malloc(packed_size); + if (rank == 0) { + eos.Serialize(packed_data); + eos.Finalize(); // Clean up this EOS object so it can be reused. + } + MPI_Bcast(packed_data, packed_size, MPI_BYTE, 0, MPI_COMM_WORLD); + + singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; + char *shared_data; + char *mpi_base_pointer; + int mpi_unit; + MPI_Aint query_size; + MPI_Win window; + MPI_Comm shared_memory_comm; + if (use_mpi_shared_memory) { + // Create the MPI shared memory object and get a pointer to shared data + MPI_Win_allocate_shared((island_rank == 0) ? shared_size : 0, + 1, MPI_INFO_NULL, shared_memory_comm, &mpi_base_pointer, + &window); + MPI_Win_shared_query(window, MPI_PROC_NULL, &query_size, &mpi_unit, &shared_data); + // Mutex for MPI window + MPI_Win_lock_all(MPI_MODE_NOCHECK, window); + // Set SharedMemSettings + settings.data = shared_data; + settings.is_domain_root = (island_rank == 0); + } + eos.DeSerialize(packed_data, settings); + if (use_mpi_shared_memory) { + MPI_Win_unlock_all(window); + MPI_Barrier(shared_memory_comm); + free(packed_data); + } + +.. note:: + + In the case where many EOS objects may be active at once, you can + combine serialization and comm steps. You may wish to, for example, + have a single pointer containing all serialized EOS's. Same for the + shared memory. + +.. warning:: + + Since EOSPAC is a library, DeSerialization is destructive for EOSPAC + and may have side-effects. DeSerializing an EOSPAC object will + *completely* reset the EOSPAC backend. + +.. _`MPI Windows`: https://www.mpi-forum.org/docs/mpi-4.1/mpi41-report/node311.htm + .. _variant section: Variants @@ -445,6 +604,23 @@ unmodified EOS model, call The return value here will be either the type of the ``EOS`` variant type or the unmodified model (for example ``IdealGas``) or, depending + + + + + + + + + + + + + + + + + on whether this method was callled within a variant or on a standalone model outside a variant. diff --git a/singularity-eos/base/constants.hpp b/singularity-eos/base/constants.hpp index 30e43808e9..73934daf31 100644 --- a/singularity-eos/base/constants.hpp +++ b/singularity-eos/base/constants.hpp @@ -39,11 +39,11 @@ constexpr Real ATMOSPHERIC_PRESSURE = 1e6; struct SharedMemSettings { SharedMemSettings() = default; - SharedMemSettings(char *data_, bool is_root_node_) - : data(data_), is_root_node(is_root_node_) {} - bool CopyNeeded() const { return (data != nullptr) && is_root_node; } + SharedMemSettings(char *data_, bool is_domain_root_) + : data(data_), is_domain_root(is_domain_root_) {} + bool CopyNeeded() const { return (data != nullptr) && is_domain_root; } char *data = nullptr; - bool is_root_node = false; // default true or false? + bool is_domain_root = false; // default true or false? }; const SharedMemSettings DEFAULT_SHMEM_STNGS = SharedMemSettings(); From 2942ac161b7ba5a990de268308a61a813cd0fb1b Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Sat, 24 Aug 2024 17:09:00 -0600 Subject: [PATCH 30/48] tests pass with eospac --- singularity-eos/eos/eos_eospac.hpp | 8 +++++--- test/test_eos_tabulated.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index ea769975ee..32a553212c 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -1235,9 +1235,10 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, robust::ratio(dpde_ref_ * cv_ref_, rho_ref_ * rho_ref_ * pressureFromSesame(DPDR)); } -inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return packed_size_; } +inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { + return packed_size_; +} inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { - printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; @@ -1247,9 +1248,10 @@ inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { } inline std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings &stngs) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); - printf("Shared size, packed size = %ld, %ld\n", shared_size_, packed_size_); // DEBUG EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; + eos_DestroyAll(&error_code); + eosCheckError(error_code, "eos_DestroyAll", Verbosity::Debug); #ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY PORTABLE_ALWAYS_REQUIRE( stngs.data != nullptr, diff --git a/test/test_eos_tabulated.cpp b/test/test_eos_tabulated.cpp index 7f8c615537..df80ba360c 100644 --- a/test/test_eos_tabulated.cpp +++ b/test/test_eos_tabulated.cpp @@ -270,9 +270,9 @@ SCENARIO("SpinerEOS and EOSPAC Serialization", SpinerEOSDependsRhoSie rhoSie_orig = SpinerEOSDependsRhoSie(eosName, steelID); EOS eospac_orig = EOSPAC(steelID); THEN("They report dynamic vs static memory correctly") { - REQUIRE(rhoT_orig.StaticMemoryIsThis()); - REQUIRE(rhoSie_orig.StaticMemoryIsThis()); - REQUIRE(!eospac_orig.StaticMemoryIsThis()); + REQUIRE(rhoT_orig.AllDynamicMemoryIsShareable()); + REQUIRE(rhoSie_orig.AllDynamicMemoryIsShareable()); + REQUIRE(!eospac_orig.AllDynamicMemoryIsShareable()); REQUIRE(eospac_orig.SerializedSizeInBytes() > eospac_orig.DynamicMemorySizeInBytes()); } @@ -295,7 +295,6 @@ SCENARIO("SpinerEOS and EOSPAC Serialization", const std::size_t eospac_shared_size = eospac_orig.DynamicMemorySizeInBytes(); REQUIRE(eospac_size > eospac_shared_size); - eospac_orig.Finalize(); THEN("We can deserialize into shared memory") { using singularity::SharedMemSettings; using RhoTTricks = singularity::table_utils::SpinerTricks; @@ -318,9 +317,10 @@ SCENARIO("SpinerEOS and EOSPAC Serialization", REQUIRE(read_size_rhoSie == rhoSie_size); REQUIRE(RhoSieTricks::DataBoxesPointToDifferentMemory(rhoSie_orig, eos_rhoSie)); + eospac_orig.Finalize(); EOS eos_eospac = EOSPAC(); - std::size_t read_size_eospac = eos_rhoSie.DeSerialize( - rhoSie_data, SharedMemSettings(rhoSie_shared_data, true)); + std::size_t read_size_eospac = eos_eospac.DeSerialize( + eospac_data, SharedMemSettings(eospac_shared_data, true)); REQUIRE(read_size_eospac == eospac_size); AND_THEN("EOS lookups work") { From a73245d4f0d28f38a16cf254d50e52d8a57a8ff1 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Sat, 24 Aug 2024 17:09:24 -0600 Subject: [PATCH 31/48] formatting --- singularity-eos/eos/eos_eospac.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index 32a553212c..fc624ced35 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -1235,9 +1235,7 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, robust::ratio(dpde_ref_ * cv_ref_, rho_ref_ * rho_ref_ * pressureFromSesame(DPDR)); } -inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { - return packed_size_; -} +inline std::size_t EOSPAC::DynamicMemorySizeInBytes() const { return packed_size_; } inline std::size_t EOSPAC::DumpDynamicMemory(char *dst) { static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; From 263bea62beaf067c8e654a099e720937ad47cb84 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Sat, 24 Aug 2024 17:27:34 -0600 Subject: [PATCH 32/48] CC, CHANGELOG, and some minor typos --- CHANGELOG.md | 1 + singularity-eos/eos/eos_base.hpp | 2 +- singularity-eos/eos/eos_davis.hpp | 4 ++-- singularity-eos/eos/eos_variant.hpp | 2 +- singularity-eos/eos/modifiers/scaled_eos.hpp | 2 +- singularity-eos/eos/modifiers/shifted_eos.hpp | 2 +- test/test_eos_helmholtz.cpp | 2 +- test/test_eos_ideal.cpp | 2 +- test/test_eos_modifiers.cpp | 2 +- test/test_eos_tabulated.cpp | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a920d422aa..47253aa283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Current develop ### Added (new features/APIs/variables/...) +- [[PR410]](https://github.com/lanl/singularity-eos/pull/410) Enable serialization and de-serialization - [[PR330]](https://github.com/lanl/singularity-eos/pull/330) Piecewise grids for Spiner EOS. ### Fixed (Repair bugs, etc) diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index dc0c8ac9e1..cfeca0c9f5 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/singularity-eos/eos/eos_davis.hpp b/singularity-eos/eos/eos_davis.hpp index f81bca867d..2bfd96ad76 100644 --- a/singularity-eos/eos/eos_davis.hpp +++ b/singularity-eos/eos/eos_davis.hpp @@ -43,8 +43,8 @@ class DavisReactants : public EosBase { DavisReactants GetOnDevice() { return *this; } PORTABLE_INLINE_FUNCTION void CheckParams() const { - PORTABLE_REQUIRE(rho0 >= 0, "Density must be positive"); - PORTABLE_REQUIRE(T0 >= 0, "Temperature must be positive"); + PORTABLE_REQUIRE(_rho0 >= 0, "Density must be positive"); + PORTABLE_REQUIRE(_T0 >= 0, "Temperature must be positive"); } template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index ab8b90ba9b..6b08349aab 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/singularity-eos/eos/modifiers/scaled_eos.hpp b/singularity-eos/eos/modifiers/scaled_eos.hpp index 2c0dd871ab..bf64e90a04 100644 --- a/singularity-eos/eos/modifiers/scaled_eos.hpp +++ b/singularity-eos/eos/modifiers/scaled_eos.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/singularity-eos/eos/modifiers/shifted_eos.hpp b/singularity-eos/eos/modifiers/shifted_eos.hpp index 411a89b333..79eaad6e4e 100644 --- a/singularity-eos/eos/modifiers/shifted_eos.hpp +++ b/singularity-eos/eos/modifiers/shifted_eos.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/test/test_eos_helmholtz.cpp b/test/test_eos_helmholtz.cpp index 2691659c8d..01a2aa1103 100644 --- a/test/test_eos_helmholtz.cpp +++ b/test/test_eos_helmholtz.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/test/test_eos_ideal.cpp b/test/test_eos_ideal.cpp index 0c9ec78675..d33c883ea0 100644 --- a/test/test_eos_ideal.cpp +++ b/test/test_eos_ideal.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/test/test_eos_modifiers.cpp b/test/test_eos_modifiers.cpp index cabccc25f6..12ab05911e 100644 --- a/test/test_eos_modifiers.cpp +++ b/test/test_eos_modifiers.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 diff --git a/test/test_eos_tabulated.cpp b/test/test_eos_tabulated.cpp index df80ba360c..d18969e74d 100644 --- a/test/test_eos_tabulated.cpp +++ b/test/test_eos_tabulated.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 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 From 9d2b76cc13c4322f0aa614d522f843033eaec0c5 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Mon, 26 Aug 2024 15:14:12 -0600 Subject: [PATCH 33/48] Add BulkSerializer --- doc/sphinx/src/using-eos.rst | 95 +++++++++++++++-- singularity-eos/CMakeLists.txt | 1 + singularity-eos/base/serialization_utils.hpp | 105 +++++++++++++++++++ singularity-eos/eos/eos_base.hpp | 6 +- singularity-eos/eos/eos_variant.hpp | 4 +- test/test_eos_modifiers.cpp | 18 +++- 6 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 singularity-eos/base/serialization_utils.hpp diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index dd74f4959a..3468442b4c 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -83,7 +83,17 @@ and returns the number of bytes written to ``dst``. The function .. cpp:function:: std::pair EOS::Serialize(); allocates a ``char*`` pointer to contain serialized data and fills -it. The pair is the pointer and its size. The function +it. + +.. warning:: + + Serialization and de-serialization may only be performed on objects + that live in host memory, before you have called + ``eos.GetOnDevice()``. Attempting to serialize device-initialized + objects is undefined behavior, but will likely result in a + segmentation fault. + +The pair is the pointer and its size. The function .. code-block:: cpp @@ -183,12 +193,85 @@ Putting everything together, a full sequence with MPI might look like this: free(packed_data); } -.. note:: +In the case where many EOS objects may be active at once, you can +combine serialization and comm steps. You may wish to, for example, +have a single pointer containing all serialized EOS's. Same for the +shared memory. ``singularity-eos`` provides machinery to do this in +the ``singularity-eos/base/serialization_utils.hpp`` header. This +provides a helper struct, ``BulkSerializer``: + +.. code-block:: cpp + + template + singularity::BulkSerializer + +which may be initialized by an initializer list of ``EOS`` objects or +a ``std::vector`` of them. It then provides all the above-described +functions: ``SerializedSizeInBytes``, ``SharedMemorySizeInBytes``, +``Serialize``, and ``DeSerialize``, but it operates on all ``EOS`` +objects it was initialized with, not just one. Example usage might +look like this: + +.. code-block:: cpp + + int packed_size, shared_size; + if (rank == 0) { // load eos object + // Code to initialize a bunch of EOS objects into a std::vector + /* + Initialization code goes here + */ + singularity::BulkSerializer serializer(eos_vec); + packed_size = serializer.SerializedSizeInBytes(); + shared_size = serializer.SharedMemorySizeInBytes(); + } + + // Send sizes + MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + + // Allocate data needed + packed_data = (char*)malloc(packed_size); + if (rank == 0) { + serializer.Serialize(packed_data); + serializer.Finalize(); // Clean up all EOSs owned by the serializer + } + MPI_Bcast(packed_data, packed_size, MPI_BYTE, 0, MPI_COMM_WORLD); + + singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; + char *shared_data; + char *mpi_base_pointer; + int mpi_unit; + MPI_Aint query_size; + MPI_Win window; + MPI_Comm shared_memory_comm; + if (use_mpi_shared_memory) { + // Create the MPI shared memory object and get a pointer to shared data + MPI_Win_allocate_shared((island_rank == 0) ? shared_size : 0, + 1, MPI_INFO_NULL, shared_memory_comm, &mpi_base_pointer, + &window); + MPI_Win_shared_query(window, MPI_PROC_NULL, &query_size, &mpi_unit, &shared_data); + // Mutex for MPI window + MPI_Win_lock_all(MPI_MODE_NOCHECK, window); + // Set SharedMemSettings + settings.data = shared_data; + settings.is_domain_root = (island_rank == 0); + } + // note the number of EOSes to deserialize is required. + singularity::BulkSerializer deserializer; + deserializer.DeSerialize(packed_data, settings); + if (use_mpi_shared_memory) { + MPI_Win_unlock_all(window); + MPI_Barrier(shared_memory_comm); + free(packed_data); + } + // extract each individual EOS and do something with it + std::vector eos_host_vec = deserializer.eos_objects; + // get on device if you want + for (auto EOS : eos_host_vec) { + EOS eos_device = eos.GetOnDevice(); + // ... + } - In the case where many EOS objects may be active at once, you can - combine serialization and comm steps. You may wish to, for example, - have a single pointer containing all serialized EOS's. Same for the - shared memory. .. warning:: diff --git a/singularity-eos/CMakeLists.txt b/singularity-eos/CMakeLists.txt index b3d6e17235..669d129b43 100644 --- a/singularity-eos/CMakeLists.txt +++ b/singularity-eos/CMakeLists.txt @@ -27,6 +27,7 @@ register_headers( base/fast-math/logs.hpp base/robust_utils.hpp base/root-finding-1d/root_finding.hpp + base/serialization_utils.hpp base/spiner_table_utils.hpp base/variadic_utils.hpp base/math_utils.hpp diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp new file mode 100644 index 0000000000..be41e39e9d --- /dev/null +++ b/singularity-eos/base/serialization_utils.hpp @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// © 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_BASE_SERIALIZATION_UTILS_ +#define SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ + +#include +#include +#include +#include + +#include +#include + +#include + +namespace singularity { + +template +struct BulkSerializer { + BulkSerializer() = default; + explicit BulkSerializer(const std::initializer_list &eos_objects_) + : eos_objects(eos_objects_) {} + explicit BulkSerializer(const std::vector &eos_objects_) + : eos_objects(eos_objects_) {} + explicit BulkSerializer(const int N) : eos_objects(N) {} + const EOS &Get(std::size_t i) const { return eos_objects[i]; } + EOS &Get(std::size_t i) { return eos_objects[i]; } + void Finalize() { + for (auto &eos : eos_objects) { + eos.Finalize(); + } + } + const auto Size() const { return eos_objects.size(); } + std::size_t SerializedSizeInBytes() const { + return sizeof(std::size_t) + accumulate_([](std::size_t tot, const EOS &eos) { + return tot + eos.SerializedSizeInBytes(); + }); + } + std::size_t SharedMemorySizeInBytes() const { + return accumulate_([](std::size_t tot, const EOS &eos) { + return tot + eos.SharedMemorySizeInBytes(); + }); + } + std::size_t Serialize(char *dst) { + std::size_t vsize = eos_objects.size(); + memcpy(dst, &vsize, sizeof(std::size_t)); + std::size_t offst = sizeof(std::size_t); + for (auto &eos : eos_objects) { + offst += eos.Serialize(dst + offst); + } + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization successful"); + return offst; + } + auto Serialize() { + std::size_t size = SerializedSizeInBytes(); + char *dst = (char *)malloc(size); + std::size_t new_size = Serialize(dst); + PORTABLE_REQUIRE(size == new_size, "Serialization successful"); + return std::make_pair(size, dst); + } + std::size_t DeSerialize(char *src, + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { + std::size_t vsize; + memcpy(&vsize, src, sizeof(std::size_t)); + eos_objects.resize(vsize); + SharedMemSettings stngs_loc = stngs; // non-const + std::size_t offst = sizeof(std::size_t); + std::size_t shared_offst = 0; + for (auto &eos : eos_objects) { + std::size_t shared_bytes = eos.SharedMemorySizeInBytes(); + offst += eos.DeSerialize(src + offst, stngs_loc); + stngs_loc.data += shared_bytes; + shared_offst += shared_bytes; + } + PORTABLE_REQUIRE(offst = SerializedSizeInBytes(), "De-Serialization successful"); + PORTABLE_REQUIRE(shared_offst = SharedMemorySizeInBytes(), + "De-Serialization into shared memory successful"); + return offst; + } + + private: + template + std::size_t accumulate_(const F &f) const { + std::size_t init = 0; + return std::accumulate(eos_objects.cbegin(), eos_objects.cend(), init, f); + } + + public: + std::vector eos_objects; +}; + +} // namespace singularity +#endif // SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index cfeca0c9f5..3b45a17aae 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -700,7 +700,7 @@ class EosBase { offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - PORTABLE_REQUIRE(offst == tot_size, "Serialization succesful"); + PORTABLE_REQUIRE(offst == tot_size, "Serialization successful"); return offst; } auto Serialize() { @@ -708,7 +708,7 @@ class EosBase { std::size_t size = pcrtp->SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t size_new = Serialize(dst); - PORTABLE_REQUIRE(size_new == size, "Serialization succesful"); + PORTABLE_REQUIRE(size_new == size, "Serialization successful"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, @@ -725,7 +725,7 @@ class EosBase { offst += pcrtp->SetDynamicMemory(src + offst, stngs); } const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - PORTABLE_REQUIRE(offst == tot_size, "Deserialization succesful"); + PORTABLE_REQUIRE(offst == tot_size, "Deserialization successful"); return offst; } diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 6b08349aab..301d696cec 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1053,14 +1053,14 @@ class Variant { if (dyn_size > 0) { offst += DumpDynamicMemory(dst + offst); } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization succesful"); + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization successful"); return offst; } auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t new_size = Serialize(dst); - PORTABLE_REQUIRE(size == new_size, "Serialization succesful"); + PORTABLE_REQUIRE(size == new_size, "Serialization successful"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, diff --git a/test/test_eos_modifiers.cpp b/test/test_eos_modifiers.cpp index 12ab05911e..23ac236e91 100644 --- a/test/test_eos_modifiers.cpp +++ b/test/test_eos_modifiers.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -312,28 +313,37 @@ SCENARIO("Serialization of modified EOSs preserves their properties", constexpr Real rho_test = 1.0; constexpr Real sie_test = 1.0; + constexpr Real temp_trivial = sie_test / (Cv); // = 1./2. constexpr Real temp_test = sie_test / (Cv * scale); // = 1./4. constexpr Real EPS = 10 * std::numeric_limits::epsilon(); ScaledEOS eos(IdealGas(gm1, Cv), scale); REQUIRE(isClose(eos.TemperatureFromDensityInternalEnergy(rho_test, sie_test), temp_test, EPS)); + EOS eos_scaled = eos; + + EOS eos_trivial = ScaledEOS(IdealGas(gm1, Cv), 1.0); + REQUIRE(isClose(eos_trivial.TemperatureFromDensityInternalEnergy(rho_test, sie_test), + temp_trivial, EPS)); THEN("The size of the object is larger than just the ideal gas by itself") { REQUIRE(eos.SerializedSizeInBytes() > sizeof(IdealGas)); } WHEN("We serialize the EOS") { - auto [size, data] = eos.Serialize(); - REQUIRE(size == eos.SerializedSizeInBytes()); + singularity::BulkSerializer serializer({eos_scaled, eos_trivial}); + auto [size, data] = serializer.Serialize(); + REQUIRE(size == serializer.SerializedSizeInBytes()); REQUIRE(size > 0); REQUIRE(data != nullptr); THEN("We can de-serialize the EOS") { - ScaledEOS eos_new; - eos_new.DeSerialize(data); + singularity::BulkSerializer deserializer; + deserializer.DeSerialize(data); + REQUIRE(deserializer.Size() == serializer.Size()); AND_THEN("The de-serialized EOS still evaluates properly") { + auto eos_new = deserializer.Get(0); REQUIRE( isClose(eos_new.TemperatureFromDensityInternalEnergy(rho_test, sie_test), temp_test, EPS)); From d8f92c941956b86f177b22d64e9db09cb2f119bf Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Mon, 26 Aug 2024 15:15:04 -0600 Subject: [PATCH 34/48] typos Brandon caught --- doc/sphinx/src/using-eos.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 3468442b4c..749f02c933 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -49,10 +49,10 @@ distributed memory environment. In particular, there are two use-cases the library seeks to support: #. To avoid stressing a filesystem, it may desirable to load a table from one thread (e.g., MPI rank) and broadcast this data to all other ranks. -#. To save memory it may be desirable to place tabulated data, which is read-only after it has been loaded from file, into shared memory on a given node, even if al other data is thread local in a distributed-memory environment. This is possible via, e.g., `MPI Windows`_. +#. To save memory it may be desirable to place tabulated data, which is read-only after it has been loaded from file, into shared memory on a given node, even if all other data is thread local in a distributed-memory environment. This is possible via, e.g., `MPI Windows`_. -Therefore exposes several methods that can be used in this -context. The function +Therefore ``singularity-eos`` exposes several methods that can be used +in this context. The function .. cpp:function:: std::size_t EOS::SerializedSizeInBytes() const; From 7856aa51f8d561e577bf58928b3333c2a7490477 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 14:45:39 -0600 Subject: [PATCH 35/48] typo --- singularity-eos/base/serialization_utils.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp index be41e39e9d..2b10037b6d 100644 --- a/singularity-eos/base/serialization_utils.hpp +++ b/singularity-eos/base/serialization_utils.hpp @@ -84,8 +84,8 @@ struct BulkSerializer { stngs_loc.data += shared_bytes; shared_offst += shared_bytes; } - PORTABLE_REQUIRE(offst = SerializedSizeInBytes(), "De-Serialization successful"); - PORTABLE_REQUIRE(shared_offst = SharedMemorySizeInBytes(), + PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "De-Serialization successful"); + PORTABLE_REQUIRE(shared_offst == SharedMemorySizeInBytes(), "De-Serialization into shared memory successful"); return offst; } From 9f24343b563ea9a26b4473fd0dd2218547c4f61b Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 14:46:08 -0600 Subject: [PATCH 36/48] Update doc/sphinx/src/using-eos.rst Co-authored-by: Jeff Peterson <83598606+jhp-lanl@users.noreply.github.com> --- doc/sphinx/src/using-eos.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 749f02c933..a052c45634 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -68,7 +68,7 @@ returns the amount of data (in bytes) that a given object can place into shared Many models may not be able to utilize shared memory at all. This holds for most analytic models, for example. The ``EOSPAC`` backend - will only utilize shared memory if ``EOSPAC`` is sufficiently recent + will only utilize shared memory if the ``EOSPAC`` version is sufficiently recent to support it and if ``singularity-eos`` is built with serialization support for ``EOSPAC`` (enabled with ``-DSINGULARITY_EOSPAC_ENABLE_SHMEM=ON``). From 1214961ee87c93fa66a698745a4f644a56e38e84 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 14:48:13 -0600 Subject: [PATCH 37/48] jhp suggested doc changes --- doc/sphinx/src/using-eos.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 749f02c933..a3016ae345 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -115,8 +115,8 @@ and a ``is_domain_root`` boolean: SharedMemSettings(); SharedMemSettings(char *data_, bool is_domain_root_) : data(data_), is_domain_root(is_domain_root_) {} - char *data; - bool is_domain_root; + char *data = nullptr; // defaults + bool is_domain_root = false; }; The ``data`` pointer should point to a shared memory allocation. The @@ -276,8 +276,7 @@ look like this: .. warning:: Since EOSPAC is a library, DeSerialization is destructive for EOSPAC - and may have side-effects. DeSerializing an EOSPAC object will - *completely* reset the EOSPAC backend. + and may have side-effects. .. _`MPI Windows`: https://www.mpi-forum.org/docs/mpi-4.1/mpi41-report/node311.htm From f190325731a7dfae2e17774aa9a95dbc78657196 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 15:47:55 -0600 Subject: [PATCH 38/48] jhp comments round 2 --- doc/sphinx/src/using-eos.rst | 42 ++++++++++++---- singularity-eos/base/serialization_utils.hpp | 52 +++++++++++++------- singularity-eos/eos/eos_base.hpp | 6 +-- singularity-eos/eos/eos_eospac.hpp | 5 +- singularity-eos/eos/eos_variant.hpp | 4 +- test/test_eos_modifiers.cpp | 6 +-- test/test_get_sg_eos.cpp | 3 +- 7 files changed, 79 insertions(+), 39 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 648a3d427f..a7d0b6a2ae 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -202,15 +202,35 @@ provides a helper struct, ``BulkSerializer``: .. code-block:: cpp - template + template singularity::BulkSerializer -which may be initialized by an initializer list of ``EOS`` objects or -a ``std::vector`` of them. It then provides all the above-described -functions: ``SerializedSizeInBytes``, ``SharedMemorySizeInBytes``, -``Serialize``, and ``DeSerialize``, but it operates on all ``EOS`` -objects it was initialized with, not just one. Example usage might -look like this: +which may be initialized by a collection of ``EOS`` objects or by +simply assigning (or constructing) its member field, ``eos_objects`` +appropriately. An example ``Container_t`` might be +``Kokkos::View`` or ``std::vector``. A specialization for +``vector`` is provided as ``VectorSerializer`` and, if ``Kokkos`` is +enabled through ``ports-of-call``, a ``ViewSerializer`` is also +provided. The ``Resizer_t`` is a functor that knows how to resize a +collection. For example, the ``MemberResizor`` functor used for +``std::vector``s + +.. code-block:: cpp + + struct MemberResizer { + template + void operator()(Collection_t &collection, std::size_t count) { + collection.resize(count); + } + }; + +which will work for any ``stl`` container with a ``resize`` method. + +The ``BulkSerializer`` provides all the above-described serialization +functions for ``EOS`` objects: ``SerializedSizeInBytes``, +``SharedMemorySizeInBytes``, ``Serialize``, and ``DeSerialize``, but +it operates on all ``EOS`` objects contained in the container it +wraps, not just one. Example usage might look like this: .. code-block:: cpp @@ -220,7 +240,7 @@ look like this: /* Initialization code goes here */ - singularity::BulkSerializer serializer(eos_vec); + singularity::VectorSerializer serializer(eos_vec); packed_size = serializer.SerializedSizeInBytes(); shared_size = serializer.SharedMemorySizeInBytes(); } @@ -257,7 +277,7 @@ look like this: settings.is_domain_root = (island_rank == 0); } // note the number of EOSes to deserialize is required. - singularity::BulkSerializer deserializer; + singularity::VectorSerializer deserializer; deserializer.DeSerialize(packed_data, settings); if (use_mpi_shared_memory) { MPI_Win_unlock_all(window); @@ -272,6 +292,10 @@ look like this: // ... } +It is also possible to (with care) mix serializers... i.e., you might +serialize with a ``VectorSerializer`` and de-serialize with a +``ViewSerializer``, as all that is required is that a container have a +``size``, provide iterators, and be capable of being resized. .. warning:: diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp index 2b10037b6d..c4c001f404 100644 --- a/singularity-eos/base/serialization_utils.hpp +++ b/singularity-eos/base/serialization_utils.hpp @@ -15,7 +15,6 @@ #ifndef SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ #define SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ -#include #include #include #include @@ -27,16 +26,12 @@ namespace singularity { -template +template struct BulkSerializer { + Container_t eos_objects; + BulkSerializer() = default; - explicit BulkSerializer(const std::initializer_list &eos_objects_) - : eos_objects(eos_objects_) {} - explicit BulkSerializer(const std::vector &eos_objects_) - : eos_objects(eos_objects_) {} - explicit BulkSerializer(const int N) : eos_objects(N) {} - const EOS &Get(std::size_t i) const { return eos_objects[i]; } - EOS &Get(std::size_t i) { return eos_objects[i]; } + BulkSerializer(const Container_t &eos_objects_) : eos_objects(eos_objects_) {} void Finalize() { for (auto &eos : eos_objects) { eos.Finalize(); @@ -44,12 +39,12 @@ struct BulkSerializer { } const auto Size() const { return eos_objects.size(); } std::size_t SerializedSizeInBytes() const { - return sizeof(std::size_t) + accumulate_([](std::size_t tot, const EOS &eos) { + return sizeof(std::size_t) + accumulate_([](std::size_t tot, const auto &eos) { return tot + eos.SerializedSizeInBytes(); }); } std::size_t SharedMemorySizeInBytes() const { - return accumulate_([](std::size_t tot, const EOS &eos) { + return accumulate_([](std::size_t tot, const auto &eos) { return tot + eos.SharedMemorySizeInBytes(); }); } @@ -60,21 +55,21 @@ struct BulkSerializer { for (auto &eos : eos_objects) { offst += eos.Serialize(dst + offst); } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(offst == SerializedSizeInBytes(), "Serialization failed!"); return offst; } auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t new_size = Serialize(dst); - PORTABLE_REQUIRE(size == new_size, "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(size == new_size, "Serialization failed!"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) { std::size_t vsize; memcpy(&vsize, src, sizeof(std::size_t)); - eos_objects.resize(vsize); + Resizer_t()(eos_objects, vsize); SharedMemSettings stngs_loc = stngs; // non-const std::size_t offst = sizeof(std::size_t); std::size_t shared_offst = 0; @@ -84,9 +79,9 @@ struct BulkSerializer { stngs_loc.data += shared_bytes; shared_offst += shared_bytes; } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "De-Serialization successful"); - PORTABLE_REQUIRE(shared_offst == SharedMemorySizeInBytes(), - "De-Serialization into shared memory successful"); + PORTABLE_ALWAYS_REQUIRE(offst == SerializedSizeInBytes(), "De-Serialization failed!"); + PORTABLE_ALWAYS_REQUIRE(shared_offst == SharedMemorySizeInBytes(), + "De-Serialization into shared memory failed!"); return offst; } @@ -96,10 +91,29 @@ struct BulkSerializer { std::size_t init = 0; return std::accumulate(eos_objects.cbegin(), eos_objects.cend(), init, f); } +}; + +struct MemberResizer { + template + void operator()(Collection_t &collection, std::size_t count) { + collection.resize(count); + } +}; + +template +using VectorSerializer = BulkSerializer, MemberResizer>; - public: - std::vector eos_objects; +#ifdef PORTABILITY_STRATEGY_KOKKOS +struct ViewResizer { + template + void operator()(Collection_t &collection, std::size_t count) { + Kokkos::resize(collection, count); + } }; +template +using ViewSerializer = + BulkSerializer::HostMirror, ViewResizer>; +#endif // PORTABILITY_STRATEGY_KOKKOS } // namespace singularity #endif // SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index 3b45a17aae..ac18c84f1e 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -700,7 +700,7 @@ class EosBase { offst += pcrtp->DumpDynamicMemory(dst + sizeof(CRTP)); } const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - PORTABLE_REQUIRE(offst == tot_size, "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(offst == tot_size, "Serialization failed!"); return offst; } auto Serialize() { @@ -708,7 +708,7 @@ class EosBase { std::size_t size = pcrtp->SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t size_new = Serialize(dst); - PORTABLE_REQUIRE(size_new == size, "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(size_new == size, "Serialization failed!"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, @@ -725,7 +725,7 @@ class EosBase { offst += pcrtp->SetDynamicMemory(src + offst, stngs); } const std::size_t tot_size = pcrtp->SerializedSizeInBytes(); - PORTABLE_REQUIRE(offst == tot_size, "Deserialization successful"); + PORTABLE_ALWAYS_REQUIRE(offst == tot_size, "Deserialization failed!"); return offst; } diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index fc624ced35..e65c71d95c 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -141,7 +141,9 @@ class EOSPAC : public EosBase { eospacSplit apply_splitting = eospacSplit::none, bool linear_interp = false); PORTABLE_INLINE_FUNCTION void CheckParams() const { - // TODO(JMM): I really don't know what to put here... + // TODO(JMM): More validation checks? + PORTABLE_ALWAYS_REQUIRE(rho_min_ >= 0, "Non-negative minimum density"); + PORTABLE_ALWAYS_REQUIRE(temp_min_ >= 0, "Non-negative minimum temperature"); } inline EOSPAC GetOnDevice() { return *this; } @@ -1248,7 +1250,6 @@ inline std::size_t EOSPAC::SetDynamicMemory(char *src, const SharedMemSettings & static_assert(sizeof(char) == sizeof(EOS_CHAR), "EOS_CHAR is one byte"); EOS_INTEGER NTABLES[] = {NT}; EOS_INTEGER error_code = EOS_OK; - eos_DestroyAll(&error_code); eosCheckError(error_code, "eos_DestroyAll", Verbosity::Debug); #ifdef SINGULARITY_EOSPAC_ENABLE_SHARED_MEMORY PORTABLE_ALWAYS_REQUIRE( diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 301d696cec..22bed2ba69 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1053,14 +1053,14 @@ class Variant { if (dyn_size > 0) { offst += DumpDynamicMemory(dst + offst); } - PORTABLE_REQUIRE(offst == SerializedSizeInBytes(), "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(offst == SerializedSizeInBytes(), "Serialization failed!"); return offst; } auto Serialize() { std::size_t size = SerializedSizeInBytes(); char *dst = (char *)malloc(size); std::size_t new_size = Serialize(dst); - PORTABLE_REQUIRE(size == new_size, "Serialization successful"); + PORTABLE_ALWAYS_REQUIRE(size == new_size, "Serialization failed!"); return std::make_pair(size, dst); } std::size_t DeSerialize(char *src, diff --git a/test/test_eos_modifiers.cpp b/test/test_eos_modifiers.cpp index 23ac236e91..24619fd458 100644 --- a/test/test_eos_modifiers.cpp +++ b/test/test_eos_modifiers.cpp @@ -331,19 +331,19 @@ SCENARIO("Serialization of modified EOSs preserves their properties", } WHEN("We serialize the EOS") { - singularity::BulkSerializer serializer({eos_scaled, eos_trivial}); + singularity::VectorSerializer serializer({eos_scaled, eos_trivial}); auto [size, data] = serializer.Serialize(); REQUIRE(size == serializer.SerializedSizeInBytes()); REQUIRE(size > 0); REQUIRE(data != nullptr); THEN("We can de-serialize the EOS") { - singularity::BulkSerializer deserializer; + singularity::VectorSerializer deserializer; deserializer.DeSerialize(data); REQUIRE(deserializer.Size() == serializer.Size()); AND_THEN("The de-serialized EOS still evaluates properly") { - auto eos_new = deserializer.Get(0); + auto eos_new = deserializer.eos_objects[0]; REQUIRE( isClose(eos_new.TemperatureFromDensityInternalEnergy(rho_test, sie_test), temp_test, EPS)); diff --git a/test/test_get_sg_eos.cpp b/test/test_get_sg_eos.cpp index 7a9ea0c6b6..686f10b39a 100644 --- a/test/test_get_sg_eos.cpp +++ b/test/test_get_sg_eos.cpp @@ -82,7 +82,8 @@ int run_sg_get_eos_tests() { } // obtain converged and consistent PTE solution // do rho-T input solve - Real p_check, vfrac_check[NMAT], ie_check[NMAT]; + Real p_check = 1; // sanitize pressure guess + Real vfrac_check[NMAT], ie_check[NMAT]; get_sg_eos(NMAT, 1, 1, -3, eos_offset, eoss, &cell_offset, &p_check, &pmax, &v_true, &spvol, &sie_tot_check, &T_true_ev, &bmod, &dpde, &cv, mfrac, vfrac_check, ie_check, nullptr, nullptr, nullptr, 1.0e-12); From 44650e6ad0ec9f4850fba26f5b4f43f13820b334 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 15:48:13 -0600 Subject: [PATCH 39/48] Update singularity-eos/eos/eos_gruneisen.hpp Co-authored-by: Jeff Peterson <83598606+jhp-lanl@users.noreply.github.com> --- singularity-eos/eos/eos_gruneisen.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/singularity-eos/eos/eos_gruneisen.hpp b/singularity-eos/eos/eos_gruneisen.hpp index 3ac2f9dd8c..29361b23ea 100644 --- a/singularity-eos/eos/eos_gruneisen.hpp +++ b/singularity-eos/eos/eos_gruneisen.hpp @@ -65,8 +65,11 @@ class Gruneisen : public EosBase { const Real s3, const Real rho0); PORTABLE_INLINE_FUNCTION void CheckParams() const { - PORTABLE_ALWAYS_REQUIRE(_T0 >= 0, "Non-negative reference temperature"); - PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Non-negative reference density"); + PORTABLE_ALWAYS_REQUIRE(_T0 >= 0, "Non-negative reference temperature required"); + PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Non-negative reference density required"); + PORTABLE_ALWAYS_REQUIRE(_C0 >= 0, "Non-negative Hugoniot intercept required"); + PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Non-negative heat capacity required"); + PORTABLE_ALWAYS_REQUIRE(_rho_max > _rho0, "Maximum density must be greater than reference"); } PORTABLE_INLINE_FUNCTION Real MaxStableDensityAtTemperature(const Real temperature) const; From b16e9f55031d9747bc4fd68839e68abaa0f1ee1d Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 15:50:43 -0600 Subject: [PATCH 40/48] formatting --- singularity-eos/eos/eos_gruneisen.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/singularity-eos/eos/eos_gruneisen.hpp b/singularity-eos/eos/eos_gruneisen.hpp index 29361b23ea..18a3a921c8 100644 --- a/singularity-eos/eos/eos_gruneisen.hpp +++ b/singularity-eos/eos/eos_gruneisen.hpp @@ -69,7 +69,8 @@ class Gruneisen : public EosBase { PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Non-negative reference density required"); PORTABLE_ALWAYS_REQUIRE(_C0 >= 0, "Non-negative Hugoniot intercept required"); PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Non-negative heat capacity required"); - PORTABLE_ALWAYS_REQUIRE(_rho_max > _rho0, "Maximum density must be greater than reference"); + PORTABLE_ALWAYS_REQUIRE(_rho_max > _rho0, + "Maximum density must be greater than reference"); } PORTABLE_INLINE_FUNCTION Real MaxStableDensityAtTemperature(const Real temperature) const; From ee7b62e3435d4fbaf73edff8103f936e67739998 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 17:31:01 -0600 Subject: [PATCH 41/48] extended MPI example a bit --- doc/sphinx/src/using-eos.rst | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index a7d0b6a2ae..fdd2c248a7 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -167,20 +167,37 @@ Putting everything together, a full sequence with MPI might look like this: } MPI_Bcast(packed_data, packed_size, MPI_BYTE, 0, MPI_COMM_WORLD); + // the default doesn't do shared memory. + // we will change it below if shared memory is enabled. singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; + char *shared_data; char *mpi_base_pointer; int mpi_unit; MPI_Aint query_size; MPI_Win window; MPI_Comm shared_memory_comm; + int island_rank, island_size; // rank in, size of shared memory region if (use_mpi_shared_memory) { + // Generate shared memory comms + MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &shared_memory_comm); + // rank on a region that shares memory + MPI_Comm_rank(shared_memory_comm, &island_rank); + // size on a region that shares memory + MPI_COMM_size(shared_memory_comm, &island_size); + // Create the MPI shared memory object and get a pointer to shared data + // this allocation is a collective and must be called on every rank. + // the total size of the allocation is the sum over ranks in the shared memory comm + // of requested memory. So it's valid to request all you want on rank 0 and nothing + // on the remaining ranks. MPI_Win_allocate_shared((island_rank == 0) ? shared_size : 0, 1, MPI_INFO_NULL, shared_memory_comm, &mpi_base_pointer, &window); + // This gets a pointer to the shared memory allocation valid in local address space + // on every rank MPI_Win_shared_query(window, MPI_PROC_NULL, &query_size, &mpi_unit, &shared_data); - // Mutex for MPI window + // Mutex for MPI window. Writing to shared memory currently allowed. MPI_Win_lock_all(MPI_MODE_NOCHECK, window); // Set SharedMemSettings settings.data = shared_data; @@ -188,7 +205,7 @@ Putting everything together, a full sequence with MPI might look like this: } eos.DeSerialize(packed_data, settings); if (use_mpi_shared_memory) { - MPI_Win_unlock_all(window); + MPI_Win_unlock_all(window); // Writing to shared memory disabled. MPI_Barrier(shared_memory_comm); free(packed_data); } From b7cd6cd8eecd8fa5ecc658d1f19de46f7cc3d749 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 17:35:41 -0600 Subject: [PATCH 42/48] update docs with MPI info --- doc/sphinx/src/using-eos.rst | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index fdd2c248a7..dc89dfa655 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -275,31 +275,16 @@ wraps, not just one. Example usage might look like this: MPI_Bcast(packed_data, packed_size, MPI_BYTE, 0, MPI_COMM_WORLD); singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; - char *shared_data; - char *mpi_base_pointer; - int mpi_unit; - MPI_Aint query_size; - MPI_Win window; - MPI_Comm shared_memory_comm; + // same MPI declarations as above if (use_mpi_shared_memory) { - // Create the MPI shared memory object and get a pointer to shared data - MPI_Win_allocate_shared((island_rank == 0) ? shared_size : 0, - 1, MPI_INFO_NULL, shared_memory_comm, &mpi_base_pointer, - &window); - MPI_Win_shared_query(window, MPI_PROC_NULL, &query_size, &mpi_unit, &shared_data); - // Mutex for MPI window - MPI_Win_lock_all(MPI_MODE_NOCHECK, window); - // Set SharedMemSettings + // same MPI code as above including setting the settings settings.data = shared_data; settings.is_domain_root = (island_rank == 0); } - // note the number of EOSes to deserialize is required. singularity::VectorSerializer deserializer; deserializer.DeSerialize(packed_data, settings); if (use_mpi_shared_memory) { - MPI_Win_unlock_all(window); - MPI_Barrier(shared_memory_comm); - free(packed_data); + // same MPI code as above } // extract each individual EOS and do something with it std::vector eos_host_vec = deserializer.eos_objects; From a0cc47ad36374ca8fa3a9b30d8b2b4bcd128256c Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 17:44:03 -0600 Subject: [PATCH 43/48] oops scoping --- doc/sphinx/src/using-eos.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index dc89dfa655..894e3bc791 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -252,12 +252,13 @@ wraps, not just one. Example usage might look like this: .. code-block:: cpp int packed_size, shared_size; + singularity::VectorSerializer serializer; if (rank == 0) { // load eos object // Code to initialize a bunch of EOS objects into a std::vector /* Initialization code goes here */ - singularity::VectorSerializer serializer(eos_vec); + serializer = singularity::VectorSerializer(eos_vec); packed_size = serializer.SerializedSizeInBytes(); shared_size = serializer.SharedMemorySizeInBytes(); } From 5d7cb38f7d508b7b4cb1d01a19c5b49b67f7aebf Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 17:50:58 -0600 Subject: [PATCH 44/48] actually we can't use views they don't have built in iterators... only in experimental. --- doc/sphinx/src/using-eos.rst | 14 ++++++-------- singularity-eos/base/serialization_utils.hpp | 12 ------------ 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 894e3bc791..27c90609a3 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -225,12 +225,10 @@ provides a helper struct, ``BulkSerializer``: which may be initialized by a collection of ``EOS`` objects or by simply assigning (or constructing) its member field, ``eos_objects`` appropriately. An example ``Container_t`` might be -``Kokkos::View`` or ``std::vector``. A specialization for -``vector`` is provided as ``VectorSerializer`` and, if ``Kokkos`` is -enabled through ``ports-of-call``, a ``ViewSerializer`` is also -provided. The ``Resizer_t`` is a functor that knows how to resize a -collection. For example, the ``MemberResizor`` functor used for -``std::vector``s +``std::vector``. A specialization for ``vector`` is provided as +``VectorSerializer``. The ``Resizer_t`` is a functor that knows how to +resize a collection. For example, the ``MemberResizor`` functor used +for ``std::vector``s .. code-block:: cpp @@ -297,8 +295,8 @@ wraps, not just one. Example usage might look like this: It is also possible to (with care) mix serializers... i.e., you might serialize with a ``VectorSerializer`` and de-serialize with a -``ViewSerializer``, as all that is required is that a container have a -``size``, provide iterators, and be capable of being resized. +different container, as all that is required is that a container have +a ``size``, provide iterators, and be capable of being resized. .. warning:: diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp index c4c001f404..909ffe6fb1 100644 --- a/singularity-eos/base/serialization_utils.hpp +++ b/singularity-eos/base/serialization_utils.hpp @@ -103,17 +103,5 @@ struct MemberResizer { template using VectorSerializer = BulkSerializer, MemberResizer>; -#ifdef PORTABILITY_STRATEGY_KOKKOS -struct ViewResizer { - template - void operator()(Collection_t &collection, std::size_t count) { - Kokkos::resize(collection, count); - } -}; -template -using ViewSerializer = - BulkSerializer::HostMirror, ViewResizer>; -#endif // PORTABILITY_STRATEGY_KOKKOS - } // namespace singularity #endif // SINGULARITY_EOS_BASE_SERIALIZATION_UTILS_ From 8375015ca559119650c5936ba591de4783e386ba Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 27 Aug 2024 17:52:39 -0600 Subject: [PATCH 45/48] Default Resizer is MemberResizer. --- doc/sphinx/src/using-eos.rst | 2 +- singularity-eos/base/serialization_utils.hpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 27c90609a3..4f6927e297 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -219,7 +219,7 @@ provides a helper struct, ``BulkSerializer``: .. code-block:: cpp - template + template singularity::BulkSerializer which may be initialized by a collection of ``EOS`` objects or by diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp index 909ffe6fb1..34e8b1aae5 100644 --- a/singularity-eos/base/serialization_utils.hpp +++ b/singularity-eos/base/serialization_utils.hpp @@ -26,7 +26,14 @@ namespace singularity { -template +struct MemberResizer { + template + void operator()(Collection_t &collection, std::size_t count) { + collection.resize(count); + } +}; + +template struct BulkSerializer { Container_t eos_objects; @@ -93,13 +100,6 @@ struct BulkSerializer { } }; -struct MemberResizer { - template - void operator()(Collection_t &collection, std::size_t count) { - collection.resize(count); - } -}; - template using VectorSerializer = BulkSerializer, MemberResizer>; From b403596e5f96aacb62f9e98ece879010e8028424 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Thu, 29 Aug 2024 13:16:44 -0600 Subject: [PATCH 46/48] doc typo thanks Brandon for the catch --- doc/sphinx/src/using-eos.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 4f6927e297..3570744f6a 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -157,7 +157,7 @@ Putting everything together, a full sequence with MPI might look like this: // Send sizes MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&shared_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&spacked_size, 1, MPI_INT, 0, MPI_COMM_WORLD); // Allocate data needed packed_data = (char*)malloc(packed_size); From 00a191b4f5f30414470bb3de247ec48e8bfdb011 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Tue, 3 Sep 2024 12:57:54 -0600 Subject: [PATCH 47/48] dholladay comments --- doc/sphinx/src/using-eos.rst | 33 +++++---------------- singularity-eos/base/spiner_table_utils.hpp | 8 ++++- singularity-eos/eos/eos_base.hpp | 17 +++++++++++ singularity-eos/eos/eos_variant.hpp | 14 +++++++++ 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 3570744f6a..fe570ad625 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -98,7 +98,7 @@ The pair is the pointer and its size. The function .. code-block:: cpp std::size_t EOS::DeSerialize(char *src, - const SharedMemSettings &stngs = DEFAULT_SHMEM_SETTINGS) + const SharedMemSettings &stngs = DEFAULT_SHMEM_STNGS) Sets an EOS object based on the serialized representation contained in ``src``. It returns the number of bytes read from ``src``. Optionally, @@ -156,8 +156,8 @@ Putting everything together, a full sequence with MPI might look like this: } // Send sizes - MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&spacked_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&packed_size, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&spacked_size, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); // Allocate data needed packed_data = (char*)malloc(packed_size); @@ -169,7 +169,7 @@ Putting everything together, a full sequence with MPI might look like this: // the default doesn't do shared memory. // we will change it below if shared memory is enabled. - singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; + singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_STNGS; char *shared_data; char *mpi_base_pointer; @@ -262,8 +262,8 @@ wraps, not just one. Example usage might look like this: } // Send sizes - MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&packed_size, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&packed_size, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + MPI_Bcast(&packed_size, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); // Allocate data needed packed_data = (char*)malloc(packed_size); @@ -273,7 +273,7 @@ wraps, not just one. Example usage might look like this: } MPI_Bcast(packed_data, packed_size, MPI_BYTE, 0, MPI_COMM_WORLD); - singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_SETTINGS; + singularity::SharedMemSettings settings = singularity::DEFAULT_SHMEM_STNGS; // same MPI declarations as above if (use_mpi_shared_memory) { // same MPI code as above including setting the settings @@ -710,24 +710,7 @@ unmodified EOS model, call .. cpp:function:: auto GetUnmodifiedObject(); The return value here will be either the type of the ``EOS`` variant -type or the unmodified model (for example ``IdealGas``) or, depending - - - - - - - - - - - - - - - - - +type or the unmodified model (for example ``IdealGas``), depending on whether this method was callled within a variant or on a standalone model outside a variant. diff --git a/singularity-eos/base/spiner_table_utils.hpp b/singularity-eos/base/spiner_table_utils.hpp index 601e95c324..06b167e244 100644 --- a/singularity-eos/base/spiner_table_utils.hpp +++ b/singularity-eos/base/spiner_table_utils.hpp @@ -284,7 +284,13 @@ class Bounds { }; // JMM: Making this a struct with static methods, rather than a -// namespace, saves a few "friend" declarations +// namespace, saves a few "friend" declarations. Broadly these methods +// rely on the EOS providing a `GetDataBoxPointers_` method and +// declaring this class a friend. Doing so lets us loop over each data +// box member of a spiner-based EOS ond operate on it. For example, by +// calling `finalize` or `getOnDevice`. The intent here is that the +// static methods of `SpinerTricks` are called from class methods of +// spiner-based EOS's. template struct SpinerTricks { static auto GetOnDevice(EOS *peos_h) { diff --git a/singularity-eos/eos/eos_base.hpp b/singularity-eos/eos/eos_base.hpp index ac18c84f1e..0d627e75fe 100644 --- a/singularity-eos/eos/eos_base.hpp +++ b/singularity-eos/eos/eos_base.hpp @@ -671,6 +671,21 @@ class EosBase { } // Serialization + /* + The methodology here is there are *three* size methods all EOS's provide: + - `SharedMemorySizeInBytes()` which is the amount of memory a class can share + - `DynamicMemorySizeInBytes()` which is the amount of memory not covered by + `sizeof(this)` + - `SerializedSizeInBytes()` which is the total size of the object. + + I wanted serialization machinery to work if you use a standalone + class or if you use the variant. To make that possible, each class + provides its own implementation of `SharedMemorySizeInBytes` and + `DynamicMemorySizeInBytes()`. But then there is a separate + implementation for the variant and for the base class for + `SerializedSizeInBytes`, `Serialize`, and `DeSerialize`. + */ + // JMM: These must frequently be special-cased. std::size_t DynamicMemorySizeInBytes() const { return 0; } std::size_t DumpDynamicMemory(char *dst) { return 0; } @@ -685,6 +700,8 @@ class EosBase { } constexpr bool AllDynamicMemoryIsShareable() const { return true; } // JMM: These are generic and never need to be special-cased. + // However, there must be a separate implementation for these + // separately in the base class and in the variant. std::size_t SerializedSizeInBytes() const { // sizeof(*this) returns the size of JUST the base class. const CRTP *pcrtp = static_cast(this); diff --git a/singularity-eos/eos/eos_variant.hpp b/singularity-eos/eos/eos_variant.hpp index 22bed2ba69..507e888423 100644 --- a/singularity-eos/eos/eos_variant.hpp +++ b/singularity-eos/eos/eos_variant.hpp @@ -1020,6 +1020,20 @@ class Variant { } // Serialization + /* + The methodology here is there are *three* size methods all EOS's provide: + - `SharedMemorySizeInBytes()` which is the amount of memory a class can share + - `DynamicMemorySizeInBytes()` which is the amount of memory not covered by + `sizeof(this)` + - `SerializedSizeInBytes()` which is the total size of the object. + + I wanted serialization machinery to work if you use a standalone + class or if you use the variant. To make that possible, each class + provides its own implementation of `SharedMemorySizeInBytes` and + `DynamicMemorySizeInBytes()`. But then there is a separate + implementation for the variant and for the base class for + `SerializedSizeInBytes`, `Serialize`, and `DeSerialize`. + */ // JMM: This must be implemented separately for Variant vs the base // class/individual EOS's so that the variant state is properly // carried. Otherwise de-serialization would need to specify a type. From a8c43bdf10cdb268fe49304fb6ddf46cf18adeb0 Mon Sep 17 00:00:00 2001 From: Jonah Miller Date: Thu, 5 Sep 2024 17:04:39 -0600 Subject: [PATCH 48/48] bug in deserialize based on when SharedMemorySizeInBytes is available --- singularity-eos/base/serialization_utils.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/singularity-eos/base/serialization_utils.hpp b/singularity-eos/base/serialization_utils.hpp index 34e8b1aae5..2c3028d54f 100644 --- a/singularity-eos/base/serialization_utils.hpp +++ b/singularity-eos/base/serialization_utils.hpp @@ -81,8 +81,9 @@ struct BulkSerializer { std::size_t offst = sizeof(std::size_t); std::size_t shared_offst = 0; for (auto &eos : eos_objects) { - std::size_t shared_bytes = eos.SharedMemorySizeInBytes(); offst += eos.DeSerialize(src + offst, stngs_loc); + // needs to be after eos.Deserialize so type/size are unpacked + std::size_t shared_bytes = eos.SharedMemorySizeInBytes(); stngs_loc.data += shared_bytes; shared_offst += shared_bytes; }