Read a PLEXOS expansion plan, and the years it states - #18
Open
thomaschristopherking wants to merge 1 commit into
Open
thomaschristopherking wants to merge 1 commit into
thomaschristopherking wants to merge 1 commit into
Conversation
A PLEXOS model states what it may build in `Build Cost`, `Max Units Built`, `WACC`, `Economic Life`, `Technical Life` and `FO&M Charge`, and states when each unit arrives and leaves in a dated `Units` property. The reader named none of them. The AEMO 2024 ISP file alone carries 8,539 `Generator.Build Cost` rows, 372 objects with a `Max Units Built` and 604 dated generator rows, and all of it stopped here. `Max Units Built` above zero makes an object a candidate. A candidate's capacity is one unit's rated power times `Max Units Built` rather than the zero its `Units` states, and that one rule drives `p_nom_extendable`, `p_nom_min`, `p_nom_max`, `overnight_cost`, `discount_rate` and `lifetime`. PyPSA works the annuity out from the last three, so the translator assembles no capital cost of its own. Three values have no PyPSA column, so they travel in the extensions sidecar: the size of one unit, the technology lifetime, and the yearly `FO&M Charge`. PyPSA reads `fom_cost` as a charge for the whole modelled horizon and adds it without scaling, so a yearly number written there prices a two-day run as if it lasted a year. `stage_plexos_xml` stages every date band beside the value in force rather than narrowing each dated property to the year being translated, and `_lifespan` walks those bands for the build year and the retirement year. The dated years and the expansion plan arrive together because they are one reading, not two: the generator and storage derivation takes a `Lifespan` alongside the candidate it rates, and seven modules read both. Signed-off-by: Thomas C. King <thomas.k@transitionzero.org>
|
Warning Review limit reachedNext included review available in 59 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (27)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Sep 11, 2026
thomaschristopherking
added this pull request to stack #23
September 11, 2026 09:56
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.
TL;DR
A PLEXOS model states what it may build in
Build Cost,Max Units Built,WACC,Economic Life,Technical LifeandFO&M Charge, and states when each unit arrives andleaves in a dated
Unitsproperty. The reader named none of them, so the AEMO 2024 ISP file's8,539
Generator.Build Costrows, 372 objects with aMax Units Builtand 604 datedgenerator rows all stopped here.
Max Units Builtabove zero now makes an object a candidate,and a candidate becomes an extendable PyPSA component carrying what building it costs.
Second of five for transition-zero/tz-infra-interop#116,
stacked on #17.
Files to review (27, +1679 / -289):
docs/specs/2026-09-08-plexos-sienna-investments-design.md(start here)interop/plugins/shared/plexos_pypsa_translations/_expansion.py(new)interop/plugins/shared/plexos_pypsa_translations/_lifespan.py(new)Unitsbands for the build year and the retirement year.interop/plugins/sources/plexos_dated_properties.pyinterop/plugins/shared/plexos_pypsa_translations/_storage_shared.pydocs/translation_mappings/translation-from-plexos-to-pypsa.mdWhat a candidate is, and the dated-property rules.Why
A capacity-expansion plan is most of what a PLEXOS model says. Before this, an object with no
units in service looked retired and a dated property collapsed to the single year being
translated, so a user could translate the AEMO ISP and get a network that could not answer
the question the ISP exists to answer.
How
A candidate is an object with something left to build. Its capacity is one unit's rated
power times
Max Units Built, not the zero itsUnitsstates, because PyPSA readsp_nomfor every per-unit field on the component. One rule drives the six expansion fields, and
PyPSA works the annuity out from
overnight_cost,discount_rateandlifetimerather thanthe translator assembling a capital cost of its own.
A build nobody prices is not a build. A candidate that states no
Build Cost,WACCorEconomic Life, or states aBuild CostorEconomic Lifeof zero, would be built for freeor priced as a perpetuity. An object that already runs keeps the capacity it runs and loses
only its build; one with nothing running is left out entirely. A
WACCof zero is kept: itis the rate of a model that does not discount.
Three values travel in the extensions sidecar because PyPSA has no column for them. The
yearly
FO&M Chargeis the interesting one: PyPSA readsfom_costas a charge for the wholemodelled horizon and adds it to the annuitised build cost without scaling, so writing a yearly
number there prices a two-day run as if it lasted a year.
Reviewer notes
Lifespanalongside the candidate it rates, and seven modules read both. Splitting themwould mean inventing an intermediate state that never existed, so they arrive together.
Ratingreads against one unit. PLEXOS states aRatingper unit,as it states
Max Capacity. A generator that runs has ap_nomof however many units itruns, so the two agree; a candidate has a
p_nomof every unit it may build, so itsRatingderates one unit'sMax Capacityand is held at full availability.derive_expansionandfind_unpriced_candidatein_expansion.py. Thosetwo decide which objects reach the network at all.
Tests
608 scenarios pass, and all 17 pre-commit hooks.
Open workspace in Conductor