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

@@ -361,3 +361,80 @@ TEST_CASE(
CHECK(recovered->preparedResidual);
CHECK(preparedOperator.IsPrepared());
}
TEST_CASE(
"Hydrostatic Tensor Preparation Matches Pointwise Preparation And Rebuilds On Mode Changes",
tags::barotrope_hydrostatic_prepared_residual &tags::unit
) {
const auto args = test_utils::setup_args();
auto f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(f.okay());
using namespace prepared_hydrostatic_test_utils;
mean_field::operators::PreparedHydrostaticEquilibriumOperator fast(f, *f.domainMapperStateless);
mean_field::operators::PreparedHydrostaticEquilibriumOperator reference(f, *f.domainMapperStateless);
auto h = make_enthalpy(f), phi = make_gravity_potential(f);
const auto dh = make_enthalpy(f, 0.53), dp = make_gravity_potential(f, 0.71);
const auto du = field_dof_test_utils::make_supported_displacement(f, 0.31);
const auto rotation = make_rotation();
auto dependencies = make_dependencies();
for (double scale : {0.0, 0.42, 0.73}) {
CAPTURE(scale);
const auto displacement = field_dof_test_utils::make_supported_displacement(f, scale);
h *= 1.01; phi *= 0.99;
++dependencies.displacement.revision;
++dependencies.enthalpy.revision;
++dependencies.gravityPotential.revision;
const auto state = make_state(h, phi, displacement, 0.39);
REQUIRE(fast.Prepare(state, dependencies, rotation).DidAnyWork());
REQUIRE(reference.PrepareReference(state, dependencies, rotation).DidAnyWork());
CHECK(fast.GetTensorDisplacementElementCount() > 0);
const auto compare = [&](auto &&apply) {
mfem::Vector a, b;
apply(fast, a); apply(reference, b);
CHECK(gravity_prepared_test_utils::relative_error(a, b, f.mesh->GetComm()) < 2.0e-11);
};
compare([](auto &op, auto &out) { op.BuildResidual(out); });
compare([&](auto &op, auto &out) { op.ApplyEnthalpyJacobianAction(dh, out); });
compare([&](auto &op, auto &out) { op.ApplyGravityPotentialJacobianAction(dp, out); });
compare([](auto &op, auto &out) { op.ApplyBernoulliConstantJacobianAction(0.13, out); });
compare([&](auto &op, auto &out) { op.ApplyDisplacementJacobianAction(du, out); });
compare([&](auto &op, auto &out) { op.ApplyCompleteJacobianAction(dh, dp, 0.13, du, out); });
compare([](auto &op, auto &out) { op.AssembleEnthalpyJacobianDiagonal(out); });
CHECK_FALSE(fast.Prepare(state, dependencies, rotation).DidAnyWork());
CHECK_FALSE(reference.PrepareReference(state, dependencies, rotation).DidAnyWork());
CHECK(fast.PrepareReference(state, dependencies, rotation).DidAnyWork());
compare([](auto &op, auto &out) { op.BuildResidual(out); });
CHECK_FALSE(fast.PrepareReference(state, dependencies, rotation).DidAnyWork());
CHECK(fast.Prepare(state, dependencies, rotation).DidAnyWork());
compare([&](auto &op, auto &out) { op.ApplyCompleteJacobianAction(dh, dp, 0.13, du, out); });
CHECK_FALSE(fast.Prepare(state, dependencies, rotation).DidAnyWork());
}
mfem::ParGridFunction foldedField(f.displacementFes.get());
mfem::VectorFunctionCoefficient fold(3, [](const mfem::Vector &x, mfem::Vector &u) {
u = x; u *= -2.0;
});
foldedField.ProjectCoefficient(fold);
mfem::Vector foldedTrue; foldedField.GetTrueDofs(foldedTrue);
const auto folded = fast.GetDisplacementMap().gather(foldedTrue);
++dependencies.displacement.revision;
const auto rejectedState = make_state(h, phi, folded, 0.39);
const auto rejected = fast.TryPrepare(rejectedState, dependencies, rotation);
const auto referenceRejected = reference.TryPrepareReference(rejectedState, dependencies, rotation);
REQUIRE_FALSE(rejected.has_value());
REQUIRE_FALSE(referenceRejected.has_value());
CHECK(rejected.error().reason == referenceRejected.error().reason);
CHECK(rejected.error().mappingStatus == mean_field::mapping::MappingStatus::non_positive_determinant);
CHECK_FALSE(fast.IsPrepared());
CHECK_FALSE(reference.IsPrepared());
const auto recovered = make_state(h, phi, du, 0.39);
++dependencies.displacement.revision;
REQUIRE(fast.TryPrepare(recovered, dependencies, rotation).has_value());
REQUIRE(reference.TryPrepareReference(recovered, dependencies, rotation).has_value());
mfem::Vector a, b;
fast.BuildResidual(a); reference.BuildResidual(b);
CHECK(gravity_prepared_test_utils::relative_error(a, b, f.mesh->GetComm()) < 2.0e-11);
}