gdm-flow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. gdm_flow-0.1.0/PKG-INFO +389 -0
  2. gdm_flow-0.1.0/README.md +363 -0
  3. gdm_flow-0.1.0/pyproject.toml +46 -0
  4. gdm_flow-0.1.0/setup.cfg +4 -0
  5. gdm_flow-0.1.0/src/gdm_flow/__init__.py +102 -0
  6. gdm_flow-0.1.0/src/gdm_flow/_utils.py +20 -0
  7. gdm_flow-0.1.0/src/gdm_flow/ac_opf.py +994 -0
  8. gdm_flow-0.1.0/src/gdm_flow/ac_pf.py +414 -0
  9. gdm_flow-0.1.0/src/gdm_flow/cli.py +1895 -0
  10. gdm_flow-0.1.0/src/gdm_flow/dashboard.py +1916 -0
  11. gdm_flow-0.1.0/src/gdm_flow/dc_opf.py +532 -0
  12. gdm_flow-0.1.0/src/gdm_flow/export_cli.py +241 -0
  13. gdm_flow-0.1.0/src/gdm_flow/lindistflow.py +540 -0
  14. gdm_flow-0.1.0/src/gdm_flow/mcp/__init__.py +9 -0
  15. gdm_flow-0.1.0/src/gdm_flow/mcp/server.py +844 -0
  16. gdm_flow-0.1.0/src/gdm_flow/multiperiod.py +1017 -0
  17. gdm_flow-0.1.0/src/gdm_flow/sqlite_export.py +1065 -0
  18. gdm_flow-0.1.0/src/gdm_flow/time_series.py +1033 -0
  19. gdm_flow-0.1.0/src/gdm_flow/ybus.py +432 -0
  20. gdm_flow-0.1.0/src/gdm_flow.egg-info/PKG-INFO +389 -0
  21. gdm_flow-0.1.0/src/gdm_flow.egg-info/SOURCES.txt +40 -0
  22. gdm_flow-0.1.0/src/gdm_flow.egg-info/dependency_links.txt +1 -0
  23. gdm_flow-0.1.0/src/gdm_flow.egg-info/entry_points.txt +4 -0
  24. gdm_flow-0.1.0/src/gdm_flow.egg-info/requires.txt +22 -0
  25. gdm_flow-0.1.0/src/gdm_flow.egg-info/top_level.txt +1 -0
  26. gdm_flow-0.1.0/tests/test_ac_opf_additional.py +238 -0
  27. gdm_flow-0.1.0/tests/test_cli.py +1350 -0
  28. gdm_flow-0.1.0/tests/test_component_specs.py +152 -0
  29. gdm_flow-0.1.0/tests/test_dc_opf.py +68 -0
  30. gdm_flow-0.1.0/tests/test_dc_opf_additional.py +244 -0
  31. gdm_flow-0.1.0/tests/test_export_cli.py +101 -0
  32. gdm_flow-0.1.0/tests/test_export_cli_additional.py +154 -0
  33. gdm_flow-0.1.0/tests/test_gdmloader_integration.py +27 -0
  34. gdm_flow-0.1.0/tests/test_lindistflow.py +60 -0
  35. gdm_flow-0.1.0/tests/test_lindistflow_additional.py +296 -0
  36. gdm_flow-0.1.0/tests/test_mcp_server.py +100 -0
  37. gdm_flow-0.1.0/tests/test_multiperiod.py +262 -0
  38. gdm_flow-0.1.0/tests/test_optimization.py +38 -0
  39. gdm_flow-0.1.0/tests/test_sqlite_export.py +311 -0
  40. gdm_flow-0.1.0/tests/test_time_series.py +271 -0
  41. gdm_flow-0.1.0/tests/test_ybus.py +221 -0
  42. gdm_flow-0.1.0/tests/test_ybus_additional.py +168 -0
@@ -0,0 +1,389 @@
1
+ Metadata-Version: 2.4
2
+ Name: gdm-flow
3
+ Version: 0.1.0
4
+ Summary: Power flow utilities for grid-data-models distribution systems
5
+ Author: NLR Distribution Suite
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: numpy>=1.24
10
+ Requires-Dist: grid-data-models>=2.3.6
11
+ Requires-Dist: typer>=0.9
12
+ Requires-Dist: rich>=13.0
13
+ Provides-Extra: sparse
14
+ Requires-Dist: scipy>=1.10; extra == "sparse"
15
+ Provides-Extra: optimization
16
+ Requires-Dist: scipy>=1.10; extra == "optimization"
17
+ Provides-Extra: plotting
18
+ Requires-Dist: plotly>=5.0; extra == "plotting"
19
+ Provides-Extra: mcp
20
+ Requires-Dist: mcp>=1.0.0; extra == "mcp"
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8.0; extra == "dev"
23
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
24
+ Requires-Dist: pre-commit>=3.7; extra == "dev"
25
+ Requires-Dist: ruff>=0.6; extra == "dev"
26
+
27
+ # gdm-flow
28
+
29
+ [![CI](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/ci.yml/badge.svg)](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/ci.yml) • [![Docs](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/docs.yml/badge.svg)](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/docs.yml) • [![Publish](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/publish.yml/badge.svg)](https://github.com/NLR-Distribution-Suite/gdm_flow/actions/workflows/publish.yml) • [![codecov](https://codecov.io/github/NLR-Distribution-Suite/gdm_flow/branch/main/graph/badge.svg)](https://codecov.io/github/NLR-Distribution-Suite/gdm_flow) • ![MCP Server](https://img.shields.io/badge/MCP_Server-enabled-brightgreen) • ![MCP Tools](https://img.shields.io/badge/MCP_Tools-11-blue) • [![GitHub issues](https://img.shields.io/github/issues/NLR-Distribution-Suite/gdm_flow)](https://github.com/NLR-Distribution-Suite/gdm_flow/issues)
30
+
31
+ Utilities for OPF and power-flow style preprocessing on top of
32
+ `grid-data-models` distribution systems.
33
+
34
+ ## Current features
35
+
36
+ - **Y-Bus Construction** — Phase-domain admittance matrices from GDM components (branches, transformers, switches) with matrix and sequence impedance support
37
+ - **Four Solvers** — AC OPF (nonlinear least-squares), AC PF (Newton-Raphson power flow), DC OPF (quadratic programming), and LinDistFlow (backward/forward sweep)
38
+ - **Multi-Phase Support** — Full three-phase and split-phase (center-tapped transformer) modeling
39
+ - **Component Integration** — Direct integration with GDM loads, solar PV, batteries, capacitors, and regulators
40
+ - **Interactive Dashboards** — Plotly-based HTML dashboards with voltage profiles, power flow, branch loading, losses, and equipment state
41
+ - **QSTS Simulation** — Quasi-static time series with warm-starting across timesteps for any solver
42
+ - **Multi-Period OPF** — Joint optimization across a time horizon with battery SOC coupling and ramp constraints (DC OPF and LinDistFlow)
43
+ - **Time Series Discovery** — Inspect available load, solar, and battery time series profiles in GDM models
44
+ - **Modern CLI** — Rich terminal interface with `info`, `run`, `compare`, `plot`, `export`, `ts-info`, `qsts`, `multiperiod`, `plot-ts`, and reporting commands
45
+ - **SQLite Export** — Structured database output with voltage/loading limit tracking, violation reporting, and streaming time series results
46
+ - **MCP Server** — Model Context Protocol server exposing all solvers as AI-callable tools
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install -e .
52
+ ```
53
+
54
+ If you also want sparse matrix return support:
55
+
56
+ ```bash
57
+ pip install -e .[sparse]
58
+ ```
59
+
60
+ If you want optimization support:
61
+
62
+ ```bash
63
+ pip install -e '.[optimization]'
64
+ ```
65
+
66
+ If you want interactive plotting dashboards:
67
+
68
+ ```bash
69
+ pip install -e '.[plotting]'
70
+ ```
71
+
72
+ If you want to run the MCP server:
73
+
74
+ ```bash
75
+ pip install -e '.[mcp,optimization]'
76
+ gdm-flow-mcp-server
77
+ ```
78
+
79
+ ## Development checks
80
+
81
+ Install development dependencies and enable pre-commit hooks:
82
+
83
+ ```bash
84
+ pip install -e '.[dev]'
85
+ pre-commit install
86
+ ```
87
+
88
+ Run the same lint checks used in CI:
89
+
90
+ ```bash
91
+ pre-commit run --all-files
92
+ ```
93
+
94
+ ## Examples
95
+
96
+ An end-to-end examples folder is included at `examples/` with a downloaded demo
97
+ distribution model and runnable scripts for each optimization flavor:
98
+
99
+ - `examples/models/p5r.json`
100
+ - `examples/run_ac_opf_example.py`
101
+ - `examples/run_dc_opf_example.py`
102
+ - `examples/run_lindistflow_example.py`
103
+ - `examples/compare_plotly_results.py` — interactive Plotly comparison across all solvers
104
+
105
+ Run from the repository root:
106
+
107
+ ```bash
108
+ python examples/run_ac_opf_example.py
109
+ python examples/run_dc_opf_example.py
110
+ python examples/run_lindistflow_example.py
111
+ python examples/compare_plotly_results.py
112
+ ```
113
+
114
+ ## Usage
115
+
116
+ ```python
117
+ from gdm.distribution import DistributionSystem
118
+ from gdm_flow import calculate_ybus
119
+
120
+ system = DistributionSystem.from_json("path/to/system.json")
121
+ result = calculate_ybus(system, include_shunt=False)
122
+
123
+ Y = result.ybus
124
+ labels = result.index_to_label
125
+ ```
126
+
127
+ `labels[k]` is a `(bus_name, phase)` tuple for row/column `k` of `Y`.
128
+
129
+ ## Optimization usage
130
+
131
+ ```python
132
+ from gdm.distribution import DistributionSystem
133
+ from gdm_flow import optimize_ac_power_flow
134
+
135
+ system = DistributionSystem.from_json("path/to/system.json")
136
+
137
+ # Specify net nodal injections in SI units: +generation, -load
138
+ p_spec_w = {("bus_5", "A"): -20_000.0, ("bus_5", "B"): -20_000.0, ("bus_5", "C"): -20_000.0}
139
+ q_spec_var = {("bus_5", "A"): -5_000.0, ("bus_5", "B"): -5_000.0, ("bus_5", "C"): -5_000.0}
140
+
141
+ result = optimize_ac_power_flow(
142
+ system,
143
+ p_spec_w=p_spec_w,
144
+ q_spec_var=q_spec_var,
145
+ )
146
+
147
+ print(result.success, result.final_objective)
148
+ ```
149
+
150
+ ### Auto-build specs from components
151
+
152
+ If your model already contains `DistributionLoad` and `DistributionSolar` components,
153
+ you can build nodal injections automatically:
154
+
155
+ ```python
156
+ from gdm.distribution import DistributionSystem
157
+ from gdm_flow import optimize_ac_power_flow_from_components
158
+
159
+ system = DistributionSystem.from_json("path/to/system.json")
160
+
161
+ result = optimize_ac_power_flow_from_components(
162
+ system,
163
+ include_loads=True,
164
+ include_solar=True,
165
+ include_capacitor=True,
166
+ include_battery=False,
167
+ include_regulator_targets=True,
168
+ include_regulator_limits=True,
169
+ )
170
+
171
+ print(result.success, result.final_objective)
172
+ ```
173
+
174
+ Notes:
175
+
176
+ - `include_capacitor=True` adds capacitor reactive injections into nodal `Q` specs.
177
+ - `include_regulator_targets=True` adds soft voltage-target constraints derived from regulator controllers.
178
+ - `include_regulator_limits=True` adds hard voltage magnitude bounds from regulator min/max limits.
179
+
180
+ ## AC Power Flow (Newton-Raphson)
181
+
182
+ `gdm-flow` includes a classical Newton-Raphson AC power flow solver. Unlike the AC OPF
183
+ which *optimises* voltage magnitudes within bounds, the AC PF solves for exact bus
184
+ voltages given fixed P/Q injections and a slack bus:
185
+
186
+ ```python
187
+ from gdm.distribution import DistributionSystem
188
+ from gdm_flow import solve_ac_power_flow_from_components
189
+
190
+ system = DistributionSystem.from_json("path/to/system.json")
191
+
192
+ result = solve_ac_power_flow_from_components(
193
+ system,
194
+ include_loads=True,
195
+ include_solar=True,
196
+ include_capacitor=True,
197
+ )
198
+
199
+ print(result.success, result.iterations)
200
+ print(result.max_mismatch_pu) # convergence metric
201
+ print(result.voltage_pu) # per-unit voltage magnitudes
202
+ ```
203
+
204
+ The solver uses sparse LU factorisation with a damped update and LinDistFlow warm-start
205
+ for robust convergence on heavily loaded feeders.
206
+
207
+ ## DC OPF module
208
+
209
+ `gdm-flow` also includes a separate DC OPF module:
210
+
211
+ ```python
212
+ from gdm.distribution import DistributionSystem
213
+ from gdm_flow import solve_dc_opf_from_components
214
+
215
+ system = DistributionSystem.from_json("path/to/system.json")
216
+
217
+ result = solve_dc_opf_from_components(
218
+ system,
219
+ include_solar_generators=True,
220
+ include_battery_generators=True,
221
+ include_loads=True,
222
+ )
223
+
224
+ print(result.success, result.objective)
225
+ print(result.generator_dispatch_w)
226
+ ```
227
+
228
+ ## LinDistFlow module
229
+
230
+ `gdm-flow` includes a separate radial LinDistFlow approximation module:
231
+
232
+ ```python
233
+ from gdm.distribution import DistributionSystem
234
+ from gdm_flow import solve_lindistflow
235
+
236
+ system = DistributionSystem.from_json("path/to/system.json")
237
+
238
+ result = solve_lindistflow(system)
239
+
240
+ print(result.success)
241
+ print(result.voltage_v) # {(bus, phase): voltage_in_volts}
242
+ print(result.p_flow_w) # {(branch_name, phase): active_flow_w}
243
+ ```
244
+
245
+ ## SQLite export module
246
+
247
+ You can export results from AC OPF, DC OPF, and LinDistFlow into one SQLite database:
248
+
249
+ ```python
250
+ from gdm_flow import export_all_results_to_sqlite
251
+
252
+ run_ids = export_all_results_to_sqlite(
253
+ "results.sqlite",
254
+ ac_result=ac_result,
255
+ dc_result=dc_result,
256
+ lindistflow_result=lindistflow_result,
257
+ )
258
+
259
+ print(run_ids)
260
+ ```
261
+
262
+ Or export each result type separately:
263
+
264
+ - `export_ac_opf_result_to_sqlite(...)`
265
+ - `export_dc_opf_result_to_sqlite(...)`
266
+ - `export_lindistflow_result_to_sqlite(...)`
267
+
268
+ ## Interactive dashboards
269
+
270
+ Generate interactive Plotly HTML dashboards from the CLI:
271
+
272
+ ```bash
273
+ # Generate dashboard with all four solvers
274
+ gdm-flow plot examples/models/p5r.json
275
+
276
+ # Select specific solvers
277
+ gdm-flow plot examples/models/p5r.json -s ac -s pf
278
+
279
+ # Custom output path
280
+ gdm-flow plot examples/models/p5r.json -o my_dashboard.html
281
+ ```
282
+
283
+ ## Time series simulation
284
+
285
+ GDM-Flow supports time series simulation for models with time-varying load and solar
286
+ profiles. Two modes are available:
287
+
288
+ ### QSTS (Quasi-Static Time Series)
289
+
290
+ Sequential snapshot solves at each timestep with automatic warm-starting:
291
+
292
+ ```python
293
+ from gdm.distribution import DistributionSystem
294
+ from gdm_flow import run_qsts
295
+
296
+ system = DistributionSystem.from_json("model.json")
297
+
298
+ summary = run_qsts(
299
+ system,
300
+ solver="ldf", # any solver: ac, pf, dc, ldf
301
+ timestep_range=range(96), # 24 hours at 15-min resolution
302
+ db_path="qsts_results.db", # stream results to SQLite
303
+ )
304
+
305
+ print(f"Converged: {summary.num_converged}/{summary.num_timesteps}")
306
+ ```
307
+
308
+ ### Multi-Period OPF
309
+
310
+ Joint optimization across the time horizon with battery SOC coupling:
311
+
312
+ ```python
313
+ from gdm_flow import solve_multiperiod_dc_opf
314
+ from gdm_flow.dc_opf import build_dc_generators_from_components
315
+
316
+ generators = build_dc_generators_from_components(system)
317
+
318
+ result = solve_multiperiod_dc_opf(
319
+ system,
320
+ generators=generators,
321
+ timestep_range=range(96),
322
+ ramp_limit_w=5000.0,
323
+ db_path="multiperiod.db",
324
+ )
325
+
326
+ print(f"Objective: {result.objective:.2f}")
327
+ ```
328
+
329
+ ### CLI commands
330
+
331
+ ```bash
332
+ # Check available time series
333
+ gdm-flow ts-info model.json
334
+
335
+ # QSTS simulation
336
+ gdm-flow qsts model.json --solver ldf --end 96 --db results.db
337
+
338
+ # Multi-period DC OPF
339
+ gdm-flow multiperiod model.json --solver dc --end 96 --ramp 5000 --db results.db
340
+
341
+ # Plot time series results
342
+ gdm-flow plot-ts results.db -o timeseries.html
343
+ ```
344
+
345
+ The dashboard includes:
346
+ - Voltage-distance profiles along feeder paths
347
+ - Per-phase voltage comparison across solvers
348
+ - Branch power flow and loading analysis
349
+ - Line loss breakdown
350
+ - Equipment state (capacitors, regulators, transformers)
351
+
352
+ Requires the `plotting` extra: `pip install -e '.[plotting]'`
353
+
354
+ ### CLI export from JSON
355
+
356
+ Use the CLI to load saved result JSON files and export to SQLite in one command:
357
+
358
+ ```bash
359
+ gdm-flow-export --db results.sqlite --ac-json ac_result.json --dc-json dc_result.json --lindistflow-json ldf_result.json
360
+ ```
361
+
362
+ Generate starter JSON templates:
363
+
364
+ ```bash
365
+ gdm-flow-export --write-templates ./templates
366
+ ```
367
+
368
+ This creates:
369
+
370
+ - `templates/ac_result.template.json`
371
+ - `templates/dc_result.template.json`
372
+ - `templates/lindistflow_result.template.json`
373
+
374
+ Expected JSON fields:
375
+
376
+ - AC JSON:
377
+ - `success`, `message`, `iterations`, `initial_objective`, `final_objective`
378
+ - `index_to_label`: `[["bus", "phase"], ...]`
379
+ - `voltage`: `[{"real": ..., "imag": ...}, ...]`
380
+ - `power_injection`: `[{"real": ..., "imag": ...}, ...]`
381
+ - DC JSON:
382
+ - `success`, `message`, `objective`, `iterations`, `slack_injection_w`
383
+ - `generator_dispatch_w`: `{name: value}`
384
+ - `theta_rad`: `{"bus|phase": value, ...}`
385
+ - `nodal_balance_w`: `{"bus|phase": value, ...}`
386
+ - LinDistFlow JSON:
387
+ - `success`, `message`, `source_bus`
388
+ - `voltage_v`, `p_flow_w`, `q_flow_var`, `p_net_w`, `q_net_var`
389
+ - All series use `{"name|phase": value, ...}` format.