Loading networks
GridSim loads a network through one of four doors, and the solver neither knows
nor cares which: built-in named cases (embedded in GridSim.Core),
MATPOWER .m files (data/matpower/ or any path), JSON case
directories (data/uk, data/gb-synthetic, and anything you write), and
GDA-materialised cases (the real GB network, assembled outside the repo).
This chapter shows how to select each on the CLI and in the desktop app, and
ends with the case-library reference table.
Built-in cases
Nine standard systems are compiled into GridSim.Core as IeeeCases
factories, so they load with no files on disk. Select them by name:
dotnet run --project src/GridSim.Cli case9 # single solve, prints the report
dotnet run --project src/GridSim.Cli case118 # runs live (add --once for one report)
| CLI name | Case | Buses | Gens | Branches | Notes |
|---|---|---|---|---|---|
case9 (or ieee9) |
WSCC 9-bus | 9 | 3 | 9 | hand-coded, carries the published inertia constants; the physics ground truth |
case14 |
IEEE 14-bus | 14 | 5 | 20 | |
case30 |
IEEE 30-bus | 30 | 6 | 41 | |
case57 |
IEEE 57-bus | 57 | 7 | 80 | |
case118 |
IEEE 118-bus | 118 | 54 | 186 | |
case300 |
IEEE 300-bus | 300 | 69 | 411 | |
case145 |
IEEE 145-bus (dynamic) | 145 | 50 | 453 | |
case24 (or rts) |
IEEE RTS-79 24-bus (case24_ieee_rts) |
24 | 33 | 38 | |
cigre |
CIGRE MV benchmark (cigre_mv) |
15 | 1 | 14 | radial MV feeder; small enough that Newton still converges |
An unrecognised name fails loud with usage and exit code 2 - it is never
silently treated as the default model. With no case argument at all, the CLI
loads the UK reduced 10-zone model from data/uk.
Only the hand-coded case9 carries generator inertia (H); MATPOWER files
have no H column, so every parsed case has H = 0 and the frequency verbs
have nothing to work with there.
MATPOWER .m files
Pass any .m file path (or use --mpc <file>.m):
dotnet run --project src/GridSim.Cli data/matpower/pegase/case9241pegase.m
dotnet run --project src/GridSim.Cli --mpc path/to/mycase.m --once
The parser handles Inf limits, transformer-by-tap-ratio, non-contiguous bus
ids, and drops isolated (type-4) and out-of-service elements. Files loaded by
path are additionally run through a unit normaliser that auto-fixes raw ohm/kW
distribution files into per-unit-on-base form.
The committed archive lives under data/matpower/; tools/fetch-cases.sh
expands it into the full PGLib-OPF + MATPOWER universe (~161 cases, up to
~78,000 buses) into data/matpower/pglib/ and data/matpower/matpower-all/.
Anything under data/matpower/ is auto-discovered recursively by the desktop
app's source picker, and analysis verbs (transient, bench, ...) accept a path
relative to data/matpower/ (for example pegase/case1354pegase.m).
JSON case directories
A JSON case is a folder of human-editable files - the format both GB models
ship in and the format GDA materialises to. Load one with --dir:
dotnet run --project src/GridSim.Cli --dir data/gb-synthetic --once
dotnet run --project src/GridSim.Cli --dir ./gda-out/zone-nged
A case directory contains:
| File | Required | Contents |
|---|---|---|
system.json |
recommended (identifies the folder as a case) | name, base MVA, nominal frequency |
buses.json |
yes | id, name, nominal kV, type, shunts, 0-1 map coordinates x/y |
generation.json |
yes (at least one "slack" role, unless a bus is typed slack) |
per-generator capacity, output, voltage setpoint, Q limits, inertia H, type, role (slack/pv/pq) |
demand.json |
optional | per-point MW (+ MVAr or power factor), aggregated onto buses |
transmission.json |
optional | lines: per-unit R/X/B, rating, parallel-circuit count |
transformer.json |
optional | transformers: per-unit R/X, tap ratio, phase shift, rating |
onloadtapchanger.json |
optional | OLTCs: controlled bus, target p.u., tap range/step/deadband |
boundaries.json |
optional | named transmission-boundary cuts with MW limits (drives the boundary panels) |
Generation is dispatched from capacities on load (merit order, marginal slack), so the model arrives balanced and ready to solve. Multiple slack generators are allowed - a multi-island model needs one reference per island.
Two JSON cases ship in the repo: data/uk (the reduced 10-zone GB model, the
CLI and GUI default) and data/gb-synthetic (a procedurally generated,
entirely synthetic GB-shaped network down the voltage ladder). Regenerate or
rescale the synthetic case with gridsim synth --scale 1.5.
GDA-materialised cases: gb-full, gb-spine, zone-*
The real GB network is assembled from the GDA data lake outside the
repository - the repo carries only the schema mapping, never the data. The
materialised output is the same multi-file JSON case format, written to a
git-ignored directory (conventionally gda-out/ at the repo root):
gb-full- the full GB transmission model (3,539 buses).gb-spine- the GSP-level spine (316 buses, real ETYS Appendix B circuit impedances and ratings where the register resolves). Addsfold_map.json, recording which full-model buses folded into each spine bus.zone-nged,zone-ukpn,zone-ssen,zone-spen,zone-npg,zone-enwl- per-DNO zone cuts of the full model.
These carry the standard files above plus, where emitted, fold_map.json and
diagnostics.json (assembly provenance - read them, do not edit them). DNO
distribution footprints can also be materialised directly from the lake on an
authorised machine:
gridsim gda --root /gda --out ./gda-out # whole DNO footprint -> git-ignored JSON
gridsim --dir ./gda-out/<case> # then run it like any other case
Once materialised, a GDA case is just a case directory: --dir on the CLI, and
verbs that take a case argument (estimate, crossval, bench --estimate)
accept the directory path directly - any folder containing system.json is
recognised as a case.
Selecting a case in the desktop app
The NETWORK picker in the header lists everything discovered at startup:
| Picker label | Source | Discovered from |
|---|---|---|
GB reduced 10-zone |
data/uk |
bundled next to the app |
GB synthetic distribution depth |
data/gb-synthetic |
bundled next to the app |
GDA <case> |
each materialised case directory | any gda-out/ folder found walking up from the app directory |
MATPOWER <stem> |
each .m file |
data/matpower/** recursively |
Replay <run> |
pre-solved run directories | any nearby results/ folder (see 04-the-desktop-app.md) |
Live bridge |
the GDA bridge stream | shown when a bridge endpoint is configured |
Imported MATPOWER cases carry no coordinates, so the app synthesises a layout (force-directed, with a graph-derived voltage hierarchy); the electrical model and the solve are untouched.
Case library at a glance
Condensed from the committed archive, verified against data/matpower/.
Class: A converges from flat start; B OPF operating point - expected
non-convergence as a plain power flow; C radial feeder - needs the
backward/forward sweep; D fails to load (unevaluated arithmetic literal -
a known parser limitation).
| Folder | Cases | Buses | Class |
|---|---|---|---|
lib/ |
case9, case14, case30, case57, case118, case145, case300, case24_ieee_rts |
9-300 | A |
pegase/ |
case1354pegase, case2869pegase, case9241pegase |
1,354-9,241 | A1 |
rts/ |
pglib_opf_case73_ieee_rts (RTS-96) |
73 | B |
nesta/ |
pglib_opf_case{3_lmbd, 5_pjm, 30_as, 162_ieee_dtc, 240_pserc, 588_sdet} |
3-588 | B |
benchmarks/ |
cigre_mv |
15 | A |
dist/ |
case18, case22, case33bw, case69, case85 |
18-85 | C |
dist/ |
case533mt_hi |
533 | D |
1 case9241pegase solves on the sparse path; the dense path runs out of memory
at that scale - use the automatic engine selection and it never arises.
A class-B or class-C outcome is a property of the input, not a solver bug: a
pglib_opf_ file ships an optimisation snapshot, not a solved power-flow
point (its non-OPF twin solves in a handful of iterations), and a radial feeder
is routed to the sweep automatically when it is strictly radial after parsing.
See 17-troubleshooting.md for the canonical
non-convergence list.
To add your own case: drop a valid MATPOWER .m anywhere under
data/matpower/ (discovery is recursive; a stem that duplicates an embedded
classic is ignored - the embedded bytes win), or write a JSON case directory
and load it with --dir.
See also
- 01-getting-started.md - build, test, first solve
- 03-running-power-flows.md - what happens after the case loads
- 04-the-desktop-app.md - the source picker, replay runs, and the bridge
- 13-the-gda-bridge.md - streaming GDA cases instead of materialising them