Read a PLEXOS expansion plan and write a Sienna investments portfolio - #14
Read a PLEXOS expansion plan and write a Sienna investments portfolio#14thomaschristopherking wants to merge 2 commits into
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 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 |
|
Gate: ✅ PASS All files grade A. Full report
|
c53bc70 to
c23ab24
Compare
Mutation testing reportScore: 80.6% (319 killed / 396 tested)
Timeout-prone functionsEach timeout burns its whole budget (
|
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`, 604 dated generator rows and 186 Constraints, and all of it stopped at the first leg. `Max Units Built` above zero now makes an object a candidate, and a candidate becomes an extendable PyPSA component carrying what building it costs. `stage_plexos_xml` stages every date band beside the value in force, and a readable Constraint reaches the extensions sidecar. `plexos-to-sienna-investments` writes a SiennaSchemas `PortfolioDocument` beside the base system it expands, and `pypsa-to-sienna-investments` does the same for a PyPSA network that states its own expansion. The AEMO case study gains the expansion path, and the gap analysis gains the portfolio's gaps. Closes the work of transition-zero/tz-infra-interop#116. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas C. King <thomas.k@transitionzero.org>
c23ab24 to
66820a5
Compare
The `code-review/` directory held what an automated review cycle had learned about this repository: a ledger of every comment and its verdict, plus the always-flag and never-flag rules a reviewer had to obey. The ledger reached 494 records and 502 of this branch's added lines, and told a reviewer nothing about the code it sat beside. Nothing reads any of it. No test, script, pre-commit hook or workflow references the directory, so this removes the four files and no more. Signed-off-by: Thomas C. King <thomas.k@transitionzero.org>
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 ISPfile's 8,539
Generator.Build Costrows, 372 objects with aMax Units Built, 604 datedgenerator rows and 186 Constraints all stopped at the first leg. A PLEXOS expansion plan now
reaches PyPSA as extendable components and Sienna as a
PortfolioDocument.Closes the work of transition-zero/tz-infra-interop#116.
Replaces the four-branch stack #9, #10, #11 and #12, squashed into one commit.
Files to review (101, +7270 / -750): one feature commit, plus
0ef9fab, which deletesthe
code-review/directory.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/steps/pypsa_to_sienna_investments_map_technologies.py(new)interop/plugins/shared/sienna_investments_constants.py(new)interop/plugins/sinks/emit_sienna_portfolio.py(new)PortfolioDocumentbeside the operations system.interop/plugins/shared/pypsa_sienna_translations/_shared.pycapacity_choice: which column rates a component, and the value that column states.docs/translation_mappings/translation-from-plexos-to-sienna-investments.md(new)Why
A capacity-expansion model is most of what a PLEXOS plan says. Before this, the translator
read the dispatch fleet and dropped the plan: an object with no units in service looked
retired, a dated property collapsed to the single year being translated, and a
Constraintwas reported as not carried. 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.
Max Units Builtabove zero makesone, and its capacity is
one unit's rated power x Max Units Builtrather than the zero itsUnitsstates. That one rule drives the PyPSA side:p_nom_extendable,p_nom_min,p_nom_max,overnight_cost,discount_rateandlifetimeall follow from it, and PyPSAworks out the annuity from the last three rather than the translator assembling a capital
cost of its own.
Three PyPSA fields have no home for what PLEXOS states, so they travel in the extensions
sidecar: the size of one unit, the technology lifetime, and the yearly
FO&M Charge. Thecharge is the interesting one. PyPSA reads
fom_costas a charge for the whole modelledhorizon and adds it to the annuitised build cost without scaling, so writing a yearly number
there priced a two-day run as if it lasted a year. Sienna's
operation_costs.fixedisyearly, so the portfolio reads the sidecar and falls back to
fom_costfor a network a userwrote themselves.
Capacity the plan has not decided is not capacity an operations model may dispatch. The
pypsa-to-siennaleg rates a component byp_nom_opt, then by the lower ofp_nom_minandp_nom, then byp_nom. A component with none of those is a build, not a plant, and thegenerator, renewable, hydro, storage and link mappings leave it out and record it as skipped.
Capping
p_nom_minbyp_nomis what separates a brownfield plant from a forced minimumbuild on a greenfield candidate.
Reviewer notes
commits, including every review fix. The squash merges the current lower stack into the tip
first;
a118f7bin the pre-squash history is the one integration fix that needed, where theportfolio's
operation_costs.fixedread afom_costcolumn the review rounds had removed.shape: this work makes a zero
base_power,p_nomormax_hoursan ordinary value, andcode downstream divided by it.
code-review/directory goes. It held a ledger of every review comment and theflag rules a reviewer had to obey. Nothing read any of it, so
0ef9fabremoves the fourfiles. That commit is a clean deletion and needs no review.
built of nothing, a hydro unit that converts no water: each is left out of the output and
named in
decisions.mdand the log, rather than raising or writing a number nobody meant.capacity_choiceinpypsa_sienna_translations/_shared.pydecides both thecapacity and the source attribute
decisions.mdnames for it. One chain gives both so theycannot disagree, and I would like a second opinion on the
p_nom_mincap.Tests
638 scenarios pass. Every gate passes:
ruff,mypy --strict,lint-imports, the twoplugin lints, and the four repository lint scripts.
Follow-up
The portfolio's gaps are listed in
docs/translation_mappings/plexos-to-sienna-gap-analysis.md.