test: validate transient shell thermal physics and diagnostic reference

This commit is contained in:
KOKO\Mimi
2026-10-03 23:44:16 +09:00
parent 95ba2c5957
commit 9e8afb9c8f
8 changed files with 1828 additions and 6 deletions
@@ -0,0 +1,70 @@
// Generated by thermal_oracle_generator.py; exact root/weight certificates.
#ifndef FESA_TESTS_THERMAL_GAUSS_ORACLE_H_
#define FESA_TESTS_THERMAL_GAUSS_ORACLE_H_
#include <array>
namespace thermal_oracle {
struct GaussPoint {
double x_lo, x_hi, w_lo, w_hi;
};
inline constexpr std::array<GaussPoint, 12> kGauss12{{
{-0x1.f68f1d8e42e82p-1, -0x1.f68f1d8e42e80p-1, 0x1.8275d9de72d45p-5,
0x1.8275d9dedaddep-5},
{-0x1.cee874ffb88b5p-1, -0x1.cee874ffb88b3p-1, 0x1.b60602bcd3d56p-4,
0x1.b60602bcf85a4p-4},
{-0x1.8a30aeed88f37p-1, -0x1.8a30aeed88f35p-1, 0x1.47d7258f1fdcdp-3,
0x1.47d7258f25d51p-3},
{-0x1.2cb4f05c077fap-1, -0x1.2cb4f05c077f8p-1, 0x1.a0163e6b1a279p-3,
0x1.a0163e6b1b46ap-3},
{-0x1.78a8d20a8b19ep-2, -0x1.78a8d20a8b19cp-2, 0x1.de3155c256a18p-3,
0x1.de3155c256b52p-3},
{-0x1.007a5f8f630e5p-3, -0x1.007a5f8f630e3p-3, 0x1.fe40ce6d4f01bp-3,
0x1.fe40ce6d4f030p-3},
{0x1.007a5f8f630e3p-3, 0x1.007a5f8f630e5p-3, 0x1.fe40ce6d4f01bp-3,
0x1.fe40ce6d4f030p-3},
{0x1.78a8d20a8b19cp-2, 0x1.78a8d20a8b19ep-2, 0x1.de3155c256a18p-3,
0x1.de3155c256b52p-3},
{0x1.2cb4f05c077f8p-1, 0x1.2cb4f05c077fap-1, 0x1.a0163e6b1a279p-3,
0x1.a0163e6b1b46ap-3},
{0x1.8a30aeed88f35p-1, 0x1.8a30aeed88f37p-1, 0x1.47d7258f1fdcdp-3,
0x1.47d7258f25d51p-3},
{0x1.cee874ffb88b3p-1, 0x1.cee874ffb88b5p-1, 0x1.b60602bcd3d56p-4,
0x1.b60602bcf85a4p-4},
{0x1.f68f1d8e42e80p-1, 0x1.f68f1d8e42e82p-1, 0x1.8275d9de72d45p-5,
0x1.8275d9dedaddep-5},
}};
inline constexpr std::array<GaussPoint, 16> kGauss16{{
{-0x1.fa92c264d787fp-1, -0x1.fa92c264d787dp-1, 0x1.bcddab41dec5ap-6,
0x1.bcddab55197bep-6},
{-0x1.e39f56616f9b1p-1, -0x1.e39f56616f9afp-1, 0x1.fdfb1a27efbd3p-5,
0x1.fdfb1a30350e0p-5},
{-0x1.bb3403514e484p-1, -0x1.bb3403514e482p-1, 0x1.85c4ee78dfd1dp-4,
0x1.85c4ee7ab8792p-4},
{-0x1.82c45dda4726cp-1, -0x1.82c45dda4726ap-1, 0x1.fe7af2ba91fc7p-4,
0x1.fe7af2bb1510fp-4},
{-0x1.3c5a466d5e8b9p-1, -0x1.3c5a466d5e8b7p-1, 0x1.325f61bc9dd8dp-3,
0x1.325f61bca9bf1p-3},
{-0x1.d50259a43a773p-2, -0x1.d50259a43a771p-2, 0x1.5a6ebbb5a6fa2p-3,
0x1.5a6ebbb5a7c56p-3},
{-0x1.205cae642337dp-2, -0x1.205cae642337bp-2, 0x1.75f8c77e0bf66p-3,
0x1.75f8c77e0c0b8p-3},
{-0x1.852bd6676a9fap-4, -0x1.852bd6676a9f8p-4, 0x1.83feae80e4df6p-3,
0x1.83feae80e4e01p-3},
{0x1.852bd6676a9f8p-4, 0x1.852bd6676a9fap-4, 0x1.83feae80e4df6p-3,
0x1.83feae80e4e01p-3},
{0x1.205cae642337bp-2, 0x1.205cae642337dp-2, 0x1.75f8c77e0bf66p-3,
0x1.75f8c77e0c0b8p-3},
{0x1.d50259a43a771p-2, 0x1.d50259a43a773p-2, 0x1.5a6ebbb5a6fa2p-3,
0x1.5a6ebbb5a7c56p-3},
{0x1.3c5a466d5e8b7p-1, 0x1.3c5a466d5e8b9p-1, 0x1.325f61bc9dd8dp-3,
0x1.325f61bca9bf1p-3},
{0x1.82c45dda4726ap-1, 0x1.82c45dda4726cp-1, 0x1.fe7af2ba91fc7p-4,
0x1.fe7af2bb1510fp-4},
{0x1.bb3403514e482p-1, 0x1.bb3403514e484p-1, 0x1.85c4ee78dfd1dp-4,
0x1.85c4ee7ab8792p-4},
{0x1.e39f56616f9afp-1, 0x1.e39f56616f9b1p-1, 0x1.fdfb1a27efbd3p-5,
0x1.fdfb1a30350e0p-5},
{0x1.fa92c264d787dp-1, 0x1.fa92c264d787fp-1, 0x1.bcddab41dec5ap-6,
0x1.bcddab55197bep-6},
}};
} // namespace thermal_oracle
#endif
@@ -0,0 +1,244 @@
"""Generate test-only certified Gauss brackets from exact rational arithmetic.
Newton/Decimal produces candidates only. Exact Fraction signs prove n distinct
Legendre roots; rational interval recurrence encloses the associated weights.
No runtime solver dependency, reference modification, or libm ULP premise.
"""
from decimal import Decimal, localcontext
from fractions import Fraction as F
from pathlib import Path
import math
import re
import json
def add(a, b):
return a[0] + b[0], a[1] + b[1]
def neg(a):
return -a[1], -a[0]
def mul(a, b):
v = [x * y for x in a for y in b]
return min(v), max(v)
def div(a, b):
assert b[0] > 0 or b[1] < 0
return mul(a, (1 / b[1], 1 / b[0]))
def scale(a, b):
return mul(a, (F(b), F(b)))
def legendre(n, x):
p, q = (F(1), F(1)), x
for k in range(2, n + 1):
p, q = q, scale(add(scale(mul(x, q), 2 * k - 1), neg(scale(p, k - 1))), F(1, k))
derivative = div(scale(add(mul(x, q), neg(p)), n), add(mul(x, x), (-F(1), -F(1))))
return q, derivative
def bracket(value):
return math.nextafter(float(value[0]), -math.inf), math.nextafter(float(value[1]), math.inf)
def rule(n):
result = []
for i in range(n):
with localcontext() as context:
context.prec = 90
z = Decimal(str(math.cos(math.pi * (i + .75) / (n + .5))))
for _ in range(30):
p, q = Decimal(1), z
for k in range(2, n + 1):
p, q = q, ((2 * k - 1) * z * q - (k - 1) * p) / k
d = n * (z * q - p) / (z * z - 1)
z -= q / d
lo, hi = bracket((F(z), F(z)))
pl = legendre(n, (F(lo), F(lo)))[0][0]
ph = legendre(n, (F(hi), F(hi)))[0][0]
assert pl * ph < 0
x = F(lo), F(hi)
derivative = legendre(n, x)[1]
w = div((F(2), F(2)), mul(add((F(1), F(1)), neg(mul(x, x))), mul(derivative, derivative)))
result.append((lo, hi, *bracket(w)))
result.sort()
assert all(a[1] < b[0] for a, b in zip(result, result[1:]))
assert sum(F(r[2]) for r in result) < 2 < sum(F(r[3]) for r in result)
return result
def slab_fixtures():
# Approved Appendix A supplies the independently implemented Cholesky /
# Jacobi spectral candidates; Appendix E supplies certified transcendentals.
document = Path(__file__).resolve().parents[3] / "docs/shell-transient-heat-transfer/numerical-oracle-scratch.md"
blocks = re.findall(r"```python\n(.*?)```", document.read_text(encoding="utf-8-sig"), re.S)
spectral = {}
exec(blocks[0].split('out={"lambda"')[0], spectral)
interval_scope = {}
exec(blocks[-1].split("\nfor t in [.001")[0], interval_scope)
iv, ia, im, isc = (interval_scope[k] for k in ("interval", "add", "mul", "scale"))
ex = interval_scope["exneg"]
n = 4
def exact_inverse(matrix):
a = [list(row) + [F(i == j) for j in range(n)] for i, row in enumerate(matrix)]
for k in range(n):
pivot = next(i for i in range(k, n) if a[i][k])
a[k], a[pivot] = a[pivot], a[k]
divisor = a[k][k]
a[k] = [x / divisor for x in a[k]]
for i in range(n):
if i != k:
factor = a[i][k]
a[i] = [x - factor * y for x, y in zip(a[i], a[k])]
return [row[n:] for row in a]
def exact_mm(a, b):
return [[sum((x*y for x, y in zip(row, col)), F(0)) for col in zip(*b)] for row in a]
def matrix_multiply(a, b):
return [[sum_intervals([im(x, y) for x, y in zip(row, col)]) for col in zip(*b)] for row in a]
def sum_intervals(values):
total = iv(0)
for v in values:
total = ia(total, v)
return total
def apply(a, v):
return [sum_intervals([im(x, y) for x, y in zip(row, v)]) for row in a]
def power(a, count):
result = [[iv(i == j) for j in range(n)] for i in range(n)]
while count:
if count & 1:
result = matrix_multiply(result, a)
count >>= 1
if count:
a = matrix_multiply(a, a)
return result
c = [[F(0) for _ in range(5)] for _ in range(5)]
k = [[F(0) for _ in range(5)] for _ in range(5)]
for offset in (0, 2):
for i in range(3):
for j in range(3):
c[offset+i][offset+j] += F([[4, 2, -1], [2, 16, 2], [-1, 2, 4]][i][j], 60)
k[offset+i][offset+j] += F(2, 3)*[[7, -8, 1], [-8, 16, -8], [1, -8, 7]][i][j]
cf, kf = [r[1:] for r in c[1:]], [r[1:] for r in k[1:]]
inverse = exact_inverse(cf)
d = exact_mm(inverse, kf)
y = [-1-sum(inverse[i][j]*c[j+1][0] for j in range(n)) for i in range(n)]
def matrix_exponential(t):
# An independent enclosure of exp(-Cff^-1 Kff t) certifies all spectral
# eigenpair/coefficient errors together, rather than assuming libm ULPs.
# For ||B||inf<=1/2, the 64-term exponential remainder is bounded by
# 2*(1/2)^65/65!. Entrywise intervals preserve subsequent squarings.
magnitude = max(sum(abs(x*t) for x in row) for row in d)
shift = 0
while magnitude > F(1, 2):
magnitude /= 2
shift += 1
a = [[iv(-x*t/F(2)**shift) for x in row] for row in d]
term = [[iv(i == j) for j in range(n)] for i in range(n)]
result = [row[:] for row in term]
for order in range(1, 65):
term = [[isc(x, F(1, order)) for x in row] for row in matrix_multiply(term, a)]
result = [[ia(x, z) for x, z in zip(row, terms)] for row, terms in zip(result, term)]
remainder = 2*F(1, 2)**65/math.factorial(65)
result = [[ia(x, iv(-remainder, remainder)) for x in row] for row in result]
for _ in range(shift):
result = matrix_multiply(result, result)
return result
def outputs(error):
temperature = [iv(1)] + [ia(iv(1), z) for z in error]
derivative = [iv(0)] + apply([[iv(-x) for x in row] for row in d], error)
flux = []
for offset, s in ((0, -1), (0, 0), (0, 1), (2, -1), (2, 0), (2, 1)):
deriv = [F(4)*F(s-F(1, 2)), F(-8*s), F(4)*F(s+F(1, 2))]
flux.append(sum_intervals([isc(temperature[offset+i], -deriv[i]) for i in range(3)]))
energy = sum_intervals([isc(temperature[j], sum(c[i][j] for i in range(5))) for j in range(5)])
reaction = sum_intervals([isc(temperature[j], k[0][j]) for j in range(5)] +
[isc(derivative[j], c[0][j]) for j in range(5)])
return temperature + flux + [energy, reaction]
def spectral_candidate(t, count):
amplitudes = []
for eigenvalue, coefficient in zip(spectral["lam"], spectral["coef"]):
decay = ex(iv(F(eigenvalue)*t)) if count is None else power_scalar(
interval_scope["div"](iv(1), iv(1+F(eigenvalue)*t/count)), count)
amplitudes.append(isc(decay, F(coefficient)))
return outputs(apply([[iv(F(x)) for x in row] for row in spectral["W"]], amplitudes))
def power_scalar(x, count):
result = iv(1)
while count:
if count & 1:
result = im(result, x)
count >>= 1
if count:
x = im(x, x)
return result
table = [[.141, 10.7, .0304, 10.9], [.0153, 1.28, .00468, .824],
[.00598, .253, .00130, .00632], [.00139, .136, .000666, .00953],
[.000142, .0284, .0000945, .000526], [.0000414, .00816, .0000159, .0000479]]
fixtures, metrics = [], []
for time, space in zip((.001, .01, .05, .1, .5, 1.), table):
t = F(time)
temperatures, flux, energy, _, _ = interval_scope["series_interval"](time)
continuum = temperatures + [flux[i] for i in (0, 1, 2, 2, 3, 4)] + [energy, flux[0]]
solutions = []
spectral_enclosure = 0.
for count in (None, 4096, 8192):
if count is None:
operator = matrix_exponential(t)
else:
a = [[cf[i][j]+t/count*kf[i][j] for j in range(n)] for i in range(n)]
operator = power([[iv(x) for x in row] for row in exact_mm(exact_inverse(a), cf)], count)
exact = outputs(apply(operator, [iv(x) for x in y]))
candidate = spectral_candidate(t, count)
enclosed = [(min(a[0], b[0]), max(a[1], b[1])) for a, b in zip(exact, candidate)]
spectral_enclosure = max(spectral_enclosure, max(float(hi-lo) for lo, hi in enclosed))
solutions.append(enclosed)
fixtures.append((time, space, continuum, *solutions))
metrics.append({"time": time, "spectral_and_matrix_function_enclosure": spectral_enclosure})
print(json.dumps({"eigenvalues": spectral["lam"], "slab_oracle_metrics": metrics}, indent=2))
return fixtures
if __name__ == "__main__":
output = ["// Generated by thermal_oracle_generator.py; exact root/weight certificates.",
"#ifndef FESA_TESTS_THERMAL_GAUSS_ORACLE_H_", "#define FESA_TESTS_THERMAL_GAUSS_ORACLE_H_",
"#include <array>", "namespace thermal_oracle {",
"struct GaussPoint { double x_lo,x_hi,w_lo,w_hi; };"]
for n in (12, 16):
rows = rule(n)
output.append(f"inline constexpr std::array<GaussPoint,{n}> kGauss{n}{{{{")
output.extend(" {" + ",".join(x.hex() for x in row) + "}," for row in rows)
output.append("}};")
output.extend(["}", "#endif", ""])
destination = Path(__file__).with_name("thermal_gauss_oracle.h")
destination.write_text("\n".join(output), encoding="utf-8")
print("Certified Legendre roots/weights: 12 + 16 distinct roots;", destination.name)
fixtures = slab_fixtures()
output = ["// Generated by thermal_oracle_generator.py. Outward binary64 brackets.",
"#ifndef FESA_TESTS_THERMAL_SLAB_ORACLE_H_", "#define FESA_TESTS_THERMAL_SLAB_ORACLE_H_",
"#include <array>", "namespace thermal_oracle {",
"struct Bracket { double lo,hi; };",
"struct SlabCase { double time; std::array<double,4> space; std::array<Bracket,13> fourier,continuous,be4096,be8192; };",
"inline constexpr std::array<SlabCase,6> kSlab{{"]
for time, space, *values in fixtures:
output.append("{" + time.hex() + ",{{" + ",".join(x.hex() for x in space) + "}},")
for rows in values:
output.append("{{" + ",".join("{" + ",".join(x.hex() for x in bracket(row)) + "}" for row in rows) + "}},")
output.append("},")
output.extend(["}};", "}", "#endif", ""])
Path(__file__).with_name("thermal_slab_oracle.h").write_text("\n".join(output), encoding="utf-8")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,359 @@
// Generated by thermal_oracle_generator.py. Outward binary64 brackets.
#ifndef FESA_TESTS_THERMAL_SLAB_ORACLE_H_
#define FESA_TESTS_THERMAL_SLAB_ORACLE_H_
#include <array>
namespace thermal_oracle {
struct Bracket {
double lo, hi;
};
struct SlabCase {
double time;
std::array<double, 4> space;
std::array<Bracket, 13> fourier, continuous, be4096, be8192;
};
inline constexpr std::array<SlabCase, 6> kSlab{{
{
0x1.0624dd2f1a9fcp-10,
{{0x1.20c49ba5e353fp-3, 0x1.5666666666666p+3, 0x1.f212d77318fc5p-6,
0x1.5cccccccccccdp+3}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.85b89453c09acp-26, 0x1.85b89453c09aep-26},
{0x1.fe4543738e03ap-95, 0x1.0ff4c2f026ce0p-94},
{-0x1.64845561fdc38p-101, 0x1.c12311737a124p-99},
{-0x1.68eca14e83537p-101, 0x1.c008fe7858ae5p-99},
{0x1.1d75b94accf81p+4, 0x1.1d75b94accf83p+4},
{0x1.88168e094c2d6p-19, 0x1.88168e094c2d8p-19},
{0x1.e433884766565p-87, 0x1.02b7b8a2bf31ap-86},
{0x1.e433884766565p-87, 0x1.02b7b8a2bf31ap-86},
{-0x1.3a94ff682132fp-91, 0x1.b25320f2bf337p-92},
{-0x1.09df47f0c0666p-91, 0x1.09df47f0c0666p-91},
{0x1.244f96d3c38d6p-5, 0x1.244f96d3c38d8p-5},
{0x1.1d75b94accf81p+4, 0x1.1d75b94accf83p+4}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{-0x1.d37c7f414f866p-4, -0x1.d37c7f414f859p-4},
{0x1.1eb81bc756156p-3, 0x1.1eb81bc75615ap-3},
{-0x1.17e5fa341d20bp-6, -0x1.17e5fa341d110p-6},
{0x1.2d98feedf9757p-5, 0x1.2d98feedf9788p-5},
{0x1.cc5b11a49f520p+2, 0x1.cc5b11a49f523p+2},
{0x1.b851f90e2a7a9p+0, 0x1.b851f90e2a7abp+0},
{-0x1.e0642a3b1429cp+1, -0x1.e0642a3b14296p+1},
{0x1.0ce0640ae3c9bp+0, 0x1.0ce0640ae3cbbp+0},
{0x1.a6a3b817af6eap-3, 0x1.a6a3b817af708p-3},
{-0x1.466eec09efdf1p-1, -0x1.466eec09efdc2p-1},
{0x1.0e51bf4794d1ep-4, 0x1.0e51bf4794d3ap-4},
{0x1.be34bece7dbcbp+2, 0x1.be34bece7dbd0p+2}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{-0x1.d37cd7bcda5f0p-4, -0x1.d37cd7bcda5e4p-4},
{0x1.1eb8818ac9073p-3, 0x1.1eb8818ac9077p-3},
{-0x1.17e77bedcde83p-6, -0x1.17e77bedcdd88p-6},
{0x1.2d9a6a607059ep-5, 0x1.2d9a6a60705d0p-5},
{0x1.cc5b231047dc3p+2, 0x1.cc5b231047dc6p+2},
{0x1.b851df9d4dbe2p+0, 0x1.b851df9d4dbe4p+0},
{-0x1.e064668341fa9p+1, -0x1.e064668341fa4p+1},
{0x1.0ce0f74bd7864p+0, 0x1.0ce0f74bd7884p+0},
{0x1.a6a3cde559e00p-3, 0x1.a6a3cde559e1dp-3},
{-0x1.467007a5021f8p-1, -0x1.467007a5021c9p-1},
{0x1.0e51b2b4d8688p-4, 0x1.0e51b2b4d86a3p-4},
{0x1.be34d80c5223ap+2, 0x1.be34d80c5223fp+2}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{-0x1.d37cab7f333f2p-4, -0x1.d37cab7f333e5p-4},
{0x1.1eb84ea93c6aep-3, 0x1.1eb84ea93c6b2p-3},
{-0x1.17e6bb11c7d2ep-6, -0x1.17e6bb11c7c33p-6},
{0x1.2d99b4a80421ep-5, 0x1.2d99b4a80424fp-5},
{0x1.cc5b1a5a7a2e7p+2, 0x1.cc5b1a5a7a2eap+2},
{0x1.b851ec55b0e53p+0, 0x1.b851ec55b0e55p+0},
{-0x1.e064485f43780p+1, -0x1.e064485f4377ap+1},
{0x1.0ce0adaba68aep+0, 0x1.0ce0adaba68cdp+0},
{0x1.a6a3c2fe76c36p-3, 0x1.a6a3c2fe76c53p-3},
{-0x1.466f79d811b70p-1, -0x1.466f79d811b41p-1},
{0x1.0e51b8fe3293cp-4, 0x1.0e51b8fe32958p-4},
{0x1.be34cb6d72726p+2, 0x1.be34cb6d7272bp+2}}},
},
{
0x1.47ae147ae147bp-7,
{{0x1.f559b3d07c84bp-7, 0x1.47ae147ae147bp+0, 0x1.32b55ef1fddecp-8,
0x1.a5e353f7ced91p-1}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.3bcd133aa0ffbp-4, 0x1.3bcd133aa0ffdp-4},
{0x1.aab859b20ac9ep-12, 0x1.aab859b20aca0p-12},
{0x1.e87470e505fc1p-24, 0x1.e87470e505fc3p-24},
{0x1.b0c1a759f773cp-39, 0x1.b0c1a759f773ep-39},
{0x1.6914d24534247p+2, 0x1.6914d24534249p+2},
{0x1.2ebf3dcc9f22ep+0, 0x1.2ebf3dcc9f230p+0},
{0x1.64e3dcd3af4bap-7, 0x1.64e3dcd3af4bcp-7},
{0x1.64e3dcd3af4bap-7, 0x1.64e3dcd3af4bcp-7},
{0x1.27c272dde935ep-18, 0x1.27c272dde9360p-18},
{-0x1.64c3500000001p-300, 0x1.64c3500000001p-300},
{0x1.ce2f21a042be1p-4, 0x1.ce2f21a042be3p-4},
{0x1.6914d24534247p+2, 0x1.6914d24534249p+2}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.7a435a2984e32p-4, 0x1.7a435a2984e3ap-4},
{0x1.9dc400057caf6p-12, 0x1.9dc400057d765p-12},
{0x1.ad9feeec8c48dp-7, 0x1.ad9feeec8c649p-7},
{-0x1.986d06319bd56p-7, -0x1.986d06319bcd8p-7},
{0x1.50c482dacf8f7p+2, 0x1.50c482dacf8f9p+2},
{0x1.ffcc477fff504p+0, 0x1.ffcc477fff508p+0},
{-0x1.43797c6b3f9d5p+0, -0x1.43797c6b3f9d2p+0},
{-0x1.05044c3c6933ap-3, -0x1.05044c3c69290p-3},
{0x1.a55b2631c7b93p-6, 0x1.a55b2631c7baep-6},
{0x1.6e5b15c8db17bp-3, 0x1.6e5b15c8db21fp-3},
{0x1.e15645f1d96e9p-4, 0x1.e15645f1d9703p-4},
{0x1.345d88b145b6ap+2, 0x1.345d88b145b6ep+2}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.7a374829b1404p-4, 0x1.7a374829b140cp-4},
{0x1.af3900931af0ap-12, 0x1.af3900931bb78p-12},
{0x1.ad81aefddf88dp-7, 0x1.ad81aefddfa49p-7},
{-0x1.983e6ad119e83p-7, -0x1.983e6ad119e05p-7},
{0x1.50c690c2ce70cp+2, 0x1.50c690c2ce70ep+2},
{0x1.ffca18dfed9c8p+0, 0x1.ffca18dfed9cbp+0},
{-0x1.4386114b5e8a2p+0, -0x1.4386114b5e89ep+0},
{-0x1.04baf9d759bb3p-3, -0x1.04baf9d759b09p-3},
{0x1.a5b832d5b2be1p-6, 0x1.a5b832d5b2bfcp-6},
{0x1.6e29068cc6608p-3, 0x1.6e29068cc66acp-3},
{0x1.e154626664a52p-4, 0x1.e154626664a6cp-4},
{0x1.34600de90e320p+2, 0x1.34600de90e323p+2}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.7a3d511a6a009p-4, 0x1.7a3d511a6a012p-4},
{0x1.a67e9a3b3c161p-12, 0x1.a67e9a3b3cdd0p-12},
{0x1.ad90cec9c0f6fp-7, 0x1.ad90cec9c112bp-7},
{-0x1.9855b85b10049p-7, -0x1.9855b85b0ffcbp-7},
{0x1.50c589d18499bp+2, 0x1.50c589d18499ep+2},
{0x1.ffcb302cb8985p+0, 0x1.ffcb302cb8989p+0},
{-0x1.437fc6eca1366p+0, -0x1.437fc6eca1362p+0},
{-0x1.04dfa2a190d26p-3, -0x1.04dfa2a190c7cp-3},
{0x1.a589ad2ce9e39p-6, 0x1.a589ad2ce9e54p-6},
{0x1.6e420deccb411p-3, 0x1.6e420deccb4b5p-3},
{0x1.e1555429f7bf1p-4, 0x1.e1555429f7c0bp-4},
{0x1.345ecb5088dc7p+2, 0x1.345ecb5088dcbp+2}}},
},
{
0x1.999999999999ap-5,
{{0x1.87e7c06e19b91p-8, 0x1.03126e978d4fep-2, 0x1.54c985f06f694p-10,
0x1.9e30014f8b589p-8}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b77efb25b8dd2p-2, 0x1.b77efb25b8dd4p-2},
{0x1.d252b304ed681p-4, 0x1.d252b304ed683p-4},
{0x1.235c8909400c5p-6, 0x1.235c8909400c7p-6},
{0x1.9a5c5e03484dep-9, 0x1.9a5c5e03484e0p-9},
{0x1.42f6019270650p+1, 0x1.42f6019270652p+1},
{0x1.d89101a46e842p+0, 0x1.d89101a46e844p+0},
{0x1.721a47b716779p-1, 0x1.721a47b71677bp-1},
{0x1.721a47b716779p-1, 0x1.721a47b71677bp-1},
{0x1.343beb6102cc6p-3, 0x1.343beb6102cc8p-3},
{-0x1.3f24600000001p-301, 0x1.3f24600000001p-301},
{0x1.025e67b9cdad7p-2, 0x1.025e67b9cdad9p-2},
{0x1.42f6019270650p+1, 0x1.42f6019270652p+1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b8566cd59dd36p-2, 0x1.b8566cd59dd3ap-2},
{0x1.b9d5c5e3870abp-4, 0x1.b9d5c5e3870c1p-4},
{0x1.1587ab02cfe81p-6, 0x1.1587ab02cff38p-6},
{0x1.1ad4cd8131fbap-7, 0x1.1ad4cd8131fd0p-7},
{0x1.6346ef889a9d2p+1, 0x1.6346ef889a9d4p+1},
{0x1.c8c547438f1e7p+0, 0x1.c8c547438f1ecp+0},
{0x1.95f95eebd2052p-1, 0x1.95f95eebd205ep-1},
{0x1.0ed51015fadbfp-1, 0x1.0ed51015fade0p-1},
{0x1.967b2c3360cb1p-3, 0x1.967b2c3360cc9p-3},
{-0x1.0e5de7f129e18p-3, -0x1.0e5de7f129d6ep-3},
{0x1.010a6df46a07bp-2, 0x1.010a6df46a082p-2},
{0x1.43c4ee9a8ce2bp+1, 0x1.43c4ee9a8ce2fp+1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b84e9bd4911f6p-2, 0x1.b84e9bd4911fap-2},
{0x1.b9ccf55bd5095p-4, 0x1.b9ccf55bd50abp-4},
{0x1.15b1a7159d30ap-6, 0x1.15b1a7159d3c1p-6},
{0x1.1b178ee6bb5d6p-7, 0x1.1b178ee6bb5ecp-7},
{0x1.634e33812c311p+1, 0x1.634e33812c313p+1},
{0x1.c8c66154855eap+0, 0x1.c8c66154855eep+0},
{0x1.95e0b74d64b63p-1, 0x1.95e0b74d64b6ep-1},
{0x1.0ec60ab6ae53dp-1, 0x1.0ec60ab6ae55ep-1},
{0x1.966a037efd9d7p-3, 0x1.966a037efd9f0p-3},
{-0x1.0e4423dcbe1c4p-3, -0x1.0e4423dcbe11ap-3},
{0x1.0108815a6658cp-2, 0x1.0108815a66593p-2},
{0x1.43cb51041b9e3p+1, 0x1.43cb51041b9e7p+1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b85284545e3fep-2, 0x1.b85284545e402p-2},
{0x1.b9d15d4ee5b37p-4, 0x1.b9d15d4ee5b4dp-4},
{0x1.159ca92438c35p-6, 0x1.159ca92438cebp-6},
{0x1.1af6311dbcc58p-7, 0x1.1af6311dbcc6ep-7},
{0x1.634a9180901b3p+1, 0x1.634a9180901b5p+1},
{0x1.c8c5d45623495p+0, 0x1.c8c5d4562349ap+0},
{0x1.95ed0b564cb88p-1, 0x1.95ed0b564cb94p-1},
{0x1.0ecd8d3b0bfa0p-1, 0x1.0ecd8d3b0bfc1p-1},
{0x1.9672972b2e1aap-3, 0x1.9672972b2e1c2p-3},
{-0x1.0e510695d3bacp-3, -0x1.0e510695d3b02p-3},
{0x1.010977a63dfebp-2, 0x1.010977a63dff1p-2},
{0x1.43c81fc9071c0p+1, 0x1.43c81fc9071c4p+1}}},
},
{
0x1.999999999999ap-4,
{{0x1.6c61522a6f3f5p-10, 0x1.16872b020c49cp-3, 0x1.5d2d01c0ca601p-11,
0x1.38476f2a5a46ap-7}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.270906ee5a6cfp-1, 0x1.270906ee5a6d1p-1},
{0x1.0eb16bef11388p-2, 0x1.0eb16bef1138ap-2},
{0x1.945c98b83c928p-4, 0x1.945c98b83c92ap-4},
{0x1.9f4a5c2b49fb7p-5, 0x1.9f4a5c2b49fb9p-5},
{0x1.c8b1bdc9d3f27p+0, 0x1.c8b1bdc9d3f29p+0},
{0x1.8673042a10047p+0, 0x1.8673042a10049p+0},
{0x1.e5a6c4f8749dfp-1, 0x1.e5a6c4f8749e1p-1},
{0x1.e5a6c4f8749dfp-1, 0x1.e5a6c4f8749e1p-1},
{0x1.9af613adf14c0p-2, 0x1.9af613adf14c2p-2},
{-0x1.c357400000001p-302, 0x1.c357400000001p-302},
{0x1.6d631d0d902e4p-2, 0x1.6d631d0d902e6p-2},
{0x1.c8b1bdc9d3f27p+0, 0x1.c8b1bdc9d3f29p+0}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.26f65a0fd4a73p-1, 0x1.26f65a0fd4a75p-1},
{0x1.0e6d0af83d0acp-2, 0x1.0e6d0af83d0b2p-2},
{0x1.916bd5fe070d9p-4, 0x1.916bd5fe07101p-4},
{0x1.93ecedc1f0d7fp-5, 0x1.93ecedc1f0d89p-5},
{0x1.eb5d1d3ccbe86p+0, 0x1.eb5d1d3ccbe89p+0},
{0x1.78c97a83e17a7p+0, 0x1.78c97a83e17aap+0},
{0x1.0635d7caf70c6p+0, 0x1.0635d7caf70cdp+0},
{0x1.cc58e8a2ee2c2p-1, 0x1.cc58e8a2ee2dfp-1},
{0x1.b7deda7ffddf7p-2, 0x1.b7deda7ffde03p-2},
{-0x1.47a0e22f04e5ep-5, -0x1.47a0e22f04c0dp-5},
{0x1.6cb487831db4ap-2, 0x1.6cb487831db50p-2},
{0x1.cb21e9c5f325fp+0, 0x1.cb21e9c5f3263p+0}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.26f24a61a564bp-1, 0x1.26f24a61a564dp-1},
{0x1.0e667df8508a0p-2, 0x1.0e667df8508a6p-2},
{0x1.9170e359fb821p-4, 0x1.9170e359fb849p-4},
{0x1.9417f976522f8p-5, 0x1.9417f97652303p-5},
{0x1.eb6a157592b20p+0, 0x1.eb6a157592b23p+0},
{0x1.78ccc103d7badp+0, 0x1.78ccc103d7bb1p+0},
{0x1.062f6c921cc39p+0, 0x1.062f6c921cc3fp+0},
{0x1.cc4595bdc0604p-1, 0x1.cc4595bdc0621p-1},
{0x1.b7c6fd930c880p-2, 0x1.b7c6fd930c88cp-2},
{-0x1.47e982ab3d9f7p-5, -0x1.47e982ab3d7a5p-5},
{0x1.6cb19975e1802p-2, 0x1.6cb19975e1808p-2},
{0x1.cb2cb028081f8p+0, 0x1.cb2cb028081fcp+0}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.26f45238988fdp-1, 0x1.26f45238988ffp-1},
{0x1.0e69c46af3672p-2, 0x1.0e69c46af3678p-2},
{0x1.916e5ca776061p-4, 0x1.916e5ca776088p-4},
{0x1.940274204c9cdp-5, 0x1.940274204c9d8p-5},
{0x1.eb63995317741p+0, 0x1.eb63995317743p+0},
{0x1.78cb1dca864c4p+0, 0x1.78cb1dca864c8p+0},
{0x1.0632a241f5246p+0, 0x1.0632a241f524cp+0},
{0x1.cc4f3f1d6dc15p-1, 0x1.cc4f3f1d6dc32p-1},
{0x1.b7d2ebcdd3a6fp-2, 0x1.b7d2ebcdd3a7bp-2},
{-0x1.47c534f9a1c17p-5, -0x1.47c534f9a19c6p-5},
{0x1.6cb3107b2e3dep-2, 0x1.6cb3107b2e3e4p-2},
{0x1.cb274cef49caep+0, 0x1.cb274cef49cb1p+0}}},
},
{
0x1.0000000000000p-1,
{{0x1.29cbab649d389p-13, 0x1.d14e3bcd35a86p-6, 0x1.8c5c9a34ca0c3p-14,
0x1.13c68661ae70cp-11}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b7590ca5d56abp-1, 0x1.b7590ca5d56adp-1},
{0x1.79c27556059fcp-1, 0x1.79c27556059fep-1},
{0x1.509c59ccb1964p-1, 0x1.509c59ccb1966p-1},
{0x1.422975f1d50c3p-1, 0x1.422975f1d50c5p-1},
{0x1.2a37abf469800p-1, 0x1.2a37abf469802p-1},
{0x1.1382380277aa0p-1, 0x1.1382380277aa2p-1},
{0x1.a5b316788e428p-2, 0x1.a5b316788e42ap-2},
{0x1.a5b316788e428p-2, 0x1.a5b316788e42ap-2},
{0x1.c86932802133fp-3, 0x1.c869328021341p-3},
{-0x1.26ee800000001p-303, 0x1.26ee800000001p-303},
{0x1.87247f6ca05d8p-1, 0x1.87247f6ca05dap-1},
{0x1.2a37abf469800p-1, 0x1.2a37abf469802p-1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b7553624e5316p-1, 0x1.b7553624e5318p-1},
{0x1.79b5b3c71720bp-1, 0x1.79b5b3c71720dp-1},
{0x1.509288faf814fp-1, 0x1.509288faf8152p-1},
{0x1.4216f7b692db3p-1, 0x1.4216f7b692db6p-1},
{0x1.38c1b66704b5dp-1, 0x1.38c1b66704b63p-1},
{0x1.0c949871d1be7p-1, 0x1.0c949871d1be9p-1},
{0x1.c0cef4f93d8ddp-2, 0x1.c0cef4f93d8e5p-2},
{0x1.b3b7bc7fdfa53p-2, 0x1.b3b7bc7fdfa69p-2},
{0x1.bcf5e084222b4p-3, 0x1.bcf5e084222bdp-3},
{0x1.27c480885099dp-7, 0x1.27c4808850cf9p-7},
{0x1.87181cfb04848p-1, 0x1.87181cfb0484ap-1},
{0x1.2a7c94e9a3a3dp-1, 0x1.2a7c94e9a3a41p-1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b751be282259dp-1, 0x1.b751be28225a0p-1},
{0x1.79af4d5fe0284p-1, 0x1.79af4d5fe0286p-1},
{0x1.508a2ff978465p-1, 0x1.508a2ff978468p-1},
{0x1.420defb8a1c5ap-1, 0x1.420defb8a1c5dp-1},
{0x1.38d0a97ead811p-1, 0x1.38d0a97ead816p-1},
{0x1.0ca165403faf5p-1, 0x1.0ca165403faf8p-1},
{0x1.c0e44203a3bafp-2, 0x1.c0e44203a3bb7p-2},
{0x1.b3cc5fc984930p-2, 0x1.b3cc5fc984946p-2},
{0x1.bd0aed39f3147p-3, 0x1.bd0aed39f3150p-3},
{0x1.27d1ae0dd005dp-7, 0x1.27d1ae0dd03b9p-7},
{0x1.87125aea910c9p-1, 0x1.87125aea910cbp-1},
{0x1.2a8ad7437b2aep-1, 0x1.2a8ad7437b2b1p-1}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.b7537a2158170p-1, 0x1.b7537a2158173p-1},
{0x1.79b28088e2c65p-1, 0x1.79b28088e2c67p-1},
{0x1.508e5c6b105ecp-1, 0x1.508e5c6b105efp-1},
{0x1.421273a69f88ep-1, 0x1.421273a69f891p-1},
{0x1.38c9300704d3bp-1, 0x1.38c9300704d40p-1},
{0x1.0c9afeee3a733p-1, 0x1.0c9afeee3a736p-1},
{0x1.c0d99baae0253p-2, 0x1.c0d99baae025bp-2},
{0x1.b3c20e5419820p-2, 0x1.b3c20e5419836p-2},
{0x1.bd00671219eacp-3, 0x1.bd00671219eb4p-3},
{0x1.27cb17c00cee7p-7, 0x1.27cb17c00d243p-7},
{0x1.87153be8d5e91p-1, 0x1.87153be8d5e93p-1},
{0x1.2a83b62aa8393p-1, 0x1.2a83b62aa8396p-1}}},
},
{
0x1.0000000000000p+0,
{{0x1.5b49d2b1e91bbp-15, 0x1.0b630a91537a0p-7, 0x1.0ac1fae1b30dep-16,
0x1.91d0777c385fcp-15}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.ead7f87070237p-1, 0x1.ead7f87070239p-1},
{0x1.d8e87b7ae7a62p-1, 0x1.d8e87b7ae7a64p-1},
{0x1.ccec8c4ec5ef1p-1, 0x1.ccec8c4ec5ef3p-1},
{0x1.c8b73b9ac9a1dp-1, 0x1.c8b73b9ac9a1fp-1},
{0x1.5b5c75846aaf9p-3, 0x1.5b5c75846aafbp-3},
{0x1.40eb7cceb0482p-3, 0x1.40eb7cceb0484p-3},
{0x1.eb3e2ce365fd5p-4, 0x1.eb3e2ce365fd7p-4},
{0x1.eb3e2ce365fd5p-4, 0x1.eb3e2ce365fd7p-4},
{0x1.09dbd573f51e4p-4, 0x1.09dbd573f51e6p-4},
{-0x1.586e000000001p-305, 0x1.586e000000001p-305},
{0x1.dcce118e2abfap-1, 0x1.dcce118e2abfcp-1},
{0x1.5b5c75846aaf9p-3, 0x1.5b5c75846aafbp-3}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.eada37c43dbcdp-1, 0x1.eada37c43dbd0p-1},
{0x1.d8eb0b5ab5aebp-1, 0x1.d8eb0b5ab5aeep-1},
{0x1.ccf1f94448ecfp-1, 0x1.ccf1f94448ed1p-1},
{0x1.c8badb25ce1b3p-1, 0x1.c8badb25ce1b6p-1},
{0x1.6c11624df5d8dp-3, 0x1.6c11624df5d96p-3},
{0x1.38a7a52a52899p-3, 0x1.38a7a52a5289dp-3},
{0x1.053de806af3a2p-3, 0x1.053de806af3a6p-3},
{0x1.fb41824cb7384p-4, 0x1.fb41824cb739ap-4},
{0x1.0303034e7937cp-4, 0x1.0303034e79384p-4},
{0x1.58908a0766c2ap-9, 0x1.58908a0767016p-9},
{0x1.dcd0247fc702ap-1, 0x1.dcd0247fc702dp-1},
{0x1.5b75854f419a5p-3, 0x1.5b75854f419aap-3}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.ead630c226440p-1, 0x1.ead630c226443p-1},
{0x1.d8e399ff30e90p-1, 0x1.d8e399ff30e93p-1},
{0x1.cce84031702f6p-1, 0x1.cce84031702f8p-1},
{0x1.c8b05490c3638p-1, 0x1.c8b05490c363bp-1},
{0x1.6c56b7b4bec58p-3, 0x1.6c56b7b4bec60p-3},
{0x1.38e3300678b71p-3, 0x1.38e3300678b76p-3},
{0x1.056fa85832a89p-3, 0x1.056fa85832a8dp-3},
{0x1.fba21c895611fp-4, 0x1.fba21c8956135p-4},
{0x1.033456e6d857dp-4, 0x1.033456e6d8585p-4},
{0x1.58d2288b53912p-9, 0x1.58d2288b53cfep-9},
{0x1.dcc97107ca959p-1, 0x1.dcc97107ca95cp-1},
{0x1.5bb7b0fadf43fp-3, 0x1.5bb7b0fadf445p-3}}},
{{{0x1.fffffffffffffp-1, 0x1.0000000000001p+0},
{0x1.ead8344139715p-1, 0x1.ead8344139717p-1},
{0x1.d8e752a94ecadp-1, 0x1.d8e752a94ecafp-1},
{0x1.cced1cb61a4edp-1, 0x1.cced1cb61a4f0p-1},
{0x1.c8b597d621e34p-1, 0x1.c8b597d621e37p-1},
{0x1.6c340d23482b2p-3, 0x1.6c340d23482bap-3},
{0x1.38c56ab589a8cp-3, 0x1.38c56ab589a90p-3},
{0x1.0556c847cb264p-3, 0x1.0556c847cb268p-3},
{0x1.fb71cf9a50858p-4, 0x1.fb71cf9a5086ep-4},
{0x1.031bad32ce78bp-4, 0x1.031bad32ce792p-4},
{0x1.58b159698d54ep-9, 0x1.58b159698d939p-9},
{0x1.dccccac08134cp-1, 0x1.dccccac08134fp-1},
{0x1.5b969b4572366p-3, 0x1.5b969b457236cp-3}}},
},
}};
} // namespace thermal_oracle
#endif
@@ -13,7 +13,7 @@ std::string Bytes(const std::filesystem::path& path) {
std::ifstream in{path, std::ios::binary};
return {std::istreambuf_iterator<char>{in}, std::istreambuf_iterator<char>{}};
}
TEST(ThermalReference, OriginalAbaqusNt11AtExactTime37) {
TEST(ThermalReference, OriginalAbaqusNt11RemainsAnExplicitFailingDiagnostic) {
const auto folder =
std::filesystem::path{FESA_TEST_SOURCE_DIR} / "reference/shell-thermal";
const auto input = folder / "shell-thermal.inp";
@@ -52,9 +52,17 @@ TEST(ThermalReference, OriginalAbaqusNt11AtExactTime37) {
<< " B=" << r.family.near_zero_band
<< " RMS/S=" << r.family.relative_rms
<< " max_abs=" << r.family.maximum_absolute_error
<< " failed_rows=" << failed << " passed=" << r.passed << '\n';
<< " failed_rows=" << failed << " numerical_passed=" << r.passed
<< " classification=diagnostic blocking=" << r.family.blocking
<< '\n';
EXPECT_EQ(r.family.reference_scale, 1000);
EXPECT_EQ(r.family.near_zero_band, 10);
EXPECT_TRUE(r.passed);
EXPECT_FALSE(r.family.blocking);
EXPECT_FALSE(r.passed);
EXPECT_FALSE(r.family.rms_passed);
EXPECT_EQ(failed, 87U);
EXPECT_GT(r.family.relative_rms,
fesa::test::ReferenceTolerancePolicy::kRelativeRmsTolerance);
EXPECT_GT(r.family.maximum_absolute_error, r.family.near_zero_band);
}
} // namespace
@@ -154,14 +154,14 @@ Result<ThermalReferenceReport> CompareThermalSnapshots(
ReferenceToleranceFamily family{
"shell-thermal/Step-1/time=37/NT11/temperature/user-consistent",
{"NT11"},
true,
false,
{}};
for (auto label : labels) family.rows.push_back({a.at(label), r.at(label)});
const auto evaluation = ReferenceTolerancePolicy::Evaluate({family});
Require(evaluation.valid && evaluation.families.size() == 1,
"Invalid tolerance evaluation.");
ThermalReferenceReport report{
evaluation.passed, {}, evaluation.families[0]};
evaluation.families[0].passed, {}, evaluation.families[0]};
std::size_t index = 0;
for (auto label : labels)
report.rows.push_back({instance, label, 11, a.at(label), r.at(label),
@@ -32,6 +32,8 @@ struct ThermalReferenceRowDecision {
ReferenceToleranceRowDecision tolerance;
};
struct ThermalReferenceReport {
// Numerical family verdict, retained even when the original artifact is
// classified as nonblocking diagnostic by the approved option A decision.
bool passed = false;
std::vector<ThermalReferenceRowDecision> rows;
ReferenceToleranceFamilyDecision family;
@@ -217,7 +217,7 @@ TEST(ThermalReferenceComparison,
fesa::test::ReferenceToleranceBranch::kRelative);
EXPECT_EQ(result.Value().family.reference_scale, 1000);
EXPECT_EQ(result.Value().family.near_zero_band, 10);
EXPECT_TRUE(result.Value().family.blocking);
EXPECT_FALSE(result.Value().family.blocking);
}
TEST(ThermalReferenceComparison,
RejectsMissingExtraDuplicateAndNonfiniteBeforeTolerance) {