feat(newton): first newton solver implementation

This commit is contained in:
2026-09-08 06:36:39 -04:00
parent 76818f2f82
commit b3c04d507a
98 changed files with 20397 additions and 11040 deletions

View File

@@ -3,6 +3,7 @@
#include <cmath>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <catch2/catch_test_macros.hpp>
@@ -205,6 +206,7 @@ TEST_CASE(
STATIC_REQUIRE_FALSE(std::is_copy_assignable_v<Operator>);
STATIC_REQUIRE_FALSE(std::is_move_constructible_v<Operator>);
STATIC_REQUIRE_FALSE(std::is_move_assignable_v<Operator>);
STATIC_REQUIRE(std::is_trivially_copyable_v<mean_field::operators::MassNormalizationPreparationRejection>);
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
@@ -271,6 +273,49 @@ TEST_CASE(
CHECK(mass_normalization_test_utils::relative_error(measuredScale, expectedScale) < 5e-7);
}
TEST_CASE(
"Prepared Mass Normalization Reports Non-Finite Density Interpolation Without Unwinding",
tags::barotrope_mass_normalization_context &tags::unit
) {
using namespace mass_normalization_test_utils;
mean_field::utils::Args args = test_utils::setup_args();
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
REQUIRE(f.okay());
mfem::Vector density = make_constant_density(f, -0.5 * std::numeric_limits<double>::max());
mfem::Vector displacement(f.displacementFes->GetTrueVSize());
displacement = 0.0;
auto dependencies = make_dependencies();
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext gravityContext(
f, *f.domainMapperStateless
);
prepare_gravity_context(gravityContext, f, density, displacement, dependencies);
mean_field::operators::PreparedMassNormalizationOperator massOperator(f, *f.domainMapperStateless, gravityContext);
const auto rejected = massOperator.TryPrepare({.targetMass = std::numeric_limits<double>::max()}, dependencies);
REQUIRE_FALSE(rejected.has_value());
CHECK(
rejected.error().reason ==
mean_field::operators::MassNormalizationPreparationRejectionReason::non_finite_density_interpolation
);
CHECK_FALSE(massOperator.IsPrepared());
CHECK_THROWS_AS(
massOperator.Prepare({.targetMass = std::numeric_limits<double>::max()}, dependencies), std::domain_error
);
density = make_constant_density(f, 1.0);
++dependencies.density.revision;
++dependencies.targetMass.revision;
prepare_gravity_context(gravityContext, f, density, displacement, dependencies);
const auto accepted = massOperator.TryPrepare({.targetMass = 1.0}, dependencies);
REQUIRE(accepted.has_value());
CHECK(massOperator.IsPrepared());
}
TEST_CASE(
"Prepared Mass Normalization Density Jacobian Matches Centered Difference",
tags::barotrope_mass_normalization_jacobian &tags::accuracy