GridSim Core

Newton–Raphson, done properly. Then shown, in full.

A physics-constrained AC power-flow solver and state estimator. Full polar Jacobian, quadratic convergence, generator reactive limits enforced exactly, tap changers regulated in an outer loop. Validated by an instrument that doesn't trust it — and never allowed to guess.

14/14
cases at machine ε
0 iters
case300 — where others stall
0
buses, largest solved
0
tests, all green
Three engines, one contract

Pick a backend. Get the same answer, to the bit.

Dense, sparse and radial engines sit behind one interface, and a selector picks the right one for your network. They are proven bit-identical against each other — which is not a figure of speech.

Dense reference

The full polar Jacobian assembled explicitly, factorised by textbook LU with partial pivoting. Deliberately transparent — this is the engine the validation instrument interrogates, and the yardstick everything else must match bit-for-bit.

Sparse production

Sparse admittance and Jacobian, direct sparse LU under reverse Cuthill–McKee ordering, with an ILU0-preconditioned BiCGSTAB fallback. This is what carries the 9,241-bus PEGASE network and the 3,539-bus GB model — sub-second, machine epsilon.

Radial sweep

Backward-forward sweep for distribution feeders, where Newton is the wrong tool and everyone quietly knows it. The selector routes radial networks here automatically.

one solve, full working attached CLI
> gridsim solve case118.json --backend sparse --enableExport

  converged      true
  iterations     6
  maxMismatch    3.9e-12 MW
  qLimitEvents   2 (PV→PQ, pinned at Qmax)
  export         exports/case118-solve.json   ← the math ladder, in full

Q-limit switching and the OLTC voltage-regulation loop run as outer passes — every switch and every tap movement is recorded in the export, not just the final state.

The validation report

Two independent instruments. Neither trusts the solver.

The primary check rebuilds the bus admittance matrix from the raw export using the MATPOWER π-model — in NumPy, sharing no code with GridSim — and recomputes the power balance at every single bus. The second cross-checks voltages against pandapower wherever it converges. Pass means machine epsilon and zero reactive-limit violations. There is no partial credit.

CaseBusesMax P mismatchQ-limit violationsVerdict
case9 (WSCC)91.7×10⁻¹² MW0MACHINE ε
case14142.0×10⁻⁹ MW0MACHINE ε
cigre_mv151.0×10⁻⁸ MW0MACHINE ε
case24_ieee_rts242.3×10⁻¹⁰ MW0MACHINE ε
case30309.6×10⁻⁸ MW0MACHINE ε
case57573.5×10⁻¹⁰ MW0MACHINE ε
case73_ieee_rts (RTS-96)732.8×10⁻⁸ MW0MACHINE ε
case1181183.9×10⁻¹² MW0MACHINE ε
case1451451.4×10⁻⁷ MW0MACHINE ε
case3003002.7×10⁻¹¹ MW0MACHINE ε
case1354pegase1,3542.2×10⁻⁷ MW0MACHINE ε
case2869pegase2,8692.7×10⁻¹⁰ MW0MACHINE ε
case9241pegase9,2414.3×10⁻⁹ MW0MACHINE ε
gb-full — Great Britain3,5391.3×10⁻⁹ MW0MACHINE ε

Worst mismatch anywhere in the table: ~2×10⁻⁷ MW — 0.2 milliwatts on a national grid carrying ~50 GW, one part in 2.5×10¹¹. Where pandapower converges, voltage agreement is at machine epsilon too (case9: |ΔVm| 4.4×10⁻¹⁶ pu).

The case the reference tool can't start

case300 — the IEEE 300-bus system — is notoriously hostile from a flat or DC start. pandapower's Newton implementation does not converge from that initialisation on the reconstructed network; a convergence-basin limitation, not a discrepancy. GridSim solves it in 7 iterations to a residual of 2.7×10⁻¹¹ MW, reactive limits enforced throughout.

On the PEGASE family — 1,354, 2,869 and 9,241 buses — the same reference tool reports a singular Jacobian mid-iteration. GridSim solves all three to machine epsilon. I note this because a licensee will try it, not to score points.

And the disagreement it won

On case24_ieee_rts the two tools initially disagreed by 0.08 pu at one bus. The independent residual check settled it: the reference had wrongly switched a four-generator bus from PV to PQ, while GridSim's solution carried a 2.3×10⁻¹⁰ MW mismatch and zero limit violations.

That is what the independent instrument is for. When tools disagree, you don't vote — you recompute the physics from scratch and let Kirchhoff adjudicate.

The full working

Step through the actual iterations. All of them.

Every job can emit a complete gridsim-solve-export/1 document as it executes: the admittance matrix, the starting point, every Newton iteration's mismatch and correction vectors, the Jacobian for cases up to 300 buses, every reactive-limit event — plus the git commit, the machine and the wall-clock. This one steps through a case300-shaped solve.

case300-solve.json
max |ΔS| — worst power mismatch this iteration
4.7×10⁰ MW
10⁻¹²log scale10¹
Q-limit event: bus 117 hit its reactive ceiling — switched PV→PQ and pinned at Qmax. Recorded, like everything else.

          

Illustrative trace in the solve-export format — every licensed job emits the real thing. Keyboard: ← → step the iterations.

And because the trace is observational — the solve is bit-identical with it on or off — the export is byte-for-byte reproducible. A test asserts it. Dense and sparse backends produce bit-identical voltages. GPU results are bit-for-bit the CPU's. If two runs ever differ by a byte, a test fails before you ever see it.

Warm start — the GDA effect

Cold, Britain takes nine iterations. Warm, it takes one to three.

From a flat start, the 3,539-bus GB network converges in 9 Newton iterations. Warm-started from GDA's pre-passed operating data — a converged point baked into the case, then corrected each settlement period — the same network settles in 1–3 iterations, roughly 60 milliseconds, tap changers and all. That is what replaying a country at speed actually requires.

This is the cleanest argument for the module: GDA doesn't just feed the solver data, it hands the solver the answer's neighbourhood and lets Newton do what Newton does best — finish.

gb-full · 3,539 buses · Newton iterations to convergence
Cold — flat start9 iterations
Warm — GDA pre-passed1–3 iterations · ~60 ms
3.6×10⁻¹¹
final mismatch, pu
0.980–1.046
voltage band, pu
Benchmarks

Measured on real cases. Deterministic across runs.

Newton iteration counts repeat exactly run to run — so the timing noise is the machine's, never the algorithm's.

CaseBusesBackendCold solveIterations
Cold starts — flat initialisation
case118118dense / sparse< 10 ms6
case300300dense / sparse< 30 ms5 (7 with Q-limits enforced)
case2869pegase2,869sparse~185 msdeterministic
gb-full — Great Britain3,539sparse + OLTC loopsub-second9
case9241pegase9,241sparse~857 msdeterministic
Warm starts — previous solution as initial condition
case118, 500-step chain118sparseper-step ms6 cold → 5 warm, mismatch ~2.9×10⁻¹⁴
gb-full, GDA pre-passed3,539sparse + OLTC~60 ms1–3

The dense reference is deliberately memory-honest: at 9,241 buses its explicit Jacobian alone is ~2.7 GB, which is why the sparse engine (reverse Cuthill–McKee LU, ILU0/BiCGSTAB fallback) carries the national networks. GPU runs produce bit-for-bit the CPU's results. Full residual data on the validation page.

The application

Nine tabs. One transport bar. Zero mystery.

The desktop app replays the grid with a global transport bar — pause, step, scrub, speed — and a click-through inspector on everything: a fuel opens its units, a unit opens its detail, back-stack included. These are the working views.

The geolocated map

Every one of the 3,539 buses drawn where it actually is, with voltage and loading overlays. The schematic renderer keeps national-scale replay fluid; imported IEEE cases get a synthetic layout with topological voltage tiers.

Generation & inertia

The fuel mix and the inertia it carries, per tick — including the synchronous / outturn / market GVA·s split. This is where "inertia as a map, not a number" lives.

Operator

The system-operator view of the replayed period: largest-loss securing, response and reserve headroom, balancing-mechanism dispatch with fuel tags, active constraints with their £ cost, live warnings.

Market

Imbalance price, market index, net imbalance volume, BSUoS, carbon intensity and every interconnector flow — the money side of the same half-hour, streamed alongside the physics.

NESO RP1 — purchased time

The situational-awareness page. Its hero metric is purchased time: how many seconds of frequency ride-through the grid owns right now, at the live credible loss, against the 3,600 MW design basis. Inertia by source, a 30-minute stability trend, and an auto-written handover narrative.

Mechanical — the plant engineer's tab

Per-machine, risk-sorted: P-Q capability diagrams, inertia per unit, dual RoCoF relay margins (the 0.125 original and the 1.0 relaxed setting, side by side), shaft and thermal state, and a +15-minute fleet trajectory. Fields the replay can't know yet are flagged, not faked.

Assets

The full asset explorer — substations, generators, circuits, transformers, interconnectors — page-stacked with cross-navigation, so any object in the model is three clicks from any other.

Bring your own network

Your topology. The same rigour.

GridSim Core does not need GDA to be useful. Feed it a JSON topology map — buses, generators, branches, limits — or import IEEE and MATPOWER cases directly. Every solve gets the same treatment as the national grid: full Jacobian, exact reactive limits, and a math ladder on demand.

Universities run coursework networks through it. Consultancies run client networks through it. The solver does not know the difference, and the export format means your reviewers don't have to take anyone's word for anything.

my-network.json CASE MAP
{
  "baseMVA": 100,
  "buses": [
    { "id": 1, "type": "slack", "vm": 1.02, "kv": 132 },
    { "id": 2, "type": "pv", "pGenMw": 85, "vSet": 1.01,
      "qMinMvar": -40, "qMaxMvar": 60 },
    { "id": 3, "type": "pq", "pLoadMw": 120, "qLoadMvar": 35 }
  ],
  "branches": [
    { "from": 1, "to": 2, "r": 0.019, "x": 0.059, "b": 0.017 },
    { "from": 2, "to": 3, "r": 0.017, "x": 0.092, "b": 0.008 },
    { "from": 1, "to": 3, "x": 0.085, "tap": 0.978,
      "oltc": { "target": 1.0, "range": [0.9, 1.1] } }
  ]
}

GridSim without GDA is a very good solver. With GDA, it's twenty-five years of Britain.