FA-71191 / Weather index computation / Open access
Hargreaves reference evapotranspiration: mean temperature · case 01
ET0 tracks the diurnal range instead of the air temperature.
ROOT CAUSE
The daily mean is computed from the difference of the extremes.
VERIFIED REPAIR
Tmean = (tmax + tmin)/2.
Unsuccessful approach: Using tmax alone overstates the mean temperature.
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 -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['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.92 | 1.46 | Failed |
| tmax 30 tmin 15 Ra 25.0 | 2.3 | 3.66 | Failed |
| tmax 30 tmin 15 Ra 40.0 | 3.68 | 5.86 | Failed |
| tmax 35 tmin 20 Ra 10.0 | 0.92 | 1.65 | Failed |
| tmax 35 tmin 20 Ra 25.0 | 2.3 | 4.12 | Failed |
| tmax 35 tmin 20 Ra 40.0 | 3.68 | 6.59 | Failed |
| tmax 10 tmin -2 Ra 10.0 | 0.77 | 0.71 | Failed |
| tmax 10 tmin -2 Ra 25.0 | 1.93 | 1.77 | Failed |
SHA-256 / e4bab36c1d64e418edd2bb3f1868c5c4098414d6675685c6fcdb93ca1f55a13e
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
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 -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['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.74 | 1.46 | Failed |
| tmax 30 tmin 15 Ra 25.0 | 4.34 | 3.66 | Failed |
| tmax 30 tmin 15 Ra 40.0 | 6.95 | 5.86 | Failed |
| tmax 35 tmin 20 Ra 10.0 | 1.92 | 1.65 | Failed |
| tmax 35 tmin 20 Ra 25.0 | 4.8 | 4.12 | Failed |
| tmax 35 tmin 20 Ra 40.0 | 7.68 | 6.59 | Failed |
| tmax 10 tmin -2 Ra 10.0 | 0.9 | 0.71 | Failed |
| tmax 10 tmin -2 Ra 25.0 | 2.26 | 1.77 | Failed |
SHA-256 / 6dfe50731259ee049f54e44e35ce9accfaa4085a085097b21e2f88b21c1b660a
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 -12 tmin -30 Ra 10.0', [-12, -30, 10.0], 0.0], ['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 / 70c6d5b84a2df7811c3aed5ddb7ceb35cbcac277454fccb236d0775cc1049b1d
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.457044+00:00.
Case digest / 84461e66e5a3f93d1bb516416ea8d6ca5989cce637cbbc7ab3544534d015d47f