feat(newton): first newton solver implementation
This commit is contained in:
@@ -9,6 +9,28 @@ using namespace mean_field;
|
||||
namespace prepared_test = gravity_prepared_test_utils;
|
||||
namespace gravity_context = operators::context::gravity_field;
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] mfem::Vector makeAffineDisplacement(
|
||||
const fem::FEM &finiteElements,
|
||||
const double scale
|
||||
) {
|
||||
mfem::ParGridFunction field(finiteElements.displacementFes.get());
|
||||
mfem::VectorFunctionCoefficient coefficient(
|
||||
finiteElements.mesh->Dimension(), [scale](const mfem::Vector &position, mfem::Vector &value) {
|
||||
value.SetSize(position.Size());
|
||||
for (int component = 0; component < position.Size(); ++component) {
|
||||
value(component) = scale * position(component);
|
||||
}
|
||||
}
|
||||
);
|
||||
field.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector result;
|
||||
field.GetTrueDofs(result);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE(
|
||||
"Gravity Field Linearization Context Applies Selective Invalidation",
|
||||
tags::gravity_context
|
||||
@@ -125,6 +147,70 @@ TEST_CASE(
|
||||
CHECK(context.GetGeometryContext().GetSourceOperator().GetPreparationCount() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Gravity Field Contexts Invalidate And Recover After Candidate Rejection",
|
||||
tags::gravity_context &tags::geometry &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
gravity_context::GravityFieldGeometryContext geometryContext(f, *f.domainMapperStateless);
|
||||
const mfem::Vector zeroDisplacement = geometryContext.GetDisplacementMap().gather(makeAffineDisplacement(f, 0.0));
|
||||
const mfem::Vector foldedDisplacement =
|
||||
geometryContext.GetDisplacementMap().gather(makeAffineDisplacement(f, -2.0));
|
||||
|
||||
REQUIRE(geometryContext.TryPrepare(zeroDisplacement, {.value = 0}, {.value = 0}).has_value());
|
||||
REQUIRE(geometryContext.IsPrepared());
|
||||
|
||||
const auto geometryRejection = geometryContext.TryPrepare(foldedDisplacement, {.value = 0}, {.value = 1});
|
||||
REQUIRE_FALSE(geometryRejection.has_value());
|
||||
CHECK(geometryRejection.error().reason == gravity_context::GravityFieldPreparationRejectionReason::invalid_mapping);
|
||||
CHECK(geometryRejection.error().mappingStatus == mapping::MappingStatus::non_positive_determinant);
|
||||
CHECK_FALSE(geometryContext.IsPrepared());
|
||||
|
||||
const auto geometryRecovery = geometryContext.TryPrepare(zeroDisplacement, {.value = 0}, {.value = 1});
|
||||
REQUIRE(geometryRecovery.has_value());
|
||||
CHECK(geometryRecovery->reconstructed_operators);
|
||||
CHECK(geometryContext.IsPrepared());
|
||||
|
||||
gravity_context::GravityFieldLinearizationContext linearizationContext(f, *f.domainMapperStateless);
|
||||
mfem::Vector density =
|
||||
prepared_test::make_deterministic_vector(linearizationContext.GetDensityMap().reduced_size(), 0.17);
|
||||
mfem::Vector gravityGradient =
|
||||
prepared_test::make_deterministic_vector(linearizationContext.GetGravityGradientMap().reduced_size(), 0.41);
|
||||
mfem::Vector gravityPotential =
|
||||
prepared_test::make_deterministic_vector(linearizationContext.GetGravityPotentialMap().reduced_size(), 0.73);
|
||||
gravity_context::GravityFieldRevisions revisions;
|
||||
|
||||
const auto makeState = [&](const mfem::Vector &displacement) {
|
||||
return gravity_context::GravityFieldStateView{
|
||||
.density = density,
|
||||
.displacement = displacement,
|
||||
.gravity_gradient = gravityGradient,
|
||||
.gravity_potential = gravityPotential
|
||||
};
|
||||
};
|
||||
|
||||
REQUIRE(linearizationContext.TryPrepare(makeState(zeroDisplacement), revisions).has_value());
|
||||
REQUIRE(linearizationContext.IsPrepared());
|
||||
|
||||
revisions.displacement.value = 1;
|
||||
const auto linearizationRejection = linearizationContext.TryPrepare(makeState(foldedDisplacement), revisions);
|
||||
REQUIRE_FALSE(linearizationRejection.has_value());
|
||||
CHECK(
|
||||
linearizationRejection.error().reason ==
|
||||
gravity_context::GravityFieldPreparationRejectionReason::invalid_mapping
|
||||
);
|
||||
CHECK(linearizationRejection.error().mappingStatus == mapping::MappingStatus::non_positive_determinant);
|
||||
CHECK_FALSE(linearizationContext.IsPrepared());
|
||||
|
||||
const auto linearizationRecovery = linearizationContext.TryPrepare(makeState(zeroDisplacement), revisions);
|
||||
REQUIRE(linearizationRecovery.has_value());
|
||||
CHECK(linearizationRecovery->geometry.reconstructed_operators);
|
||||
CHECK(linearizationContext.IsPrepared());
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Gravity Field Geometry Context Distinguishes Primal And Linearization Preparation",
|
||||
tags::gravity_context
|
||||
|
||||
Reference in New Issue
Block a user