Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EOSBuilder rewrite #311

Merged
merged 27 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
69273cb
Add Modify functionality. Still debugging.
jonahm-LANL Oct 13, 2023
0c6ec66
Merge branch 'main' into jmm/build-rewrite
jonahm-LANL Oct 13, 2023
9fd225e
IT WORKS
jonahm-LANL Oct 13, 2023
c64c62b
update
jonahm-LANL Oct 13, 2023
b3a8bef
oops wrong location for return type
jonahm-LANL Oct 13, 2023
4da7614
remove unneeded includes in eos_builder.hpp
jonahm-LANL Oct 13, 2023
4baef28
CHANGELOG
jonahm-LANL Oct 13, 2023
a44c73e
Mark ModifyDispatcher constexpr auto
jonahm-LANL Oct 16, 2023
e919d56
Rename types namespace to variadic_utils
jonahm-LANL Oct 18, 2023
38ab314
Remove eos.cpp file so we can be header only without the fortran bind…
jonahm-LANL Oct 18, 2023
dea245f
formatting
jonahm-LANL Oct 18, 2023
f5e2583
add some useful variadic utils and tests for them. hopefully provides…
jonahm-LANL Oct 18, 2023
9de904b
include eos.cpp
jonahm-LANL Oct 18, 2023
d799a40
oops wrong file path
jonahm-LANL Oct 18, 2023
3bee053
Merge branch 'main' into jmm/build-rewrite
Yurlungur Oct 18, 2023
790f176
typo
jonahm-LANL Oct 18, 2023
62e954d
formatting
jonahm-LANL Oct 18, 2023
1e021a3
Merge branch 'main' into jmm/build-rewrite
Yurlungur Oct 25, 2023
2b819fc
missing semicolon
jonahm-LANL Oct 25, 2023
2b7cb3f
add overload for typelist
jonahm-LANL Oct 25, 2023
eac1744
Merge branch 'jmm/build-rewrite' of github.com:lanl/singularity-eos i…
jonahm-LANL Oct 25, 2023
1380a42
starting to mess with daniels design
jonahm-LANL Nov 27, 2023
068b30a
build a simpler, faster, CRTP based modifier API. Thanks, Daniel
jonahm-LANL Nov 28, 2023
de95ba0
merge in main
jonahm-LANL Nov 28, 2023
cfdd82d
Merge branch 'main' into jmm/build-rewrite
Yurlungur Nov 28, 2023
b04303d
Merge branch 'main' into jmm/build-rewrite
Yurlungur Nov 29, 2023
b3d40b3
final comment from Daniel
jonahm-LANL Nov 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Date: 11/28/2023
- [[PR177]](https://github.com/lanl/singularity-eos/pull/177) added EOSPAC vector functions

### Changed (changing behavior/API/variables/...)
- [[PR311]](https://github.com/lanl/singularity-eos/pull/311) Refactor EOSBuilder for flexibility and extensibility
- [[PR310]](https://github.com/lanl/singularity-eos/pull/310) Speed up and clean up tests
- [[PR295]](https://github.com/lanl/singularity-eos/pull/295) Add fast logs to singularity-eos
- [[PR246]](https://github.com/lanl/singularity-eos/pull/246) Update CMake with upstream changes
Expand Down
13 changes: 13 additions & 0 deletions doc/sphinx/src/modifiers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,19 @@ Modifiers can be composed. For example:
using namespace singularity;
auto my_eos = ShiftedEOS<ScaledEOS<IdealGas>>(ScaledEOS(IdealGas(gm1, Cv), scale), shift);

You can build modifiers up iteratively by, for example:

.. code-block:: cpp

using namespace singularity;
EOS eos = IdealGas(gm1, cv);
if (do_shift) {
eos = eos.template Modify<ShiftedEOS>(shift);
}
if (do_scale) {
eos = eos.template Modify<ScaledEOS>(scale);
}

Undoing Modifiers
------------------

Expand Down
74 changes: 49 additions & 25 deletions doc/sphinx/src/using-eos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,34 @@ modifiers. However, note that modifiers do not commute, and only one
order is supported. The ordering, inside-out, is ``UnitSystem`` or
``RelativisticEOS``, then ``ScaledEOS``, then ``ShiftedEOS``.

A modified equation of state can be built up iteratively. To check if
the equation of state currently stored in the variant can modified,
you may call

.. cpp:function:: bool ModifiedInVariant<Mod>() const;

where ``Mod`` is the type of the modifier you want to apply, for
example ``ShiftedEOS``. If this function returns true, then you can
apply a modifier with the function

.. cpp:function:: Variant Modify<Mod>(Args &&..args) const;

where again ``Mod`` is the modifier you wish to apply, and ``args``
are the arguments to the constructor for that modifier, e.g., the
shift. For example, one might build up a shifted or scaled eos with a
code block like this:

.. code-block:: cpp

using namespace singularity;
EOS eos = IdealGas(gm1, cv);
if (do_shift) {
eos = eos.template Modify<ShiftedEOS>(shift);
}
if (do_scale) {
eos = eos.template Modify<ScaledEOS>(scale);
}

Relevant to the broad ``singularity-eos`` API, EOS models provide
introspection. To check if an EOS is modified, call

Expand Down Expand Up @@ -470,38 +498,34 @@ temperature or density and specific internal energy.
EOS Builder
------------

The inclusion of modifiers can make building a desired equation of
state somewhat cumbersome. To handle this, we have implemented the
``EOSBuilder`` machinery. ``EOSBuilder`` is a set of functions that
provides a declarative interface for building an equation of state
object.
The iterative construction of modifiers described above and in the
:ref:`modifiers<modifiers>` section is object oriented. For
convenience, we also provide a procedural, dispatch-based approach in
the ``EOSBuilder`` namespace and header. The key function is

The EOS Builder functions and types are defined in the
``singularity::EOSBuilder`` namespace. The key function is

.. cpp:function:: EOS EOSBuilder::buildEOS(EOSBuilder::EOSType t, EOSBuilder::params_t base_params, EOSBuilder::modifiers_t modifiers)
.. code-block:: cpp

* ``EOSBuilder::EOSType`` is an enum class with names that match the various EOS classes defined in :ref:`the models section <models>`; for example, ``EOSBuilder::EOSType::IdealGas``.
* ``EOSBuilder::params_t`` is a dictionary object with some type erasure, which maps strings to the types ``std::string``, ``int``, or ``Real``. It is used to map parameter names to their values for class constructors.
* ``EOSBuilder::modifiers_t`` is a dictionary from the ``EOSModifier`` enum class, which works identically to the ``EOSType`` enum but for modifiers, to ``params_t`` objects, specifying the constructor values for each modifier.
template <template <class> typename Mod, typename... Ts, typename... Args>
singularity::Variant<Ts...> Modify(const Variant<Ts...> &eos, Args &&...args);

Putting it all together, initializing an ``IdealGas`` with
``EOSBuilder`` looks something like this:
where ``Mod`` is an EOS modifier, ``Variant`` is either your
user-defined custom EOS variant type, or the pre-defined ``EOS`` type,
the ``eos`` object is an EOS you'd like to modify (stored as a
variant), and ``args`` are the additional arguments to the constructor
of ``Mod`` beyond the object to modify. For example, initializing an
``IdealGas`` equation of state that is optionally shifted and scaled
might look something like this:

.. code-block:: cpp

using namespace singularity;
EOSBuilder::EOSType type = EOSBuilder::EOSType::IdealGas;
EOSBuilder::modifiers_t modifiers;
EOSBuilder::params_t base_params, shifted_params, scaled_params;
base_params["Cv"].emplace<Real>(Cv);
base_params["gm1"].emplace<Real>(gm1);
shifted_params["shift"].emplace<Real>(shift);
scaled_params["scale"].emplace<Real>(scale);
modifiers[EOSBuilder::EOSModifier::Shifted] = shifted_params;
modifiers[EOSBuilder::EOSModifier::Scaled] = scaled_params;
EOS eos = EOSBuilder::buildEOS(type, base_params, modifiers);

EOS eos = IdealGas(gm1, cv);
if (do_shift) {
eos = EOSBuilder::Modify<ShiftedEOS>(eos, shift);
}
if (do_scale) {
eos = EOSBuilder::Modify<ScaledEOS>(eos, scale);
}

.. _eos methods reference section:

Expand Down
4 changes: 1 addition & 3 deletions singularity-eos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ set(EOS_HEADERS
eos/eos_stiff.hpp
)

set(EOS_SRCS
eos/eos_builder.cpp
)
set(EOS_SRCS eos/eos.cpp)

if (SINGULARITY_BUILD_CLOSURE)
list(APPEND EOS_HEADERS
Expand Down
32 changes: 30 additions & 2 deletions singularity-eos/base/variadic_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,35 @@
#include <type_traits>

namespace singularity {
namespace detail {
namespace variadic_utils {

// Some generic variatic utilities
// ======================================================================

// Backport of C++17 bool_constant.
// With C++17, can be replaced with
// using std::bool_constant
template <bool B>
using bool_constant = std::integral_constant<bool, B>;

// Implementation of std::conjunction/std::disjunction without C++17
// With C++17, can be replaced with
// using std::disjunction
template <bool...>
struct bool_pack {};
template <bool... Bs>
using conjunction = std::is_same<bool_pack<true, Bs...>, bool_pack<Bs..., true>>;
template <bool... Bs>
struct disjunction : bool_constant<!conjunction<!Bs...>::value> {};

// Checks if T is contained in the pack Ts
template <typename T, typename... Ts>
using contains = disjunction<std::is_same<T, Ts>::value...>;

template <typename T, typename... Ts>
constexpr bool contains_v() {
return contains<T, Ts...>::value;
}

// variadic list
template <typename... Ts>
Expand Down Expand Up @@ -156,7 +184,7 @@ constexpr auto pack_size(type_list<Ts...>) {
return sizeof...(Ts);
}

} // namespace detail
} // namespace variadic_utils
} // namespace singularity

#endif // SINGULARITY_EOS_BASE_VARIADIC_UTILS_HPP_
45 changes: 45 additions & 0 deletions singularity-eos/eos/eos.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
// © 2021-2023. 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.
//------------------------------------------------------------------------------

// JMM: This is a dummy file to provide a source file for cmake to
Yurlungur marked this conversation as resolved.
Show resolved Hide resolved
// compile when built without fortran.
//
// The main reason to do this is that when we build without fortran
// bindings, the library is completely header only. However WITH
// fortran bindings, it is not.
//
// cmake supports a build mode for header only libraries by marking
// those libraries INTERFACE. Without this flag, a few things will go
// wrong:
// 1. CMake will be unable to infer a proper linker
// so one must be specified by hand.
// 2. no dynamic library file (e.g., "*.a") will be generated,
// but dependencies that link against it, such as another library,
// or in our case, tests, will look for it. This will lead to
// a failure of the downstream library at link time.
//
// On the other hand, a library with implementation files
// CANNOT be marked INTERFACE, as otherwise source files will
// not be compiled.
//
// Unfortunately, switching the INTERFACE tag on and off in cmake
// is very cumbersome, as if a library is marked INTERFACE
// all its dependencies must ALSO be slurped in with an INTERFACE
// flag. This introduces significant branching in the cmake code
// and a lot of builer plate. For now, then, I simply include this
// empty source file.
//
// In the future, we could include centralized code here that we
// always want compiled, such as template instantiations or
// convenience functions.
18 changes: 9 additions & 9 deletions singularity-eos/eos/eos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ namespace singularity {

// recreate variadic list
template <typename... Ts>
using tl = singularity::detail::type_list<Ts...>;
using tl = singularity::variadic_utils::type_list<Ts...>;

template <template <typename> class... Ts>
using al = singularity::detail::adapt_list<Ts...>;
using al = singularity::variadic_utils::adapt_list<Ts...>;

// transform variadic list: applies modifiers to eos's
using singularity::detail::transform_variadic_list;
using singularity::variadic_utils::transform_variadic_list;

// all eos's
static constexpr const auto full_eos_list =
Expand Down Expand Up @@ -117,31 +117,31 @@ static constexpr const auto scaled_1 =
transform_variadic_list(full_eos_list, al<ScaledEOS>{});
// relativistic and unit system modifiers
static constexpr const auto unit_or_rel =
singularity::detail::concat(unit_system, relativistic);
singularity::variadic_utils::concat(unit_system, relativistic);
// variadic list of eos with shifted, relativistic or unit system modifiers
static constexpr const auto shifted_of_unit_or_rel =
transform_variadic_list(unit_or_rel, al<ShiftedEOS>{});
// combined list of all shifted EOS
static constexpr const auto shifted =
singularity::detail::concat(shifted_1, shifted_of_unit_or_rel);
singularity::variadic_utils::concat(shifted_1, shifted_of_unit_or_rel);
// variadic list of eos with scaled, relativistic or unit system modifiers
static constexpr const auto scaled_of_unit_or_rel =
transform_variadic_list(unit_or_rel, al<ScaledEOS>{});
// variadic list of Scaled<Shifted<T>>'s
static constexpr const auto scaled_of_shifted =
transform_variadic_list(shifted, al<ScaledEOS>{});
// combined list of all scaled EOS
static constexpr const auto scaled =
singularity::detail::concat(scaled_1, scaled_of_unit_or_rel, scaled_of_shifted);
static constexpr const auto scaled = singularity::variadic_utils::concat(
scaled_1, scaled_of_unit_or_rel, scaled_of_shifted);
// create combined list
static constexpr const auto combined_list_1 =
singularity::detail::concat(full_eos_list, shifted, scaled, unit_or_rel);
singularity::variadic_utils::concat(full_eos_list, shifted, scaled, unit_or_rel);
// make a ramped eos of everything
static constexpr const auto ramped_all =
transform_variadic_list(combined_list_1, al<BilinearRampEOS>{});
// final combined list
static constexpr const auto combined_list =
singularity::detail::concat(combined_list_1, ramped_all);
singularity::variadic_utils::concat(combined_list_1, ramped_all);
// a function that returns a Variant from a typelist
template <typename... Ts>
struct tl_to_Variant_struct {
Expand Down
34 changes: 34 additions & 0 deletions singularity-eos/eos/eos_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <ports-of-call/portability.hpp>
#include <ports-of-call/portable_errors.hpp>
#include <singularity-eos/base/variadic_utils.hpp>

namespace singularity {
namespace mfuncname {
Expand Down Expand Up @@ -137,6 +138,39 @@ class EosBase {
f(copy);
}

// EOS builder helpers
// Checks if an EOS can be modified
template <template <class> typename Mod, typename... Ts>
constexpr bool ModifiedInList() const {
return variadic_utils::contains_v<Mod<CRTP>, Ts...>();
}
// Modifies an EOS object by pulling out underlying type and modifying it
// This one returns Mod<CRT>
template <template <class> typename Mod, typename... Args>
constexpr Mod<CRTP> Modify(Args &&...args) const {
CRTP unmodified = *(static_cast<CRTP const *>(this));
return Mod<CRTP>(std::move(unmodified), std::forward<Args>(args)...);
}
// These are overloads needed for the variant, as std::visit must be
// able to return a variant of the same type every time. This lets
// us do so, even though sometimes we don't modify the object.
template <template <class> typename Mod, typename... Args>
constexpr Mod<CRTP> ConditionallyModify(std::true_type, Args &&...args) const {
return Modify<Mod>(std::forward<Args>(args)...);
}
template <template <class> typename Mod, typename... Args>
constexpr CRTP ConditionallyModify(std::false_type, Args &&...args) const {
CRTP unmodified = *(static_cast<CRTP const *>(this));
dholladay00 marked this conversation as resolved.
Show resolved Hide resolved
return unmodified;
}
template <template <class> typename Mod, typename... Ts, typename... Args>
constexpr auto ConditionallyModify(const variadic_utils::type_list<Ts...> &tl,
Args &&...args) const {
constexpr bool do_mod = variadic_utils::contains_v<Mod<CRTP>, Ts...>();
return ConditionallyModify<Mod>(variadic_utils::bool_constant<do_mod>(),
std::forward<Args>(args)...);
}

// Vector member functions
template <typename RealIndexer, typename ConstRealIndexer, typename LambdaIndexer>
inline void
Expand Down
Loading
Loading