Methodology · how the predictor works

What this model is — and isn't

A public-service site shouldn't ship a forecasting widget without showing its working. This page explains where every number on the predictor comes from, what assumptions the model makes, and what it can't tell you.

The "Day Zero" threshold: why 13.5%?

The City of Cape Town's 2019 Water Strategy and the January 2018 update to its Water Outlook set the operational trigger at 13.5% of combined storage. That sits 3.5 percentage points above the ~10% physical "dead-storage" floor — the level at which water becomes effectively unusable because of silt and the position of the dam outlets. The buffer is the safety margin needed for Day Zero protocols to activate before water is physically unrecoverable.

You'll see other numbers cited elsewhere — 20% appears in popular reporting and in the homepage's ghost-line chart as the public-warning line; 10% is the physical floor; 30%–50% are the City's "Drought Response" and "Accelerated Drought Response" bands, visible as the colored backdrop on the predictor's chart. The City's Weekly Water Dashboard currently uses a five-band drought-response framework rather than a single Day Zero threshold; we use 13.5% specifically because it's the operationally-defined activation point.

Where the seasonal pattern comes from

The model walks forward month-by-month from today's storage. For each calendar month it needs an answer to: "How much does combined storage typically change in this month, and how variable is that?" Both come from 148 weekly storage readings spanning 2017–2026, stitched together from City of Cape Town Weekly Water Dashboard PDF snapshots archived on the Wayback Machine.

Each archived dashboard contains a comparison table with the current week's reading plus same-week readings for the previous four years — so a single 2024 snapshot, for example, supplies six historical data points (this week, previous week, and the four historical-year columns). That's how 29 PDF snapshots produce 148 weekly readings rather than only 29.

For each calendar month, we aggregate readings into a single mean storage % per (year, month), then compute the year-over-year change. The mean of those changes is the typical monthly delta; the standard deviation captures rainfall variability. The numbers actually used by the model:

Month Typical Δ % Stddev (rainfall variability) Year-pairs (n)
Jan -9.71 ±4.72 6
Feb -7.47 ±5.49 4
Mar -1.46 ±1.19 3
Apr -2.65 ±3.07 6
May +8.10 ±7.41 5
Jun +13.18 ±6.83 5
Jul +9.04 ±4.89 5
Aug +1.71 ±2.32 5
Sep -2.71 ±1.22 3
Oct -2.02 ±1.32 3
Nov -4.41 ±1.69 5
Dec -5.06 ±5.30 6

The shape is the Cape Town water year: heavy negative deltas Dec–Apr (summer drawdown), strong positive deltas May–Aug (winter rains fill the dams), small deltas Sep–Nov.

The slider math, in plain language

The historical monthly delta mixes two things — winter rainfall flowing in and year-round consumption flowing out. The model decomposes them so each slider only moves the part it should:

inflow(m)  = max(0, meanDelta(m) + outflowBaseline)   ← rainfall-driven
outflow    = outflowBaseline + consumptionPerturbation ← slider-driven

storage(m+1) = storage(m)
             + (inflow(m) + noise) × rainfallFactor    ← rainfall slider
             − outflow                                  ← consumption slider

Why decompose? If the rainfall slider scaled the full monthly delta, dragging it to 50% in January (a peak summer month with mean delta of −9.7%) would paradoxically halve the drawdown — because most of January's negative is outflow, not negative inflow. Decomposing means dialling rainfall down only reduces winter inflow; summer drawdown stays the same.

Outflow baseline = 8.59% of FSC per month. This is the total system outflow — City consumption (≈3%) + agricultural and other-municipality allocation (≈1–2%) + summer evaporation (≈1–2%). Calibrated empirically as the average of the two most-negative monthly means (Jan, Feb) — those are the dry-season months where inflow ≈ 0, so the negative delta IS the outflow.

Rainfall factor = slider value ÷ 100. At 100% the model uses the historical mean exactly. At 50%, both the typical winter inflow and the rainfall variability around it are halved — drier years are also less variable.

Consumption perturbation = (your slider − 900 ML/day) × 30.4 days/month ÷ 898,221 Ml capacity × 100. The 900 ML/day baseline is the City's 2022–2024 average; the perturbation captures only how far you move from that.

We run this 1,000 times with fresh random noise each iteration (Box-Muller normal sampling on a seeded mulberry32 PRNG, so results are deterministic given the same slider state). The displayed median is the 500th-ranked value at each month; the band shows the 250th and 750th. Day Zero arrival is the first month any iteration drops below 13.5%.

What the model doesn't know

Sources

Open data

The complete inputs to this model — current storage, seasonal pattern coefficients, threshold values — are available as JSON at /api/scenario.json. Documentation: /predictor/api. Anyone can rebuild this predictor independently from the same inputs.