FA-71181 / Weather index computation / Open access
Hargreaves reference evapotranspiration: temperature offset · case 01
Moderate days show near-zero evapotranspiration.
ROOT CAUSE
The Hargreaves temperature offset is subtracted.
VERIFIED REPAIR
Use Tmean + 17.8.
Unsuccessful approach: Using the Kelvin offset inflates ET0 by an order of magnitude.
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(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 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 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['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 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 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['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 -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['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 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19]]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tmax 30 tmin 15 Ra 10.0 | 0.17 | 1.46 | Failed |
| tmax 30 tmin 15 Ra 25.0 | 0.43 | 3.66 | Failed |
| tmax 30 tmin 15 Ra 40.0 | 0.68 | 5.86 | Failed |
| tmax 35 tmin 20 Ra 10.0 | 0.35 | 1.65 | Failed |
| tmax 35 tmin 20 Ra 25.0 | 0.88 | 4.12 | Failed |
| tmax 35 tmin 20 Ra 40.0 | 1.41 | 6.59 | Failed |
| tmax 10 tmin -2 Ra 10.0 | 0.0 | 0.71 | Failed |
| tmax 10 tmin -2 Ra 25.0 | 0.0 | 1.77 | Failed |
SHA-256 / 5bd6e1edd839ee61ff4858eb60c1e634f9c65f1c3cf6fcd3bc5abd8261c9f9d1
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 + 273.15) * 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 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 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['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 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 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['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 -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['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 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19]]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tmax 30 tmin 15 Ra 10.0 | 10.75 | 1.46 | Failed |
| tmax 30 tmin 15 Ra 25.0 | 26.86 | 3.66 | Failed |
| tmax 30 tmin 15 Ra 40.0 | 42.98 | 5.86 | Failed |
| tmax 35 tmin 20 Ra 10.0 | 10.93 | 1.65 | Failed |
| tmax 35 tmin 20 Ra 25.0 | 27.32 | 4.12 | Failed |
| tmax 35 tmin 20 Ra 40.0 | 43.71 | 6.59 | Failed |
| tmax 10 tmin -2 Ra 10.0 | 9.01 | 0.71 | Failed |
| tmax 10 tmin -2 Ra 25.0 | 22.52 | 1.77 | Failed |
SHA-256 / 0e01a86a3dac5c6ee8eeab6bcb1484a5e287102c03a5d2970d509f171c55b33b
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 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 35 tmin 20 Ra 10.0', [35, 20, 10.0], 1.65], ['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 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 10 tmin -2 Ra 10.0', [10, -2, 10.0], 0.71], ['tmax -10 tmin -25 Ra 40.0', [-10, -25, 40.0], 0.04], ['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 -10 tmin -25 Ra 10.0', [-10, -25, 10.0], 0.01], ['tmax 40 tmin 18 Ra 25.0', [40, 18, 25.0], 5.15], ['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 40 tmin 18 Ra 10.0', [40, 18, 10.0], 2.06], ['tmax -5 tmin -20 Ra 10.0', [-5, -20, 10.0], 0.19]]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tmax 30 tmin 15 Ra 10.0 | 1.46 | 1.46 | Passed |
| tmax 30 tmin 15 Ra 25.0 | 3.66 | 3.66 | Passed |
| tmax 30 tmin 15 Ra 40.0 | 5.86 | 5.86 | Passed |
| tmax 35 tmin 20 Ra 10.0 | 1.65 | 1.65 | Passed |
| tmax 35 tmin 20 Ra 25.0 | 4.12 | 4.12 | Passed |
| tmax 35 tmin 20 Ra 40.0 | 6.59 | 6.59 | Passed |
| tmax 10 tmin -2 Ra 10.0 | 0.71 | 0.71 | Passed |
| tmax 10 tmin -2 Ra 25.0 | 1.77 | 1.77 | Passed |
SHA-256 / 8bb03c594506271fbc0232f4765f52dd0231c677ee5b51ad88cd65ed2ac18526
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.378829+00:00.
Case digest / 426760c8f26d7872d2cf853ee45b2078dc2fc7dc96b75fcb2d816687604a1d7f