GridShedWatch
A benchmark for early warning of grid load sheds, scored the way forecasters score weather warnings.
Website: https://gotham29.github.io/gridshedwatch (built from this repo by scripts/build_site.py).
Since 2020, US grid operators have had to cut power for lack of supply eight times. The public was warned beforehand in four of them, and in none of the four during Winter Storm Elliott. Plenty of methods claim to detect grid trouble early, but there has been no shared test of whether a warning would actually have come in time. GridShedWatch is that test: every one of those eight load sheds, public hourly data, and one fixed scoring procedure that any method can be run through.
The National Weather Service scores every warning it issues on three numbers read together: how many events were warned in advance, how much lead time people got, and how often warnings were false alarms. GridShedWatch asks the same of grid warnings, at two levels: a watch (about one a month per grid: something unusual is building) and a warning (two a year: act).
What's in it
| Events | 8 supply-shortfall load sheds of at least 250 MW, Jan 2020 to Sep 2026, chosen by a stated rule from NERC's annual lists (docs/events.md) |
| Data | A frozen snapshot of EIA-930 hourly demand, day-ahead forecast and net generation for the 8 grids, 2019-2026, and the five signals built from it (gridshedwatch/snapshot_v1.0/, gridshedwatch/data.py) |
| Rules | One shared rule that turns per-signal scores into watches and warnings, so methods differ only in how they score each hour (gridshedwatch/rules.py) |
| Scoring | Same alert budget for every method, chosen without looking at the events; events caught, lead time and false alarm ratio, with bootstrap intervals and a chance baseline (docs/scoring.md) |
| Status quo | Every operator notice in the week before each event, with times and sources (gridshedwatch/operator_notices.yaml) |
| Reference methods | An operator-style rule, a seasonal z-score, an LSTM forecaster, Chronos-Bolt (zero-shot), and HTM (gridshedwatch/baselines/) |
| Datasheet | Motivation, composition, collection, intended uses, known biases and maintenance (docs/datasheet.md) |
| Event | Grid | Shed at its worst | Split |
|---|---|---|---|
| Heat wave, Aug 2020 | California (CAISO) | about 1,000 MW | development |
| Winter Storm Uri, Feb 2021 | Texas (ERCOT) | 20,000 MW | development |
| Uri | Southwest Power Pool | 2,700 MW | held-out |
| Uri | MISO (MISO South) | 700 MW | held-out |
| Winter Storm Elliott, Dec 2022 | Tennessee Valley Authority | 3,000 MW | development |
| Elliott | Duke Energy Carolinas | up to 1,000 MW | held-out |
| Elliott | Duke Energy Progress | about 960 MW | held-out |
| Elliott | LG&E and KU (Kentucky) | about 300 MW | held-out |
Results, v1.0
| Method | Watches: caught (of 8) | held-out (of 5) | by chance | median lead (h) | Warnings: caught (of 8) | held-out (of 5) | by chance | False alarm ratio (watch / warning) |
|---|---|---|---|---|---|---|---|---|
| Operators (public notices) | 4 | 2 | - | 20 | - | - | - | - |
| Operator-style rule | 5 [3.0-7.0] | 4 | 1.2 | 85 | 2 [0.0-4.0] | 1 | 0.2 | 98% / 94% |
| Seasonal z-score | 5 [3.0-7.0] | 4 | 1.1 | 105 | 6 [4.0-8.0] | 4 | 0.2 | 98% / 92% |
| Chronos-Bolt (zero-shot) | 1 [0.0-3.0] | 1 | 0.9 | 9 | 3 [1.0-5.0] | 1 | 0.3 | 100% / 96% |
| LSTM forecaster | 6.4 [4.6-8.0] | 4.4 | 1.3 | 8 | 4.8 [2.8-6.8] | 2.8 | 0.3 | 99% / 94% |
| HTM (htm-monitor) | 6 [4.6-7.2] | 4 | 1.4 | 56 | 5.6 [3.8-7.2] | 3.6 | 0.3 | 98% / 93% |
All five reference methods are in the scores track; no alerts-track entries yet. Mean over 5 seeds for the LSTM and HTM. [a-b]: 5th-95th percentile with events resampled. Operators: public notices in the 7 days before onset, scored as watches.
Every method except Chronos's watches catches far more than chance, and none leads at both
levels. The differences are by kind of emergency: the simple rules caught all three Uri events
days ahead, the LSTM and HTM caught the Elliott events hours ahead (when the public got no
warning), and only the operators warned California. With eight events, differences of about one
event are not meaningful. Per-event results: results/v1.0/<method>_events.csv.
Quick start
pip install gridshedwatch # or, to work on the code:
git clone https://github.com/gotham29/gridshedwatch && cd gridshedwatch
pip install -e ".[test]"
gridshedwatch info # the eight events and their timelines
gridshedwatch score --oprule # score the built-in operator-style rule
python examples/my_method.py # scores track template: writes my_scores/
gridshedwatch score my_scores --name "My method"
python examples/my_alerts.py # alerts track template: writes my_alerts.csv
gridshedwatch score-alerts my_alerts.csv --name "My rule"
Add your method
There are two ways in.
Scores track (the controlled comparison). Your method says, for every grid, every hour and
each of the five signals, how unusual that signal is now, as a score in [0, 1], using data up to
that hour only. Write the scores in the submission layout (my_scores/s<seed>/<grid>.csv, see
gridshedwatch/submission.py) and run gridshedwatch score. The
shared rules, the label-free budget step and the scoring are done for you, so your method
cannot be tuned toward the eight events. Template: examples/my_method.py.
Alerts track (any method). If your method decides on its own when to raise a watch or a warning (a rule, a classifier, a weather-based model, a human forecaster), list when each alert started:
grid,level,start_utc,seed
tx,watch,2021-02-11 03:00,0
and run gridshedwatch score-alerts alerts.csv --name "My method". It is scored exactly like
the scores track, at the same budget (median grid at most 12 watches and 2 warnings a year, no
grid above 3 times that). Format: gridshedwatch/alerts.py; template:
examples/my_alerts.py; worked examples: the five reference methods'
alerts in results/v1.0/alerts/, which reproduce the table above.
- Scores track: use the five signals provided (and 2019 for calibration). Alerts track: any data available at the time of each alert. Methods that use data beyond the five signals are listed separately.
- If your method is random, submit several seeds; results are averaged.
- To add a result to the table, open a pull request with your scores or alerts (or a link to
them), the code that produced them, the output of
--json, and short answers on the data used and, for the alerts track, which events you looked at while developing (docs/scoring.md). Every result is added, including ones that beat the reference methods.
Reproducing v1.0
python -m pytest -q # rebuilds the rule and z-score results from the data
python scripts/fetch_reference.py # reference scores for LSTM, Chronos, HTM (about 100 MB)
python -m pytest -q # now also checks those three against results/v1.0/
python scripts/reproduce_v1.py # writes results/v1.0/ from scratch
docker build -t gridshedwatch . && docker run --rm gridshedwatch
The LSTM and Chronos can be rerun with gridshedwatch baseline lstm|chronos -o DIR (needs
pip install -e ".[lstm]" or ".[chronos]"). Neural-network training is not bit-identical
across platforms and library versions, so a rerun gives close but not identical scores; the
reference scores are the official v1.0 results. HTM's scores come from
htm-monitor, scored here like any other submission.
Limits
- Eight events, seven from two storms (Uri and Elliott). One storm of a new kind could change the picture.
- Three events were used to design the shared rules; five were held out and scored once.
- Reference methods see only five signals from EIA-930: no weather, outage or market data. The alerts track is open to methods that use more.
- The status quo row covers operators' public notices; their notices to the industry and their false alarms in ordinary years are not yet compiled.
GridShedWatch grows as new events happen: each load shed that meets the rule is added in a new version and scored with the rules frozen in v1.0.
Citation and license
DOI: 10.5281/zenodo.23626223 (archived on Zenodo with every release). See CITATION.cff. Code: MIT. Event list, timelines, documentation and results: CC BY 4.0. EIA-930 data: U.S. public domain (DATA_LICENSE.md).
Metadata
Release files for gridshedwatch 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| gridshedwatch-1.1.1.tar.gz | 5.8 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gridshedwatch-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 11.7 MB
Release files / gridshedwatch-1.1.1.tar.gz
| Download URL | gridshedwatch-1.1.1.tar.gz |
|---|---|
| Size | 5.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ef748ed40babc7bd15e652f3936abc30b1642f00162bd9d7bf9740baab2e279
|
|
BLAKE2b-256 checksum How to use checksums |
5794286742505bfe3a41d050a60201676e7091641ac694b29e24230cb1e8ad6f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / gridshedwatch-1.1.1-py3-none-any.whl
| Download URL | gridshedwatch-1.1.1-py3-none-any.whl |
|---|---|
| Size | 5.8 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f7641afa3c57f39faf3af99a079e6caeb2c4cb2849e529bf8057331bab91e6ac
|
|
BLAKE2b-256 checksum How to use checksums |
06376c9beea59b1026f617536eabd09c01b384a9613b5440ab28e138ae4e2339
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for gridshedwatch 1.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for gridshedwatch-1.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.