docs(pypsa): a committable unit built in a later period starts from off, and the big M follows pypsa for an infinite build cap - #817
Merged
Conversation
…e commitment rows, as in pypsa master
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
…ff, and the big M follows pypsa for an infinite build cap
Documentation build overview
23 files changed ·
|
# Conflicts: # CHANGELOG.md
…ocs/pypsa-commitment-edges
FabianHofmann
added a commit
that referenced
this pull request
Oct 2, 2026
FabianHofmann
force-pushed
the
docs/pypsa-fixed-modular
branch
from
October 2, 2026 09:06
df7f835 to
34af2a0
Compare
…-edges # Conflicts: # CHANGELOG.md # docs/examples/pypsa.md # docs/examples/pypsa/generator_ramping.md # docs/examples/pypsa/link.md # docs/examples/pypsa/link_ramping.md # docs/examples/pypsa/process_ramping.md # docs/examples/pypsa_linearized_uc.md # examples/pypsa.yaml # examples/pypsa/generator_ramping.yaml # examples/pypsa/link_ramping.yaml # examples/pypsa/process_ramping.yaml # examples/pypsa_linearized_uc.yaml # examples/references/pypsa/references.json # tests/test_pypsa_references.py
FabianHofmann
added a commit
that referenced
this pull request
Oct 2, 2026
…ep steps, and a capital cost says where fom_cost and overnight_cost enter (#816) * docs(pypsa): the pypsa references are recorded against pypsa master * docs(pypsa): add the changelog line * docs(pypsa): a fixed modular committable unit gets only its per-module commitment rows, as in pypsa master * docs(pypsa): add the changelog line * test(pypsa): read the masks with the exclusivity evaluator, not eval * docs(pypsa): the pypsa page lists seven more refusals and eight data-prep steps, and a capital cost says where fom_cost and overnight_cost enter Data prep section: n 20, median 19, over25 4. * docs(pypsa): add the changelog line * docs(pypsa): the shut-down-ramp refusal moves to #817, which assumes the case
15 of 44 tasks
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.
A committable unit built in a later period now starts from off, so it pays its start-up cost. The big M states PyPSA's rule for an infinite build cap. A start-up or shut-down ramp alone now also triggers the
came_in_runningrefusal.Part of #783 (step 4, group 2). Stacks on #787, which stacks on #786. Base:
docs/pypsa-fixed-modular.Method, gate output, PyPSA cites, alternatives
PyPSA cites are on master
02bdcbba.Late-opening committable unit. PyPSA builds
status - status.shift(1).fillna(0)(optimize/constraints.py:297). The status is masked byactive(variables.py:71-95), so at the first snapshot a unit stands in, the previous status is zero. The file'sshift(Generator_status)was absent there. So thecom-transition-start-uprow was not built, and the unit started for free.Generator_previous_status(and the Link and Process ones) now has a caseopening_late: zero whereposition(snapshot) > 0 AND NOT shift(Generator_active, …). The old cases move into a new expression,Generator_status_carried_over. One block with both cases is refused at load, because the loader cannot tellposition(snapshot) == 0and a neighbour predicate apart. A block with one case may read a neighbour. The alternative was a data-prep booleanGenerator_opens_latewith two assumptions per component, asStorageUnit_opens_latehas. That costs three parameters and six assumptions, and adds no guarantee.Rung 64 (
rung_64_commitment_edges.py) is new. It has two periods, a committable generator, link and process built in 2030 with start-up costs 100, 70 and 40, and a committable extendable unit withp_nom_max = inf. PyPSA solves it to9245.0. I put the rung in before the change. Then I took PyPSA's model, set the start-up rows of the three late units at the first 2030 snapshot to>= -1, and solved again:9035.0. That model is what the file stated before, and it is 210 lower, the sum of the three start-up costs. The repository runs no solver, so no test here can show this failure.Big M with an infinite
p_nom_max(components/components.py:1050-1121). M isp_nom_max × max_t p_max_puwhere the cap is finite and positive. Otherwise it iscommittable_big_m × max_t p_max_pu, and without that keyword10 × max(peak total load, largest finite p_nom, largest finite p_nom_max)of the component, or1e6.Generator_big_m,Link_big_mandProcess_big_mnow state this rule, still as data prep. In rung 64 the inferred M is3000and the unit builds70. Withcommittable_big_m=50, PyPSA solves to11745.0and builds50, so M can cap output. The page says this.First-snapshot ramp from a start-up or shut-down ramp alone (
constraints.py:1052-1053, mask at:1142,:1160). The file already built these rows (rung 28). The three{c}_came_in_running_unless_committableassumptions, and the Generator one inpypsa_linearized_uc.yaml, now also apply toramp_limit_start_upandramp_limit_shut_down. Withoutup_time_before, PyPSA builds the same capped first-snapshot row for these units (:1097-1100,:1116-1118, PyPSA/PyPSA#1943). The Refusals row and the rung 28 prose say so. The Refusals row also names the bound PyPSA gives with only a shut-down ramp,p >= (ramp_limit_shut_down - 1) * p_nom(:1146-1148,:1153-1158). This is the seventh #783 refusal; #816 leaves it to this PR, because the widened assumption covers it. No rung covers this: #783 says "no rung until PyPSA chooses".Gates, in this order on the final tree:
pixi run python -m tools.pypsa_split split examples/pypsaandpixi run python -m tools.gallery: regenerated the fragments and the pages.uv run --script examples/references/pypsa/reference.py: recordedrung_64_commitment_edges(objective9245.0). No other record changed.uv run --script examples/references/pypsa/reference.py --check:every rung solves to its record.pixi run lint: pass.pixi run ci: pass (2626 tests, docs-build, compile-tex 55 documents).Not done. The PyPSA line cites outside the blocks above are not re-anchored; #806 does that. The cites I touched are on
02bdcbba. I did not add a guard test for the new case: the suite runs no solver, and a test that reads the case structure would test the implementation. Nothing needed language work.