docs(examples): the PyPSA file states a constraint once where PyPSA builds one row set, rather than a block per regime - #257
Merged
Conversation
Documentation build overview
24 files changed ·
|
Contributor
Author
|
@FabianHofmann Do you want to review? I dont think its necessary. Just ping me quickly |
FBumann
force-pushed
the
feat/cases-proved-apart
branch
from
August 31, 2026 09:42
5c63589 to
427ae2f
Compare
…uilds one row set, rather than a block per regime Sixteen PyPSA names were stated by two to four blocks apiece, split by a regime the language had no way to name: the first snapshot a shift vacates, a cyclic store, an extendable build, a committed unit. `cases:` names the regime in the quantity instead, so each name is one block again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8skeF7J54HymyTZayV3Ug (cherry picked from commit 88ce831)
FBumann
force-pushed
the
feat/pypsa-cases
branch
from
August 31, 2026 09:44
88ce831 to
ecb755f
Compare
FBumann
added a commit
that referenced
this pull request
Aug 31, 2026
…uilds one row set, rather than a block per regime (#257) (#292) Sixteen PyPSA names were stated by two to four blocks apiece, split by a regime the language had no way to name: the first snapshot a shift vacates, a cyclic store, an extendable build, a committed unit. `cases:` names the regime in the quantity instead, so each name is one block again. Claude-Session: https://claude.ai/code/session_01N8skeF7J54HymyTZayV3Ug (cherry picked from commit 88ce831) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 31, 2026
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.
Note
The following content was generated by AI.
Stacked on #168 — it adds
cases:; this is the port that needed it. Both were rebased ontomainate412e0b, after #271 and #273 landed in the same file; the counts below were re-derived on that base and are unchanged.Twelve PyPSA names — sixteen, counted once per file they appear in — were stated by two to four blocks apiece, split by a regime the language could not name inside a quantity. Now each is one block, and the two examples lose 18 and 4 constraints without losing a row. That is #123's failure class — same math, different bookkeeping — closed for every name
cases:can reach.pypsa.yamlpypsa_linearized_uc.yamlThe five that remain are the GlobalConstraint sense-splits, where the split is in the operator rather than in a value.
cases:is value-level and cannot reach them; that is #239, untouched here.What replaced each split
Eight cased quantities, and the regime moves into them:
so
StorageUnit-energy_balanceis one block with nowhere:at all, where it was three.#124's opening question — "what about storages having cyclic and non cyclic?" — is that case list.The others:
Generator_previous_statusandGenerator_previous_pcarry the boundary,Generator_p_nom_effectiveandLink_p_nom_effectivecarry extendable-or-not, andGenerator_ramp_up_allowance/_down_allowancecarry committed-or-not — which is what letsGenerator-p-ramp_limit_upgo from four blocks to one.Verified
pixi run cigreen — lint, 886 tests,mkdocs build --strict, 27 compiled documents.Beyond that, the collapse is only correct if the rows did not move, so both halves were checked exhaustively against
HEADrather than argued. For each PyPSA name, its blocks'where:strings are parsed with the repo's ownparse_where, every assignment of their atoms is enumerated (× the first snapshot and any other), and a row is taken to exist where the mask holds and no term is absent — absence being a bareshift(… over=snapshot …)at the first snapshot, followed through each cased expression into the region that world selects.shift()is held as an opaque symbol, and both sides are compared as polynomials rather than as text. Every row is the row the old blocks built.Both runs
rowsets.py— the masksalgebra.py— the coefficientsWhat I could not check, and what it costs
The dual-parity gate did not run. It lives in lpspec's
differential/pypsa/, which is not in this tree and is not checked out on this machine, so nothing here compares a solved objective or a row dual againstpypsa 1.3.0. The two checks above prove the rows are the same rows; they do not prove an engine builds them.lpspec needs a companion change, because ten constraint blocks are gone and four are renamed —
Generator_p_ramp_limit_up_fix/_ext/_combecomeGenerator_p_ramp_limit_up, and so on. Anything keyed on those names inreferences.jsonordeviations.yamlhas to move with them. Worth landing before this, or beside it.One thing the feature cannot say, worth knowing before more ports use it.
expressions:takes nowhere:, so a cased quantity is total over itsforeach:—Generator_previous_statusis declared for every generator, and for a non-committable one it has no value,Generator_statusbeing masked. Nothing here reads it there, and the constraints that use it all carrywhere: Generator_committable. But a consumer that materialises a named expression over its whole frame — which is whatresult.expression(name)promises — would meet that absence. Not filed; raising it here first.Deliberately not done
<=,>=and==are data, andcases:gives a value per region, not an operator. A different feature.Bus-meshed-*split still has no fixture, and a fixed modular build still cannot be stated. Neither is a case-split.bus2— is untouched for the same reason.