This notebook runs all three GDM-Flow solvers on the same system and produces interactive Plotly plots to compare results.
from gdm.distribution import DistributionSystem
system = DistributionSystem.from_json("../examples/models/p5r.json")Run All Solvers¶
from gdm_flow import (
optimize_ac_power_flow_from_components,
solve_dc_opf_from_components,
solve_lindistflow,
)
ac = optimize_ac_power_flow_from_components(
system,
include_loads=True,
include_solar=True,
include_capacitor=True,
)
dc = solve_dc_opf_from_components(
system,
include_solar_generators=True,
include_battery_generators=True,
include_loads=True,
)
ldf = solve_lindistflow(system)
print(f"AC OPF: success={ac.success}")
print(f"DC OPF: success={dc.success}")
print(f"LinDistFlow: success={ldf.success}")Source Power Comparison¶
import numpy as np
# AC source power
src_bus = system.get_source_bus().name
idx_map = ac.ybus_result.index_to_label
v = ac.voltage
ybus = ac.ybus_result.ybus
s = v * np.conj(ybus @ v)
src_idx = [i for i, lbl in enumerate(idx_map) if lbl[0] == src_bus]
ac_source_p = sum(s[i].real for i in src_idx)
# DC source power (grid generators only)
dc_source_p = sum(
v for k, v in dc.generator_dispatch_w.items() if k.startswith("grid:")
)
# LDF source power
ldf_source_p = sum(ldf.p_net_w.values())
print(f"AC source P: {ac_source_p:.1f} W")
print(f"DC source P: {dc_source_p:.1f} W")
print(f"LDF source P: {ldf_source_p:.1f} W")
print(
f"Max disagreement: {max(ac_source_p, dc_source_p, ldf_source_p) - min(ac_source_p, dc_source_p, ldf_source_p):.1f} W"
)Voltage Profile Plot¶
import plotly.graph_objects as go
# Extract bus voltages from AC
ac_buses = {}
for i, (bus, phase) in enumerate(idx_map):
key = f"{bus}/{phase}"
ac_buses[key] = abs(v[i])
# Extract bus voltages from LDF
ldf_buses = {f"{bus}/{phase}": volt for (bus, phase), volt in ldf.voltage_v.items()}
# Common bus list
common = sorted(set(ac_buses) & set(ldf_buses))
fig = go.Figure()
fig.add_trace(go.Bar(name="AC OPF", x=common, y=[ac_buses[b] for b in common]))
fig.add_trace(go.Bar(name="LinDistFlow", x=common, y=[ldf_buses[b] for b in common]))
fig.update_layout(
title="Voltage Profile Comparison (AC vs LinDistFlow)",
xaxis_title="Bus / Phase",
yaxis_title="Voltage (V)",
barmode="group",
height=500,
)
fig.show()DC OPF Dispatch Breakdown¶
# Categorize generators
categories = {"Grid": 0, "Solar": 0, "Battery": 0}
for name, dispatch in dc.generator_dispatch_w.items():
if name.startswith("grid:"):
categories["Grid"] += dispatch
elif name.startswith("solar:"):
categories["Solar"] += dispatch
elif name.startswith("battery:"):
categories["Battery"] += dispatch
fig = go.Figure(
go.Pie(
labels=list(categories.keys()),
values=list(categories.values()),
hole=0.4,
textinfo="label+value",
texttemplate="%{label}<br>%{value:.0f} W",
)
)
fig.update_layout(title="DC OPF Generation Dispatch", height=400)
fig.show()