feat(newton): first newton solver implementation
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
@@ -177,6 +178,26 @@ namespace gravity_displacement_force_test_utils {
|
||||
return direction;
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Vector make_affine_displacement(
|
||||
const mean_field::fem::FEM &f,
|
||||
const double scale
|
||||
) {
|
||||
mfem::ParGridFunction field(f.displacementFes.get());
|
||||
mfem::VectorFunctionCoefficient coefficient(
|
||||
f.mesh->Dimension(), [scale](const mfem::Vector &position, mfem::Vector &value) {
|
||||
value.SetSize(position.Size());
|
||||
for (int dimension = 0; dimension < position.Size(); ++dimension) {
|
||||
value(dimension) = scale * position(dimension);
|
||||
}
|
||||
}
|
||||
);
|
||||
field.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector result;
|
||||
field.GetTrueDofs(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Vector make_vacuum_only_density(const mean_field::fem::FEM &f) {
|
||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||
densityField = 0.0;
|
||||
@@ -422,6 +443,85 @@ TEST_CASE(
|
||||
CHECK(gravity_prepared_test_utils::global_norm(vacuumResidual, f.mesh->GetComm()) == 0.0);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Gravity Displacement Force Reports Candidate Mapping And Arithmetic Rejections",
|
||||
tags::gravity_unit
|
||||
) {
|
||||
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 = gravity_displacement_force_test_utils::make_density(f, 0.21);
|
||||
mfem::Vector gravityGradient = gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.37);
|
||||
mfem::Vector displacement = gravity_displacement_force_test_utils::make_affine_displacement(f, -2.0);
|
||||
mfem::Vector residual;
|
||||
|
||||
const auto invalidMapping = mean_field::operators::kernels::try_apply_gravity_displacement_force_residual(
|
||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
||||
);
|
||||
REQUIRE_FALSE(invalidMapping.has_value());
|
||||
CHECK(
|
||||
invalidMapping.error().reason ==
|
||||
mean_field::operators::kernels::GravityDisplacementForceRejectionReason::invalid_mapping
|
||||
);
|
||||
CHECK(invalidMapping.error().mappingStatus == mean_field::mapping::MappingStatus::non_positive_determinant);
|
||||
CHECK_THROWS_AS(
|
||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
||||
),
|
||||
std::domain_error
|
||||
);
|
||||
|
||||
displacement = 0.0;
|
||||
density = 1.0e200;
|
||||
gravityGradient = 1.0e200;
|
||||
const auto nonFiniteArithmetic = mean_field::operators::kernels::try_apply_gravity_displacement_force_residual(
|
||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
||||
);
|
||||
REQUIRE_FALSE(nonFiniteArithmetic.has_value());
|
||||
CHECK(
|
||||
nonFiniteArithmetic.error().reason ==
|
||||
mean_field::operators::kernels::GravityDisplacementForceRejectionReason::non_finite_arithmetic
|
||||
);
|
||||
|
||||
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
||||
gravityPotential = 0.0;
|
||||
auto revisions = gravity_displacement_force_test_utils::make_revisions();
|
||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext gravityContext(
|
||||
f, *f.domainMapperStateless
|
||||
);
|
||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||
gravityContext, density, displacement, gravityGradient, gravityPotential, revisions
|
||||
);
|
||||
mean_field::operators::PreparedGravityDisplacementForceOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, gravityContext
|
||||
);
|
||||
const auto preparedRejection = preparedOperator.TryPrepare();
|
||||
REQUIRE_FALSE(preparedRejection.has_value());
|
||||
CHECK(
|
||||
preparedRejection.error().reason ==
|
||||
mean_field::operators::kernels::GravityDisplacementForceRejectionReason::non_finite_arithmetic
|
||||
);
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
CHECK_THROWS_AS(preparedOperator.Prepare(), std::domain_error);
|
||||
|
||||
density = gravity_displacement_force_test_utils::make_density(f, 0.21);
|
||||
gravityGradient = gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.37);
|
||||
++revisions.density.value;
|
||||
++revisions.gravity_gradient.value;
|
||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||
gravityContext, density, displacement, gravityGradient, gravityPotential, revisions
|
||||
);
|
||||
const auto preparedAccepted = preparedOperator.TryPrepare();
|
||||
REQUIRE(preparedAccepted.has_value());
|
||||
CHECK(preparedOperator.IsPrepared());
|
||||
|
||||
const auto accepted = mean_field::operators::kernels::try_apply_gravity_displacement_force_residual(
|
||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
||||
);
|
||||
CHECK(accepted.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Gravity Displacement Force Reuses Shared Gravity Revisions",
|
||||
tags::gravity_prepared
|
||||
|
||||
Reference in New Issue
Block a user