feat(thermal): certify shell geometry and local heat operators

This commit is contained in:
KOKO\Mimi
2026-09-29 19:22:44 +09:00
parent e33ee6a04f
commit 32f0c161af
11 changed files with 1639 additions and 83 deletions
+36 -26
View File
@@ -38,7 +38,8 @@ bool Subtract(const UInt128& a, const UInt128& b, UInt128& result) {
std::uint64_t borrow = 0;
for (std::size_t i = 0; i < 4; ++i) {
const std::uint64_t sub = std::uint64_t{b.digit[i]} + borrow;
result.digit[i] = static_cast<std::uint32_t>(std::uint64_t{a.digit[i]} - sub);
result.digit[i] =
static_cast<std::uint32_t>(std::uint64_t{a.digit[i]} - sub);
borrow = std::uint64_t{a.digit[i]} < sub ? 1U : 0U;
}
return borrow == 0;
@@ -68,8 +69,8 @@ bool Multiply(const UInt128& a, std::uint64_t multiplier, UInt128& result) {
if (a.digit[i] != 0 && factor != 0) return false;
continue;
}
const std::uint64_t product = std::uint64_t{a.digit[i]} * factor +
result.digit[i + j] + carry;
const std::uint64_t product =
std::uint64_t{a.digit[i]} * factor + result.digit[i + j] + carry;
result.digit[i + j] = static_cast<std::uint32_t>(product);
carry = product >> 32;
}
@@ -85,7 +86,8 @@ struct Cell {
bool closed;
};
/// @brief Constructs ORIGINAL binary64 cells, including subnormal/maxfinite gaps.
/// @brief Constructs ORIGINAL binary64 cells, including subnormal/maxfinite
/// gaps.
bool MakeCell(double value, int period_exponent, Cell& cell) {
std::uint64_t bits = 0;
std::memcpy(&bits, &value, sizeof(bits));
@@ -108,21 +110,23 @@ bool MakeCell(double value, int period_exponent, Cell& cell) {
Add(cell.center, upper_gap, cell.upper);
}
/// @brief Returns source-neutral utility failure for parser/procedure decoration.
/// @brief Returns source-neutral utility failure for parser/procedure
/// decoration.
Status GridFailure(const char* code, const char* message) {
return Status::Failure(FailureCategory::kModel,
{{Severity::kError, code, {}, "HEAT TRANSFER", "",
message}});
return Status::Failure(
FailureCategory::kModel,
{{Severity::kError, code, {}, "HEAT TRANSFER", "", message}});
}
} // namespace
Result<ThermalTimeGrid> ThermalTimeGrid::Create(
double period, double increment, std::uint32_t maximum) {
Result<ThermalTimeGrid> ThermalTimeGrid::Create(double period, double increment,
std::uint32_t maximum) {
if (!std::isfinite(period) || !std::isfinite(increment) || period <= 0 ||
increment <= 0 || maximum == 0) {
return Result<ThermalTimeGrid>::Failure(GridFailure(
"invalid-thermal-time-grid", "Time controls must be finite and positive."));
return Result<ThermalTimeGrid>::Failure(
GridFailure("invalid-thermal-time-grid",
"Time controls must be finite and positive."));
}
if (increment >= period) {
return Result<ThermalTimeGrid>::Success(
@@ -152,8 +156,7 @@ Result<ThermalTimeGrid> ThermalTimeGrid::Create(
const int first = Compare(period_cell.upper, lower);
const int second = Compare(upper, period_cell.lower);
const bool closed = period_cell.closed && increment_cell.closed;
const bool close = nearest != 0 &&
(first > 0 || (first == 0 && closed)) &&
const bool close = nearest != 0 && (first > 0 || (first == 0 && closed)) &&
(second > 0 || (second == 0 && closed));
std::uint64_t count = nearest;
if (!close && exact_ok) {
@@ -180,11 +183,14 @@ Result<ThermalTimeGrid> ThermalTimeGrid::Create(
return Result<ThermalTimeGrid>::Failure(GridFailure(
"thermal-increment-limit", "Thermal increment count exceeds INC."));
}
const double last = close ? increment :
std::fma(-static_cast<double>(count - 1), increment, period);
ThermalTimeGrid grid{period, increment, static_cast<std::uint32_t>(count), last};
const double last =
close ? increment
: std::fma(-static_cast<double>(count - 1), increment, period);
ThermalTimeGrid grid{period, increment, static_cast<std::uint32_t>(count),
last};
const auto frame = grid.Frame(grid.Count());
if (!frame.HasValue()) return Result<ThermalTimeGrid>::Failure(frame.GetStatus());
if (!frame.HasValue())
return Result<ThermalTimeGrid>::Failure(frame.GetStatus());
// For j <= 2^32, adjacent exact j*d are separated by more than 2^19 ULPs
// (subnormal products are exact). Thus the terminal check also suffices for
// O(1) preflight; every requested frame still checks its own stored interval.
@@ -192,8 +198,10 @@ Result<ThermalTimeGrid> ThermalTimeGrid::Create(
}
ThermalTimeGrid::ThermalTimeGrid(double period, double increment,
std::uint32_t count, double final_delta)
: period_{period}, increment_{increment}, count_{count},
std::uint32_t count, double final_delta)
: period_{period},
increment_{increment},
count_{count},
final_delta_{final_delta} {}
std::uint32_t ThermalTimeGrid::Count() const noexcept { return count_; }
@@ -205,16 +213,18 @@ double ThermalTimeGrid::Delta(std::uint32_t index) const noexcept {
}
Result<ThermalTimeFrame> ThermalTimeGrid::Frame(std::uint32_t index) const {
if (index == 0 || index > count_) {
return Result<ThermalTimeFrame>::Failure(GridFailure(
"invalid-thermal-time-frame", "Completed frame index is outside the grid."));
return Result<ThermalTimeFrame>::Failure(
GridFailure("invalid-thermal-time-frame",
"Completed frame index is outside the grid."));
}
const double time = Time(index);
const double delta = Delta(index);
const double previous = Time(index - 1);
if (!std::isfinite(time) || !std::isfinite(previous) || !std::isfinite(delta) ||
!(time > previous) || !(delta > 0)) {
return Result<ThermalTimeFrame>::Failure(GridFailure(
"invalid-thermal-time-frame", "Stored times must be finite and strictly increasing."));
if (!std::isfinite(time) || !std::isfinite(previous) ||
!std::isfinite(delta) || !(time > previous) || !(delta > 0)) {
return Result<ThermalTimeFrame>::Failure(
GridFailure("invalid-thermal-time-frame",
"Stored times must be finite and strictly increasing."));
}
return Result<ThermalTimeFrame>::Success({time, delta});
}