A rainfall-driven water table
Generated by build_wt_coupled.py. Step 2 of next_steps.md, built on the same store the runoff model uses, with the signed-exchange departure agreed before building.
Generated by build_wt_coupled.py. Step 2 of next_steps.md, built on the same store the runoff model uses, with the signed-exchange departure agreed before building.
The structure
SOIL sm += rain - pet*(sm/smax); recharge = overflow
AQUIFER h += recharge/Sy - k*(h - h_base)
k*(h - h_base) is SIGNED. Positive means the aquifer is feeding surface water; negative means surface water is recharging the aquifer. The direction falls out of the state instead of being assumed, so the sum over any period is a net flux with a sign - which is what makes step 3’s closed balance possible rather than retro-fitted. A one-way leaky tank would have counted the same water twice: once as baseflow in the river, again as storage in the aquifer.
h_baseis calibrated and CONSTANT, because step 1 (rainfall to river level) does not exist yet. That makes the exchange a signed linear reservoir - the standard baseflow formulation, and a correct special case of what we want, not a different model. When step 1 lands,h_basebecomes a time series and nothing else in the file changes. The structure was built now so that substitution is one line.
Does it work?
Fitted on the first 70% of each record and scored on the last 30%, which the fit never sees. Models are reported by their VALIDATION score.
- stations fitted: 60
- validation NSE > 0.5: 36 (60%)
- median validation NSE: 0.67 (calibration 0.70)

By aquifer
| aquifer | n | median val NSE | half-life d | recharge mm/yr | net exchange m/yr |
|---|---|---|---|---|---|
| Chalk | 26 | 0.67 | 45 | 472 | +9.206 |
| unknown | 23 | 0.68 | 233 | 491 | +2.114 |
| Inferior Oolite | 2 | 0.38 | 31 | 231 | +4.676 |
| Carboniferous Limestone | 2 | 0.80 | 42 | 536 | +56.057 |
| Great Oolite | 2 | -0.03 | 1,706 | 277 | +9.533 |
| Bridport Sand | 1 | 0.85 | 100 | 549 | +5.357 |
| Bridport Sand & Lias Group | 1 | 0.83 | 312 | 492 | +4.858 |
| Chalk & Upper Greensand | 1 | 0.03 | 329 | 106 | +0.443 |
| Great Oolite & Fuller’s Earth | 1 | -564.15 | 74 | 21 | +30.563 |
| Upper Greensand | 1 | -0.18 | 411 | 33 | +0.691 |
half-life is ln2/k - how long the aquifer takes to give up half its head above base level. Read it against the registry’s T1/T2/T3 tiers: a short half-life is a conduit however much storage it appears to hold. A POSITIVE net exchange means the aquifer is a net feeder of surface water over the record, which is what an unstressed outcrop aquifer should be.
What this still is not
h_baseconstant, per the note above - step 1 replaces it- rainfall is the REGIONAL MEAN of the nine catchment series, not the nearest catchment per borehole. Assigning boreholes to catchments is step 1’s job
- PET is a calibrated seasonal sinusoid, not a Penman calculation - there is no radiation or temperature series in this project. It carries the seasonality, which is what recharge needs, and its amplitude is fitted
- no injection. Nothing in the record contains one, so nothing here is validated for it. Step 3.