Add crosssection_escalation: larger LV cross-section instead of cable stacking on overload (#377) - #730
Open
nader-00 wants to merge 3 commits into
Open
Add crosssection_escalation: larger LV cross-section instead of cable stacking on overload (#377)#730nader-00 wants to merge 3 commits into
crosssection_escalation: larger LV cross-section instead of cable stacking on overload (#377)#730nader-00 wants to merge 3 commits into
Conversation
reinforce_lines_overloading() currently only stacks parallel standard lines to solve overloading, which #377 flags as sometimes producing an implausibly large number of parallel cables where a larger LV cross-section would carry the same load. This adds an opt-in crosssection_escalation flag (default False): for LV lines that would otherwise need more than two parallel standard lines, select_cable() is tried first (up to two parallel cables, never below the standard cross-section), falling back to today's behaviour otherwise.
) crosssection_escalation only ever reached lines handled by _replace_by_parallel_standard_lines(); lines that were already the standard cross-section (e.g. native multi-cable ding0 lines) were scaled up via _add_parallel_standard_lines() instead, which never attempted escalation. This adds crosssection_escalation_existing (requires crosssection_escalation=True) to also cover that path, using the same >2-parallel-lines gate and select_cable() logic. Unlike the base flag, this can replace cross-sections that were part of the original input topology, not only eDisGo's own prior reinforcement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds an opt-in LV overload reinforcement measure: trying a larger cable
cross-section (up to 2 parallel cables) via
select_cable()instead offalling back to many parallel standard cables, wherever the existing
overload logic would otherwise install more than 2 parallel standard lines.
Part of the broader effort in #377 (add/improve grid reinforcement methods),
addressing the "too many parallel lines" critique directly.
Problem
reinforce_lines_overloading()today always upgrades an overloaded LV lineto the one configured standard cable type, adding as many parallel systems of
that type as needed (
ceil(apparent_power / standard_capacity)). Forsufficiently overloaded lines this results in cable stacks of 3, sometimes up
to 9, parallel standard cables — in real grids a larger cross-section would
usually be chosen instead, and it's also already what
select_cable()(anexisting, previously unused eDisGo helper) is built to do: pick the smallest
cable that carries a given apparent power at a given maximum parallel count.
Solution
crosssection_escalation: bool = Falseparameter onreinforce_grid()(and passed through
reinforce_lines_overloading()/_reinforce_lines_overloading_per_grid_level()). LV only in this PR — seeScope below.
parallel standard cables,
select_cable(..., max_cables=2)is tried first.If a cross-section up to 2 parallel cables suffices, that type/count is
used instead of the standard-type stack. If not (or if the result would
ever fall below the standard type's
I_max_th— defensively checked,should be unreachable by construction), falls back to today's behaviour
unchanged.
crosssection_escalation_existing: bool = False(requirescrosssection_escalation=True): extends the same escalation attempt to LVlines that are already the standard cross-section with more than 2
parallel systems — a separate code path
(
_add_parallel_standard_lines()), not reachable by the main flag alone(see the two-commit history / Root-cause finding below for why this needed
a second, explicit extension rather than being automatic).
equipment_changeslogging, no changes to the costcalculation — an escalated cross-section is logged exactly like today's
standard-type replacement (
equipment_changesreadstype_infolive fromthe topology after the change, independent of how that type was chosen).
crosssection_escalation_existing=False, crosssection_escalation=False(both defaults): reinforcement is bit-identical to current
dev(seeValidation below) — this PR changes no default behaviour.
Root-cause finding that shaped this PR (two commits, not one)
The first integration run (base feature only) landed only 12 of 42 known
LV cable stacks (
num_parallel > 2) at n<=2, far short of an offlineestimate of ~40/42. Root-cause diagnosis found 21 of the 30 shortfall cases
(70%) were not physics (impossible to escalate) but an architecture gap:
the escalation logic lived exclusively in
_replace_by_parallel_standard_ lines(), which a line only reaches if it is not yet the standard typeat overload-check time. Lines that were already standard type with
num_parallel > 1— as 100% of the 21 gap cases were, straight from the rawding0 input, not from any prior eDisGo decision — are handled by a
completely separate function,
_add_parallel_standard_lines(), which thebase feature never touches (confirmed structurally: it's a nested closure
only reachable from inside
_reinforce_lines_overloading_per_grid_level(),and
reinforce_lines_voltage_issues()— the voltage path — never calls itat all, so this extension cannot be reached from voltage-driven
reinforcement).
crosssection_escalation_existingcloses that gap using thesame
select_cable(max_cables=2)call and the same>2threshold, appliedto the line's current total capacity (
num_parallel_current x standard_single_capacity, which for an already-standard line is exactly itsmeasured apparent power — no under-dimensioning risk, no design choice, a
direct consequence of the data model only storing one
type_info+num_parallelper line).One notable consequence, called out explicitly: unlike the base feature
(which only ever replaces eDisGo's own, not-yet-built reinforcement
decisions),
crosssection_escalation_existingcan also replace cable stacksthat are part of the original ding0 input topology — real, already
"laid" infrastructure in the model, not a hypothetical planning decision.
The cost model treats both cases identically, but this is a conceptually
stronger intervention and is named as its own consideration here rather than
left implicit in the diff.
Cost-model caveat (must be read alongside the validation numbers below)
eDisGo's line cost model is flat:
costs_cable_lvis a single kEUR/km valuefor all LV cable types (
costs.py), multiplied only by length andquantity — never by cross-section. A cross-section upgrade at the same
parallel count therefore never costs more in this model, by construction.
The measured cost savings below are partly an artifact of the same cost-
model limitation that motivates the "too many parallel lines" critique in
#377 in the first place (no cross-section/trenching-cost differentiation).
A more realistic cost model (material cost rising with cross-section) would
likely shrink the advantage of escalation, though probably not reverse it —
trenching cost is incurred once regardless of parallel count either way
(confirmed: earthwork cost in this package is already per-line, not
per-parallel-system), and fewer parallel systems also mean fewer joints/bay
positions in practice, which the current cost model ignores entirely (to the
detriment of today's cable-stacking practice, not of this PR).
Scope
LV only for this PR. The code path (
_reinforce_lines_overloading_per_grid_ level()) is symmetric for MV and LV, but all 42 validated cable stacks areLV — there is no MV evidence from this validation. Enabling MV would be
unvalidated extrapolation.
Validation
test_reinforce_lines_overloading_crosssection_escalationandtest_reinforce_lines_overloading_crosssection_escalation_existing(new),plus all existing tests in
test_reinforce_measures.py— 8/8 passed.crosssection_escalation=False(default) confirmedbit-identical to
dev(transformers_df,topology_lines_df,equipment_changes,grid_expansion_costs, compared viapandas.testing.assert_frame_equalon the standardding0_test_network_1reinforcement scenario).
num_parallel > 2)across all 10 real test networks:
— see root-cause finding above).
crosssection_escalation_existing: 27/42 land at n<=2 — 15 ofthe 21 architecture-gap cases now succeed; the remaining 6 (plus 9 other
cases) reflect genuine impedance feedback (changing a line's type/count
shifts the load-flow distribution enough that the offline, single-pass
estimate no longer holds) rather than an escalation-logic gap. Reported
as a validation number, not asserted as a hard cost/count threshold —
the exact figure depends on grid data and would break on unrelated
config changes if hard-coded into a test.
Type of change
Checklist:
pre-commithooks