feat(newton): first newton solver implementation
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <mfem.hpp>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
import mean_field;
|
||||
@@ -101,6 +102,22 @@ namespace prepared_barotropic_closure_test_utils {
|
||||
return project_scalar(finiteElementSpace, coefficient);
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Vector make_folding_displacement(const mean_field::fem::FEM &f) {
|
||||
mfem::ParGridFunction fieldValue(f.displacementFes.get());
|
||||
mfem::VectorFunctionCoefficient coefficient(
|
||||
f.mesh->Dimension(), [](const mfem::Vector &position, mfem::Vector &value) {
|
||||
value.SetSize(position.Size());
|
||||
value = 0.0;
|
||||
value(0) = -2.0 * position(0);
|
||||
}
|
||||
);
|
||||
fieldValue.ProjectCoefficient(coefficient);
|
||||
|
||||
mfem::Vector result;
|
||||
fieldValue.GetTrueDofs(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Vector reduce(
|
||||
const field::FieldDofMap &map,
|
||||
const mfem::Vector &full
|
||||
@@ -263,6 +280,7 @@ namespace prepared_barotropic_closure_test_utils {
|
||||
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::BarotropicClosurePreparationRejection>);
|
||||
|
||||
auto args = test_utils::setup_args();
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
@@ -303,6 +321,115 @@ namespace prepared_barotropic_closure_test_utils {
|
||||
CHECK(globalEnthalpyReduced < globalEnthalpyFull);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Reports Expected EOS Rejections Without Unwinding",
|
||||
tags::barotrope &tags::closure &tags::prepared &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
const Maps maps(f);
|
||||
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, equationOfState
|
||||
);
|
||||
|
||||
mfem::Vector density(maps.density.reduced_size());
|
||||
mfem::Vector enthalpy(maps.enthalpy.reduced_size());
|
||||
mfem::Vector displacement(maps.displacement.reduced_size());
|
||||
density = 0.0;
|
||||
enthalpy = -1.0;
|
||||
displacement = 0.0;
|
||||
auto dependencies = make_dependencies();
|
||||
|
||||
const auto outsideDomain =
|
||||
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
REQUIRE_FALSE(outsideDomain.has_value());
|
||||
CHECK(
|
||||
outsideDomain.error().reason ==
|
||||
mean_field::operators::BarotropicClosurePreparationRejectionReason::equation_of_state
|
||||
);
|
||||
CHECK(outsideDomain.error().equationOfStateError == mean_field::eos::EvaluationErrorCode::outside_domain);
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
try {
|
||||
(void)preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
FAIL("The compatibility Prepare overload accepted an out-of-domain EOS input.");
|
||||
} catch (const mean_field::eos::EvaluationError &error) {
|
||||
CHECK(error.code() == mean_field::eos::EvaluationErrorCode::outside_domain);
|
||||
}
|
||||
|
||||
// Keep the interpolated input finite while forcing the n = 3
|
||||
// polytropic density evaluation to overflow.
|
||||
enthalpy = 1.0e150;
|
||||
++dependencies.enthalpy.revision;
|
||||
|
||||
const auto rejected =
|
||||
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
REQUIRE_FALSE(rejected.has_value());
|
||||
CHECK(
|
||||
rejected.error().reason ==
|
||||
mean_field::operators::BarotropicClosurePreparationRejectionReason::equation_of_state
|
||||
);
|
||||
CHECK(rejected.error().equationOfStateError == mean_field::eos::EvaluationErrorCode::nonfinite_result);
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
try {
|
||||
(void)preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
FAIL("The compatibility Prepare overload accepted a non-finite EOS result.");
|
||||
} catch (const mean_field::eos::EvaluationError &error) {
|
||||
CHECK(error.code() == mean_field::eos::EvaluationErrorCode::nonfinite_result);
|
||||
}
|
||||
|
||||
enthalpy = 1.0;
|
||||
++dependencies.enthalpy.revision;
|
||||
const auto accepted =
|
||||
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
REQUIRE(accepted.has_value());
|
||||
CHECK(preparedOperator.IsPrepared());
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Reports Invalid Candidate Geometry Without Unwinding",
|
||||
tags::barotrope &tags::closure &tags::prepared &tags::geometry &tags::unit
|
||||
) {
|
||||
auto args = test_utils::setup_args();
|
||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
|
||||
const Maps maps(f);
|
||||
const mean_field::eos::Polytrope equationOfState(3.0, 1.5);
|
||||
mean_field::operators::PreparedBarotropicClosureOperator preparedOperator(
|
||||
f, *f.domainMapperStateless, equationOfState
|
||||
);
|
||||
|
||||
mfem::Vector density(maps.density.reduced_size());
|
||||
mfem::Vector enthalpy(maps.enthalpy.reduced_size());
|
||||
density = 1.0;
|
||||
enthalpy = 1.0;
|
||||
mfem::Vector displacement = reduce(maps.displacement, make_folding_displacement(f));
|
||||
auto dependencies = make_dependencies();
|
||||
|
||||
const auto rejected =
|
||||
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
REQUIRE_FALSE(rejected.has_value());
|
||||
CHECK(
|
||||
rejected.error().reason ==
|
||||
mean_field::operators::BarotropicClosurePreparationRejectionReason::mapping_failure
|
||||
);
|
||||
CHECK(rejected.error().mappingStatus == mean_field::mapping::MappingStatus::non_positive_determinant);
|
||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||
CHECK_THROWS_AS(
|
||||
preparedOperator.Prepare(make_state_view(density, enthalpy, displacement), dependencies), std::domain_error
|
||||
);
|
||||
|
||||
displacement = 0.0;
|
||||
++dependencies.displacement.revision;
|
||||
const auto accepted =
|
||||
preparedOperator.TryPrepare(make_state_view(density, enthalpy, displacement), dependencies);
|
||||
REQUIRE(accepted.has_value());
|
||||
CHECK(preparedOperator.IsPrepared());
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Prepared Barotropic Closure Matches Full Stateless Kernels Through FieldDof Restriction",
|
||||
tags::barotrope &tags::closure &tags::hydro &tags::prepared &tags::field &tags::integration
|
||||
|
||||
Reference in New Issue
Block a user