Skip to content

Conversation

@FabianHofmann
Copy link
Collaborator

@FabianHofmann FabianHofmann commented Nov 26, 2025

Summary

Fix curtailment(), capacity(), and capex() expressions returning zero for networks with only non-extendable generators.

Closes #1316

Root Cause

The methods accessed optimization model variables directly (n.model.variables[f"{c}-{attr}"]). For non-extendable generators, this variable doesn't exist since there's nothing to optimize. The @pass_none_if_keyerror decorator caught the KeyError and returned None, resulting in zero expressions.

Solution

  • Check if the optimization variable exists before accessing it
  • Create a constant LinearExpression for non-extendable components when the variable doesn't exist
  • Use comp.fixed property and comp._operational_attrs["nom"] for cleaner, more idiomatic code
  • Removed unused nominal_attrs import

Test Plan

  • Added unit tests
  • ruff check and format pass

The curtailment(), capacity(), and capex() methods in the optimization
expressions module now correctly handle networks with only non-extendable
generators. Previously, these methods raised KeyError when accessing
optimization variables that don't exist for fixed capacities.

Uses comp.fixed property and comp._operational_attrs for cleaner code.

Closes #1316
Copy link
Contributor

@Irieo Irieo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FabianHofmann This works. I tried cases with mixed capacity (ext & non-est), things like max_hours for storage units. Don't see any issues but for an xarray warning which I mention above.

query = f"~{nominal_attrs[c]}_extendable"
capacity = capacity + n.c[c].static.query(query)["p_nom"]
costs = n.c[c].static[cost_attribute][capacity.indexes["name"]]
comp = n.c[c]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The internal convention we started is c for pypsa.Component and component as parameter name to pass any string or pypsa.Component. I think we can just also rename c: str here since this is internal. I will just adjust

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure thing, I'll do that

@lkstrp lkstrp enabled auto-merge (squash) December 3, 2025 17:03
@lkstrp lkstrp merged commit 6c46fdd into master Dec 3, 2025
21 of 22 checks passed
@lkstrp lkstrp deleted the fix-1316 branch December 3, 2025 18:04
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.

Curtailment expression returns zero for non-extendable generators

4 participants