Snapshot optimized solver and audit diagnostics before numerical experiments

This commit is contained in:
2026-09-16 14:34:06 -04:00
parent 75cc638739
commit 80cc3d83d7
64 changed files with 11969 additions and 267 deletions

View File

@@ -1,6 +1,7 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <cmath>
#include <memory>
#include <mfem.hpp>
#include <stdexcept>
@@ -12,6 +13,27 @@ using Catch::Matchers::WithinAbs;
namespace prepared_test = gravity_prepared_test_utils;
namespace {
// Deliberately not a KelvinCompactification dynamic type: the prepared
// operator must keep arbitrary exterior maps on the general derivative.
class DelegatingExteriorMap final : public mapping::compactification::ExteriorDomainMap {
public:
explicit DelegatingExteriorMap(mapping::compactification::options::KelvinCompactificationOptions options)
: kelvin(options) {}
mapping::MappingStatus Evaluate(const mapping::compactification::ExteriorMapInput &input,
mapping::compactification::ExteriorMapResult &result) const override {
return kelvin.Evaluate(input, result);
}
mapping::MappingStatus EvaluateVariation(const mapping::compactification::ExteriorMapInput &input,
const mapping::compactification::ExteriorMapResult &result,
const mapping::compactification::ExteriorMapDirection &direction,
mapping::compactification::ExteriorMapVariation &variation) const override {
return kelvin.EvaluateVariation(input, result, direction, variation);
}
std::string_view GetName() const noexcept override { return "DelegatingExteriorMap"; }
private:
mapping::compactification::KelvinCompactification kelvin;
};
[[nodiscard]] mfem::Vector make_folding_displacement(const mean_field::fem::FEM &f) {
mfem::ParGridFunction field(f.displacementFes.get());
mfem::VectorFunctionCoefficient coefficient(
@@ -65,9 +87,15 @@ TEST_CASE(
const mfem::Vector displacementTrue = prepared_test::make_displacement(f, scale);
const mfem::Vector displacement = preparedOperator.GetDisplacementMap().gather(displacementTrue);
preparedOperator.Prepare(displacement);
CHECK(preparedOperator.GetFastVariationElementCount() == f.mesh->GetNE());
CHECK(preparedOperator.GetTensorVariationElementCount() == f.mesh->GetNE());
preparedOperator.MultDisplacementVariationTrue(first, direction, firstAction);
mfem::Vector referenceAction;
preparedOperator.MultDisplacementVariationTrueCachedReference(first, direction, referenceAction);
CHECK(prepared_test::relative_error(firstAction, referenceAction, communicator) < 2.0e-11);
preparedOperator.MultDisplacementVariationTrueReference(first, direction, referenceAction);
CHECK(prepared_test::relative_error(firstAction, referenceAction, communicator) < 2.0e-11);
operators::kernels::apply_mapped_hdiv_mass_variation(
f, *f.domainMapperStateless, first, displacementTrue, direction, referenceAction
);
@@ -85,6 +113,39 @@ TEST_CASE(
CHECK(preparedOperator.GetPreparationCount() == 2);
}
TEST_CASE("Prepared Hdiv Tangent Retains General Exterior Map Fallback",
tags::gravity_prepared_jacobian_accuracy) {
auto args = test_utils::setup_args();
auto f = fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(f.okay());
mapping::DomainMapper mapper(args.domain_mapper_options, std::make_unique<DelegatingExteriorMap>(args.kelvin_options));
operators::PreparedMappedHDivMassOperator prepared(f, mapper);
const auto base = prepared_test::make_displacement(f, 0.7);
const auto direction = prepared_test::make_displacement(f, 0.43);
const auto flux = prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.31);
prepared.Prepare(prepared.GetDisplacementMap().gather(base));
int stellarElements = 0;
for (int element = 0; element < f.mesh->GetNE(); ++element)
stellarElements += !mapper.IsCompactifiedElement(*f.mesh->GetElementTransformation(element));
CHECK(prepared.GetFastVariationElementCount() == stellarElements);
mfem::Vector actual, expected;
prepared.MultDisplacementVariationTrue(flux, direction, actual);
operators::kernels::apply_mapped_hdiv_mass_variation(f, mapper, flux, base, direction, expected);
CHECK(prepared_test::relative_error(actual, expected, f.mesh->GetComm()) < 2.0e-11);
prepared.PreparePrimal(prepared.GetDisplacementMap().gather(base));
CHECK_FALSE(prepared.HasVariationData());
CHECK(prepared.GetFastVariationElementCount() == 0);
CHECK(prepared.GetFastMassElementCount() == f.mesh->GetNE());
mfem::Vector primal, primalReference;
const auto reducedFlux = prepared.GetFluxMap().gather(flux);
prepared.Mult(reducedFlux, primal);
prepared.MultReference(reducedFlux, primalReference);
CHECK(prepared_test::relative_error(primal, primalReference, f.mesh->GetComm()) < 2.0e-11);
prepared.Prepare(prepared.GetDisplacementMap().gather(base));
prepared.MultDisplacementVariationTrue(flux, direction, actual);
CHECK(prepared_test::relative_error(actual, expected, f.mesh->GetComm()) < 2.0e-11);
}
TEST_CASE(
"Prepared Mapped Hdiv Mass Reports Invalid Candidate Geometry Without Unwinding",
tags::gravity_prepared_unit &tags::geometry
@@ -144,6 +205,13 @@ TEST_CASE(
mfem::Vector prepared_action;
prepared_operator.Mult(gravity_gradient, prepared_action);
CHECK(prepared_operator.GetFastMassElementCount() == f.mesh->GetNE());
mfem::Vector mfemAction;
prepared_operator.MultReference(gravity_gradient, mfemAction);
CHECK(prepared_test::relative_error(prepared_action, mfemAction, communicator) < 2.0e-11);
// Reference calls must restore the optimized mode and leave PA data intact.
prepared_operator.Mult(gravity_gradient, mfemAction);
CHECK(prepared_test::relative_error(prepared_action, mfemAction, communicator) < 2.0e-14);
mfem::Vector reference_action_true;
operators::kernels::apply_mapped_hdiv_mass(
f, *f.domainMapperStateless, gravity_gradient_true, displacement_true, reference_action_true