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-server entrypoint 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

SteinerTreeStrategy

Steiner tree with uniform weights (default, backward-compatible)

WeightedSteinerTreeStrategy

Steiner tree with geodesic distance weights

ShortestPathTreeStrategy

Dijkstra shortest-path tree from source

MinimumSpanningTreeStrategy

MST over terminals via pairwise shortest paths

FullRoadGraphStrategy

Full road network as topology (no reduction)

CostOptimizedStrategy

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

MeshSteinerStrategy

Rectangular mesh + Steiner tree (default, backward-compatible)

RadialStrategy

Direct star connection from transformer to loads

DelaunayStrategy

Delaunay triangulation + MST pruning

OpenStreetSecondaryStrategy

Route secondary along local roads

HubLineStrategy

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-models dependency 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.