Version 0.8.0#
Interactive UI Studio and REST API#
SHIFT now includes an integrated FastAPI-based UI service and browser studio for interactive feeder design.
Highlights
New
shift-ui-serverentrypoint for launching the UI service.New optional dependency group:
pip install -e ".[ui]".Interactive map workflow for source selection and spatial context.
Configurable network presets and routing/secondary strategy overrides.
Side-by-side strategy comparison endpoint and UI controls.
Mapper, system build, and export endpoints exposed for guided end-to-end workflows.
Try it
pip install -e ".[ui]"
shift-ui-server
Then open http://127.0.0.1:8000 in your browser.
Recent Feature Additions#
Version 0.7.0#
Pluggable routing strategies for primary network#
New routing_strategy parameter on PRSG and OpenStreetGraphBuilder allows selecting
the algorithm used to route the primary distribution network through the road graph:
Strategy |
Description |
|---|---|
|
Steiner tree with uniform weights (default, backward-compatible) |
|
Steiner tree with geodesic distance weights |
|
Dijkstra shortest-path tree from source |
|
MST over terminals via pairwise shortest paths |
|
Full road network as topology (no reduction) |
|
MILP cost minimization (placeholder for future solver integration) |
References:
Ali et al. (2023). Modeling synthetic power distribution network and datasets with industrial validation. Journal of Industrial Information Integration.
Trpovski et al. (2018). Synthetic Distribution Grid Generation Using Power System Planning: Case Study of Singapore. IEEE ISGT-Europe.
Caetano et al. (2026). Bayesian model-based generation of synthetic unbalanced distribution networks incorporating reliability indices. Electric Power Systems Research.
from shift import (
WeightedSteinerTreeStrategy,
)
# Example: Use weighted Steiner tree for more realistic primary routing
# builder = PRSG(
# groups=clusters,
# source_location=GeoLocation(-97.3, 32.75),
# routing_strategy=WeightedSteinerTreeStrategy(),
# )
print("Available routing strategies:")
print(" - SteinerTreeStrategy (default)")
print(" - WeightedSteinerTreeStrategy (geodesic distance weights)")
print(" - ShortestPathTreeStrategy (Dijkstra from source)")
print(" - MinimumSpanningTreeStrategy (MST over terminals)")
print(" - FullRoadGraphStrategy (full road graph, no reduction)")
print(" - CostOptimizedStrategy (MILP placeholder)")
Pluggable secondary network strategies#
New secondary_strategy parameter on PRSG allows selecting the algorithm used
to connect loads to their serving transformer:
Strategy |
Description |
|---|---|
|
Rectangular mesh + Steiner tree (default, backward-compatible) |
|
Direct star connection from transformer to loads |
|
Delaunay triangulation + MST pruning |
|
Route secondary along local roads |
|
k-NN consumer-to-transformer assignment |
References:
Ali et al. (2023). Hub-line algorithm for consumer-to-transformer assignment.
Bidel et al. (2021). Synthetic Distribution Grid Generation Based on High Resolution Spatial Data. IEEE EEEIC.
Shahraeini (2023). An Algorithm for Generating Synthetic Distribution Grids based on Erdős–Rényi Random Graph Model. IEEE SGC.
# Example: Combine weighted primary + radial secondary
# builder = PRSG(
# groups=clusters,
# source_location=GeoLocation(-97.3, 32.75),
# routing_strategy=WeightedSteinerTreeStrategy(),
# secondary_strategy=RadialStrategy(),
# )
print("Available secondary strategies:")
print(" - MeshSteinerStrategy (default)")
print(" - RadialStrategy (star topology)")
print(" - DelaunayStrategy (organic layout)")
print(" - OpenStreetSecondaryStrategy (road-aware)")
print(" - HubLineStrategy (k-NN assignment)")
Custom weight functions#
WeightedSteinerTreeStrategy and ShortestPathTreeStrategy accept an optional
weight_fn callback for custom edge weighting. This enables domain-specific
routing policies such as:
Penalizing road crossings
Applying distance-zone penalties (Caetano et al. 2026)
Super-linear distance costs
Terrain-aware routing
from shift.utils.split_network_edges import get_distance_between_points
from shift.data_model import GeoLocation
def penalized_weight(graph, u, v):
"""Super-linear distance penalty — discourages long edges."""
dist = (
get_distance_between_points(
GeoLocation(graph.nodes[u]["x"], graph.nodes[u]["y"]),
GeoLocation(graph.nodes[v]["x"], graph.nodes[v]["y"]),
)
.to("m")
.magnitude
)
return dist**1.5
strategy = WeightedSteinerTreeStrategy(weight_fn=penalized_weight)
print(f"Strategy: {strategy.__class__.__name__}")
print(f"Weight function: {strategy.weight_fn.__name__}")
Road network reduce_to_mst parameter#
The get_road_network() function now accepts a reduce_to_mst parameter
(default True). Set to False to retrieve the full road network graph
without minimum spanning tree reduction — useful with FullRoadGraphStrategy.
# Default: returns MST of road network
# mst_graph = get_road_network("Fort Worth, TX", Distance(500, "m"))
# New: get full road network (more edges, may contain cycles)
# full_graph = get_road_network("Fort Worth, TX", Distance(500, "m"), reduce_to_mst=False)
print("get_road_network() signature:")
print(" get_road_network(location, max_distance=500m, reduce_to_mst=True)")
print()
print(" reduce_to_mst=True → MST of undirected road graph (original behavior)")
print(" reduce_to_mst=False → Full undirected road graph (for FullRoadGraphStrategy)")
Version 0.6.3#
Dependency update#
Updated
grid-data-modelsdependency to v2.3.7.
MCP Server#
Added Model Context Protocol (MCP) server for AI-assisted distribution modeling.
Supports graph construction, equipment mapping, and system building via tool calls.
Jupyter Book documentation#
Migrated documentation from Sphinx conf.py to Jupyter Book format.
Added interactive example notebook.