FAILURE MAP
← Case archive

FA-71186 / Weather index computation / Open access

Hargreaves reference evapotranspiration: cold day clamp · case 01

Deep-cold days report negative evapotranspiration.

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

ROOT CAUSE

The result is not clamped at zero when Tmean < -17.8.

VERIFIED REPAIR

Clamp negative ET0 to zero.

Unsuccessful approach: Taking the absolute value turns frost into positive water demand.

Case contract

Daily tmax/tmin degC (tmax >= tmin) and extraterrestrial radiation Ra in MJ/m2/day. Convert Ra to mm/day with 0.408. ET0 = 0.0023*Ra_mm*(Tmean+17.8)*sqrt(tmax-tmin), Tmean=(tmax+tmin)/2; negative results clamp to 0; round to 0.01 mm.

Why this case matters

Irrigation scheduling uses ET0 where full meteorological data are unavailable.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tmax, tmin, ra_mj):
    tmean = (tmax + tmin) / 2
    et = 0.0023 * 0.408 * ra_mj * (tmean + 17.8) * math.sqrt(tmax - tmin)
    return round(et, 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tmax 30 tmin 15 Ra 10.0', [30, 15, 10.0], 1.46], ['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0]], [['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax 10 tmin -2 Ra 40.0', [10, -2, 40.0], 2.83], ['tmax -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax -10 tmin -25 Ra 25.0', [-10, -25, 25.0], 0.03], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0], ['tmax 25 tmin 25 Ra 10.0', [25, 25, 10.0], 0.0], ['tmax 25 tmin 25 Ra 25.0', [25, 25, 25.0], 0.0], ['tmax 25 tmin 25 Ra 40.0', [25, 25, 40.0], 0.0], ['tmax 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['tmax 40 tmin 18 Ra 40.0', [40, 18, 40.0], 8.24]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax 22 tmin 8 Ra 10.0', [22, 8, 10.0], 1.15], ['tmax 22 tmin 8 Ra 25.0', [22, 8, 25.0], 2.88], ['tmax 22 tmin 8 Ra 40.0', [22, 8, 40.0], 4.61], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19], ['tmax -5 tmin -20 Ra 25.0', [-5, -20, 25.0], 0.48], ['tmax -5 tmin -20 Ra 40.0', [-5, -20, 40.0], 0.77]], [['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.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
tmax 30 tmin 15 Ra 10.01.461.46Passed
tmax 30 tmin 15 Ra 25.03.663.66Passed
tmax 30 tmin 15 Ra 40.05.865.86Passed
tmax 35 tmin 20 Ra 10.01.651.65Passed
tmax 35 tmin 20 Ra 25.04.124.12Passed
tmax 35 tmin 20 Ra 40.06.596.59Passed
tmax -12 tmin -30 Ra 10.0-0.130.0Failed
tmax -12 tmin -30 Ra 25.0-0.320.0Failed

SHA-256 / 1ff917afb235dc54c5e59efa099c5a6b1460386cceafd63e33d599bd5e0dddd6

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tmax, tmin, ra_mj):
    tmean = (tmax + tmin) / 2
    et = 0.0023 * 0.408 * ra_mj * (tmean + 17.8) * math.sqrt(tmax - tmin)
    return round(abs(et), 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tmax 30 tmin 15 Ra 10.0', [30, 15, 10.0], 1.46], ['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0]], [['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax 10 tmin -2 Ra 40.0', [10, -2, 40.0], 2.83], ['tmax -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax -10 tmin -25 Ra 25.0', [-10, -25, 25.0], 0.03], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0], ['tmax 25 tmin 25 Ra 10.0', [25, 25, 10.0], 0.0], ['tmax 25 tmin 25 Ra 25.0', [25, 25, 25.0], 0.0], ['tmax 25 tmin 25 Ra 40.0', [25, 25, 40.0], 0.0], ['tmax 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['tmax 40 tmin 18 Ra 40.0', [40, 18, 40.0], 8.24]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax 22 tmin 8 Ra 10.0', [22, 8, 10.0], 1.15], ['tmax 22 tmin 8 Ra 25.0', [22, 8, 25.0], 2.88], ['tmax 22 tmin 8 Ra 40.0', [22, 8, 40.0], 4.61], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19], ['tmax -5 tmin -20 Ra 25.0', [-5, -20, 25.0], 0.48], ['tmax -5 tmin -20 Ra 40.0', [-5, -20, 40.0], 0.77]], [['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.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
tmax 30 tmin 15 Ra 10.01.461.46Passed
tmax 30 tmin 15 Ra 25.03.663.66Passed
tmax 30 tmin 15 Ra 40.05.865.86Passed
tmax 35 tmin 20 Ra 10.01.651.65Passed
tmax 35 tmin 20 Ra 25.04.124.12Passed
tmax 35 tmin 20 Ra 40.06.596.59Passed
tmax -12 tmin -30 Ra 10.00.130.0Failed
tmax -12 tmin -30 Ra 25.00.320.0Failed

SHA-256 / 3068738c3ff3806a19aba4ed02cebd6a0f1cdfe740439cd1e630162c134a7e2e

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tmax, tmin, ra_mj):
    tmean = (tmax + tmin) / 2
    et = 0.0023 * 0.408 * ra_mj * (tmean + 17.8) * math.sqrt(tmax - tmin)
    return round(max(et, 0.0), 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tmax 30 tmin 15 Ra 10.0', [30, 15, 10.0], 1.46], ['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0]], [['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax 10 tmin -2 Ra 40.0', [10, -2, 40.0], 2.83], ['tmax -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax -10 tmin -25 Ra 25.0', [-10, -25, 25.0], 0.03], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 40.0', [-12, -30, 40.0], 0.0], ['tmax 25 tmin 25 Ra 10.0', [25, 25, 10.0], 0.0], ['tmax 25 tmin 25 Ra 25.0', [25, 25, 25.0], 0.0], ['tmax 25 tmin 25 Ra 40.0', [25, 25, 40.0], 0.0], ['tmax 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['tmax 40 tmin 18 Ra 40.0', [40, 18, 40.0], 8.24]], [['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['tmax -12 tmin -30 Ra 25.0', [-12, -30, 25.0], 0.0], ['tmax 22 tmin 8 Ra 10.0', [22, 8, 10.0], 1.15], ['tmax 22 tmin 8 Ra 25.0', [22, 8, 25.0], 2.88], ['tmax 22 tmin 8 Ra 40.0', [22, 8, 40.0], 4.61], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19], ['tmax -5 tmin -20 Ra 25.0', [-5, -20, 25.0], 0.48], ['tmax -5 tmin -20 Ra 40.0', [-5, -20, 40.0], 0.77]], [['tmax 30 tmin 15 Ra 25.0', [30, 15, 25.0], 3.66], ['tmax 30 tmin 15 Ra 40.0', [30, 15, 40.0], 5.86], ['tmax 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['tmax 35 tmin 20 Ra 25.0', [35, 20, 25.0], 4.12], ['tmax 35 tmin 20 Ra 40.0', [35, 20, 40.0], 6.59], ['tmax 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax 10 tmin -2 Ra 25.0', [10, -2, 25.0], 1.77], ['tmax -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.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
tmax 30 tmin 15 Ra 10.01.461.46Passed
tmax 30 tmin 15 Ra 25.03.663.66Passed
tmax 30 tmin 15 Ra 40.05.865.86Passed
tmax 35 tmin 20 Ra 10.01.651.65Passed
tmax 35 tmin 20 Ra 25.04.124.12Passed
tmax 35 tmin 20 Ra 40.06.596.59Passed
tmax -12 tmin -30 Ra 10.00.00.0Passed
tmax -12 tmin -30 Ra 25.00.00.0Passed

SHA-256 / d0c04cc6a97dcf7b97e35f96e09d48159ed907f7f7633d1d197da868d3f0f431

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:27.416634+00:00.

Case digest / 41de98641ac445bd3a304f22f583a16455df56fe7de7ed4a21185a7fb18daae0