feat(newton): first newton solver implementation
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
module;
|
||||
#include "profile.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
#include <numbers>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <mpi.h>
|
||||
|
||||
module mean_field;
|
||||
import :operators.prepared_gravity_source;
|
||||
@@ -12,6 +18,54 @@ import :operators.prepared_gravity_source;
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
[[nodiscard]] bool is_candidate_mapping_failure(const mean_field::mapping::MappingStatus status) {
|
||||
using mean_field::mapping::MappingStatus;
|
||||
return status == MappingStatus::non_finite_input || status == MappingStatus::non_finite_result ||
|
||||
status == MappingStatus::non_positive_determinant;
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::GravitySourcePreparationResult synchronize_preparation_failure(
|
||||
const mean_field::mapping::MappingStatus localMappingStatus,
|
||||
const bool localNonFiniteArithmetic,
|
||||
const MPI_Comm communicator
|
||||
) {
|
||||
std::array<int, 3> localFailures{0, 0, localNonFiniteArithmetic ? 1 : 0};
|
||||
if (localMappingStatus != mean_field::mapping::MappingStatus::valid) {
|
||||
const int encodedStatus = static_cast<int>(localMappingStatus) + 1;
|
||||
localFailures[is_candidate_mapping_failure(localMappingStatus) ? 0 : 1] = encodedStatus;
|
||||
}
|
||||
|
||||
std::array<int, 3> globalFailures{};
|
||||
if (MPI_Allreduce(
|
||||
localFailures.data(), globalFailures.data(), static_cast<int>(localFailures.size()), MPI_INT, MPI_MAX,
|
||||
communicator
|
||||
) != MPI_SUCCESS) {
|
||||
throw std::runtime_error("PreparedMappedGravitySourceOperator could not synchronize candidate validity.");
|
||||
}
|
||||
if (globalFailures[1] != 0) {
|
||||
throw std::runtime_error(
|
||||
"PreparedMappedGravitySourceOperator encountered a structural mapping failure with status " +
|
||||
std::to_string(globalFailures[1] - 1) + "."
|
||||
);
|
||||
}
|
||||
if (globalFailures[0] != 0) {
|
||||
return std::unexpected(
|
||||
mean_field::operators::GravitySourcePreparationRejection{
|
||||
.reason = mean_field::operators::GravitySourcePreparationRejectionReason::invalid_mapping,
|
||||
.mappingStatus = static_cast<mean_field::mapping::MappingStatus>(globalFailures[0] - 1)
|
||||
}
|
||||
);
|
||||
}
|
||||
if (globalFailures[2] != 0) {
|
||||
return std::unexpected(
|
||||
mean_field::operators::GravitySourcePreparationRejection{
|
||||
.reason = mean_field::operators::GravitySourcePreparationRejectionReason::non_finite_arithmetic
|
||||
}
|
||||
);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
int get_operator_height(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr, "PreparedMappedGravitySourceOperator requires the "
|
||||
@@ -135,55 +189,33 @@ namespace {
|
||||
);
|
||||
|
||||
if (status != mean_field::mapping::MappingStatus::valid) {
|
||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
||||
|
||||
mfem::Vector displacement_shape(displacement_element.GetDof());
|
||||
mfem::Vector compactification_shape(compactification_element.GetDof());
|
||||
mfem::Vector reference_position(m_domain_mapper.GetDimension());
|
||||
mfem::Vector displacement_value(m_domain_mapper.GetDimension());
|
||||
|
||||
displacement_element.CalcShape(integration_point, displacement_shape);
|
||||
compactification_element.CalcShape(integration_point, compactification_shape);
|
||||
transformation.Transform(integration_point, reference_position);
|
||||
m_displacement_data->GetDofMatrix().MultTranspose(displacement_shape, displacement_value);
|
||||
|
||||
const double compactification_coordinate = m_compactification_data->GetDofs() * compactification_shape;
|
||||
|
||||
MFEM_ABORT(
|
||||
"Stateless domain mapping failed while preparing the "
|
||||
"gravity "
|
||||
"source operator."
|
||||
<< "\nMapping status = " << static_cast<int>(status) << "\nElement ID = " << element_id
|
||||
<< "\nElement attribute = " << transformation.Attribute
|
||||
<< "\nIntegration-point index = " << integration_point.index << "\nIntegration point = <"
|
||||
<< integration_point.x << ", " << integration_point.y << ", " << integration_point.z << ">"
|
||||
<< "\nReference position = <" << reference_position(0) << ", " << reference_position(1) << ", "
|
||||
<< reference_position(2) << ">"
|
||||
<< "\nReference radius = " << reference_position.Norml2() << "\nDisplacement value = <"
|
||||
<< displacement_value(0) << ", " << displacement_value(1) << ", " << displacement_value(2) << ">"
|
||||
<< "\nDisplacement magnitude = " << displacement_value.Norml2()
|
||||
<< "\nCompactification coordinate = " << compactification_coordinate
|
||||
<< "\nDisplacement ordering = " << static_cast<int>(m_fem.displacementFes->GetOrdering())
|
||||
);
|
||||
m_mappingFailure = status;
|
||||
return 0.0;
|
||||
}
|
||||
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
||||
"Prepared gravity source operator encountered a non-positive "
|
||||
"or "
|
||||
"non-finite mapping determinant."
|
||||
);
|
||||
|
||||
m_inverse_element_jacobian = mapping_context.quadrature.J_inv;
|
||||
m_inverse_element_jacobian = mapping_context.quadrature.J_inv;
|
||||
|
||||
return 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
|
||||
const double value = 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
|
||||
if (!std::isfinite(value)) {
|
||||
m_nonFiniteArithmetic = true;
|
||||
return 0.0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::DenseMatrix &GetInverseElementJacobian() const noexcept {
|
||||
return m_inverse_element_jacobian;
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::mapping::MappingStatus GetMappingFailure() const noexcept {
|
||||
return m_mappingFailure;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasNonFiniteArithmetic() const noexcept {
|
||||
return m_nonFiniteArithmetic;
|
||||
}
|
||||
|
||||
private:
|
||||
void LoadElement(const int element_id) {
|
||||
if (element_id == m_cached_element_id) {
|
||||
@@ -239,6 +271,8 @@ namespace {
|
||||
mean_field::mapping::DomainMapper::Workspace m_workspace;
|
||||
mfem::DenseMatrix m_inverse_element_jacobian;
|
||||
int m_cached_element_id{-1};
|
||||
mean_field::mapping::MappingStatus m_mappingFailure{mean_field::mapping::MappingStatus::valid};
|
||||
bool m_nonFiniteArithmetic{false};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -306,15 +340,32 @@ namespace mean_field::operators {
|
||||
|
||||
void PreparedMappedGravitySourceOperator::Prepare(const mfem::Vector &displacement) {
|
||||
MEAN_FIELD_PROFILE_SCOPE_WARMUP("PreparedMappedGravitySourceOperator::Prepare linearization", 0);
|
||||
PrepareImpl(displacement, PreparationMode::linearization);
|
||||
auto result = TryPrepareImpl(displacement, PreparationMode::linearization);
|
||||
if (!result.has_value()) {
|
||||
throwGravitySourcePreparationRejection(result.error());
|
||||
}
|
||||
}
|
||||
|
||||
void PreparedMappedGravitySourceOperator::PreparePrimal(const mfem::Vector &displacement) {
|
||||
MEAN_FIELD_PROFILE_SCOPE_WARMUP("PreparedMappedGravitySourceOperator::Prepare primal", 0);
|
||||
PrepareImpl(displacement, PreparationMode::primal);
|
||||
auto result = TryPrepareImpl(displacement, PreparationMode::primal);
|
||||
if (!result.has_value()) {
|
||||
throwGravitySourcePreparationRejection(result.error());
|
||||
}
|
||||
}
|
||||
|
||||
void PreparedMappedGravitySourceOperator::PrepareImpl(
|
||||
GravitySourcePreparationResult PreparedMappedGravitySourceOperator::TryPrepare(const mfem::Vector &displacement) {
|
||||
MEAN_FIELD_PROFILE_SCOPE_WARMUP("PreparedMappedGravitySourceOperator::TryPrepare linearization", 0);
|
||||
return TryPrepareImpl(displacement, PreparationMode::linearization);
|
||||
}
|
||||
|
||||
GravitySourcePreparationResult
|
||||
PreparedMappedGravitySourceOperator::TryPreparePrimal(const mfem::Vector &displacement) {
|
||||
MEAN_FIELD_PROFILE_SCOPE_WARMUP("PreparedMappedGravitySourceOperator::TryPrepare primal", 0);
|
||||
return TryPrepareImpl(displacement, PreparationMode::primal);
|
||||
}
|
||||
|
||||
GravitySourcePreparationResult PreparedMappedGravitySourceOperator::TryPrepareImpl(
|
||||
const mfem::Vector &displacement,
|
||||
const PreparationMode mode
|
||||
) {
|
||||
@@ -325,11 +376,18 @@ namespace mean_field::operators {
|
||||
"with the wrong size."
|
||||
);
|
||||
|
||||
bool localNonFiniteInput = false;
|
||||
for (int i = 0; i < displacement.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(displacement(i)), "PreparedMappedGravitySourceOperator received a non-finite "
|
||||
"displacement value."
|
||||
localNonFiniteInput = localNonFiniteInput || !std::isfinite(displacement(i));
|
||||
}
|
||||
if (auto inputResult = synchronize_preparation_failure(
|
||||
localNonFiniteInput ? mapping::MappingStatus::non_finite_input : mapping::MappingStatus::valid, false,
|
||||
m_fem.mesh->GetComm()
|
||||
);
|
||||
!inputResult.has_value()) {
|
||||
m_is_prepared = false;
|
||||
m_has_variation_data = false;
|
||||
return inputResult;
|
||||
}
|
||||
|
||||
m_is_prepared = false;
|
||||
@@ -340,6 +398,7 @@ namespace mean_field::operators {
|
||||
m_elements.reserve(m_fem.mesh->GetNE());
|
||||
|
||||
FrozenMappedGravitySourceCoefficient source_coefficient(m_fem, m_domain_mapper, m_displacement_true);
|
||||
bool localNonFiniteQuadrature = false;
|
||||
|
||||
for (int element_id = 0; element_id < m_fem.mesh->GetNE(); ++element_id) {
|
||||
const int attribute = m_fem.mesh->GetAttribute(element_id);
|
||||
@@ -414,6 +473,11 @@ namespace mean_field::operators {
|
||||
|
||||
const double coefficient_value = source_coefficient.Eval(transformation, integration_point);
|
||||
|
||||
if (source_coefficient.GetMappingFailure() != mapping::MappingStatus::valid ||
|
||||
source_coefficient.HasNonFiniteArithmetic()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == PreparationMode::linearization) {
|
||||
const mfem::DenseMatrix &inverse_element_jacobian = source_coefficient.GetInverseElementJacobian();
|
||||
for (int row = 0; row < dimension; ++row) {
|
||||
@@ -428,15 +492,26 @@ namespace mean_field::operators {
|
||||
|
||||
const double quadrature_value = integration_point.weight * transformation.Weight() * coefficient_value;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(quadrature_value) && quadrature_value > 0.0,
|
||||
"Prepared gravity source operator encountered invalid "
|
||||
"quadrature data on element "
|
||||
<< element_id << ", quadrature point " << quadrature_point << "."
|
||||
);
|
||||
if (!std::isfinite(quadrature_value) || quadrature_value <= 0.0) {
|
||||
localNonFiniteQuadrature = true;
|
||||
break;
|
||||
}
|
||||
|
||||
data.quadrature_data(quadrature_point) = quadrature_value;
|
||||
}
|
||||
|
||||
if (source_coefficient.GetMappingFailure() != mapping::MappingStatus::valid ||
|
||||
source_coefficient.HasNonFiniteArithmetic() || localNonFiniteQuadrature) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool localNonFiniteArithmetic = source_coefficient.HasNonFiniteArithmetic() || localNonFiniteQuadrature;
|
||||
auto preparationResult = synchronize_preparation_failure(
|
||||
source_coefficient.GetMappingFailure(), localNonFiniteArithmetic, m_fem.mesh->GetComm()
|
||||
);
|
||||
if (!preparationResult.has_value()) {
|
||||
return preparationResult;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!m_elements.empty(), "PreparedMappedGravitySourceOperator found no stellar elements.");
|
||||
@@ -444,6 +519,7 @@ namespace mean_field::operators {
|
||||
m_is_prepared = true;
|
||||
m_has_variation_data = mode == PreparationMode::linearization;
|
||||
++m_preparation_count;
|
||||
return {};
|
||||
}
|
||||
void PreparedMappedGravitySourceOperator::Mult(
|
||||
const mfem::Vector &density,
|
||||
|
||||
Reference in New Issue
Block a user