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:
124
tests/surface/relations.cpp
Normal file
124
tests/surface/relations.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
|
||||
#include "serif/geometry/surface/evaluation.hpp"
|
||||
#include "serif/tests/surface/contexts.hpp"
|
||||
|
||||
namespace {
|
||||
using namespace serif;
|
||||
using namespace serif::tests::surface;
|
||||
|
||||
using PressureLast = eos::relations::Relation<quantities::SpecificEnthalpy, quantities::Entropy, quantities::Pressure>;
|
||||
|
||||
struct PressureLastEOS {
|
||||
using Relations = eos::relations::RelationCatalog<PressureLast>;
|
||||
|
||||
/// Distinct coefficients detect an accidental permutation of pressure and state arguments.
|
||||
[[nodiscard]] quantities::SpecificEnthalpyValue evaluate(PressureLast, const quantities::EntropyValue entropy, const quantities::PressureValue pressure) const {
|
||||
return quantities::SpecificEnthalpyValue{3.0 * entropy.value() + 2.0 * pressure.value()};
|
||||
}
|
||||
|
||||
/// Pressure is prescribed, so the only partial needed is the entropy derivative.
|
||||
[[nodiscard]] quantities::PartialDerivative<quantities::SpecificEnthalpy, quantities::Entropy> partial_derivative(PressureLast, quantities::WithRespectTo<quantities::Entropy>, quantities::EntropyValue, quantities::PressureValue) const {
|
||||
return quantities::PartialDerivative<quantities::SpecificEnthalpy, quantities::Entropy>{3.0};
|
||||
}
|
||||
};
|
||||
|
||||
using CarrierInput = eos::relations::Relation<quantities::MassDensity, quantities::Pressure, quantities::MassDensity>;
|
||||
|
||||
struct CarrierInputEOS {
|
||||
using Relations = eos::relations::RelationCatalog<CarrierInput>;
|
||||
|
||||
/// A manufactured implicit-carrier relation checks the identity contribution against a nonzero EOS carrier partial.
|
||||
[[nodiscard]] quantities::DensityValue evaluate(CarrierInput, const quantities::PressureValue pressure, const quantities::DensityValue density) const {
|
||||
return quantities::DensityValue{pressure.value() + 0.5 * density.value()};
|
||||
}
|
||||
|
||||
/// The final residual's density partial must be 1 - 0.5.
|
||||
[[nodiscard]] quantities::PartialDerivative<quantities::MassDensity, quantities::MassDensity> partial_derivative(CarrierInput, quantities::WithRespectTo<quantities::MassDensity>, quantities::PressureValue, quantities::DensityValue) const {
|
||||
return quantities::PartialDerivative<quantities::MassDensity, quantities::MassDensity>{0.5};
|
||||
}
|
||||
};
|
||||
|
||||
struct ForwardOnlyEOS {
|
||||
using Relations = eos::relations::RelationCatalog<PressureFromDensityAndTemperature>;
|
||||
|
||||
/// This model exposes only pressure evaluation; there is no callable density inverse.
|
||||
[[nodiscard]] quantities::PressureValue evaluate(PressureFromDensityAndTemperature, const quantities::DensityValue density, const quantities::TemperatureValue temperature) const {
|
||||
return quantities::PressureValue{density.value() * temperature.value()};
|
||||
}
|
||||
|
||||
/// The row's density derivative comes directly from the forward relation.
|
||||
[[nodiscard]] quantities::PartialDerivative<quantities::Pressure, quantities::MassDensity> partial_derivative(PressureFromDensityAndTemperature, quantities::WithRespectTo<quantities::MassDensity>, quantities::DensityValue, const quantities::TemperatureValue temperature) const {
|
||||
return quantities::PartialDerivative<quantities::Pressure, quantities::MassDensity>{temperature.value()};
|
||||
}
|
||||
|
||||
/// The temperature coupling is required even though density supplies the replaced row.
|
||||
[[nodiscard]] quantities::PartialDerivative<quantities::Pressure, quantities::Temperature> partial_derivative(PressureFromDensityAndTemperature, quantities::WithRespectTo<quantities::Temperature>, const quantities::DensityValue density, quantities::TemperatureValue) const {
|
||||
return quantities::PartialDerivative<quantities::Pressure, quantities::Temperature>{density.value()};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Surface EOS arguments follow relation order even when pressure is last", "[surface][unit]") {
|
||||
using State = dependencies::Bindings<dependencies::Binding<quantities::Entropy, Entropy>, dependencies::Binding<quantities::SpecificEnthalpy, Enthalpy>>;
|
||||
using Formulation = physics::PressureSurfaceFormulation<PressureLastEOS, State>;
|
||||
physics::SurfacePoint<Formulation> point{};
|
||||
point.fields.get<Enthalpy>() = 1.7;
|
||||
point.fields.get<Entropy>() = 0.2;
|
||||
const auto result = physics::evaluate_pressure_surface<Formulation>(PressureLastEOS{}, physics::IsobaricSurface{quantities::PressureValue{0.4}}, point);
|
||||
REQUIRE(result);
|
||||
CHECK(result->residual == 1.7 - (3.0 * 0.2 + 2.0 * 0.4));
|
||||
CHECK(result->field_derivatives.get<Entropy>() == -3.0);
|
||||
}
|
||||
|
||||
TEST_CASE("A carrier appearing among EOS inputs retains both derivative contributions", "[surface][unit]") {
|
||||
using State = dependencies::Bindings<dependencies::Binding<quantities::MassDensity, Density>>;
|
||||
using Formulation = physics::PressureSurfaceFormulation<CarrierInputEOS, State>;
|
||||
physics::SurfacePoint<Formulation> point{};
|
||||
point.fields.get<Density>() = 0.8;
|
||||
const auto result = physics::evaluate_pressure_surface<Formulation>(CarrierInputEOS{}, physics::IsobaricSurface{quantities::PressureValue{0.4}}, point);
|
||||
REQUIRE(result);
|
||||
CHECK(result->residual == 0.0);
|
||||
CHECK(result->field_derivatives.get<Density>() == 0.5);
|
||||
}
|
||||
|
||||
TEST_CASE("A forward-only EOS can impose the same isobaric condition without inversion", "[surface][unit]") {
|
||||
using Formulation = physics::DirectPressureSurfaceFormulation<ForwardOnlyEOS, GasState, quantities::MassDensity, PressureFromDensityAndTemperature>;
|
||||
const auto result = physics::evaluate_pressure_surface<Formulation>(ForwardOnlyEOS{}, physics::IsobaricSurface{quantities::PressureValue{0.8}}, gas_point(0.4, 2.0));
|
||||
REQUIRE(result);
|
||||
CHECK(result->residual == 0.0);
|
||||
CHECK(result->field_derivatives.get<Density>() == 2.0);
|
||||
CHECK(result->field_derivatives.get<Temperature>() == 0.4);
|
||||
}
|
||||
|
||||
TEST_CASE("Pressure-only surface relations retain their analytic residual and derivative", "[surface][unit]") {
|
||||
using Formulation = physics::PressureSurfaceFormulation<OffsetEOS, BarotropicState>;
|
||||
const OffsetEOS model;
|
||||
for (const double pressure : {0.0, 0.03125, 0.4}) {
|
||||
const physics::IsobaricSurface condition{quantities::PressureValue{pressure}};
|
||||
for (const double enthalpy : {-0.2, 0.0, 0.7}) {
|
||||
physics::SurfacePoint<Formulation> point{};
|
||||
point.fields.get<Enthalpy>() = enthalpy;
|
||||
const auto actual = physics::evaluate_pressure_surface<Formulation>(model, condition, point);
|
||||
REQUIRE(actual);
|
||||
CHECK(actual->residual == enthalpy - (model.offset + 2.0 * pressure));
|
||||
CHECK(actual->field_derivatives.get<Enthalpy>() == 1.0);
|
||||
CHECK(actual->position_derivative == discretization::forms::VectorValue{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Equal EOS values cannot conceal changed surface derivatives", "[surface][unit]") {
|
||||
GeneralEOS model;
|
||||
auto cache = dependencies::make_computation_cache<physics::SurfaceFailure>(physics::make_pressure_surface_graph<GeneralFormulation>(), general_context(model, 0.0, {0.4}, {0.0}, {0.0}));
|
||||
REQUIRE(cache.try_prepare(general_context(model, 0.0, {0.4}, {0.0}, {0.0})));
|
||||
CHECK(cache.get<physics::keys::EOSResponse>()[0].value.value() == 0.0);
|
||||
|
||||
model.scale = 2.0;
|
||||
const auto report = cache.try_prepare(general_context(model, 0.0, {0.4}, {0.0}, {0.0}));
|
||||
REQUIRE(report);
|
||||
CHECK(report->computed_count() == 2);
|
||||
CHECK(cache.get<physics::keys::EOSResponse>()[0].value.value() == 0.0);
|
||||
CHECK(cache.get<physics::keys::Linearization>()[0].field_derivatives.get<Entropy>() == -6.0);
|
||||
}
|
||||
Reference in New Issue
Block a user