feat(thermal): certify shell geometry and local heat operators
This commit is contained in:
@@ -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});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user