test(tests): added test suite
The test suite is extensive. Note that LLMs were used to aid in the development of the test suite. All LLM generated code was manually reviewed.
This commit is contained in:
196
tests/eos/polytropic_eos_relations.cpp
Normal file
196
tests/eos/polytropic_eos_relations.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
// Ported from MeanField tests/physics/polytropic_eos_relations.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
|
||||
#include "serif/eos/evaluation.hpp"
|
||||
#include "serif/eos/exceptions.hpp"
|
||||
#include "serif/eos/models/polytropic.hpp"
|
||||
|
||||
#include "serif/tests/test_tags.hpp"
|
||||
|
||||
namespace eos = serif::eos;
|
||||
namespace dimensions = serif::dimensions;
|
||||
|
||||
TEST_CASE(
|
||||
"Polytropic EOS Typed Relations Preserve Analytic Values",
|
||||
tags::unit & tags::eos
|
||||
) {
|
||||
constexpr std::array<double, 3> polytropic_indices{1.0, 1.5, 3.0};
|
||||
constexpr std::array<double, 2> polytropic_constants{0.25, 0.73};
|
||||
constexpr std::array<double, 4> densities{0.0, 1.0e-6, 0.2, 2.0};
|
||||
constexpr std::array<double, 4> specific_enthalpies{-0.3, 0.0, 0.2, 1.7};
|
||||
constexpr std::array<double, 4> pressures{0.0, 1.0e-8, 0.3, 4.0};
|
||||
|
||||
for (const double polytropic_index : polytropic_indices) {
|
||||
for (const double polytropic_constant : polytropic_constants) {
|
||||
const eos::models::Polytrope equation_of_state(polytropic_index, polytropic_constant);
|
||||
|
||||
for (const double density : densities) {
|
||||
CAPTURE(polytropic_index, polytropic_constant, density);
|
||||
|
||||
const double expected_pressure = polytropic_constant * std::pow(density, 1.0 + 1.0 / polytropic_index);
|
||||
const double expected_specific_enthalpy =
|
||||
(polytropic_index + 1.0) * polytropic_constant * std::pow(density, 1.0 / polytropic_index);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::Pressure>(equation_of_state, dimensions::DensityValue{density}).value() ==
|
||||
expected_pressure
|
||||
);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::SpecificEnthalpy>(equation_of_state, dimensions::DensityValue{density})
|
||||
.value() == expected_specific_enthalpy
|
||||
);
|
||||
|
||||
CHECK_THAT(
|
||||
(eos::partial_derivative<dimensions::Pressure, dimensions::MassDensity>(
|
||||
equation_of_state, dimensions::DensityValue{density}
|
||||
)
|
||||
.value()),
|
||||
Catch::Matchers::WithinRel(
|
||||
density == 0.0 ? 0.0 : expected_specific_enthalpy / polytropic_index, 2.0e-15
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (const double specific_enthalpy : specific_enthalpies) {
|
||||
CAPTURE(polytropic_index, polytropic_constant, specific_enthalpy);
|
||||
|
||||
const double expected_density =
|
||||
specific_enthalpy <= 0.0
|
||||
? 0.0
|
||||
: std::pow(
|
||||
specific_enthalpy / ((polytropic_index + 1.0) * polytropic_constant), polytropic_index
|
||||
);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::MassDensity>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{specific_enthalpy}
|
||||
)
|
||||
.value() == expected_density
|
||||
);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::Pressure>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{specific_enthalpy}
|
||||
)
|
||||
.value() ==
|
||||
(specific_enthalpy <= 0.0 ? 0.0 : expected_density * specific_enthalpy / (polytropic_index + 1.0))
|
||||
);
|
||||
|
||||
CHECK(
|
||||
(eos::partial_derivative<dimensions::Pressure, dimensions::SpecificEnthalpy>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{specific_enthalpy}
|
||||
)
|
||||
.value() == expected_density)
|
||||
);
|
||||
}
|
||||
|
||||
for (const double pressure : pressures) {
|
||||
CAPTURE(polytropic_index, polytropic_constant, pressure);
|
||||
|
||||
const double index_plus_one = polytropic_index + 1.0;
|
||||
const double expected_specific_enthalpy =
|
||||
index_plus_one * std::pow(polytropic_constant, polytropic_index / index_plus_one) *
|
||||
std::pow(pressure, 1.0 / index_plus_one);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::SpecificEnthalpy>(equation_of_state, dimensions::PressureValue{pressure})
|
||||
.value() == expected_specific_enthalpy
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Typed Polytropic EOS Preserves Domain And Exterior Semantics",
|
||||
tags::unit & tags::eos
|
||||
) {
|
||||
const eos::models::Polytrope equation_of_state(3.0, 0.75);
|
||||
|
||||
try {
|
||||
static_cast<void>(eos::evaluate<dimensions::Pressure>(equation_of_state, dimensions::DensityValue{-0.1}));
|
||||
FAIL("A negative density must be rejected.");
|
||||
} catch (const eos::EOSEvaluationError& error) {
|
||||
CHECK(std::string_view{error.what()}.find("EOS_INVALID_THERMODYNAMIC_INPUT") != std::string_view::npos);
|
||||
}
|
||||
|
||||
try {
|
||||
static_cast<void>(eos::evaluate<dimensions::SpecificEnthalpy>(
|
||||
equation_of_state, dimensions::PressureValue{std::numeric_limits<double>::quiet_NaN()}
|
||||
));
|
||||
FAIL("A nonfinite pressure must be rejected.");
|
||||
} catch (const eos::EOSEvaluationError& error) {
|
||||
CHECK(std::string_view{error.what()}.find("EOS_INVALID_THERMODYNAMIC_INPUT") != std::string_view::npos);
|
||||
}
|
||||
|
||||
constexpr double exterior_specific_enthalpy = -0.3;
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::MassDensity>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{exterior_specific_enthalpy}
|
||||
)
|
||||
.value() == 0.0
|
||||
);
|
||||
|
||||
CHECK(
|
||||
eos::evaluate<dimensions::Pressure>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{exterior_specific_enthalpy}
|
||||
)
|
||||
.value() == 0.0
|
||||
);
|
||||
|
||||
CHECK(
|
||||
(eos::partial_derivative<dimensions::MassDensity, dimensions::SpecificEnthalpy>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{exterior_specific_enthalpy}
|
||||
)
|
||||
.value() == 0.0)
|
||||
);
|
||||
|
||||
CHECK(
|
||||
(eos::partial_derivative<dimensions::Pressure, dimensions::SpecificEnthalpy>(
|
||||
equation_of_state, dimensions::SpecificEnthalpyValue{exterior_specific_enthalpy}
|
||||
)
|
||||
.value() == 0.0)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("Density based polytropic EOS supplies surface density and bulk Newton curvature", tags::unit & tags::eos) {
|
||||
for (const double index : {1.0, 1.5, 2.0, 2.5, 3.0}) {
|
||||
const eos::models::Polytrope model(index, 0.73);
|
||||
for (const double density : {1.0e-6, 0.2, 2.0}) {
|
||||
CAPTURE(index, density);
|
||||
const dimensions::DensityValue state{density};
|
||||
const auto pressure = eos::evaluate<dimensions::Pressure>(model, state);
|
||||
const double recovered = eos::evaluate<dimensions::MassDensity>(model, pressure).value();
|
||||
CHECK_THAT(recovered, Catch::Matchers::WithinRel(density, 3.0e-15));
|
||||
const double step = density * 1.0e-4;
|
||||
const double plus = eos::partial_derivative<dimensions::Pressure, dimensions::MassDensity>(
|
||||
model, dimensions::DensityValue{density + step}).value();
|
||||
const double minus = eos::partial_derivative<dimensions::Pressure, dimensions::MassDensity>(
|
||||
model, dimensions::DensityValue{density - step}).value();
|
||||
const double derivative = eos::second_partial_derivative<dimensions::Pressure, dimensions::MassDensity, dimensions::MassDensity>(model, state).value();
|
||||
CHECK_THAT(derivative, Catch::Matchers::WithinRel((plus - minus) / (2.0 * step), 3.0e-9));
|
||||
}
|
||||
CHECK(eos::evaluate<dimensions::MassDensity>(model, dimensions::PressureValue{0.0}).value() == 0.0);
|
||||
if (index == 1.0) {
|
||||
CHECK((eos::second_partial_derivative<dimensions::Pressure, dimensions::MassDensity, dimensions::MassDensity>(
|
||||
model, dimensions::DensityValue{0.0}).value() == 1.46));
|
||||
} else {
|
||||
CHECK_THROWS_AS((eos::second_partial_derivative<dimensions::Pressure, dimensions::MassDensity, dimensions::MassDensity>(
|
||||
model, dimensions::DensityValue{0.0})), eos::EOSEvaluationError);
|
||||
}
|
||||
for (const double invalid : {-0.1, std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN()}) {
|
||||
CHECK_THROWS_AS(eos::evaluate<dimensions::MassDensity>(model, dimensions::PressureValue{invalid}), eos::EOSEvaluationError);
|
||||
CHECK_THROWS_AS((eos::second_partial_derivative<dimensions::Pressure, dimensions::MassDensity, dimensions::MassDensity>(
|
||||
model, dimensions::DensityValue{invalid})), eos::EOSEvaluationError);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user