Skip to content

Add check for turning off transmission expnasion if limit reached#952

Merged
fneum merged 2 commits intoPyPSA:masterfrom
koen-vg:transmission-expansion-limit-reached
Mar 11, 2024
Merged

Add check for turning off transmission expnasion if limit reached#952
fneum merged 2 commits intoPyPSA:masterfrom
koen-vg:transmission-expansion-limit-reached

Conversation

@koen-vg
Copy link
Copy Markdown
Contributor

@koen-vg koen-vg commented Feb 28, 2024

Changes proposed in this Pull Request

I recently ran into an issue with myopic optimisations where if the transmission expansion limit has been reached in one time horizon, this could run into model infeasibility when solving at the next time horizon. What happened was that the minimum transmission network capacity given by s_nom_min and p_nom_min combined equalled the global limit set in n.global_constraints up to 12 significant digits. But with the lower limit through *_nom_min so close to the upper limit given by the global constraint, the model ran into numerical problems and was declared infeasible.

I think the "morally correct" approach is to check of transmission is already at the limit, and if so, fix the capacities at those given by *_nom_min, make them non-extendable and remove the global limit. That's what I've implemented in this PR.

The implementation seems to be working fine on my side, though I haven't gotten around to testing it yet for the volume limit, only the cost limit. However, do let me know if anyone can think of any potential issues or better ways of dealing with this.

Checklist

  • I tested my contribution locally and it seems to work fine.
  • Code and workflow changes are sufficiently documented.
  • Changed dependencies are added to envs/environment.yaml.
  • Changes in configuration options are added in all of config.default.yaml.
  • Changes in configuration options are also documented in doc/configtables/*.csv.
  • A release note doc/release_notes.rst is added.

@fneum
Copy link
Copy Markdown
Member

fneum commented Mar 5, 2024

Sounds familiar. We also came across this issue for the volume limit recently and fixed it very similarly in add_brownfield.py.

def disable_grid_expansion_if_LV_limit_hit(n):
if "lv_limit" not in n.global_constraints.index:
return
total_expansion = (
n.lines.eval("s_nom_min * length").sum()
+ n.links.query("carrier == 'DC'").eval("p_nom_min * length").sum()
).sum()
lv_limit = n.global_constraints.at["lv_limit", "constant"]
# allow small numerical differences
if lv_limit - total_expansion < 1:
logger.info("LV is already reached, disabling expansion and LV limit")
extendable_acs = n.lines.query("s_nom_extendable").index
n.lines.loc[extendable_acs, "s_nom_extendable"] = False
n.lines.loc[extendable_acs, "s_nom"] = n.lines.loc[extendable_acs, "s_nom_min"]
extendable_dcs = n.links.query("carrier == 'DC' and p_nom_extendable").index
n.links.loc[extendable_dcs, "p_nom_extendable"] = False
n.links.loc[extendable_dcs, "p_nom"] = n.links.loc[extendable_dcs, "p_nom_min"]
n.global_constraints.drop("lv_limit", inplace=True)

I think this is the slightly better place to handle this since it only affects the myopic optimization.

Maybe you can expand this function to also cover the cost limit case? It should just be adding a "capital_cost * " prefix to the calculation if I am not wrong. What I liked about your PR is that it goes by global constraint type, not just the index name.

@koen-vg koen-vg force-pushed the transmission-expansion-limit-reached branch from 3ffcab3 to 61e4123 Compare March 7, 2024 08:28
@koen-vg
Copy link
Copy Markdown
Contributor Author

koen-vg commented Mar 7, 2024

Right, somehow I missed that this already existed but just for the volume limit! I've just force-pushed a sort of combination; you can see if you like it. Probably the for loop over global constraints of a particular type is slightly unnecessary but I don't think it hurts just in case. I think when checking where two things are numerically "close" it's better to normalise first so that this works for models of different scales.

@fneum fneum merged commit 0a0a35e into PyPSA:master Mar 11, 2024
thogin added a commit to thogin/pypsa-eur that referenced this pull request Mar 6, 2026
…ibility

When brownfield carries forward s_nom_opt from a previous horizon as
s_nom_min, solver floating-point tolerance can make s_nom_min exceed
s_nom_max by a tiny amount (e.g., 0.00013 MW on a 33,585 MW line).
This creates an infeasible constraint that crashes the solver.

Extends the fix from PRs PyPSA#840 and PyPSA#952 (which handle global transmission
constraints) to also cover per-line s_nom_max and DC link p_nom_max.
lkstrp added a commit that referenced this pull request Mar 25, 2026
…ibility (#2115)

* fix: clamp s/p_nom_max in brownfield to prevent floating-point infeasibility

When brownfield carries forward s_nom_opt from a previous horizon as
s_nom_min, solver floating-point tolerance can make s_nom_min exceed
s_nom_max by a tiny amount (e.g., 0.00013 MW on a 33,585 MW line).
This creates an infeasible constraint that crashes the solver.

Extends the fix from PRs #840 and #952 (which handle global transmission
constraints) to also cover per-line s_nom_max and DC link p_nom_max.

* fix: clip H2/gas retrofit remaining capacity to non-negative

When barrier solutions without crossover produce slightly imprecise
p_nom_opt values, the already-retrofitted H2 pipeline capacity can
marginally exceed the original pipe capacity. This makes
remaining_capacity negative, setting p_nom_max < p_nom_min = 0,
which causes infeasibility at the next planning horizon.

Observed on 115-cluster myopic runs with BarConvTol=1e-4:
  H2 pipeline retrofitted ES2 7 -> FR2 1: p_nom_max = -0.000649 MW
  H2 pipeline retrofitted GB1 3 -> GB1 7: p_nom_max = -0.000169 MW

Apply the same clip(lower=0) pattern used for AC lines and DC links.

---------

Co-authored-by: Fabian Neumann <[email protected]>
Co-authored-by: Lukas Trippe <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants