Snapshot optimized solver and audit diagnostics before numerical experiments
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user