feat(libmeanfield): centrifugal + pressure

This commit is contained in:
2026-08-04 14:24:55 -04:00
parent 9bc4f2758a
commit dc912fd15e
115 changed files with 260058 additions and 163261 deletions

View File

@@ -0,0 +1,266 @@
module;
#include <cmath>
#include <mfem.hpp>
#include <stdexcept>
module mean_field;
namespace {
bool vector_is_finite(const mfem::Vector &vector) {
for (int i = 0; i < vector.Size(); ++i) {
if (!std::isfinite(vector(i)))
return false;
}
return true;
}
bool matrix_is_finite(const mfem::DenseMatrix &matrix) {
for (int i = 0; i < matrix.Height(); ++i) {
for (int j = 0; j < matrix.Width(); ++j) {
if (!std::isfinite(matrix(i, j)))
return false;
}
}
return true;
}
} // namespace
namespace mean_field::mapping::compactification {
KelvinCompactification::KelvinCompactification(
options::KelvinCompactificationOptions options
)
: m_options(options) {
if (!std::isfinite(m_options.r_star_ref) ||
!std::isfinite(m_options.r_inf_ref)) {
throw std::invalid_argument(
"Kelvin compactification radii must be finite."
);
}
if (m_options.r_star_ref <= 0.0 ||
m_options.r_inf_ref <= m_options.r_star_ref) {
throw std::invalid_argument(
"Kelvin compactification requires 0 < r_star_ref < r_inf_ref."
);
}
if (!std::isfinite(m_options.coordinate_tolerance) ||
m_options.coordinate_tolerance < 0.0 ||
m_options.coordinate_tolerance >= 1.0) {
throw std::invalid_argument(
"Kelvin compactification coordinate tolerance must be finite "
"and lie "
"in [0, 1)."
);
}
}
MappingStatus KelvinCompactification::ComputeRadialFactors(
const double compactification_coordinate,
RadialFactors &factors
) const {
if (!std::isfinite(compactification_coordinate))
return MappingStatus::non_finite_input;
const double tolerance = m_options.coordinate_tolerance;
if (compactification_coordinate < -tolerance ||
compactification_coordinate > 1.0 + tolerance) {
return MappingStatus::outside_reference_domain;
}
double coordinate = compactification_coordinate;
if (coordinate < 0.0)
coordinate = 0.0;
if (coordinate >= 1.0 - tolerance) {
return MappingStatus::at_compactified_infinity;
}
const double radial_extent = m_options.r_inf_ref - m_options.r_star_ref;
const double computational_radius =
m_options.r_star_ref + coordinate * radial_extent;
if (!std::isfinite(computational_radius) ||
computational_radius <= 0.0) {
return MappingStatus::invalid_reference_radius;
}
const double one_minus_coordinate = 1.0 - coordinate;
const double denominator = computational_radius * one_minus_coordinate;
if (!std::isfinite(denominator) || denominator <= 0.0) {
return MappingStatus::non_finite_result;
}
const double scale = m_options.r_star_ref / denominator;
const double scale_derivative =
scale *
(1.0 / one_minus_coordinate - radial_extent / computational_radius);
if (!std::isfinite(scale) || !std::isfinite(scale_derivative)) {
return MappingStatus::non_finite_result;
}
factors.coordinate = coordinate;
factors.computational_radius = computational_radius;
factors.scale = scale;
factors.scale_derivative = scale_derivative;
return MappingStatus::valid;
}
MappingStatus KelvinCompactification::Evaluate(
const ExteriorMapInput &input,
ExteriorMapResult &result
) const {
const int dimension = input.reference_position.Size();
if (dimension <= 0 || input.displaced_position.Size() != dimension ||
input.compactification_coordinate_gradient.Size() != dimension) {
return MappingStatus::invalid_dimension;
}
if (input.displacement_jacobian.Height() != dimension ||
input.displacement_jacobian.Width() != dimension) {
return MappingStatus::invalid_dimension;
}
if (!vector_is_finite(input.reference_position) ||
!vector_is_finite(input.displaced_position) ||
!vector_is_finite(input.compactification_coordinate_gradient) ||
!matrix_is_finite(input.displacement_jacobian)) {
return MappingStatus::non_finite_input;
}
RadialFactors factors;
const MappingStatus factor_status =
ComputeRadialFactors(input.compactification_coordinate, factors);
if (factor_status != MappingStatus::valid)
return factor_status;
result.physical_position.SetSize(dimension);
result.mapping_jacobian.SetSize(dimension, dimension);
for (int i = 0; i < dimension; ++i) {
result.physical_position(i) =
factors.scale * input.displaced_position(i);
for (int j = 0; j < dimension; ++j) {
const double scale_gradient =
factors.scale_derivative *
input.compactification_coordinate_gradient(j);
result.mapping_jacobian(i, j) =
factors.scale * input.displacement_jacobian(i, j) +
input.displaced_position(i) * scale_gradient;
}
}
if (!vector_is_finite(result.physical_position) ||
!matrix_is_finite(result.mapping_jacobian)) {
return MappingStatus::non_finite_result;
}
const double mapping_determinant = result.mapping_jacobian.Det();
if (!std::isfinite(mapping_determinant))
return MappingStatus::non_finite_result;
if (mapping_determinant <= 0.0)
return MappingStatus::non_positive_determinant;
return MappingStatus::valid;
}
MappingStatus KelvinCompactification::EvaluateVariation(
const ExteriorMapInput &input,
const ExteriorMapResult &result,
const ExteriorMapDirection &direction,
ExteriorMapVariation &variation
) const {
const int dimension = input.reference_position.Size();
if (dimension <= 0 || input.displaced_position.Size() != dimension ||
input.compactification_coordinate_gradient.Size() != dimension) {
return MappingStatus::invalid_dimension;
}
if (input.displacement_jacobian.Height() != dimension ||
input.displacement_jacobian.Width() != dimension) {
return MappingStatus::invalid_dimension;
}
if (result.physical_position.Size() != dimension ||
result.mapping_jacobian.Height() != dimension ||
result.mapping_jacobian.Width() != dimension) {
return MappingStatus::invalid_dimension;
}
if (direction.displaced_position_variation.Size() != dimension ||
direction.displacement_jacobian_variation.Height() != dimension ||
direction.displacement_jacobian_variation.Width() != dimension) {
return MappingStatus::invalid_dimension;
}
if (!vector_is_finite(input.reference_position) ||
!vector_is_finite(input.displaced_position) ||
!vector_is_finite(input.compactification_coordinate_gradient) ||
!matrix_is_finite(input.displacement_jacobian)) {
return MappingStatus::non_finite_input;
}
if (!vector_is_finite(result.physical_position) ||
!matrix_is_finite(result.mapping_jacobian) ||
!vector_is_finite(direction.displaced_position_variation) ||
!matrix_is_finite(direction.displacement_jacobian_variation)) {
return MappingStatus::non_finite_input;
}
RadialFactors factors;
const MappingStatus factor_status =
ComputeRadialFactors(input.compactification_coordinate, factors);
if (factor_status != MappingStatus::valid)
return factor_status;
variation.physical_position_variation.SetSize(dimension);
variation.mapping_jacobian_variation.SetSize(dimension, dimension);
for (int i = 0; i < dimension; ++i) {
variation.physical_position_variation(i) =
factors.scale * direction.displaced_position_variation(i);
for (int j = 0; j < dimension; ++j) {
const double scale_gradient =
factors.scale_derivative *
input.compactification_coordinate_gradient(j);
variation.mapping_jacobian_variation(i, j) =
factors.scale *
direction.displacement_jacobian_variation(i, j) +
direction.displaced_position_variation(i) * scale_gradient;
}
}
if (!vector_is_finite(variation.physical_position_variation) ||
!matrix_is_finite(variation.mapping_jacobian_variation)) {
return MappingStatus::non_finite_result;
}
return MappingStatus::valid;
}
std::string_view KelvinCompactification::GetName() const noexcept {
return "KelvinCompactification";
}
double KelvinCompactification::GetReferenceStellarRadius() const noexcept {
return m_options.r_star_ref;
}
double KelvinCompactification::GetReferenceInfinityRadius() const noexcept {
return m_options.r_inf_ref;
}
double KelvinCompactification::GetCoordinateTolerance() const noexcept {
return m_options.coordinate_tolerance;
}
} // namespace mean_field::mapping::compactification