Integrate Refactor solver sources and dual MSVC CMake builds

This commit is contained in:
KOKO\Mimi
2026-10-18 02:10:51 +09:00
parent 7ee32e5837
commit 12d51480de
218 changed files with 17842 additions and 9689 deletions
+36 -60
View File
@@ -16,11 +16,14 @@
#include "fesa/solvers/linear/linear_solver.h"
#include "fesa/solvers/linear/tangent_solver.h"
#include "math/dense_blas_internal.h"
#include "math/compensated_sum.h"
namespace fesa {
namespace hht_internal {
namespace {
using math_internal::AddCompensated;
/// @brief Attaches a fail-closed dynamic diagnostic to the source model.
Status Failure(const Domain& domain, const std::string& code,
const std::string& message) {
@@ -148,48 +151,23 @@ Status CheckLocalMass(const Domain& domain, const SparseMatrix& matrix,
return Failure(domain, "dynamic-positive-mass",
"A nonempty physical mass block has no positive scale.");
}
double norm = 0.0;
for (std::size_t i = 0; i < size; ++i) {
double sum = 0.0;
for (std::size_t j = 0; j < size; ++j) {
block(i, j) /= scale;
sum += std::abs(block(i, j));
}
norm = std::max(norm, sum);
}
Matrix lower{size, size};
Matrix inverse_lower{size, size};
auto factor_failure = dense_blas_internal::CholeskyFailure::kNone;
for (std::size_t i = 0; i < size; ++i)
for (std::size_t j = 0; j < size; ++j) block(i, j) /= scale;
try {
if (!dense_blas_internal::CholeskyLowerAndInverse(
block, lower, inverse_lower, &factor_failure)) {
if (factor_failure == dense_blas_internal::CholeskyFailure::kInverse)
return Failure(
domain, "dynamic-positive-mass-conditioning",
"A nodal free physical block reciprocal condition is below 2^-32.");
const auto factor = dense_blas_internal::DenseFactor::Cholesky(block);
if (!factor.HasValue())
return Failure(
domain, "dynamic-positive-mass",
"Physical mass requires strictly positive Cholesky pivots.");
}
const auto rcond = factor.Value().ReciprocalConditionInfinity();
if (!rcond.HasValue() || !std::isfinite(rcond.Value()) ||
!(rcond.Value() >= std::ldexp(1.0, -32)))
return Failure(
domain, "dynamic-positive-mass-conditioning",
"A nodal free physical block reciprocal condition is below 2^-32.");
} catch (const std::exception& error) {
return Failure(domain, "dynamic-positive-mass", error.what());
}
const Matrix inverse =
dense_blas_internal::MultiplyTransposeLeft(inverse_lower, inverse_lower);
std::array<double, 6> sums{};
for (std::size_t column = 0; column < size; ++column) {
for (std::size_t i = 0; i < size; ++i) {
sums[i] += std::abs(inverse(i, column));
}
}
const double inverse_norm = *std::max_element(sums.begin(), sums.end());
const double rcond = 1.0 / norm / inverse_norm;
if (!std::isfinite(inverse_norm) || !std::isfinite(rcond) ||
!(rcond >= std::ldexp(1.0, -32))) {
return Failure(
domain, "dynamic-positive-mass-conditioning",
"A nodal free physical block reciprocal condition is below 2^-32.");
}
return Status::Ok();
}
@@ -468,15 +446,6 @@ Result<SparseMatrix> ConstraintGradient(const DynamicAssembly& assembly,
std::move(entries));
}
/// @brief Accumulates one deterministic sparse contraction without lost sums.
void AddCompensated(const double term, double* sum, double* correction) {
const double next = *sum + term;
*correction += std::abs(*sum) >= std::abs(term)
? (*sum - next) + term
: (term - next) + *sum;
*sum = next;
}
/// @brief Stores W-scaled regularity with exact inverse-action infinity norms.
struct Regularity {
SparseMatrix matrix;
@@ -553,23 +522,10 @@ Result<Regularity> CheckRegularity(const Domain& domain,
sum += std::abs(matrix.Value().Values()[index]);
norm = std::max(norm, sum);
}
Vector inverse_sums{nodes.size()};
// Columns are discarded after their absolute row sums are accumulated;
// a global dense inverse is never retained.
for (std::size_t column = 0; column < nodes.size(); ++column) {
Vector rhs{nodes.size()};
rhs[column] = 1.0;
Vector solution{nodes.size()};
const Status solved = solver.SolveCorrection(rhs, solution);
if (!solved.IsOk()) return Result<Regularity>::Failure(solved);
const Status checked = CheckLinearSolve(matrix.Value(), rhs, solution);
if (!checked.IsOk()) return Result<Regularity>::Failure(checked);
for (std::size_t row = 0; row < nodes.size(); ++row)
inverse_sums[row] += std::abs(solution[row]);
}
double inverse_norm = 0.0;
for (std::size_t row = 0; row < nodes.size(); ++row)
inverse_norm = std::max(inverse_norm, inverse_sums[row]);
const Status accumulated =
AccumulateCheckedCanonicalNorm(matrix.Value(), solver, inverse_norm);
if (!accumulated.IsOk()) return Result<Regularity>::Failure(accumulated);
const double condition = 1.0 / norm / inverse_norm;
if (!std::isfinite(norm) || !std::isfinite(inverse_norm) ||
!std::isfinite(condition) || !(condition >= std::ldexp(1.0, -32))) {
@@ -662,6 +618,26 @@ Status HiddenEvidence(const Domain& domain, const DynamicAssembly& assembly,
} // namespace
Status AccumulateCheckedCanonicalNorm(const SparseMatrix& matrix,
TangentSolver& solver, double& norm) {
const auto size = matrix.Rows();
Vector row_sums{size};
for (std::size_t column = 0U; column < size; ++column) {
Vector rhs{size};
rhs[column] = 1.0;
Vector solution{size};
const Status solved = solver.SolveCorrection(rhs, solution);
if (!solved.IsOk()) return solved;
const Status checked = CheckLinearSolve(matrix, rhs, solution);
if (!checked.IsOk()) return checked;
for (std::size_t row = 0U; row < size; ++row)
row_sums[row] += std::abs(solution[row]);
}
for (std::size_t row = 0U; row < size; ++row)
norm = (std::max)(norm, row_sums[row]);
return Status::Ok();
}
double OrderedNullMetric(const SparseMatrix& metric, const std::size_t node,
const Vector3& direction) {
Vector left{9U};