User manual — chapter list

Running power flows

This chapter covers the CLI's default surface: load a case and solve it - once, live, or as a recorded time-domain run - plus how the solver engine is chosen, what lands on disk, and how to read the console output. The analysis, evidence and estimation verbs each have their own chapter.

The three outcomes of a bare run

GridSim.Cli <case> (a built-in name, a .m path, --mpc <file>.m, or --dir <folder> - see 02-loading-networks.md) ends in exactly one of three ways:

You add What runs
(nothing) the live loop: re-solve a day/night demand curve each tick until a key is pressed
--once one solve, one full engineering report, exit
--ticks N the live loop, headless: N ticks, one summary line each, exit
--enableExport[=path] one fully-traced solve dumped to JSON, exit

case9 is the exception: it always solves once, prints the report and exits (it is the ground-truth benchmark; animating it is never the point) - unless --enableExport is present, in which case it is dumped like any other case.

Global switches can appear anywhere on the line and combine with any of the above:

Switch Default Meaning
--once off solve once and print the detailed report
--ticks N 0 (interactive) run N headless live ticks then exit; a malformed N exits 2
--cpu / --gpu[=rocm\|opencl\|cuda] --cpu compute backend; --gpu auto-detects AMD-first (ROCm -> OpenCL -> CUDA); a missing device (or an OpenCL device without FP64) warns and falls back to CPU
--bfs off force the radial backward/forward-sweep solver
--inertia-model lumped\|distributed lumped inertia model for the dynamics verbs (trip integrates distributed; other dynamics verbs warn and run lumped)
--enableExport[=path] off dump one traced solve (schema gridsim-solve-export/1)
--export-jacobian off force the (large) Jacobian into the export, past its size gate

Solver selection

Power flow runs on one of three engines behind one interface, and selection is automatic:

  1. Radial network (one slack, exactly buses - 1 in-service branches), or --bfs given -> backward/forward sweep - the distribution-class solver for tree feeders the transmission Newton method is not built for.
  2. More than 3,000 buses -> sparse Newton-Raphson (the dense Jacobian stops fitting and stops being fast past a few thousand buses).
  3. Otherwise -> dense Newton-Raphson, the validated reference.

Where both Newton engines solve a case they agree on iteration count and final mismatch, so the automatic choice never changes the answer, only the cost. transient exposes the same choice explicitly as --solver auto|dense|sparse|bfs; the desktop app's SOLVER picker is the same set again. Default solve options are a mismatch tolerance of 1e-8 p.u., a 30-iteration cap, and generator Q-limits enforced (PV->PQ switching).

The compute backend (--cpu/--gpu) swaps the linear solver inside each Newton step; the physics never changes. Check what your machine offers before relying on --gpu:

dotnet run --project src/GridSim.Cli gpucheck

gpucheck probes CPU, ROCm, OpenCL and CUDA in turn, runs a tiny dense and sparse solve on each present backend, and prints a FAIL line naming any failing call. Every report and run directory stamps the backend it actually used, including cpu (<requested> requested but unavailable) when a GPU was asked for but absent.

The OLTC outer loop

Whatever engine is picked, it is wrapped in a steady-state outer loop that settles the on-load tap changers: solve, step any OLTC whose controlled bus is outside its deadband, re-solve, up to 25 passes (the synth verb takes --oltc N, default 30). The convergence line reports both loops:

Converged (3 NR iters, 3 OLTC passes, max mismatch 1.29E-011 p.u.)

Zero OLTC passes just means the case has no tap changers (all the MATPOWER cases) or none needed to move.

Reading the console output

The --once report, top to bottom: a header (name, bus/branch/generator counts, base MVA, frequency); the convergence line above; system totals (generation, demand, losses, inertia); a per-bus table (kV, Vm p.u., Va deg, net P and Q); boundary flows when the case defines them, flagged OVERLOAD past 100 %; the five most-loaded branches; and a closing voltage-range verdict (in band is 0.94-1.06 p.u.) with total real and reactive losses.

The live loop starts a simulated clock at 08:00 and advances 20 simulated minutes per tick, scaling demand along the GB daily curve and re-solving. Interactively it redraws a full terminal dashboard; frequency reads a constant 50.00 Hz because each tick is a steady-state solve - dynamics live in transient and the dashboards. With --ticks N it prints one line per tick:

t=08:00 tick  0  load 27.65GW  gen 27.68GW  loss   27MW  V 0.998-1.040  ok (3 NR)

48 ticks is a simulated day. ok/DIV is the convergence verdict; a non-convergence in a case that normally solves is worth investigating (see 17-troubleshooting.md).

Solve exports (--enableExport)

dotnet run --project src/GridSim.Cli case118 --enableExport
[export] dense-newton: converged=True iters=6 maxMis=2.85E-014  ->  ...\exports\case118-solve.json

This runs one traced solve on the raw engine (no OLTC loop, iteration cap raised to 100, Q-limits on) and writes everything the solve touched - Y-bus, per-unit spec, per-iteration mismatch and correction, Q-limit switching, converged state and flows - as a gridsim-solve-export/1 JSON document, by default to exports/<case>-solve.json under the current directory. Add --export-jacobian to include the full Jacobian. The metadata block records case, backend, git commit, timestamp, elapsed ms and machine. This is the document crossval diffs against pandapower and the desktop app replays, so one schema serves export, validation and replay (see 15-exports-and-formats.md).

Recorded runs: transient and the run directory

transient is the headless time-domain form: it drives the live simulator (hold-steady, warm-started) for a simulated duration at a fine time slice, integrating swing-equation frequency each slice, and records the lot.

dotnet run --project src/GridSim.Cli transient case118 --minutes 10 --dt-ms 20 --trip 1000 --trip-at 60
dotnet run --project src/GridSim.Cli transient --cases suite --minutes 5
Flag Default Meaning
<case> / --cases a,b,c / --cases suite case9 one case, a list, or the built-in suite (case9...case300 + pegase/case1354pegase.m)
--minutes M (alias --duration) 60 simulated duration
--dt-ms D 1.0 slice length in milliseconds
--trip MW --trip-at S off trip that many MW of infeed at S seconds; a --trip-at past the run end aborts (exit 2) rather than silently answering "no event"
--trip-window S 2.0 seconds around the trip in which every slice is exported
--log-every N 1 CSV row cadence
--export-every N 0 also export a full solve every N slices (--export-jac adds the Jacobian)
--solver auto\|dense\|sparse\|bfs auto engine override
--out DIR results/transient-<case>-<stamp> run directory

The run directory is the standard output shape most recording verbs share:

results/transient-case118-20260713-141530/
|-- run-metadata.json      what ran: description, machine, runtime, git commit, backend
|-- timeseries.csv         per-slice: t, frequency, RoCoF, gen/demand, iterations, mismatch, V range, solve ms, converged
`-- exports/
   `-- slice-000000001.json    full solve exports (first slice, the trip window, every --export-every N)

replay-event, scenario, fleet, evidence, gda-replay, estimate and crossval write the same pattern - results/<verb>-<id>/ with a run-metadata.json - so any result can be traced to the commit and backend that produced it. Run directories under results/ are auto-discovered by the desktop app and can be stepped through frame by frame (04-the-desktop-app.md).

The console summary at the end of a transient run names the nadir, the worst RoCoF and their times, plus any non-converged slices; the CSV carries the full trace for plotting.

See also