feat(newton): first newton solver implementation
This commit is contained in:
@@ -2,7 +2,10 @@
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <mfem.hpp>
|
||||
@@ -49,24 +52,30 @@ TEST_CASE(
|
||||
) {
|
||||
using namespace mean_field;
|
||||
|
||||
utils::Args args = test_utils::setup_args();
|
||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(f.okay());
|
||||
utils::Args args = test_utils::setup_args();
|
||||
fem::FEM physicalFiniteElements = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(physicalFiniteElements.okay());
|
||||
|
||||
fem::FEM borderedFiniteElements = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(borderedFiniteElements.okay());
|
||||
|
||||
models::StellarModel stellarModel{
|
||||
models::structure::PolytropicStructure{eos::Polytrope{3.0, 0.25}, 1.0},
|
||||
surface::ConstantPressureSurface{dimensions::PressureValue{0.0}}
|
||||
};
|
||||
operators::PreparedStellarEquilibriumOperator physicalOperator(f, *f.domainMapperStateless, stellarModel);
|
||||
operators::PreparedStellarEquilibriumOperator physicalOperator(
|
||||
physicalFiniteElements, *physicalFiniteElements.domainMapperStateless, stellarModel
|
||||
);
|
||||
auto equilibriumProblem = equilibrium::discretize(
|
||||
model::StellarModel(
|
||||
constraint::FixedCentralDensity({.RhoC = dimensions::DensityValue{1.0}}),
|
||||
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.0}}),
|
||||
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}), eos::Polytrope({.n = 3.0, .K = 0.25})
|
||||
),
|
||||
equilibrium::StellarDiscretization{f, *f.domainMapperStateless}
|
||||
std::move(borderedFiniteElements)
|
||||
);
|
||||
auto &borderedOperator = equilibriumProblem.GetPreparedOperator();
|
||||
auto &borderedOperator = equilibriumProblem.GetPreparedOperator();
|
||||
const MPI_Comm communicator = equilibriumProblem.GetCommunicator();
|
||||
|
||||
STATIC_CHECK(
|
||||
std::same_as<
|
||||
@@ -87,8 +96,7 @@ TEST_CASE(
|
||||
CHECK(borderedOperator.GetRootManifest().constraints().size() == 3);
|
||||
CHECK(borderedOperator.GetRootManifest().specificationDescriptors().size() == 4);
|
||||
|
||||
const auto ¢ralDescriptor =
|
||||
borderedOperator.GetRootManifest().specification<constraint::FixedCentralDensity>();
|
||||
const auto ¢ralDescriptor = borderedOperator.GetRootManifest().specification<constraint::FixedCentralDensity>();
|
||||
CHECK(centralDescriptor.stableId == "FixedCentralDensity");
|
||||
CHECK(centralDescriptor.role == models::SpecificationRole::phase_condition);
|
||||
CHECK(centralDescriptor.columnPolicy == operators::RootColumnPolicy::solver_border);
|
||||
@@ -99,10 +107,9 @@ TEST_CASE(
|
||||
CHECK(centralDescriptor.residualUnits == "specific_enthalpy");
|
||||
|
||||
mfem::Vector physicalState(physicalOperator.Width());
|
||||
physicalState = 0.0;
|
||||
const auto physicalStateView =
|
||||
physicalOperator.GetRootManifest().stateView(physicalState);
|
||||
physicalStateView.block(utils::blocks::density_field.mass_term) = 1.0;
|
||||
physicalState = 0.0;
|
||||
const auto physicalStateView = physicalOperator.GetRootManifest().stateView(physicalState);
|
||||
physicalStateView.block(utils::blocks::density_field.mass_term) = 1.0;
|
||||
physicalStateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
|
||||
|
||||
mfem::Vector borderedState(borderedOperator.Width());
|
||||
@@ -152,7 +159,7 @@ TEST_CASE(
|
||||
localCenterDirection += enthalpyDirection(centerDof);
|
||||
}
|
||||
double globalCenterDirection = 0.0;
|
||||
MPI_Allreduce(&localCenterDirection, &globalCenterDirection, 1, MPI_DOUBLE, MPI_SUM, f.mesh->GetComm());
|
||||
MPI_Allreduce(&localCenterDirection, &globalCenterDirection, 1, MPI_DOUBLE, MPI_SUM, communicator);
|
||||
CHECK(borderedAction(borderedAction.Size() - 1) == globalCenterDirection);
|
||||
|
||||
const auto repeatedReport = borderedOperator.Prepare(borderedState, dependencies, rotation);
|
||||
@@ -181,6 +188,60 @@ TEST_CASE(
|
||||
localBorderEntry += enthalpyAction(centerDof);
|
||||
}
|
||||
double globalBorderEntry = 0.0;
|
||||
MPI_Allreduce(&localBorderEntry, &globalBorderEntry, 1, MPI_DOUBLE, MPI_SUM, f.mesh->GetComm());
|
||||
MPI_Allreduce(&localBorderEntry, &globalBorderEntry, 1, MPI_DOUBLE, MPI_SUM, communicator);
|
||||
CHECK(globalBorderEntry == -0.625);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Central Density Variadic Preparation Rejects A Non-Finite Phase Coordinate Without Unwinding",
|
||||
tags::central_density_phase_integration
|
||||
) {
|
||||
using namespace mean_field;
|
||||
|
||||
utils::Args args = test_utils::setup_args();
|
||||
fem::FEM finiteElements = fem::setup_fem(args.mesh_file, args, 0);
|
||||
REQUIRE(finiteElements.okay());
|
||||
|
||||
auto equilibriumProblem = equilibrium::discretize(
|
||||
model::StellarModel(
|
||||
constraint::FixedCentralDensity({.RhoC = dimensions::DensityValue{1.0}}),
|
||||
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{1.0}}),
|
||||
surface::Isobaric({.Psurf = dimensions::PressureValue{0.0}}), eos::Polytrope({.n = 3.0, .K = 0.25})
|
||||
),
|
||||
std::move(finiteElements)
|
||||
);
|
||||
auto &preparedOperator = equilibriumProblem.GetPreparedOperator();
|
||||
|
||||
mfem::Vector state(preparedOperator.Width());
|
||||
state = 0.0;
|
||||
const auto stateView = preparedOperator.GetRootManifest().stateView(state);
|
||||
stateView.block(utils::blocks::density_field.mass_term) = 1.0;
|
||||
stateView.block(utils::blocks::enthalpy_field.specific_term) = 1.0;
|
||||
|
||||
const operators::StellarEquilibriumDependencies dependencies = make_dependencies();
|
||||
const physics::RigidRotation rotation = make_zero_rotation();
|
||||
REQUIRE(equilibriumProblem.TryPrepare(state, dependencies, rotation).has_value());
|
||||
|
||||
int rank = 0;
|
||||
REQUIRE(MPI_Comm_rank(equilibriumProblem.GetCommunicator(), &rank) == MPI_SUCCESS);
|
||||
auto phaseCoordinate = preparedOperator.GetRootManifest().stateView(state).block(
|
||||
utils::blocks::fixed_central_density_phase.central_value_term
|
||||
);
|
||||
REQUIRE(phaseCoordinate.Size() == 1);
|
||||
if (rank == 0) {
|
||||
phaseCoordinate(0) = std::numeric_limits<double>::quiet_NaN();
|
||||
phaseCoordinate.SyncAliasMemory(state);
|
||||
}
|
||||
|
||||
const auto rejected = equilibriumProblem.TryPrepare(state, dependencies, rotation);
|
||||
REQUIRE_FALSE(rejected.has_value());
|
||||
CHECK(rejected.error().reason == operators::StellarEquilibriumPreparationRejectionReason::non_finite_physics);
|
||||
CHECK(rejected.error().stage == operators::StellarEquilibriumPreparationStage::model_specification);
|
||||
CHECK_FALSE(equilibriumProblem.IsPrepared());
|
||||
CHECK_THROWS_AS(equilibriumProblem.Prepare(state, dependencies, rotation), std::domain_error);
|
||||
|
||||
phaseCoordinate(0) = 0.0;
|
||||
phaseCoordinate.SyncAliasMemory(state);
|
||||
REQUIRE(equilibriumProblem.TryPrepare(state, dependencies, rotation).has_value());
|
||||
CHECK(equilibriumProblem.IsPrepared());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user