gdm-flow
Utilities for OPF and power-flow style preprocessing on top of
grid-data-models distribution systems.
Current features
- Y-Bus Construction — Phase-domain admittance matrices from GDM components (branches, transformers, switches) with matrix and sequence impedance support
- Four Solvers — AC OPF (nonlinear least-squares), AC PF (Newton-Raphson power flow), DC OPF (quadratic programming), and LinDistFlow (backward/forward sweep)
- Multi-Phase Support — Three-phase and grounded split-phase services; explicit/floating split-phase neutrals are unsupported
- Component Integration — Direct integration with GDM loads, solar PV, batteries, capacitors, and regulators
- GDM 2.4 Equipment — Lumped series reactors, static station switches, and connection-aware two-winding station transformers in the AC network model; see equipment scope
- Interactive Dashboards — Plotly-based HTML dashboards with voltage profiles, power flow, branch loading, losses, and equipment state
- QSTS Simulation — Quasi-static time series with warm-starting across timesteps for any solver
- Multi-Period OPF — Joint optimization across a time horizon with battery SOC coupling and ramp constraints (DC OPF and LinDistFlow)
- Time Series Discovery — Inspect available load, solar, and battery time series profiles in GDM models
- Modern CLI — Rich terminal interface with
info,run,compare,plot,export,ts-info,qsts,multiperiod,plot-ts, and reporting commands - SQLite Export — Structured database output with voltage/loading limit tracking, violation reporting, and streaming time series results
- MCP Server — Model Context Protocol server exposing all solvers as AI-callable tools
Install
Python 3.11+ and grid-data-models 2.4.0+ are required. Imports use the canonical
gdm.systems.distribution namespace. Older external GDM JSON can still load
through GDM's compatibility layer, which may emit a deprecation warning for
legacy serialized module paths.
pip install -e .
SciPy, sparse matrix support, and optimization solvers are included in the core installation.
If you want interactive plotting dashboards:
pip install -e '.[plotting]'
If you want to run the MCP server:
pip install -e '.[mcp]'
gdm-flow-mcp-server
Development checks
Install development dependencies and enable pre-commit hooks:
pip install -e '.[dev]'
pre-commit install
Run the same lint checks used in CI:
pre-commit run --all-files
Examples
An end-to-end examples folder is included at examples/ with a downloaded demo
distribution model and runnable scripts for each optimization flavor:
examples/models/p5r.jsonexamples/run_ac_opf_example.pyexamples/run_dc_opf_example.pyexamples/run_lindistflow_example.pyexamples/compare_plotly_results.py— interactive Plotly comparison across all solvers
Run from the repository root:
python examples/run_ac_opf_example.py
python examples/run_dc_opf_example.py
python examples/run_lindistflow_example.py
python examples/compare_plotly_results.py
Usage
from gdm.systems.distribution import DistributionSystem
from gdm_flow import calculate_ybus
system = DistributionSystem.from_json("path/to/system.json")
result = calculate_ybus(system, include_shunt=False)
Y = result.ybus
labels = result.index_to_label
labels[k] is a (bus_name, phase) tuple for row/column k of Y.
Optimization usage
from gdm.systems.distribution import DistributionSystem
from gdm_flow import optimize_ac_power_flow
system = DistributionSystem.from_json("path/to/system.json")
# Specify net nodal injections in SI units: +generation, -load
p_spec_w = {("bus_5", "A"): -20_000.0, ("bus_5", "B"): -20_000.0, ("bus_5", "C"): -20_000.0}
q_spec_var = {("bus_5", "A"): -5_000.0, ("bus_5", "B"): -5_000.0, ("bus_5", "C"): -5_000.0}
result = optimize_ac_power_flow(
system,
p_spec_w=p_spec_w,
q_spec_var=q_spec_var,
)
print(result.success, result.final_objective)
Auto-build specs from components
If your model already contains DistributionLoad and DistributionSolar components,
you can build nodal injections automatically:
from gdm.systems.distribution import DistributionSystem
from gdm_flow import optimize_ac_power_flow_from_components
system = DistributionSystem.from_json("path/to/system.json")
result = optimize_ac_power_flow_from_components(
system,
include_loads=True,
include_solar=True,
include_capacitor=True,
include_battery=False,
include_regulator_targets=True,
include_regulator_limits=True,
)
print(result.success, result.final_objective)
Notes:
include_capacitor=Trueadds capacitor reactive injections into nodalQspecs.include_regulator_targets=Trueadds soft voltage-target constraints derived from regulator controllers.include_regulator_limits=Trueadds hard voltage magnitude bounds from regulator min/max limits.
AC Power Flow (Newton-Raphson)
gdm-flow includes a classical Newton-Raphson AC power flow solver. Unlike the AC OPF
which optimises voltage magnitudes within bounds, the AC PF solves for exact bus
voltages given fixed P/Q injections and a slack bus:
from gdm.systems.distribution import DistributionSystem
from gdm_flow import solve_ac_power_flow_from_components
system = DistributionSystem.from_json("path/to/system.json")
result = solve_ac_power_flow_from_components(
system,
include_loads=True,
include_solar=True,
include_capacitor=True,
)
print(result.success, result.iterations)
print(result.max_mismatch_pu) # convergence metric
print(result.voltage_pu) # per-unit voltage magnitudes
The solver uses sparse LU factorisation with a damped update and LinDistFlow warm-start for robust convergence on heavily loaded feeders.
DC OPF module
gdm-flow also includes a separate DC OPF module:
from gdm.systems.distribution import DistributionSystem
from gdm_flow import solve_dc_opf_from_components
system = DistributionSystem.from_json("path/to/system.json")
result = solve_dc_opf_from_components(
system,
include_solar_generators=True,
include_battery_generators=True,
include_loads=True,
)
print(result.success, result.objective)
print(result.generator_dispatch_w)
LinDistFlow module
gdm-flow includes a separate radial LinDistFlow approximation module:
from gdm.systems.distribution import DistributionSystem
from gdm_flow import solve_lindistflow
system = DistributionSystem.from_json("path/to/system.json")
result = solve_lindistflow(system)
print(result.success)
print(result.voltage_v) # {(bus, phase): voltage_in_volts}
print(result.p_flow_w) # {(branch_name, phase): active_flow_w}
SQLite export module
You can export results from AC OPF, DC OPF, and LinDistFlow into one SQLite database:
from gdm_flow import export_all_results_to_sqlite
run_ids = export_all_results_to_sqlite(
"results.sqlite",
ac_result=ac_result,
dc_result=dc_result,
lindistflow_result=lindistflow_result,
)
print(run_ids)
Or export each result type separately:
export_ac_opf_result_to_sqlite(...)export_dc_opf_result_to_sqlite(...)export_lindistflow_result_to_sqlite(...)
Interactive dashboards
Generate interactive Plotly HTML dashboards from the CLI:
# Generate dashboard with all four solvers
gdm-flow plot examples/models/p5r.json
# Select specific solvers
gdm-flow plot examples/models/p5r.json -s ac -s pf
# Custom output path
gdm-flow plot examples/models/p5r.json -o my_dashboard.html
Time series simulation
GDM-Flow supports time series simulation for models with time-varying load and solar profiles. Two modes are available:
QSTS (Quasi-Static Time Series)
Sequential snapshot solves at each timestep with automatic warm-starting:
from gdm.systems.distribution import DistributionSystem
from gdm_flow import run_qsts
system = DistributionSystem.from_json("model.json")
summary = run_qsts(
system,
solver="ldf", # any solver: ac, pf, dc, ldf
timestep_range=range(96), # 24 hours at 15-min resolution
db_path="qsts_results.db", # stream results to SQLite
)
print(f"Converged: {summary.num_converged}/{summary.num_timesteps}")
Multi-Period OPF
Joint optimization across the time horizon with battery SOC coupling:
from gdm_flow import solve_multiperiod_dc_opf
from gdm_flow.dc_opf import build_dc_generators_from_components
generators = build_dc_generators_from_components(system)
result = solve_multiperiod_dc_opf(
system,
generators=generators,
timestep_range=range(96),
ramp_limit_w=5000.0,
db_path="multiperiod.db",
)
print(f"Objective: {result.objective:.2f}")
CLI commands
# Check available time series
gdm-flow ts-info model.json
# QSTS simulation
gdm-flow qsts model.json --solver ldf --end 96 --db results.db
# Multi-period DC OPF
gdm-flow multiperiod model.json --solver dc --end 96 --ramp 5000 --db results.db
# Plot time series results
gdm-flow plot-ts results.db -o timeseries.html
The dashboard includes:
- Voltage-distance profiles along feeder paths
- Per-phase voltage comparison across solvers
- Branch power flow and loading analysis
- Line loss breakdown
- Equipment state (capacitors, regulators, transformers)
Requires the plotting extra: pip install -e '.[plotting]'
CLI export from JSON
Use the CLI to load saved result JSON files and export to SQLite in one command:
gdm-flow-export --db results.sqlite --ac-json ac_result.json --dc-json dc_result.json --lindistflow-json ldf_result.json
Generate starter JSON templates:
gdm-flow-export --write-templates ./templates
This creates:
templates/ac_result.template.jsontemplates/dc_result.template.jsontemplates/lindistflow_result.template.json
Expected JSON fields:
- AC JSON:
success,message,iterations,initial_objective,final_objectiveindex_to_label:[["bus", "phase"], ...]voltage:[{"real": ..., "imag": ...}, ...]power_injection:[{"real": ..., "imag": ...}, ...]
- DC JSON:
success,message,objective,iterations,slack_injection_wgenerator_dispatch_w:{name: value}theta_rad:{"bus|phase": value, ...}nodal_balance_w:{"bus|phase": value, ...}
- LinDistFlow JSON:
success,message,source_busvoltage_v,p_flow_w,q_flow_var,p_net_w,q_net_var- All series use
{"name|phase": value, ...}format.
Metadata
Release files for gdm-flow 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gdm_flow-0.5.0.tar.gz | 154.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gdm_flow-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 267.3 kB
Release files / gdm_flow-0.5.0.tar.gz
| Download URL | gdm_flow-0.5.0.tar.gz |
|---|---|
| Size | 154.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4f3690b42bdbf882f809060eccb8a183cc33948273e142cefbe843deb254141a
|
|
BLAKE2b-256 checksum How to use checksums |
0a2e9d8cd5d9a2f147c060cb2f513aed0b510525219d440d431a156ed639f86c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 10, 2026.
Transparency logRelease files / gdm_flow-0.5.0-py3-none-any.whl
| Download URL | gdm_flow-0.5.0-py3-none-any.whl |
|---|---|
| Size | 112.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
71cf7b887eaceb8426e2b57c0ab37f7b0aa5c3261444034d34b3838c08071571
|
|
BLAKE2b-256 checksum How to use checksums |
055757e231489cf048d34444819b7f1b2da701115f07bc52c9bc0c183d5adde4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 10, 2026.
Transparency log