User manual — chapter list

CLI reference

Every verb and flag GridSim.Cli accepts, verified against the argument parsing in src/GridSim.Cli/Program.cs. Run the CLI from the repo:

dotnet run --project src/GridSim.Cli -- <verb> [flags]

or publish it and call the binary directly (shown below as gridsim).

Parsing rules and exit codes

  • Numeric flags fail loud. A flag present with an unparseable value (--ticks 5O) prints error: <flag> expected <kind> but got '<value>' and exits 2 - the default is never silently substituted. All numbers parse invariant-culture (. decimal point).
  • String flags (--out, --catalog, --cases, ...) take the next token as their value only if it does not itself start with --.
  • Boolean flags are presence-only and may appear anywhere on the line.
  • Positional arguments (a case name, an event id) are the first free token that is neither a flag nor a flag's value.
Exit code Meaning
0 Success.
1 Input error - missing file, unloadable case, invalid measurement set.
2 Usage error, bad flag value, unknown verb/case, or a forward-inference rejection (REJECTED (forward inference)).
3 Validation or gate failure - baseline not Reproduced, estimate not converged/observable, crossval mismatch, non-converged replay steps.
77 crossval only: environment skip - no Python or no pandapower, so the check never ran.

Global switches

Parsed before the verb and usable with any command.

Flag Default Meaning
--cpu on CPU linear-solver backends (dense LU / sparse ILU0-BiCGSTAB).
--gpu off Auto-select a GPU backend, AMD-first: ROCm, then OpenCL, then CUDA, else fall back to CPU with a warning.
--gpu=rocm / --gpu=opencl / --gpu=cuda off Force a vendor; absent devices (or an OpenCL device without FP64) fall back to CPU.
--inertia-model lumped\|distributed lumped Frequency-dynamics inertia model. Only trip integrates the distributed model; transient reports the domain split but integrates lumped; evidence/scenario/fleet/replay-event warn and run lumped.
--bfs off Route the solve through the radial backward/forward-sweep solver (auto-selected for radial models anyway).
--enableExport[=path] off Dump the full math trace of one solve to JSON (exports/<case>-solve.json by default).
--export-jacobian off Force the (large) Jacobian past the size gate into the export.
--once off Bare/case/dir forms: solve once, print, exit.
--ticks N 0 Bare/case/dir forms: run N headless live ticks then exit; 0 runs interactively.
--importLicence <file.gridsim> - Install a software licence from a .gridsim file, then exit (see the licence verb and ch. 23). Fully offline. Distinct from the DNO --licence distribution-area selector.

licence

Inspect and install the software licence (ch. 23). Fully offline.

Form Does
licence status Print the active tier, holder, bus limit, expiry, and the licence-file path.
licence import <file.gridsim> Validate a .gridsim key file and install it to %LOCALAPPDATA%\GridSim\licence.gridsim.
licence path Print the licence-file path.

The global --importLicence <file.gridsim> switch is shorthand for licence import. A key can also be supplied for a single run via the GRIDSIM_LICENCE environment variable. With no licence installed, GridSim runs at the free Personal tier (1,500-bus cap on user networks; bundled test cases are always exempt). Exit code 2 on a rejected key or bad usage.

Running a case (no verb)

Argument Loads
(none) UK reduced 10-zone model (data/uk), live loop.
case9/ieee9, case14, case30, case57, case118, case300, case145, case24/rts, cigre Embedded IEEE/CIGRE cases. case9 without --enableExport prints a detailed solve and exits.
uk The UK reduced model.
<file>.m or --mpc <file>.m Any MATPOWER case (raw ohm/kW distribution files are unit-normalised).
--dir <path> / -d <path> A JSON case directory.
(anything else) error: unknown command or case, exit 2.

Contingency and analysis verbs

trip

gridsim trip [<gen>] [--dir <path>] [--export <csv>]

Trip a generator and report RoCoF, nadir and settling frequency (plus the same trip at half inertia). <gen> is a case-insensitive substring of a generator name; no match lists the available names and exits 2. Without <gen> the largest non-slack unit with inertia is tripped. The only verb that fully honours --inertia-model distributed.

Flag Default Meaning
<gen> largest unit Generator-name substring to trip.
--dir data/uk JSON case directory.
--export - Write the frequency trajectory CSV (dtm,f), playable with gridsim replay <file>.

screen

gridsim screen [--dir <path>] [--top 12] [--csv <path>]

N-1 RoCoF screening: rank every credible single infeed loss against the GB limits (RoCoF 0.125 Hz/s, statutory 49.5 Hz, LFDD risk) and report the binding case's inertia floor and headroom.

Flag Default Meaning
--dir data/uk JSON case directory.
--top 12 Rows to print (all losses are still screened and counted).
--csv - Write the full screening table to CSV.

nminus1

gridsim nminus1 [--dir <path>] (alias n-1)

Sequential N-1 branch outage screening on one model: each branch out in turn, re-solved, classified secure / violations / islanded. Default model data/uk.

nminus1-sweep

gridsim nminus1-sweep <case|--all> [--parallel N] [--sample N] [--out <path>]

Parallel N-1 branch sweep with throughput reporting, over one case or the whole case registry (--all = embedded classics + every .m under data/matpower/). Writes Markdown + CSV + run-metadata.json.

Flag Default Meaning
<case> case118 Case name or .m file.
--all off Sweep the whole registry.
--parallel 0 (all cores) Worker threads.
--sample 0 (full) Screen an evenly-spaced sample of N branches (logged, flagged (sampled)).
--out results/nminus1-sweep.md Report path (CSV alongside).

stress

gridsim stress <case|--all> [--from F] [--to F] [--step F] [--parallel N] [--out <path>]

Load-to-collapse: scale the operating point until the flow stops converging and report max loadability. Q-limits are enforced so collapse is real reactive exhaustion.

Flag Default Meaning
<case> case118 Case name or .m file (--all sweeps the registry).
--from / --to / --step 0.5 / 2.0 / 0.05 Load-multiplier sweep. --step must be positive (exit 2 otherwise).
--parallel 0 (all cores) Load points solved in parallel.
--out results/stress.md Report path (CSV alongside).

chain

gridsim chain <case> [--steps N] [--mode fixed|ramp|daily] [--ramp-pct F] [--out <path>]

Consecutive warm-started solves: each step feeds the previous solution in as the initial condition. fixed re-solves the same point (expect <=1 iteration, no drift); ramp adds --ramp-pct % load per step; daily follows the 24 h demand curve. Exit 1 if the case does not load.

Flag Default Meaning
<case> case118 Case name or .m file.
--steps 50 Number of consecutive solves.
--mode fixed fixed, ramp or daily.
--ramp-pct 0.5 Percent load increase per step (ramp).
--out results/chain-<case>.md Report path (CSV alongside).

cycle

gridsim cycle <case|--dir <path>> [--window-ms 1000] [--workers N] [--cycles K] [--shards N] [--jobs n-1,harmonics,rocof,physics,watch] [--hold-steady] [--pipeline]

The real-time prioritised parallel analysis cycle: one single-core Newton-Raphson base solve per cycle, then a worker-pool fan-out of every downstream analysis - N-1 sweep, harmonics, RoCoF screening, physics conformance and the watch list - over the shared immutable solved frame. High-priority work (base solve, hot N-1, harmonics, watch list) completes every cycle; Low-priority work (rotating N-1 shards, RoCoF, physics) is admitted best-effort while the core-millisecond budget (workers x window-ms) lasts, and any Low deferred this cycle keeps its place at the front of the rotating pool for a later one (round-robin coverage, no starvation). Per cycle it prints base-solve ms, High-tier completion, Low done/admitted/deferred, utilization %, backlog depth and N-1 shard coverage. Exits non-zero if High is ever missed. This is the perf-programme soak driver.

Flag Default Meaning
<case> / --dir data/uk Case name or JSON case directory to run the cycle on.
--window-ms 1000 Wall-clock deadline per cycle (ms); the compute budget is workers x window-ms core-ms.
--workers cores - 1 Fan-out worker pool size (one core reserved for the single-threaded base solve). Results are worker-count-independent; only throughput changes.
--cycles 10 Number of cycles to run.
--shards 8 Rotating Low-priority N-1 shard count (full branch coverage is reached over this many cycles).
--jobs all Comma list of analyses to schedule: n-1, harmonics, rocof, physics, watch.
--hold-steady off Hold the operating point fixed across cycles rather than stepping the live sim (comparable cycle-to-cycle timing).
--pipeline off Opt-in pipelining: drain the previous cycle's Low backlog against the stale-by-one frame while this cycle's base solve runs.

Frequency and dynamics verbs

freq

gridsim freq [csv]

NESO 1-second frequency statistics plus a GB limit-breach scan (RoCoF 0.125 Hz/s, operational 49.8 Hz, statutory 49.5 Hz, LFDD 48.8 Hz) and a 20 ms upsample demo. Default input: data/neso/frequency-sample.csv beside the executable. Exit 1 if the file is missing.

replay

gridsim replay [csv] [--sps F] [--seconds N] [--frames N]

Play a recorded frequency trace in the terminal (gauge + RoCoF), upsampled to 20 ms. Keys: space play/pause, up/down speed, <-/-> step, Home restart, Q quit.

Flag Default Meaning
[csv] data/neso/frequency-sample.csv Source trace.
--sps 50 Slices per second (50 = real time).
--seconds 600 Seconds of source to load.
--frames 0 > 0 runs headless for N slices then exits.

transient

gridsim transient <case|--cases a,b,c|--cases suite> [flags]

Headless demanding time-domain run: a simulated duration at a fine slice, integrating swing-equation frequency each slice. Writes timeseries.csv, sampled solve-math exports (exports/slice-*.json), summary.md and run-metadata.json. --cases suite (or all) runs case9, case14, case30, case57, case118, case300 and pegase/case1354pegase.m.

Flag Default Meaning
<case> case9 Case name or .m file under data/matpower/.
--cases - Comma list, or suite/all.
--minutes (alias --duration) 60 Simulated duration in minutes.
--dt-ms 1.0 Slice length, milliseconds.
--log-every 1 Write every N-th slice to the CSV.
--export-every 0 (off) Full solve-math export every N-th slice (slice 1 and the trip window always export).
--export-jac off Include the Jacobian in exports.
--trip 0 (none) Infeed MW to trip mid-run.
--trip-at 0 Trip time (seconds). Exit 2 if past the run end - the contingency would never fire.
--trip-window 2.0 Seconds each side of the trip always logged and exported.
--solver auto dense, sparse, bfs/sweep or auto.
--out results/transient-<case>-<stamp> Output directory (batch runs use results/transient-<stamp>/<case>).

Exit 1 if no case loaded at all.

domains

gridsim domains [--dir <path>]

Report the speed domains of the distributed-inertia model: per-domain machine count, GVA.s and GVad stiffness, and whether a dominant domain exists (deltaGVa >= 10 %). Default model data/uk. Not listed in the usage header; it is a diagnostic companion to --inertia-model distributed.

stability

gridsim stability [<case>] [--dir <path>] [--screen] [--fault-bus N] [--clear ms] [--export <json>]

Classical multi-machine transient stability (constant E' behind X'd, Kron-reduced network, RK4 swing). Default case case9 (Anderson-Fouad X'd; anything else uses a synthetic 0.30 pu default and is flagged INDICATIVE).

Flag Default Meaning
--screen off Critical clearing time at every generator bus, worst first.
--fault-bus 7 (case9) / first non-generator bus Fault location.
--clear - Fixed clearing time in ms -> STABLE/UNSTABLE verdict; omit for the critical clearing time.
--export - Write a gridsim-classical-export/1 trajectory for the scipy cross-check (tools/crossval/crossval_classical.py).

Exit 2 on a non-converged base solve, a zero-inertia case or an unknown case.

Evidence verbs

All four share the event catalogue (--catalog <f.json>, schema gridsim-event-catalog/1; built-in events gb-2019-08-09 and gb-largest-loss-1320) and the forward-inference guard: any event or trace timestamp newer than 169 h ago is rejected with exit 2. See 09-counterfactuals.md.

replay-event

gridsim replay-event <id> [--catalog <f.json>] [--trace <neso.csv>] [--out <dir>] [--dump-catalog <path>]

The credibility gate: reproduce a recorded event's RoCoF/nadir with no device. Writes baseline-frequency.json, summary.md, run-metadata.json to results/replay-<id> by default. --trace attaches a real 1-second NESO CSV to enable the per-sample RMSE check; --dump-catalog writes the built-in catalogue to disk and exits. Exit 3 for any verdict short of Reproduced (a Marginal baseline unlocks nothing).

scenario

gridsim scenario --event <id> [flags]

The counterfactual sweep (inertia x device x corners) plus the inertia risk curve. Refuses to run (exit 3, GATE FAILED) unless the no-device baseline reproduces the record. Writes matrix.csv, risk-curve.csv, counterfactual-frequency.json, summary.md to results/scenario-<id>.

Flag Default Meaning
--event required Event id (exit 2 if missing).
--inertia 260,155,120,102,50 GVA.s levels to sweep (the GB trajectory).
--device <f.json> - Device from a JSON file.
--device-inertia / --device-ffr 30.0 GVA.s / 1.0 GW Build the device from flags instead (a [VERIFY] placeholder TSGB).
--corners best,worst Comma list of best, nominal, worst.
--catalog / --out built-ins / results/scenario-<id> Catalogue file / output directory.

fleet

gridsim fleet --event <id> [flags]

Single-vs-fleet emergent behaviour: the same total device budget split across N staggered units. Intrinsic inertia is N-additive; FFR is not (fewer MW online at the nadir). Gated like scenario (exit 3 unless the baseline reproduces). Writes fleet.csv to results/fleet-<id>.

Flag Default Meaning
--event required Event id.
--units 1,100 Unit counts to compare.
--total-inertia 40.0 Total device inertia budget (GVA.s).
--total-ffr 1.5 Total device FFR budget (GW).
--stagger 10.0 Fleet onset spread (s).
--tau 0.5 Per-unit FFR time constant (s).
--deadband 0.015 Per-unit frequency deadband (Hz).
--inertia event pre-event inertia System inertia (GVA.s).
--catalog / --out built-ins / results/fleet-<id> Catalogue / output directory.

evidence

gridsim evidence --event <id> [flags]

The umbrella dossier (gridsim-evidence/1): recorded vs simulated vs counterfactual columns, risk curve, fleet comparison and avoided cost - counterfactual sections withheld (and exit 3) unless the baseline reproduces. Writes evidence.json, summary.md to results/evidence-<id>.

Flag Default Meaning
--event required Event id.
--device / --device-inertia / --device-ffr - / 30.0 / 1.0 Device file or flag-built placeholder.
--inertia 260,155,120,102,50 Risk-curve inertia levels (GVA.s).
--cf-inertia event pre-event inertia Inertia for the headline counterfactual column (GVA.s).
--units 100 Fleet size for the fleet section.
--stagger 10.0 Fleet onset spread (s).
--voll 6000.0 Value of lost load, £/MWh (a curated placeholder, labelled as such in the output).
--duration 0.5 Assumed shed duration (h) for avoided cost.
--catalog / --out built-ins / results/evidence-<id> Catalogue / output directory.

Data verbs

gda

gridsim gda --root <path> [flags]

Read the read-only GDA data lake and materialise a GridSim replica (data stays out of the repo). --root falls back to the GDA_ROOT environment variable; with neither, usage prints and the verb exits 2.

Flag Default Meaning
--root $GDA_ROOT Path to the /gda lake.
--dno nged Source reader: nged, ukpn or npg.
--licence - Restrict to one licence area (e.g. EMIDS).
--gsp - Restrict to one GSP group.
--all-gsps off Build and solve every GSP supply area in turn.
--minkv 0 Drop nodes below N kV.
--base 100 System base MVA.
--neg-gen off Embedded generation as negative load.
--no-oltc off Do not create OLTC controllers.
--no-geo off Skip geolocating buses from the substation table.
--as-of <date> now - 169 h Register as-of date (the no-forward-inference horizon; override for a specific replay date).
--out - Materialise the replica as a JSON case directory.
--solve off Solve the built model (--sparse/--dense force the backend).
--fleet off National NESO fleet report instead (inertia, largest loss, RoCoF screen, ETYS boundary limits).
--schema <path> - Print a CSV/Parquet dataset's columns and row count, then exit.

gda-replay

gridsim gda-replay (--series <ts.json> | --synth) [flags]

The historical state estimator: replay a demand time-series through the validated solver, reconstructing grid state at each past timestamp (horizon-guarded - never nowcasting). Writes state-estimate.csv, exports/state-*.json and run-metadata.json. Exit 3 if any step fails to converge.

Flag Default Meaning
--series - A GDA time-series JSON (real per-timestamp demand is data-gated).
--synth - Synthetic daily load shape instead.
--start 2024-01-01 Synthetic series start date.
--steps 48 Synthetic timestamps.
--step-min 30.0 Minutes between synthetic timestamps.
--case case118 Network to replay on.
--export-every 0 (off) Full solve export every N-th step (step 0 always exports when tracing).
--out results/gda-replay-<case> Output directory.

synth

gridsim synth [flags]

Build the synthetic GB-at-scale case (no licensed data), solve it, and materialise it as a JSON case directory.

Flag Default Meaning
--seed 20260605 Build RNG seed.
--scale 1.0 Network size scale factor.
--iters 60 Max Newton iterations for the check solve.
--oltc 30 Max OLTC passes.
--qlimits off Enforce Q-limits in the check solve.
--worst off Print the ten worst spec-vs-solved buses even when converged.
--out data/gb-synthetic Output case directory.

export

gridsim export [out.json] [--dir <path>] [--frames 72]

Write a visualisation scene (buses, branches, animation frames) for external renderers. Default output gridviz.json, default model data/uk.

estimate

gridsim estimate <case> (--measurements <m.json> | --synth) [flags]

The measurement-based WLS state estimator. <case> is a built-in name, a .m file under data/matpower/, or a JSON case directory (anything with a system.json, so gb-spine/gb-full materialisations estimate directly). See 10-state-estimation.md for the workflow.

Flag Default Meaning
--measurements - A gridsim-measurements/1 file.
--synth - Solve the case as ground truth, sample a deterministic noisy set, and score the estimate against it.
--seed 20260713 Synthetic sampler seed.
--noise 1.0 Noise scale multiplier.
--coverage-vm / --coverage-inj / --coverage-flow 1.0 / 1.0 / 1.0 Fraction of each measurement class sampled.
--method wls wls, constrained, huber or lav.
--prior flat flat keeps the set's voltage-schedule rows; solve solves the measured-injection power flow, replaces the schedule with the solved profile and warm-starts from it.
--warm-start off Warm-start from the case's own solved operating point (needed for real data).
--phaseangle - One or more space-separated BUS:ANGLE:UTC:FREQ per-bus voltage-angle observations (angle in degrees, UTC in ISO-8601 Z form, frequency in Hz), authored as VaDeg rows and merged before the prior. Genuine per-bus angle differences directly observe the estimator's weakest directions; a common-mode system angle cancels against the slack (used only as a reference frame).
--phaseangle-ref auto auto re-references to the slack via a datum bus and time-projects via frequency; referenced projects only (subtracts --phaseangle-from-gda's common-mode); raw injects as given.
--phaseangle-sigma 2.0 1-σ of each authored angle row, degrees.
--phaseangle-at set instant Common instant the angles are projected to (ISO-8601 UTC); defaults to the set's takenUtc.
--phaseangle-from-gda - GDA v1 lake root: read PHASEANGLE_INFERED (the system COI angle + true frequency/RoCoF) at the target instant and use it as the absolute reference frame / common-mode de-rotation.
--tol 1e-8 Convergence tolerance on the state update.
--max-iter 30 Iteration cap.
--no-bad-data off Skip largest-normalised-residual bad-data removal.
--backfill-removals off Replace each removed measurement with a loose prior-evaluated pseudo (observability restoration).
--lean off Skip residual-covariance solves when chi-square already passed (backfill throughput switch; normalised residuals become NaN).
--trace off Capture the per-iteration convergence path into the export.
--export-solve off Also project the estimate into a gridsim-solve-export/1 document (estimated-solve-export.json) - the estimated-state lake feed.
--out results/estimate-<case> Output directory (estimate-export.json, residuals.csv, measurements.json when synthetic).

Exit 0 only when the estimate converged and the network is observable; 3 otherwise; 1 for load errors; 2 for usage/flag errors.

crossval

gridsim crossval <case|case-dir|solve-export.json> [--tol F] [--out <dir>]

Solve a case (or take an existing export), then hand it to the pandapower sidecar (tools/crossval/crossval.py) for an independent re-solve and diff. Requires Python + pandapower on PATH. See 14-validation-tools.md.

Flag Default Meaning
--tol 1e-3 Vm agreement tolerance in pu (angle tolerance is 100x in degrees, floor 0.1 deg).
--out results/crossval-<name> Output directory (solve-export.json, crossval-diff.json).
--tool pandapower Accepted for forward compatibility but not read - pandapower is the only sidecar.

Exit 0 agrees * 3 mismatch or sidecar validation failure * 77 environment skip (no Python / no pandapower) * 2 missing argument * 1 load/script errors.

Benchmarking verbs

bench

gridsim bench [--runs N] [--parallel N] [--out <path>] [--note "text"] [--gpu]

The solver x backend matrix over the whole case archive (embedded classics + every .m under data/matpower/). Writes Markdown + CSV + run-metadata.json. GPU engines are opt-in via the global --gpu and skip cases above 3,000 buses.

Flag Default Meaning
--runs 10 Timing repeats per case (auto-reduced for big cases).
--parallel 0 (all cores) Worker threads (GPU engines always run serially).
--out docs/benchmark-results.md Report path (CSV alongside).
--note - Free-text note stamped into the header.

bench --estimate

gridsim bench --estimate [--runs N] [--cases a,b,c] [<case-dir> ...]

Times the WLS estimator per case per step backend (dense vs sparse, forced via the sparse threshold) on a fixed-seed synthetic set; sampling and the truth solve sit outside the timed region. Extra positional JSON case directories are appended.

Flag Default Meaning
--runs 3 Timing repeats (reduced above 1,000 buses).
--cases case14,case30,case57,case118,case300 Case list.

Output: results/bench-estimate/bench-estimate.csv plus a console table. Dense is skipped above 1,500 buses.

gpucheck

gridsim gpucheck

Fail-fast GPU preflight: reports CPU/CUDA/ROCm availability and runs one tiny case9 solve on each present backend, flushing every step so a crash names the failing call. No flags. See 14-validation-tools.md.

batchsolve

gridsim batchsolve [--count N] [--n M] [--runs K] [--gpu]

Solve N same-sized MxM dense systems in one batched dispatch on the selected backend - the GPU batched Gaussian-elimination kernel when a device is present, else a parallel CPU loop over the reference LU - then verify the result against the CPU reference and report timing. A demonstrator / micro-bench for the batched dense solver seam that turns a contingency sweep of many same-sized outages into a handful of batched dispatches instead of hundreds of locked single solves. A singular system is isolated (its segment returns NaN) and never fails the whole batch.

Flag Default Meaning
--count - Number of independent systems in the batch (N).
--n - Dimension M of each dense MxM system.
--runs - Timing repeats.
--gpu off Select the GPU batched backend (the global --gpu); falls back to the CPU batched reference with no device.

See also