← Back to live monitoring

Methodology

How this storm nowcasting system observes, tracks, projects and alerts — and how honestly it reports its own limits. One code base serves every monitored city (Freetown since May, Bo since 28 August). Program version v15.21, last updated 29 August 2026.

1. What the system does

Every 10 minutes, the system downloads the latest Meteosat-12 FCI infrared image (10.5 µm channel, 2 km pixel) over a 160 km study disk centred on the monitored city, detects convective storm cells from their cloud-top temperatures, tracks their motion, projects the cloud field one hour into the future, and decides whether a heavy rain core is about to cover the city. The public page shows the live picture and an animated loop of the last hour plus the coming hour; Telegram and Teams carry the push alerts. Each monitored city runs its own independent instance of the same code — its own disk, geometry, forecasts and page — selectable from the switcher at the top of the live page.

2. Data source: one primary, one true backup, honestly

Since v15.20 (29 August 2026) the primary imagery is Meteosat-12 FCI (MTG, IR 10.5 µm, 2 km pixel, 10-minute repeat cycle), decoded directly from the EUMETSAT Data Store native chunks and regridded locally; a constant registration shift, measured against the SEVIRI-validated frame over both cloud and clear-ground features and re-measured daily, aligns it with the geometry every alert has been verified on. The former primary, Meteosat SEVIRI (3 km, 15 min, Data Tailor crop), remains as an automatic same-cycle backup: if the FCI feed fails or stalls, the cycle silently falls back to SEVIRI and the page labels the source of every frame - the two chains share one contract, so nothing else changes. A SEVIRI shadow page also keeps running in parallel for verification. The three core alert thresholds carry an interim +5 K compensation (the finer FCI pixel reads colder core minima than the 3 km SEVIRI pixel it was priced on); this compensation is explicitly provisional and is being re-priced by replaying the chain against satellite rain estimates and the ground observation journal. Since v15 there is no degraded picture-quality fallback: the earlier WMS path was retired because its 217 K calibration floor made the rain-core alert structurally blind, and its different latency produced mixed timelines in the loop. When the Data Store is unavailable, the system does not pretend: the page keeps serving the most recent real frames, displays their true age, and recovers by itself.

The last hour of frames lives in a rolling ring. If an outage punches holes in that ring, an active backfill (v15) re-requests each missing slot from the Data Store by its exact timestamp, so the loop window is complete again within minutes of the outage ending instead of refilling passively over an hour. Backfill work is bounded by a per-cycle time budget (v15.3) so a slow archive can never stall the native cadence (10 min on the FCI instances, 15 on the SEVIRI shadow).

3. Motion and one-hour projection

Since v15.21 cloud motion is estimated with a dense DIS (inverse-search) optical-flow field — promoted after a ~870-start hindcast over the local archive showed it beating the previous Farnebäck engine on every metric at every lead time; Farnebäck keeps running as the shadow counterfactual, so the standing sign test now guards the new engine (on the FCI-fed instances; the SEVIRI shadow instance deliberately keeps Farnebäck, as it keeps the original thresholds - the legacy counterfactual must not move). Before v15.21 the roles were reversed. The flow is computed between consecutive frames and is dense, so displacement varies across the scene rather than assuming one uniform wind. The projection advects the observed field forward semi-Lagrangially out to +60 minutes, letting intensity evolve with the recent trend. The alert mathematics advect the cold-core mask itself, which preserves the core's area instead of diluting it through interpolation. Since v15.4 the flow is also rescaled by the true time separating the frame pair, so a missed slot can no longer make the projection run too fast.

Honesty rule (v15): if the newest available frame is older than 90 minutes, no projection is computed — forecasting one hour ahead from hours-old data would be misleading — and the page's age indicator turns red.

4. Detection and intensity tiers

Convective cells are segmented where cloud tops are at or below 235 K; cells smaller than 500 km² are ignored. Each cell is classified by its coldest pixel:

TierCore temperatureMeaning
Watch≤ 235 Kconvection worth tracking
Moderate≤ 220 Korganised convection
Severe≤ 217 K (saturated core)deep, violent convection
Extreme≤ 217 K and saturated area ≥ 2000 km² exceptional mesoscale system

Any cell whose deep core reaches the 217 K saturation band is already Severe or Extreme, so no intermediate tier exists between it and Moderate; the map legend follows the same ladder.

5. Per-pixel parallax correction (v15.2)

A cloud top seen obliquely from geostationary orbit appears displaced away from the sub-satellite point; the displacement grows with cloud height. Instead of assuming one fixed height for every pixel, each pixel's height is derived from its own brightness temperature through a tropical lapse model (300 K surface, 6.5 K/km, capped at the 17 km tropopause), and each pixel is shifted individually toward the sub-satellite point. At Freetown's viewing angle (18.4°) a 200 K top moves about 5 km. During projection, the shift maps travel with the advected core, so a moving storm keeps the correction of its own tops. The geometry is derived entirely from the configured target coordinates, so the system redeploys to another city by configuration alone — proven in production on 28 August 2026, when a second instance went live for Bo (7.96°N, 11.74°W) with its own study disk, parallax geometry, model forecasts downscaled to its own altitude, and its own name on every label and message.

Since v15.19 the correction is also applied to the displayed imagery: the maps and loops warp every pixel onto its ground footprint, and the cell markers move with their cloud, so what a user sees overhead matches what the map shows at their position. The detection and alert chain still consumes the apparent field with its own internal correction, unchanged — the warp is cosmetic by construction, switchable by configuration, and cannot alter an alert decision.

On the FCI-fed instances every tier temperature above carries the interim +5 K compensation of section 2 (the whole ladder shifts together, so tier order is preserved); the SEVIRI shadow keeps the original pricing.

6. The alert model (v14, thresholds v15.13)

Since v15.8 the page and the push share a single criterion: the page shows ALERT exactly when a rain-core event is open, from trigger to all-clear, and the tracked-cell table remains as context. The alert fires only when the parallax-corrected rain core — the part of the cloud at or below 210 K on the SEVIRI pricing (215 K interim on the FCI-fed instances, see section 2; 205 K before v15.13) — is forecast to cover a substantial fraction of the 5 km target disk (0.40 of its area, ≥ 31 km², lowered from one half on 2 July after a replayed near miss), with the crossing time interpolated along the +60 min coverage curve and a decay gate that suppresses cores already collapsing, unless the arrival is imminent: a collapsing storm about to arrive is a raining one (v15.3.1). The alert message states both the expected arrival and the expected clearing time.

Since v15.13 a second, softer tier backs the alarm: when an Extreme cell body is over the city, or approaching with an arrival under 60 minutes, for two consecutive cycles, the page shows an amber PRE-ALERT banner — web display only, no push. It exists because the 19–20 August 2026 storm proved that a mesoscale system can sit over the city while the coverage criterion stays just under its threshold; the same event is what moved the rain-core threshold from 205 to 210 K.

7. Delivery: an alert must land (v15.3)

On trigger, a video alert goes to Telegram and an adaptive card to Teams; every subsequent cycle sends a refreshed video while the event lasts, and an explicit all-clear closes it. Delivery is hardened: API calls retry transient failures with backoff; if the video upload fails the system degrades to a photo, then to plain text, rather than staying silent; and during updates the new message is confirmed delivered before the previous one is deleted, so the group is never left without an active alert mid-event. On 26–27 June 2026 this chain delivered end-to-end: a 55-minute advance warning, arrival predicted to within 4 minutes, and 3.5 hours of continuous coverage updates while the core sat over the city.

8. Reliability architecture

Each cycle is an independent process under cron, serialised by a kernel lock that dies with the process, and capped by a hard 12-minute alarm so nothing can wedge the cadence. State and ring frames are written atomically (temp file + rename), so a crash mid-write can never corrupt what the next cycle reads. Temporary satellite files are swept every cycle. An independent watchdog checks two things separately: that the monitor is running (heartbeat written at every attempt) and that the data is fresh (the sensing timestamp inside status.json, not the file's clock — v15.3) — and notifies Telegram and Teams once per incident, with a recovery notice when service resumes. Rendered maps and logs are age-purged and rotated automatically.

9. Verification and calibration

The system keeps its own evidence. Every tracked cell is logged to a calibration file (core temperature, area, distance, geometry), building a per-event history of what the satellite saw; seventeen days of season data already show near-daily deep convection (cores ≤205 K on 19 independent episodes). Ground truth is now attached to those episodes from two independent sources: rain observed and recorded at the target, and NASA GPM IMERG satellite precipitation labels fetched automatically each morning for every alert episode (first retroactive pass: 24 of the 25 alerts issued since June confirmed as rain). Since v15.15 every cycle also records its own forecast and final decision, so hit rates and lead times per horizon accumulate as the season runs, and thresholds are tuned against what actually fell on Freetown rather than assumptions. A replay bench can rescore any archived day against what the satellite saw next; it is what lowered the coverage threshold, and it is what promoted that candidate (DIS) to primary in v15.21 - the same verdict machinery now runs in reverse, with Farnebäck as the shadow guarding the new engine on every alert cycle.

Known limits, stated plainly. The satellite measures cloud-top temperature, not rainfall; cold tops usually mean heavy rain, but the mapping is being calibrated, not assumed. The push criterion protects a 5 km disk on the city centre: a violent core drenching the wider district while missing that disk will light the page red but may stay push-silent by design — whether that scope should widen is a calibration question under active study. And during a genuine Data Store outage the system ages honestly rather than inventing data: the loop and the picture keep their last real frames, labelled with their true age.

10. Version history

VersionHighlights
v13.xPermanent public loop from a rolling frame ring; field-wide projection; stale-data banners.
v14Unified coverage alert model: rain-core arrival and clearing times, decay gate; per-cycle alert updates and all-clear.
v15Data Store only (WMS retired); active ring backfill by timestamp; staleness handling for clip and projection.
v15.1Calibration logging anchored and recovered (17 days of cell history).
v15.2Per-pixel parallax correction, advected with the core; portable geometry.
v15.3Critical-path reliability: delivery retries and degradation cascade, send-before-delete updates, atomic ring writes, backfill time budget, temp-file sweep, data-age watchdog.
v15.3.1–.2Trend-gate imminence bypass; coverage threshold 0.50 → 0.40 from a 12-day archive replay.
v15.4–.6Flow normalised by true pair spacing; permanent verification bench with engine A/B and arrival scoring; candidate DIS estimator in live shadow.
v15.7–.8Ambient conditions indicator; unified alert (page red exactly when a rain-core event is open).
v15.9Review bundle: unconditional archive retention, ingestion ordered by sensing time, corrupt-state quarantine, Teams delivery parity, wording made rot-proof.
v15.10–.12Local ground-truth station (SHT45 on a forced-command SSH ingest), pressure, 24 h measured-vs-forecast chart.
v15.13Rain-core threshold 205 → 210 K after the 19–20 Aug storm; amber cell-layer PRE-ALERT tier (web only).
v15.14Deep-review fixes: page state published on the deciding cycle; offline banner repaired; alert-chain flow available from the first study frame; hardened delivery fallbacks; legend derived from configuration; basemap disk cache; filled-pixel honesty gauge.
v15.15Continuous verification: per-cycle prediction log, event ledger against recorded rain, automated daily IMERG rain labels per alert episode.
v15.16–.2Multi-city: second instance deployed for Bo (one code base, one config per city), city switcher on the pages, per-instance temp files, every label and message driven by the configured city name, ambient conditions downscaled to each city's altitude like the forecast chart.
v15.17–.18Dead-code removal after the review; pluggable satellite ingestion behind one configuration switch, carrying a shadow instance fed by Meteosat-12 (MTG FCI, 2 km, 10 min) validated side by side against the operational SEVIRI chain.
v15.19Parallax correction extended to the displayed imagery and cell markers (ground-footprint view); alert chain untouched.
v15.20Meteosat-12 FCI (2 km, 10 min) becomes the primary source for Freetown and Bo after side-by-side validation; automatic same-cycle SEVIRI fallback; constant registration onto the verified geometry; interim +5 K core thresholds pending replay re-pricing; observed loop deepened to N-60..N in 10-minute steps.
v15.21DIS becomes the primary optical-flow engine after a ~870-start archive hindcast (Farnebäck stays as shadow and fallback); campaign tooling and Fractions Skill Score added to the permanent verification kit.