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

@@ -1,5 +1,6 @@
module;
#include <cmath>
#include <expected>
#include <memory>
#include <mfem.hpp>
@@ -9,6 +10,30 @@ import :operators.context.gravity_field;
namespace {
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
[[nodiscard]] mean_field::operators::context::gravity_field::GravityFieldPreparationRejection
make_gravity_field_rejection(const mean_field::operators::HDivMassPreparationRejection &rejection) {
using ChildReason = mean_field::operators::HDivMassPreparationRejectionReason;
using Failure = mean_field::operators::context::gravity_field::GravityFieldPreparationRejection;
using Reason = mean_field::operators::context::gravity_field::GravityFieldPreparationRejectionReason;
return Failure{
.reason = rejection.reason == ChildReason::invalid_mapping ? Reason::invalid_mapping
: Reason::non_finite_arithmetic,
.mappingStatus = rejection.mappingStatus
};
}
[[nodiscard]] mean_field::operators::context::gravity_field::GravityFieldPreparationRejection
make_gravity_field_rejection(const mean_field::operators::GravitySourcePreparationRejection &rejection) {
using ChildReason = mean_field::operators::GravitySourcePreparationRejectionReason;
using Failure = mean_field::operators::context::gravity_field::GravityFieldPreparationRejection;
using Reason = mean_field::operators::context::gravity_field::GravityFieldPreparationRejectionReason;
return Failure{
.reason = rejection.reason == ChildReason::invalid_mapping ? Reason::invalid_mapping
: Reason::non_finite_arithmetic,
.mappingStatus = rejection.mappingStatus
};
}
void true_to_local(
const mfem::ParFiniteElementSpace &finite_element_space,
const mfem::Vector &true_vector,
@@ -295,7 +320,21 @@ namespace mean_field::operators::context::gravity_field {
const DiscretizationRevision discretization_revision,
const DisplacementRevision displacement_revision
) {
return PrepareImpl(
auto result = TryPrepareImpl(
displacement, discretization_revision, displacement_revision, PreparationMode::linearization
);
if (!result.has_value()) {
throwGravityFieldPreparationRejection(result.error());
}
return std::move(result).value();
}
GravityFieldPreparationResult<GravityFieldGeometryPreparation> GravityFieldGeometryContext::TryPrepare(
const mfem::Vector &displacement,
const DiscretizationRevision discretization_revision,
const DisplacementRevision displacement_revision
) {
return TryPrepareImpl(
displacement, discretization_revision, displacement_revision, PreparationMode::linearization
);
}
@@ -305,10 +344,23 @@ namespace mean_field::operators::context::gravity_field {
const DiscretizationRevision discretization_revision,
const DisplacementRevision displacement_revision
) {
return PrepareImpl(displacement, discretization_revision, displacement_revision, PreparationMode::primal);
auto result =
TryPrepareImpl(displacement, discretization_revision, displacement_revision, PreparationMode::primal);
if (!result.has_value()) {
throwGravityFieldPreparationRejection(result.error());
}
return std::move(result).value();
}
GravityFieldGeometryPreparation GravityFieldGeometryContext::PrepareImpl(
GravityFieldPreparationResult<GravityFieldGeometryPreparation> GravityFieldGeometryContext::TryPreparePrimal(
const mfem::Vector &displacement,
const DiscretizationRevision discretization_revision,
const DisplacementRevision displacement_revision
) {
return TryPrepareImpl(displacement, discretization_revision, displacement_revision, PreparationMode::primal);
}
GravityFieldPreparationResult<GravityFieldGeometryPreparation> GravityFieldGeometryContext::TryPrepareImpl(
const mfem::Vector &displacement,
const DiscretizationRevision discretization_revision,
const DisplacementRevision displacement_revision,
@@ -340,19 +392,24 @@ namespace mean_field::operators::context::gravity_field {
return preparation;
}
const auto prepare_mass = [&](PreparedMappedHDivMassOperator &mass_operator) {
// The existing child operators may be mutated by a fallible
// preparation below. Stop advertising the parent as prepared until
// every child has accepted the same candidate and the parent state is
// committed.
m_is_prepared = false;
m_variation_state_prepared = false;
const auto prepare_mass = [&](PreparedMappedHDivMassOperator &mass_operator) {
if (requires_variation) {
mass_operator.Prepare(displacement);
} else {
mass_operator.PreparePrimal(displacement);
return mass_operator.TryPrepare(displacement);
}
return mass_operator.TryPreparePrimal(displacement);
};
const auto prepare_source = [&](PreparedMappedGravitySourceOperator &source_operator) {
if (requires_variation) {
source_operator.Prepare(displacement);
} else {
source_operator.PreparePrimal(displacement);
return source_operator.TryPrepare(displacement);
}
return source_operator.TryPreparePrimal(displacement);
};
if (discretization_changed) {
@@ -361,8 +418,14 @@ namespace mean_field::operators::context::gravity_field {
auto divergence_operator = make_divergence_operator(m_fem);
auto transpose_divergence_operator = std::make_unique<mfem::TransposeOperator>(divergence_operator.get());
prepare_mass(*mass_operator);
prepare_source(*source_operator);
auto massResult = prepare_mass(*mass_operator);
if (!massResult.has_value()) {
return std::unexpected(make_gravity_field_rejection(massResult.error()));
}
auto sourceResult = prepare_source(*source_operator);
if (!sourceResult.has_value()) {
return std::unexpected(make_gravity_field_rejection(sourceResult.error()));
}
m_mass_operator = std::move(mass_operator);
m_source_operator = std::move(source_operator);
@@ -383,8 +446,14 @@ namespace mean_field::operators::context::gravity_field {
"operator."
);
prepare_mass(*m_mass_operator);
prepare_source(*m_source_operator);
auto massResult = prepare_mass(*m_mass_operator);
if (!massResult.has_value()) {
return std::unexpected(make_gravity_field_rejection(massResult.error()));
}
auto sourceResult = prepare_source(*m_source_operator);
if (!sourceResult.has_value()) {
return std::unexpected(make_gravity_field_rejection(sourceResult.error()));
}
preparation.rebuilt_mass_operator = true;
preparation.rebuilt_source_operator = true;
@@ -510,6 +579,17 @@ namespace mean_field::operators::context::gravity_field {
GravityFieldPreparationReport GravityFieldLinearizationContext::Prepare(
const GravityFieldStateView &state,
const GravityFieldRevisions &revisions
) {
auto result = TryPrepare(state, revisions);
if (!result.has_value()) {
throwGravityFieldPreparationRejection(result.error());
}
return std::move(result).value();
}
GravityFieldPreparationResult<GravityFieldPreparationReport> GravityFieldLinearizationContext::TryPrepare(
const GravityFieldStateView &state,
const GravityFieldRevisions &revisions
) {
validate_linearization_state(
m_density_map, m_geometry_context.GetDisplacementMap(), m_gravity_gradient_map, m_gravity_potential_map,
@@ -554,8 +634,17 @@ namespace mean_field::operators::context::gravity_field {
GravityFieldPreparationReport report;
report.geometry =
m_geometry_context.Prepare(state.displacement, revisions.discretization, revisions.displacement);
// Geometry preparation is fallible and may invalidate one of its
// prepared children. The linearization context must therefore remain
// inaccessible until the complete shared state has been committed.
m_is_prepared = false;
auto geometryResult =
m_geometry_context.TryPrepare(state.displacement, revisions.discretization, revisions.displacement);
if (!geometryResult.has_value()) {
return std::unexpected(geometryResult.error());
}
report.geometry = std::move(geometryResult).value();
if (density_changed) {
m_density_true.SetSize(m_density_map.full_size());