feat(newton): first newton solver implementation
This commit is contained in:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user