feat(libmeanfield): centrifugal + pressure

This commit is contained in:
2026-08-04 14:24:55 -04:00
parent 9bc4f2758a
commit dc912fd15e
115 changed files with 260058 additions and 163261 deletions

View File

@@ -0,0 +1,157 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <mfem.hpp>
import mean_field;
import test_helpers;
using namespace mean_field;
using Catch::Matchers::WithinAbs;
namespace prepared_test = gravity_prepared_test_utils;
TEST_CASE(
"Prepared Mapped Gravity Source Matches Stateless Kernel",
tags::integration &tags::mfem_operators &tags::prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedGravitySourceOperator prepared_operator(
f, *f.domainMapperStateless
);
REQUIRE(prepared_operator.Width() == f.densityFes->GetTrueVSize());
REQUIRE(
prepared_operator.Height() == f.gravityPotentialFes->GetTrueVSize()
);
const mfem::Vector density = prepared_test::make_deterministic_vector(
f.densityFes->GetTrueVSize(), 0.41
);
const MPI_Comm communicator = f.mesh->GetComm();
mfem::Vector identity_action;
mfem::Vector deformed_action;
for (const double deformation_scale : {0.0, 1.0}) {
const mfem::Vector displacement =
prepared_test::make_displacement(f, deformation_scale);
prepared_operator.Prepare(displacement);
mfem::Vector prepared_action;
mfem::Vector reference_action;
prepared_operator.Mult(density, prepared_action);
operators::kernels::apply_mapped_source(
f, *f.domainMapperStateless, density, displacement, reference_action
);
const double relative_error = prepared_test::relative_error(
prepared_action, reference_action, communicator
);
INFO("Deformation scale = " << deformation_scale);
INFO(
"Prepared source norm = "
<< prepared_test::global_norm(prepared_action, communicator)
);
INFO(
"Reference source norm = "
<< prepared_test::global_norm(reference_action, communicator)
);
INFO("Relative prepared-source error = " << relative_error);
REQUIRE(prepared_operator.IsPrepared());
CHECK_THAT(relative_error, WithinAbs(0.0, 2.0e-11));
if (deformation_scale == 0.0) {
identity_action = prepared_action;
} else {
deformed_action = prepared_action;
}
}
const double geometry_change = prepared_test::relative_error(
deformed_action, identity_action, communicator
);
INFO("Relative source change under deformation = " << geometry_change);
CHECK(prepared_operator.GetPreparationCount() == 2);
CHECK(geometry_change > 1.0e-5);
}
TEST_CASE(
"Prepared Mapped Gravity Source Preserves Linearity And Excludes Vacuum",
tags::integration &tags::gravity &tags::prepared
) {
auto args = test_utils::setup_args();
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
operators::PreparedMappedGravitySourceOperator prepared_operator(
f, *f.domainMapperStateless
);
REQUIRE(prepared_operator.Width() == f.densityFes->GetTrueVSize());
REQUIRE(
prepared_operator.Height() == f.gravityPotentialFes->GetTrueVSize()
);
const mfem::Vector displacement = prepared_test::make_displacement(f, 1.0);
prepared_operator.Prepare(displacement);
const mfem::Vector first = prepared_test::make_deterministic_vector(
f.densityFes->GetTrueVSize(), 0.27
);
const mfem::Vector second = prepared_test::make_deterministic_vector(
f.densityFes->GetTrueVSize(), 0.79
);
const mfem::Vector combination =
prepared_test::linear_combination(first, 1.3, second, -0.6);
const mfem::Vector stellar_density =
prepared_test::make_domain_supported_density(f, true);
const mfem::Vector vacuum_density =
prepared_test::make_domain_supported_density(f, false);
mfem::Vector first_action;
mfem::Vector second_action;
mfem::Vector combination_action;
mfem::Vector stellar_action;
mfem::Vector vacuum_action;
prepared_operator.Mult(first, first_action);
prepared_operator.Mult(second, second_action);
prepared_operator.Mult(combination, combination_action);
prepared_operator.Mult(stellar_density, stellar_action);
prepared_operator.Mult(vacuum_density, vacuum_action);
const mfem::Vector expected_combination = prepared_test::linear_combination(
first_action, 1.3, second_action, -0.6
);
const MPI_Comm communicator = f.mesh->GetComm();
const double linearity_error = prepared_test::relative_error(
combination_action, expected_combination, communicator
);
const double stellar_norm =
prepared_test::global_norm(stellar_action, communicator);
const double vacuum_norm =
prepared_test::global_norm(vacuum_action, communicator);
const std::uint64_t preparation_count =
prepared_operator.GetPreparationCount();
mfem::Vector repeated_action;
prepared_operator.Mult(first, repeated_action);
INFO("Relative source linearity error = " << linearity_error);
INFO("Stellar source norm = " << stellar_norm);
INFO("Vacuum-only source norm = " << vacuum_norm);
CHECK_THAT(linearity_error, WithinAbs(0.0, 2.0e-12));
CHECK(stellar_norm > 0.0);
CHECK(vacuum_norm <= 1.0e-13 * stellar_norm);
CHECK(
prepared_test::relative_error(
repeated_action, first_action, communicator
) < 2.0e-14
);
CHECK(prepared_operator.GetPreparationCount() == preparation_count);
}