Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user