FAILURE MAP
← Case archive

FA-70941 / Weather index computation / Open access

Shade apparent temperature: saturation vapour pressure denominator · case 01

Hot humid values are inflated while cold values are slightly low.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The Tetens exponent drops the temperature from its denominator.

VERIFIED REPAIR

Use 17.27*Ta/(237.7+Ta).

Unsuccessful approach: Using the Kelvin offset 273.15 in the denominator still mis-scales the exponent.

Case contract

Input air temperature degC, RH percent, wind in km/h measured at 10 m. e = RH/100*6.105*exp(17.27*Ta/(237.7+Ta)) hPa; wind in m/s = km/h / 3.6; AT = Ta + 0.33e - 0.70ws - 4.00 rounded to 0.1.

Why this case matters

Feels-like temperature on consumer forecasts uses this non-radiative apparent temperature.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
    e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / 237.7)
    ws = wind_kmh / 3.6
    at = ta + 0.33 * e - 0.70 * ws - 4.00
    return round(at, 1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3]], [['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7]], [['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2], ['12 C 90% RH wind 72 km/h', [12, 90, 72], -1.8]], [['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['20 C 10% RH wind 10 km/h', [20, 10, 10], 14.8], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8]], [['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8], ['20 C 90% RH wind 10 km/h', [20, 90, 10], 21.0]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
-5 C 10% RH wind 0 km/h-8.9-8.9Passed
-5 C 10% RH wind 10 km/h-10.8-10.8Passed
-5 C 10% RH wind 36 km/h-15.9-15.9Passed
-5 C 10% RH wind 72 km/h-22.9-22.9Passed
-5 C 50% RH wind 0 km/h-8.3-8.3Passed
-5 C 50% RH wind 10 km/h-10.2-10.2Passed
12 C 10% RH wind 0 km/h8.58.5Passed
12 C 50% RH wind 0 km/h10.410.3Failed

SHA-256 / c4b49ee7e058f5ddbe331df26f9ef6d0a7d6d2e7091d0f401e1cd3d60425afba

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
    e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / (273.15 + ta))
    ws = wind_kmh / 3.6
    at = ta + 0.33 * e - 0.70 * ws - 4.00
    return round(at, 1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3]], [['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7]], [['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2], ['12 C 90% RH wind 72 km/h', [12, 90, 72], -1.8]], [['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['20 C 10% RH wind 10 km/h', [20, 10, 10], 14.8], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8]], [['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8], ['20 C 90% RH wind 10 km/h', [20, 90, 10], 21.0]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
-5 C 10% RH wind 0 km/h-8.9-8.9Passed
-5 C 10% RH wind 10 km/h-10.8-10.8Passed
-5 C 10% RH wind 36 km/h-15.9-15.9Passed
-5 C 10% RH wind 72 km/h-22.9-22.9Passed
-5 C 50% RH wind 0 km/h-8.3-8.3Passed
-5 C 50% RH wind 10 km/h-10.2-10.2Passed
12 C 10% RH wind 0 km/h8.48.5Failed
12 C 50% RH wind 0 km/h10.110.3Failed

SHA-256 / 233bd31561a2efef47c896d0948189e153e34cb229be3732049a0f475f7fa710

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
    e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / (237.7 + ta))
    ws = wind_kmh / 3.6
    at = ta + 0.33 * e - 0.70 * ws - 4.00
    return round(at, 1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3]], [['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7]], [['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2], ['12 C 90% RH wind 72 km/h', [12, 90, 72], -1.8]], [['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['20 C 10% RH wind 10 km/h', [20, 10, 10], 14.8], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8]], [['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['20 C 50% RH wind 0 km/h', [20, 50, 0], 19.8], ['20 C 90% RH wind 10 km/h', [20, 90, 10], 21.0]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
-5 C 10% RH wind 0 km/h-8.9-8.9Passed
-5 C 10% RH wind 10 km/h-10.8-10.8Passed
-5 C 10% RH wind 36 km/h-15.9-15.9Passed
-5 C 10% RH wind 72 km/h-22.9-22.9Passed
-5 C 50% RH wind 0 km/h-8.3-8.3Passed
-5 C 50% RH wind 10 km/h-10.2-10.2Passed
12 C 10% RH wind 0 km/h8.58.5Passed
12 C 50% RH wind 0 km/h10.310.3Passed

SHA-256 / 845d5e9670934f9c8e0719b0fc442ff38338f7f7f8328704812a523809d9b72e

Verification & scope

Stipulated deterministic teaching model of an operational weather index; coefficients and thresholds are fixed by the contract and no claim of standards conformance is made. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:48:25.317668+00:00.

Case digest / 09848088f671c2eefd9b0738d27d363345a70e1b42ce08a888a2467bad6f3619