Skip to content

Commit

Permalink
Merge branch 'main' into jdolence/downstream_variant_pte
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurlungur authored Oct 13, 2023
2 parents 2640a03 + 70d370b commit 29d2656
Show file tree
Hide file tree
Showing 22 changed files with 1,713 additions and 1,513 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
- [[PR177]](https://github.com/lanl/singularity-eos/pull/177) added EOSPAC vector functions

### Changed (changing behavior/API/variables/...)
- [[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
- [[PR223]](https://github.com/lanl/singularity-eos/pull/223) Update ports-of-call and add portable error handling
Expand Down
21 changes: 14 additions & 7 deletions doc/sphinx/src/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,9 @@ test in the ``CMakeLists.txt`` file,

.. code-block:: cmake
add_executable(eos_unit_tests
add_executable(eos_analytic_unit_tests
catch2_define.cpp
eos_unit_test_helpers.hpp
test_eos_unit.cpp
test_eos_gruneisen.cpp
test_eos_vinet.cpp
test_my_new_eos.cpp
Expand All @@ -245,15 +244,23 @@ test in the ``CMakeLists.txt`` file,
in order for the test to be compiled. If your EOS requires any special
dependencies, be sure to block off the test using ``#IFDEF`` blocks.

**Important:** this is a subtlety that highlights the importance of unit tests!
Since our library is header only, the unit tests are often the only place where
a specific EOS may be instantiated when ``singularity-eos`` is compiled. Unit
tests _must_ make use of the ``EOS`` type, i.e.
.. note::

Note that there are three executables, ``eos_analytic_unit_tests``,
``eos_infrastructure_tests`` and ``eos_tabulated_unit_tests``. Pick
the executable that most closely matches what your model is.

**Important:** Since our library is header only, the unit
tests are often the only place where a specific EOS may be
instantiated when ``singularity-eos`` is compiled. Therefore to
exercise all code paths, it is best to create an ``EOS`` type
instantiated as

.. code-block:: c++

#include <singularity-eos/eos/eos.hpp>
EOS my_eos = my_new_eos(parameter1, parameter2, ...)
using EOS = singularity::Variant<MyNewEOS>;``.
EOS my_eos = MyNewEOS(parameter1, parameter2, ...)

in order to properly test the functionality of a new EOS. Simply using the
new class as the type such as
Expand Down
46 changes: 36 additions & 10 deletions doc/sphinx/src/using-eos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ conditions. The type of parallelism used depends on how
``singularity-eos`` is compiled. If the ``Kokkos`` backend is used,
any parallel dispatch supported by ``Kokkos`` is supported.

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.

.. _variant section:

Variants
Expand Down Expand Up @@ -237,23 +241,23 @@ The ``Evaluate`` call has the signature
void Evaluate(Functor_t f);
where a ``Functor_t`` is a class that *must* provide a ``void
operator() const`` method templated on EOS type. ``Evaluate`` is decorated
so that it may be evaluated on either host or device, depending on
desired use-case.
operator() const`` method templated on EOS type. ``Evaluate`` is
decorated so that it may be evaluated on either host or device,
depending on desired use-case. Alternatively, you may use an anonymous
function with an `auto` argument as the input, e.g.,

.. note::
.. code-block::
Note that for C++ versions less than C++20, the functor must be
defined as a class. Anonymous functions won't do, as they do not
support templates, and the ``operator()`` call must be
templated.
// equivalent to [=], but with device markings
eos.Evaluate(PORTABLE_LAMBDA(auto eos) { /* my code snippet */ });
.. warning::

It can be dangerous to use functors with side-effects. Especially
with GPUs it can produce very unintuitive behaviour. We recommend
you only make the ``operator()`` non-const if you really know what
you're doing.
you're doing. And in the anonymous function case, we recommend you
capture by value, not reference.

To see the utlity of the ``Evaluate`` function, it's probably just
easiest to provide an example. The following code evaluates the EOS on
Expand All @@ -275,13 +279,19 @@ is summed using the ``Kokkos::parallel_reduce`` functionality in the
// PORTABLE_INLINE_FUNCTION
// decorator here.
void operator()(const T &eos) const {
// Capturing member functions of a class in a lambda typically causes problems
// when launching a GPU kernel.
// Better to pull out new variables to capture before launching a kernel.
Real *P = P_;
Real *rho = rho_;
Real *sie = sie_;
// reduction target
Real tot_diff;
// reduction op
Kokkos::parallel_reduce(
"MyCheckPofRE", N_,
KOKKOS_LAMBDA(const int i, Real &diff) {
diff += std::abs(P_[i] - eos.PressureFromDensityInternalEnergy(rho_[i], sie_[i]));
diff += std::abs(P[i] - eos.PressureFromDensityInternalEnergy(rho[i], sie[i]));
},
tot_diff);
std::cout << "Total difference = " << tot_diff << std::endl;
Expand All @@ -304,6 +314,22 @@ is summed using the ``Kokkos::parallel_reduce`` functionality in the
// The above two lines could have been called "in-one" with:
// eos.Evaluate(CheckPofRE(P, rho, sie, N));
Alternatively, you could eliminate the functor and use an anonymous
function with:

.. code-block:: cpp
eos.Evaluate([=](auto eos) {
Real tot_diff;
Kokkos::parallel_reduce(
"MyCheckPofRE", N_,
KOKKOS_LAMBDA(const int i, Real &diff) {
diff += std::abs(P[i] - eos.PressureFromDensityInternalEnergy(rho[i], sie[i]));
},
tot_diff);
std::cout << "Total difference = " << tot_diff << std::endl;
});
This is not functionality that would be available with the standard
vector calls provided by ``singularity-eos``, at least not without
chaining multiple parallel dispatch calls. Here we can do it in a
Expand Down
2 changes: 1 addition & 1 deletion singularity-eos/eos/eos_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class EosBase {

// Generic evaluator
template <typename Functor_t>
PORTABLE_INLINE_FUNCTION void Evaluate(Functor_t &f) const {
constexpr void Evaluate(Functor_t &f) const {
CRTP copy = *(static_cast<CRTP const *>(this));
f(copy);
}
Expand Down
2 changes: 1 addition & 1 deletion singularity-eos/eos/eos_variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Variant {

// Place member functions here
template <typename Functor_t>
PORTABLE_INLINE_FUNCTION void Evaluate(Functor_t &f) const {
constexpr void Evaluate(Functor_t &f) const {
return mpark::visit([&f](const auto &eos) { return eos.Evaluate(f); }, eos_);
}

Expand Down
41 changes: 32 additions & 9 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,58 @@
# ------------------------------------------------------------------------------

add_executable(
eos_unit_tests
eos_analytic_unit_tests
catch2_define.cpp
eos_unit_test_helpers.hpp
test_eos_unit.cpp
test_eos_ideal.cpp
test_eos_gruneisen.cpp
test_eos_sap_polynomial.cpp
test_eos_vinet.cpp
test_eos_noble_abel.cpp
test_eos_stiff.cpp
)

add_executable(
eos_infrastructure_tests
catch2_define.cpp
eos_unit_test_helpers.hpp
test_eos_modifiers.cpp
test_eos_vector.cpp
test_math_utils.cpp
)

add_executable(
eos_tabulated_unit_tests
catch2_define.cpp
eos_unit_test_helpers.hpp
test_eos_vinet.cpp
test_eos_helmholtz.cpp
test_eos_tabulated.cpp
test_eos_stellar_collapse.cpp
)

if(SINGULARITY_TEST_HELMHOLTZ)
configure_file(${PROJECT_SOURCE_DIR}/data/helmholtz/helm_table.dat ${CMAKE_BINARY_DIR}/data/helmholtz/helm_table.dat COPYONLY)
target_compile_definitions(eos_unit_tests PRIVATE SINGULARITY_TEST_HELMHOLTZ SINGULARITY_USE_HELMHOLTZ)
target_compile_definitions(eos_tabulated_unit_tests PRIVATE SINGULARITY_TEST_HELMHOLTZ SINGULARITY_USE_HELMHOLTZ)
endif()

if(SINGULARITY_TEST_SESAME)
target_compile_definitions(eos_unit_tests PRIVATE SINGULARITY_TEST_SESAME)
target_compile_definitions(eos_tabulated_unit_tests PRIVATE SINGULARITY_TEST_SESAME)
endif()
if(SINGULARITY_TEST_STELLAR_COLLAPSE)
target_compile_definitions(eos_unit_tests
target_compile_definitions(eos_tabulated_unit_tests
PRIVATE SINGULARITY_TEST_STELLAR_COLLAPSE)
endif()

target_link_libraries(eos_unit_tests PRIVATE Catch2::Catch2
singularity-eos::singularity-eos)
target_link_libraries(eos_analytic_unit_tests PRIVATE Catch2::Catch2
singularity-eos::singularity-eos)
target_link_libraries(eos_infrastructure_tests PRIVATE Catch2::Catch2
singularity-eos::singularity-eos)
target_link_libraries(eos_tabulated_unit_tests PRIVATE Catch2::Catch2
singularity-eos::singularity-eos)
include(Catch)
catch_discover_tests(eos_unit_tests PROPERTIES TIMEOUT 60)
catch_discover_tests(eos_analytic_unit_tests PROPERTIES TIMEOUT 60)
catch_discover_tests(eos_infrastructure_tests PROPERTIES TIMEOUT 60)
catch_discover_tests(eos_tabulated_unit_tests PROPERTIES TIMEOUT 60)

if(SINGULARITY_USE_EOSPAC AND SINGULARITY_TEST_SESAME)
add_executable(compare_to_eospac compare_to_eospac.cpp)
Expand Down
1 change: 1 addition & 0 deletions test/catch2_define.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#ifndef CATCH_CONFIG_RUNNER
#define CATCH_CONFIG_RUNNER
#define CATCH_CONFIG_FAST_COMPILE
#include "catch2/catch.hpp"
#endif

Expand Down
83 changes: 57 additions & 26 deletions test/eos_unit_test_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#ifndef _SINGULARITY_EOS_TEST_TEST_HELPERS_
#define _SINGULARITY_EOS_TEST_TEST_HELPERS_

#ifndef CATCH_CONFIG_RUNNER
#ifndef CATCH_CONFIG_FAST_COMPILE
#define CATCH_CONFIG_FAST_COMPILE
#include "catch2/catch.hpp"
#endif
#include <cmath>
Expand Down Expand Up @@ -49,8 +50,7 @@ inline std::string demangle(const char *name) { return name; }
#endif

#include <ports-of-call/portability.hpp>

using singularity::EOS;
#include <singularity-eos/eos/eos.hpp>

PORTABLE_INLINE_FUNCTION bool isClose(Real a, Real b, Real eps = 5e-2) {
return fabs(b - a) / (fabs(a + b) + 1e-20) <= eps;
Expand All @@ -71,34 +71,65 @@ inline void array_compare(int num, X &&x, Y &&y, Z &&z, ZT &&ztrue, XN xname, YN
}
}

inline void compare_two_eoss(const EOS &test_e, const EOS &ref_e) {
template <typename E1, typename E2>
inline void compare_two_eoss(const E1 &&test_e, const E2 &&ref_e) {
// compare all individual member functions with 1 as inputs,
// this function is meant to catch mis-implementations of
// modifiers that can be initialized in such a way as to
// be equivalent of an unmodified eos. Best used with analytic
// eoss.
REQUIRE(isClose(test_e.TemperatureFromDensityInternalEnergy(1, 1),
ref_e.TemperatureFromDensityInternalEnergy(1, 1), 1.e-15));
REQUIRE(isClose(test_e.InternalEnergyFromDensityTemperature(1, 1),
ref_e.InternalEnergyFromDensityTemperature(1, 1), 1.e-15));
REQUIRE(isClose(test_e.PressureFromDensityInternalEnergy(1, 1),
ref_e.PressureFromDensityInternalEnergy(1, 1), 1.e-15));
REQUIRE(isClose(test_e.SpecificHeatFromDensityInternalEnergy(1, 1),
ref_e.SpecificHeatFromDensityInternalEnergy(1, 1), 1.e-15));
REQUIRE(isClose(test_e.BulkModulusFromDensityInternalEnergy(1, 1),
ref_e.BulkModulusFromDensityInternalEnergy(1, 1), 1.e-15));
REQUIRE(isClose(test_e.GruneisenParamFromDensityInternalEnergy(1, 1),
ref_e.GruneisenParamFromDensityInternalEnergy(1, 1), 1.e-15));
REQUIRE(isClose(test_e.PressureFromDensityTemperature(1, 1),
ref_e.PressureFromDensityTemperature(1, 1), 1.e-15));
REQUIRE(isClose(test_e.SpecificHeatFromDensityTemperature(1, 1),
ref_e.SpecificHeatFromDensityTemperature(1, 1), 1.e-15));
REQUIRE(isClose(test_e.BulkModulusFromDensityTemperature(1, 1),
ref_e.BulkModulusFromDensityTemperature(1, 1), 1.e-15));
REQUIRE(isClose(test_e.GruneisenParamFromDensityTemperature(1, 1),
ref_e.GruneisenParamFromDensityTemperature(1, 1), 1.e-15));
REQUIRE(isClose(test_e.MinimumDensity(), ref_e.MinimumDensity(), 1.e-15));
REQUIRE(isClose(test_e.MinimumTemperature(), ref_e.MinimumTemperature(), 1.e-15));
INFO("reference T: " << ref_e.TemperatureFromDensityInternalEnergy(1, 1) << " test T: "
<< test_e.TemperatureFromDensityInternalEnergy(1, 1));
CHECK(isClose(test_e.TemperatureFromDensityInternalEnergy(1, 1),
ref_e.TemperatureFromDensityInternalEnergy(1, 1), 1.e-15));
INFO("reference sie: " << ref_e.InternalEnergyFromDensityTemperature(1, 1)
<< " test sie: "
<< test_e.InternalEnergyFromDensityTemperature(1, 1));
CHECK(isClose(test_e.InternalEnergyFromDensityTemperature(1, 1),
ref_e.InternalEnergyFromDensityTemperature(1, 1), 1.e-15));
INFO("reference P: " << ref_e.PressureFromDensityInternalEnergy(1, 1)
<< " test P: " << test_e.PressureFromDensityInternalEnergy(1, 1));
CHECK(isClose(test_e.PressureFromDensityInternalEnergy(1, 1),
ref_e.PressureFromDensityInternalEnergy(1, 1), 1.e-15));
INFO("reference Cv: " << ref_e.SpecificHeatFromDensityInternalEnergy(1, 1)
<< " test Cv: "
<< test_e.SpecificHeatFromDensityInternalEnergy(1, 1));
CHECK(isClose(test_e.SpecificHeatFromDensityInternalEnergy(1, 1),
ref_e.SpecificHeatFromDensityInternalEnergy(1, 1), 1.e-15));
INFO("reference bmod: " << ref_e.BulkModulusFromDensityInternalEnergy(1, 1)
<< " test bmod: "
<< test_e.BulkModulusFromDensityInternalEnergy(1, 1));
CHECK(isClose(test_e.BulkModulusFromDensityInternalEnergy(1, 1),
ref_e.BulkModulusFromDensityInternalEnergy(1, 1), 1.e-15));
INFO("reference Grun. Param.: "
<< ref_e.GruneisenParamFromDensityInternalEnergy(1, 1)
<< " test Grun. Param.: " << test_e.GruneisenParamFromDensityInternalEnergy(1, 1));
CHECK(isClose(test_e.GruneisenParamFromDensityInternalEnergy(1, 1),
ref_e.GruneisenParamFromDensityInternalEnergy(1, 1), 1.e-15));
INFO("reference P: " << ref_e.PressureFromDensityTemperature(1, 1)
<< " test P: " << test_e.PressureFromDensityTemperature(1, 1));
CHECK(isClose(test_e.PressureFromDensityTemperature(1, 1),
ref_e.PressureFromDensityTemperature(1, 1), 1.e-15));
INFO("reference Cv: " << ref_e.SpecificHeatFromDensityTemperature(1, 1) << " test Cv: "
<< test_e.SpecificHeatFromDensityTemperature(1, 1));
CHECK(isClose(test_e.SpecificHeatFromDensityTemperature(1, 1),
ref_e.SpecificHeatFromDensityTemperature(1, 1), 1.e-15));
INFO("reference bmod: " << ref_e.BulkModulusFromDensityTemperature(1, 1)
<< " test bmod: "
<< test_e.BulkModulusFromDensityTemperature(1, 1));
CHECK(isClose(test_e.BulkModulusFromDensityTemperature(1, 1),
ref_e.BulkModulusFromDensityTemperature(1, 1), 1.e-15));
INFO("reference Grun. Param.: " << ref_e.GruneisenParamFromDensityTemperature(1, 1)
<< " test Grun. Param.: "
<< test_e.GruneisenParamFromDensityTemperature(1, 1));
CHECK(isClose(test_e.GruneisenParamFromDensityTemperature(1, 1),
ref_e.GruneisenParamFromDensityTemperature(1, 1), 1.e-15));
INFO("reference rho min.: " << ref_e.MinimumDensity()
<< " test rho min.: " << test_e.MinimumDensity());
CHECK(isClose(test_e.MinimumDensity(), ref_e.MinimumDensity(), 1.e-15));
INFO("reference T min.: " << ref_e.MinimumTemperature()
<< " test T min.: " << test_e.MinimumTemperature());
CHECK(isClose(test_e.MinimumTemperature(), ref_e.MinimumTemperature(), 1.e-15));
return;
}

Expand Down
10 changes: 4 additions & 6 deletions test/profile_eos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include <spiner/interpolation.hpp>

#include <singularity-eos/eos/eos.hpp>
#include <singularity-eos/eos/eos_builder.hpp>
#include <type_traits>

using namespace singularity;
Expand Down Expand Up @@ -67,6 +66,7 @@ inline double get_duration(Function function) {
TODO(JMM): Only profiles Pressure call
and does not accept lambdas.
*/
template <typename EOS>
inline void get_timing(int ncycles, const ivec &ncells_1d, const double rho_min,
const double rho_max, const double T_min, const double T_max,
const std::string &name, EOS &eos_h) {
Expand Down Expand Up @@ -220,11 +220,9 @@ int main(int argc, char *argv[]) {
<< "Please note that timings are for 1 node and 1 GPU respectively.\n"
<< "Beginning profiling..." << std::endl;

EOSBuilder::EOSType type = EOSBuilder::EOSType::IdealGas;
EOSBuilder::params_t params;
params["Cv"].emplace<Real>(1e7 * 0.716); // specific heat in ergs/(g K)
params["gm1"].emplace<Real>(0.4); // gamma - 1
EOS eos = EOSBuilder::buildEOS(type, params);
constexpr Real Cv = 1e7 * 0.716; // specific heat in ergs/(g K)
constexpr Real gm1 = 0.4; // gamma - 1
auto eos = singularity::IdealGas(gm1, Cv);
get_timing(ncycles, ncells_1d, RHO_MIN, RHO_MAX, T_MIN, T_MAX, "IdealGas", eos);

std::cout << "Done." << std::endl;
Expand Down
5 changes: 3 additions & 2 deletions test/test_eos_gruneisen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@
#include <cstdio>
#include <cstdlib>
#include <limits>
#ifndef CATCH_CONFIG_RUNNER
#ifndef CATCH_CONFIG_FAST_COMPILE
#define CATCH_CONFIG_FAST_COMPILE
#include "catch2/catch.hpp"
#endif

#include <singularity-eos/base/constants.hpp>
#include <singularity-eos/eos/eos.hpp>
#include <test/eos_unit_test_helpers.hpp>

using singularity::EOS;
using singularity::Gruneisen;
using EOS = singularity::Variant<Gruneisen>;

PORTABLE_INLINE_FUNCTION Real QuadFormulaMinus(Real a, Real b, Real c) {
return (-b - std::sqrt(b * b - 4 * a * c)) / (2 * a);
Expand Down
Loading

0 comments on commit 29d2656

Please sign in to comment.