Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Capacity Adequacy B (planned maintenance) constraint so that annual planned-maintenance availability (AvailabilityFactor) no longer scales a timeslice-weighted sum of sub-annual capacity factors, aligning the implementation with the documented OSeMOSYS constraint and preventing infeasibilities when both sub-annual CF profiles and non-100% availability are provided.
Changes:
- Removes the sub-annual
CapacityFactor * YearSplitaggregation from the RHS ofCAb1_PlannedMaintenance. - Simplifies the RHS to use annual capacity (
GrossCapacity) scaled only byAvailabilityFactorandCapacityToActivityUnit.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tz/osemosys/model/constraints/capacity_adequacy_b.py:42
conis split across lines without wrapping parentheses, so line 40 starts a new (discarded) expression. As a result,cononly contains the LHS sum and the constraint comparison (<= 0) is not part of the assignment, which will break or misbuild the constraint inm.add_constraints. Wrap the full expression in parentheses so the subtraction and comparison are included incon.
con = (lex["RateOfTotalActivity"] * ds["YearSplit"]).sum(dims="TIMESLICE")
- (lex["GrossCapacity"]
* ds["AvailabilityFactor"]
* ds["CapacityToActivityUnit"]) <= 0
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tz/osemosys/model/constraints/capacity_adequacy_b.py:41
- This change alters the planned-maintenance (AvailabilityFactor) constraint semantics and fixes a known infeasibility case, but there’s no regression test exercising the combination of (a) sub-annual CapacityFactor profile and (b) AvailabilityFactor < 1. Without a solve-level test, it’s easy for future refactors to reintroduce the double-scaling bug.
Consider adding an integration test that builds a 2-timeslice model with a technology that has CapacityFactor < 1 in at least one timeslice and AvailabilityFactor < 1, and asserts the model remains feasible and that annual activity respects the AvailabilityFactor bound (i.e., LHS <= GrossCapacity * AvailabilityFactor * CapacityToActivityUnit).
mask = ds["AvailabilityFactor"] < 1
con = (lex["RateOfTotalActivity"] * ds["YearSplit"]).sum(dims="TIMESLICE") - (
lex["GrossCapacity"] * ds["AvailabilityFactor"] * ds["CapacityToActivityUnit"]
) <= 0
Resolves the conflict in capacity_adequacy_b.py: keeps this branch's RHS (sub-annual CapacityFactor removed from CAb1_PlannedMaintenance) with main's renamed linopy kwarg from #191 (.sum(dims=) -> .sum(dim=)). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Covers technology-level AvailabilityFactor, which previously had no test coverage at all (only trade-level AF was exercised). - test_availability_factor_does_not_scale_sub_annual_capacity_factor pins the behaviour this branch changes: with a CF profile averaging 0.8 and AF 0.9, annual activity reaches 10 * min(0.9, 0.8) == 8.0. Under the previous formulation the two were multiplied, capping activity at 7.2 and making it impossible for a technology to reach its own capacity factor when AF < 1. - test_availability_factor_still_binds_when_below_capacity_factor pins the other side of the min (flat CF 1.0, AF 0.6 -> 6.0), guarding against the reading that dropping CapacityFactor from CAb1 made AvailabilityFactor inert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
edwardxtg
left a comment
There was a problem hiding this comment.
thanks for this.
Just added a couple tests for this behaviour.
Description