Files
MeanField_SERiF/src/lib/serif/solver/normalization/packing.cpp
Emily Boudreaux 24d4c20f82 feat(solver/normalization): Added normalization system
The dynamical range of different fields SERiF must solve for is massive. This just breaks any reasonable preconditioner / spreads the eigen modes of the system matrix out. This is a normalization system which uses charectaristic scale factors (e.g. the approximate radius estimated using the lane-emden equation) to rescale different fields to a more similar numeric scale. This turns out to be essential for stable convergence. Broadly this implements Riesz normalization along with exact diagnoal normalization.
2026-11-09 13:30:20 -05:00

53 lines
1.9 KiB
C++

#include "serif/solver/normalization/detail/packing.hpp"
#include <cstddef>
#include <utility>
#include <vector>
#include "serif/utils/error/errors.hpp"
namespace serif::solver::normalization::detail
{
namespace
{
/** @brief Preserve the declared block order while checking the total before allocating packed storage. */
[[nodiscard]] std::expected<std::vector<double>, std::string> pack_factors(std::span<const std::span<const double>> coordinates)
{
using namespace utils::errors;
std::size_t count = 0;
for (const std::span<const double> factors : coordinates)
{
if (factors.size() > std::vector<double>{}.max_size() - count)
{
return std::unexpected(format_error_message<SERiFErrorCode::INVALID_DOF_COUNT>("The packed normalization layout exceeds the supported vector size. Reduce its coordinate counts."));
}
count += factors.size();
}
std::vector<double> packed;
packed.reserve(count);
for (const std::span<const double> factors : coordinates)
{
packed.insert(packed.end(), factors.begin(), factors.end());
}
return packed;
}
}
std::expected<DiagonalNormalization, std::string> pack_normalization(std::span<const std::span<const double>> states, std::span<const std::span<const double>> residuals)
{
auto state_factors = pack_factors(states);
if (!state_factors)
{
return std::unexpected(state_factors.error());
}
auto residual_factors = pack_factors(residuals);
if (!residual_factors)
{
return std::unexpected(residual_factors.error());
}
return make_diagonal_normalization(std::move(*state_factors), std::move(*residual_factors));
}
}