Files
MeanField_SERiF/tests/model/runtime_volume.cpp
Emily Boudreaux cb20faeb3d 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.
2026-11-09 13:53:17 -05:00

83 lines
4.8 KiB
C++

#include <memory>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include "serif/backend/mfem/model/discretization.hpp"
#include "serif/backend/mfem/model/inputs.hpp"
#include "serif/backend/mfem/model/system.hpp"
#include "serif/backend/mfem/model/volume.hpp"
#include "serif/tests/equations/fixture.hpp"
namespace {
namespace backend = serif::model::backend::mfem;
namespace equation_tests = serif::tests::equations;
namespace execution = serif::operators::backend::mfem;
using Catch::Matchers::WithinAbs;
} // namespace
TEST_CASE("Model and standalone volume inputs reject missing compactification spaces before access", "[model][runtime][equations][unit]") {
namespace dependencies = serif::utils::dependencies;
namespace blocks = serif::discretization::blocks;
using Registry = serif::equations::EquationRegistry<equation_tests::Closure>;
auto fixture = std::make_shared<equation_tests::Fixture>();
const auto density = fixture->density(), enthalpy = fixture->enthalpy();
const auto coefficients = fixture->state(density, enthalpy);
const ::mfem::GridFunction unbound_compactification;
const auto bindings = dependencies::make_dependency_context(
dependencies::borrow<blocks::density::mass>(fixture->density_binding),
dependencies::borrow<::serif::tests::equations::Enthalpy>(fixture->enthalpy_binding),
dependencies::borrow<blocks::displacement::vector>(fixture->displacement_binding));
const auto discretization = backend::make_stellar_discretization(fixture, bindings, unbound_compactification, fixture->mapper);
CHECK_THROWS_AS(backend::make_model_inputs<Registry>(discretization, coefficients), std::logic_error);
CHECK_THROWS_AS(execution::make_volume_inputs<equation_tests::Closure>(discretization.equation_discretization<blocks::density::mass>(), coefficients), std::logic_error);
}
TEST_CASE("Model volume geometry adapters retain the accepted equation and complete coordinate transpose", "[model][runtime][equations][integration]") {
auto fixture = std::make_shared<equation_tests::Fixture>();
std::weak_ptr<equation_tests::Fixture> lifetime = fixture;
const auto density = fixture->density();
auto enthalpy = fixture->enthalpy();
const auto displacement = fixture->displacement(0.35);
const auto direction = fixture->displacement(0.23);
const auto dual = equation_tests::deterministic(density.Size(), 0.47);
std::shared_ptr<const backend::PhysicalSystem> system;
::mfem::Vector expected_action, expected_transpose; {
equation_tests::PreparedClosure prepared(equation_tests::Closure{serif::eos::models::Polytrope{3.0, 1.5}}, fixture->density_binding, fixture->displacement_binding, fixture->compactification, fixture->mapper);
prepared.prepare(fixture->state(density, enthalpy), displacement, fixture->workspace);
const auto accepted = prepared.cache().share<execution::volume_keys::Linearization>();
const auto geometry = backend::volume_geometry_block(accepted);
system = backend::make_physical_system(density.Size(), displacement.Size(), {{0, backend::volume_residual_values(accepted)}}, {{0, 0, geometry}}, {}, fixture);
geometry.action()->Mult(direction, expected_action);
geometry.action()->MultTranspose(dual, expected_transpose);
CHECK_THAT(dual * expected_action, WithinAbs(direction * expected_transpose, 2.0e-12));
REQUIRE(expected_action.Norml2() > 0.0);
constexpr double step = 1.0e-6;
::mfem::Vector perturbed(displacement);
perturbed.Add(step, direction);
prepared.prepare(fixture->state(density, enthalpy), perturbed, fixture->workspace);
::mfem::Vector difference(prepared.data().residual);
perturbed = displacement;
perturbed.Add(-step, direction);
prepared.prepare(fixture->state(density, enthalpy), perturbed, fixture->workspace);
difference -= prepared.data().residual;
difference *= 0.5 / step;
CHECK(equation_tests::relative_error(expected_action, difference) < 2.0e-8);
enthalpy = -1.0;
CHECK_FALSE(prepared.try_prepare(fixture->state(density, enthalpy), displacement, fixture->workspace));
::mfem::Vector repeated;
geometry.action()->Mult(direction, repeated);
CHECK(equation_tests::relative_error(repeated, expected_action) == 0.0);
}
fixture.reset();
CHECK_FALSE(lifetime.expired());
::mfem::Vector action, transpose;
system->jacobian().action()->Mult(direction, action);
system->jacobian().action()->MultTranspose(dual, transpose);
CHECK(equation_tests::relative_error(action, expected_action) == 0.0);
CHECK(equation_tests::relative_error(transpose, expected_transpose) == 0.0);
system.reset();
CHECK(lifetime.expired());
}