Bug description
tools.get_path_length_to_station assigns the path-length-to-station metric inconsistently for MV vs. LV buses, so LV buses get a value that is too large (by ~2 hops) relative to MV buses.
For MV buses the value is the number of edges (hops) to the MV station:
path = nx.shortest_path(graph, source=mv_station, target=bus)
edisgo_obj.topology.buses_df.at[bus, "path_length_to_station"] = len(path) - 1
For LV buses, however, the value is the sum of node counts of the two paths, not edges:
lv_path = nx.shortest_path(lv_graph, source=lv_station, target=bus)
edisgo_obj.topology.buses_df.at[bus, "path_length_to_station"] = (
len(path) + len(lv_path)
)
nx.shortest_path returns the list of nodes, so len(path) is edges + 1. To stay consistent with the edge-count metric used for MV buses, the LV-bus value should be edge-based, e.g.
# edges MV-station -> BusBar_MV : len(path) - 1
# edges LV-station -> LV bus : len(lv_path) - 1
# (+ 1 if the MV/LV transformer hop should be counted)
(len(path) - 1) + (len(lv_path) - 1) # + 1 for the transformer hop, if intended
As written, every LV bus is reported ~2 hops farther from the station than it really is (relative to the MV-bus convention). Note path itself is correct here — it is the MV path to the BusBar_..._MV that is exactly this LV grid's connection point, so reusing it across the inner LV loop is intended; only the node-vs-edge counting is wrong.
Location
edisgo/tools/tools.py:488-503 — get_path_length_to_station
Impact
Any consumer of path_length_to_station that compares or sorts MV and LV buses together (feeder / reinforcement distance logic) gets a skewed distance for LV buses. Pure within-LV-grid comparisons keep the right ordering but the wrong offset.
Minor / readability
The inner loop reuses the variable name bus, shadowing the outer loop variable. It does not cause a logic bug (the outer for reassigns bus on the next iteration) but is confusing — consider lv_bus.
Notes
Found during the codebase-wide performance audit (follow-up to EPIC 2, #671). Reported separately and not fixed inline to keep the performance refactors output-identical, per project policy. A perf refactor of this same function (replace the per-bus nx.shortest_path with a single nx.shortest_path_length) is tracked in the performance follow-up issue; the fix there must preserve whatever metric is decided here.
Bug description
tools.get_path_length_to_stationassigns the path-length-to-station metric inconsistently for MV vs. LV buses, so LV buses get a value that is too large (by ~2 hops) relative to MV buses.For MV buses the value is the number of edges (hops) to the MV station:
For LV buses, however, the value is the sum of node counts of the two paths, not edges:
nx.shortest_pathreturns the list of nodes, solen(path)isedges + 1. To stay consistent with the edge-count metric used for MV buses, the LV-bus value should be edge-based, e.g.As written, every LV bus is reported ~2 hops farther from the station than it really is (relative to the MV-bus convention). Note
pathitself is correct here — it is the MV path to theBusBar_..._MVthat is exactly this LV grid's connection point, so reusing it across the inner LV loop is intended; only the node-vs-edge counting is wrong.Location
edisgo/tools/tools.py:488-503—get_path_length_to_stationImpact
Any consumer of
path_length_to_stationthat compares or sorts MV and LV buses together (feeder / reinforcement distance logic) gets a skewed distance for LV buses. Pure within-LV-grid comparisons keep the right ordering but the wrong offset.Minor / readability
The inner loop reuses the variable name
bus, shadowing the outer loop variable. It does not cause a logic bug (the outerforreassignsbuson the next iteration) but is confusing — considerlv_bus.Notes
Found during the codebase-wide performance audit (follow-up to EPIC 2, #671). Reported separately and not fixed inline to keep the performance refactors output-identical, per project policy. A perf refactor of this same function (replace the per-bus
nx.shortest_pathwith a singlenx.shortest_path_length) is tracked in the performance follow-up issue; the fix there must preserve whatever metric is decided here.