Skip to content

Zambia: what a country with no ground truth at all looks like

Zambia was run end to end between 13 and 15 September 2026, from an empty start: no locally cached imagery, no building data, no calibration quadrats, no national register, and no third-party PV dataset to check against. It is the cleanest test so far of what this pipeline produces when nothing but the global open sources exist.

Interactive: Zambia PV evidence atlas.

Headline

Verified 505.8 MWp (90% 376 to 698)
Best estimate 526.3 MWp (90% 451 to 699)
Grid 1,843 cells of 0.1°, all 10 provinces
Imagery Sentinel-2 L2A, May to October 2025
Model v4_combined_all epoch 41, zero-shot

A precision floor, not an estimate

Zambia has no calibration quadrats, so there is no roofclf half and no two-detector cross-check. It also has no glint sample, so p_unmapped is 0 and p_real collapses to the OpenStreetMap-mapped fraction; and recall was deliberately skipped (--recall-reference none) rather than measured against a reference made mostly of solar-farm perimeters. Every number here is a lower bound of the kind France publishes, not a recall-corrected estimate.

Best exceeds Verified by only 20.5 MWp. The atlas is overwhelmingly the hand-mapped OpenStreetMap population converted at the project's constants, with a thin layer of model detections on top. That is the honest shape of a first pass with no local evidence.

The finding: a third of the mapped capacity was never built

Zambia's OpenStreetMap solar population is 221 features, but 20.2 of its 20.6 km² of ground area sat in sixteen power=plant perimeters of 0.3 to 2.8 km², eleven of them added in a single mapping pass on 4 August 2026. Taken at face value that population implies about 1,089 MWp, against a real Zambian fleet of roughly 100 to 150 MW.

That matters twice over: those polygons feed the Verified tier directly, and chips burns every OpenStreetMap polygon at or above 400 m² as a positive training mask. An announced-but-unbuilt project site would be both booked as capacity and taught to the model as the appearance of PV.

scripts/screen_osm_ground_perimeters.py measures, for each perimeter over every composited cell it touches, what fraction is imaged at all and what fraction the model lights up. Each flagged one was then checked against the RGB imagery by eye.

perimeters area at 0.05 kWp/m²
Array visible, model covers 34 to 99% 6 6.4 km² counted
Fully imaged, model finds nothing, imagery shows bare ground, bush or fields 8 11.7 km² 583 MWp, removed
Not judgeable 1 2.1 km² ~104 MWp, kept and flagged

Removing them moved Verified from 755.1 to 505.8 MWp.

The screen only ranks what to look at. det_frac is the model's opinion about its own training labels and settles nothing by itself. Two things make the zeros credible: the same checkpoint covers Bangweulu at 98.8% and Itimpi at 99.7% of their imaged area in the same country and the same imagery epoch, so it is demonstrably not blind to Zambian ground-mount; and p_max is exactly 0.00 over a full square kilometre, which is a different statement from a low mean. The verdicts came from the imagery. The audit trail, screen table and RGB crops are in results/zambia_osm_ground_screen/, and the exclusions are a hand-written, commented list at configs/zambia_osm_ground_exclusions.txt.

This is not a claim that the projects do not exist, only that no array had been built as of the imagery epoch. A site that fills in will come back on a re-screen.

The one perimeter that could not be judged failed for an unexpected reason: its cell (0069_0068) carries a genuine nodata hole exactly under the polygon, 25,993 pixels that are zero in all ten bands, and the cell is only 22.8% filled. That is rare rather than systemic (of 120 cells sampled nationally, median fill is 100% and only two are below 50%). Re-composing that single cell on a wider window would settle it.

In-domain retraining was measured, and rejected

Zambia's OpenStreetMap holds 221 solar features. After dissolve_overlapping merges nested power=plant and power=generator elements, and after the screen, the country has 34 distinct installations at or above the 400 m² floor. sample_chip_centers dedupes positives sharing a ~2 km cell, and Zambian PV is concentrated in a handful of sites, so those collapse to 25 spatially distinct training positives (18 train, 7 validation) with zero background chips.

A localisation retrain was built and then not shipped. On the held-out Copperbelt cluster, roughly 700 km from the Lusaka training cluster, zero-shot v4 already detects 3 of 3 installations at 95.6% median area coverage. There is no headroom on a three-installation holdout for a retrain to demonstrate anything, and the project's own v6 France experiment is the standing evidence that a half-measure retrain can land worse than zero-shot. The config is kept at configs/terramind_pv_v7_zambia.yaml as the record.

What Zambia actually needs is hard negatives (bright bare soil, burn scars, dry-season miombo) and one exhaustively mapped calibration quadrat — not more OpenStreetMap solar polygons. See the quadrat protocol.

Plausibility gate

earthpv check-density reports 1 fail and 8 suspect of 10 provinces, and both are interpretable rather than artefacts:

  • Lusaka fails single-cell concentration, 90% of the province in cell 0064_0025. That cell is the Lusaka South Multi-Facility Economic Zone, which is genuinely where Zambia's utility and large rooftop PV is.
  • Eight provinces are flagged suspect on the ground-to-rooftop ratio, every one of them with a total between 0.7 and 7 MWp, far below the check's own 50 MWp noise floor.

Published per this project's standing precedent for a checked-genuine plausibility failure, with the failure stated rather than suppressed.

Two constants worth revisiting

Bangweulu and Ngonye together are about 88 MW over roughly 1.04 km² of mapped perimeter, which is 0.085 kWp/m² against the assumed 0.050 for ground-mount site area. Germany's own measurement against MaStR put the same constant at 0.081 (1.62x). So DEFAULT_KWP_PER_M2_LAND, currently calibrated on two Pakistani plants, looks biased low in two independent places, while the unbuilt perimeters pushed the total the other way. The country data registry now lists GMSEUS, which carries an explicit ground cover ratio for 18,502 arrays and could settle it.

Reproducing

pixi run python scripts/new_region.py check --bbox 21.999,-18.08,33.706,-8.224 --iso3 ZMB
pixi run python scripts/overpass_labels_chunked.py \
    --bbox 21.999,-18.08,33.706,-8.224 --iso3 ZMB --name zambia --tiles 4x4
systemd-run --user --collect --unit=earthpv-compose-zambia -p WorkingDirectory="$PWD" \
  -p Environment=EARTHPV_STAC_PROVIDER=earth-search \
  bash scripts/compose_loop.sh zambia 0 1000 4 3600 600
bash scripts/run_zambia_pipeline.sh data/models/v4_combined_all/terramind-pv-epoch=41-step=16590.ckpt

A country-scale Overpass pull needs the chunked script: a single national query times out on every public mirror, and the national boundary clip matters — a bbox around Zambia returns 2,283 features, of which 2,062 are Zimbabwean and Congolese.