fix(math): preserve certified sums and complete MKL algebra
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "thermal_transient_bounds.h"
|
||||
#include "math/dense_blas_internal.h"
|
||||
|
||||
namespace fesa::thermal_transient_internal {
|
||||
namespace {
|
||||
@@ -117,14 +118,9 @@ Result<Equations> Build(const ThermalSystem& s, const ThermalPartition& p,
|
||||
constrained[p.constrained[i]] = i;
|
||||
SparsePattern pattern{{0}, {}};
|
||||
std::vector<CooContribution> coo;
|
||||
SparsePattern rhs_pattern{{0U}, {}};
|
||||
std::vector<CooContribution> capacity_rhs, conductivity_rhs;
|
||||
Vector capacity_input = old;
|
||||
Vector prescribed_full{m};
|
||||
std::vector<bool> capacity_column_used(m, false);
|
||||
for (std::size_t i = 0; i < p.constrained.size(); ++i) {
|
||||
prescribed_full[p.constrained[i]] = p.prescribed[i];
|
||||
}
|
||||
const auto entries = s.c.Values().size();
|
||||
Vector capacity_diagonal{entries}, conductivity_diagonal{entries};
|
||||
Vector capacity_input{entries}, conductivity_input{entries};
|
||||
Vector b{n};
|
||||
std::vector<I> exact_a, exact_b(n);
|
||||
for (std::size_t f = 0; f < n; ++f) {
|
||||
@@ -135,43 +131,39 @@ Result<Equations> Build(const ThermalSystem& s, const ThermalPartition& p,
|
||||
const auto col = s.c.ColumnIndices()[j];
|
||||
const double c = s.c.Values()[j], k = s.k.Values()[j];
|
||||
const I cd = Div(I{c}, I{delta});
|
||||
rhs_pattern.column_indices.push_back(col);
|
||||
capacity_column_used[col] = true;
|
||||
capacity_rhs.push_back({f, col, c / delta, 0U, j});
|
||||
conductivity_rhs.push_back({f, col, k, 0U, j});
|
||||
capacity_diagonal[j] = c / delta;
|
||||
if (free[col] != n) {
|
||||
capacity_input[j] = old[col];
|
||||
coo.push_back({f, free[col], c / delta + k, 0, coo.size()});
|
||||
pattern.column_indices.push_back(free[col]);
|
||||
exact_a.push_back(Add(cd, I{k}));
|
||||
exact_b[f] = Add(exact_b[f], Mul(cd, I{old[col]}));
|
||||
} else {
|
||||
const double g = p.prescribed[constrained[col]];
|
||||
capacity_input[j] = old[col] - g;
|
||||
conductivity_diagonal[j] = k;
|
||||
conductivity_input[j] = g;
|
||||
// Preserve raw old constrained capacity; never project frame zero.
|
||||
exact_b[f] = Add(exact_b[f],
|
||||
Sub(Mul(cd, Sub(I{old[col]}, I{g})), Mul(I{k}, I{g})));
|
||||
}
|
||||
}
|
||||
pattern.row_offsets.push_back(coo.size());
|
||||
rhs_pattern.row_offsets.push_back(capacity_rhs.size());
|
||||
}
|
||||
// Do not create overflow in an absent constrained column: the original
|
||||
// free-row RHS never evaluated that subtraction. Referenced structural
|
||||
// zeros still evaluate it and reject nonfinite intermediate values.
|
||||
for (std::size_t i = 0; i < p.constrained.size(); ++i) {
|
||||
const auto column = p.constrained[i];
|
||||
if (capacity_column_used[column]) capacity_input[column] -= p.prescribed[i];
|
||||
const auto capacity_action = dense_blas_internal::MultiplyDiagonal(
|
||||
capacity_diagonal, capacity_input);
|
||||
const auto conductivity_action = dense_blas_internal::MultiplyDiagonal(
|
||||
conductivity_diagonal, conductivity_input);
|
||||
for (std::size_t f = 0; f < n; ++f) {
|
||||
const auto row = p.free[f];
|
||||
for (auto j = s.c.RowOffsets()[row]; j < s.c.RowOffsets()[row + 1]; ++j) {
|
||||
const auto col = s.c.ColumnIndices()[j];
|
||||
// Preserve the original per-entry subtraction before the row sum.
|
||||
// Separately summing C*delta and K*g loses small stable RHS terms.
|
||||
b[f] += free[col] != n ? capacity_action[j]
|
||||
: capacity_action[j] - conductivity_action[j];
|
||||
}
|
||||
}
|
||||
if (!Finite(capacity_input))
|
||||
return Result<Equations>::Failure(Failure("Nonfinite backward Euler RHS."));
|
||||
auto c_rhs = SparseMatrix::FromCoo(n, m, std::move(capacity_rhs), rhs_pattern);
|
||||
auto k_rhs = SparseMatrix::FromCoo(n, m, std::move(conductivity_rhs),
|
||||
rhs_pattern);
|
||||
if (!c_rhs.HasValue() || !k_rhs.HasValue())
|
||||
return Result<Equations>::Failure(Failure("Nonfinite backward Euler RHS."));
|
||||
const auto capacity_action = c_rhs.Value().Multiply(capacity_input);
|
||||
const auto conductivity_action = k_rhs.Value().Multiply(prescribed_full);
|
||||
for (std::size_t f = 0; f < n; ++f)
|
||||
b[f] += capacity_action[f] - conductivity_action[f];
|
||||
auto a = SparseMatrix::FromCoo(n, n, std::move(coo), pattern);
|
||||
if (!a.HasValue()) return Result<Equations>::Failure(a.GetStatus());
|
||||
if (!Finite(b))
|
||||
@@ -493,6 +485,9 @@ Result<ThermalStepCandidate> SolveThermalIncrement(
|
||||
status = Check(s, p, old, delta, equations.Value(), candidate);
|
||||
if (!status.IsOk()) return Result<ThermalStepCandidate>::Failure(status);
|
||||
return Result<ThermalStepCandidate>::Success(std::move(candidate));
|
||||
} catch (const std::invalid_argument&) {
|
||||
return Result<ThermalStepCandidate>::Failure(
|
||||
Failure("Nonfinite backward Euler RHS."));
|
||||
} catch (const std::length_error&) {
|
||||
return Result<ThermalStepCandidate>::Failure(
|
||||
Failure("Thermal sparse action exceeds the backend integer range."));
|
||||
|
||||
Reference in New Issue
Block a user