#include #include #include #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; auto fixture = std::make_shared(); 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(fixture->density_binding), dependencies::borrow<::serif::tests::equations::Enthalpy>(fixture->enthalpy_binding), dependencies::borrow(fixture->displacement_binding)); const auto discretization = backend::make_stellar_discretization(fixture, bindings, unbound_compactification, fixture->mapper); CHECK_THROWS_AS(backend::make_model_inputs(discretization, coefficients), std::logic_error); CHECK_THROWS_AS(execution::make_volume_inputs(discretization.equation_discretization(), 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(); std::weak_ptr 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 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(); 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()); }