improving Carbon Manangement Modeling#2161
Conversation
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR extends the sector network CO₂ modeling by optionally adding a dense-phase (liquefaction/compression) step prior to CO₂ transport, moving sequestration costing to marginal costs, and adding electricity demand terms to several carbon capture links.
Changes:
- Add
co2_network_liquefactionoption to model CO₂ compression/liquefaction buses and links and to route CO₂ pipelines on dense-phase buses. - Move sequestration cost from store
capital_costto sequestration linkmarginal_cost. - Add electricity-demand penalties for (post-combustion) CC in multiple conversion links and add plotting colors for new CO₂ carriers.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/prepare_sector_network.py | Adds dense-phase CO₂ buses/links, adjusts sequestration costing, updates several CC links to include electricity demand, and threads new option through network construction. |
| scripts/lib/validation/config/sector.py | Adds validation schema field co2_network_liquefaction. |
| config/schema.default.json | Exposes co2_network_liquefaction in generated JSON schema. |
| config/config.default.yaml | Adds default value for co2_network_liquefaction. |
| config/plotting.default.yaml | Adds plotting colors for new CO₂ carriers. |
| doc/release_notes.rst | Adds release note entry describing the new option and CC electricity demand update. |
Comments suppressed due to low confidence (2)
scripts/prepare_sector_network.py:1
- The link’s
efficiencyis changed toefficiency_cc, but cost scaling remains tied tocosts.at["CCGT", "efficiency"]. Given the established convention elsewhere in this file (scaling per-MWel costs by the link efficiency), this produces inconsistent economics (net efficiency changes but capex/VOM scaling doesn’t). Align the cost scaling with the effective efficiency being modeled, or alternatively keep the original generation efficiency and model CC electricity demand via an additional electricity bus/output (similar to how other multi-bus links account for auxiliary electricity).
# SPDX-FileCopyrightText: Contributors to PyPSA-Eur <https://github.com/pypsa/pypsa-eur>
scripts/prepare_sector_network.py:1
- When
options["biomass_spatial"]is false,bus4is set to""butefficiency4is set to1.0, which then becomesefficiency4=-1.0. If PyPSA interpretsbus4=""as “no 4th terminal”, the corresponding efficiency should be0.0to avoid an unintended (or invalid) extra balance term. Setefficiency4=0.0in the non-spatial branch (and apply the same pattern anywhere else abusXis disabled via an empty string).
# SPDX-FileCopyrightText: Contributors to PyPSA-Eur <https://github.com/pypsa/pypsa-eur>
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| n.add( | ||
| "Link", | ||
| spatial.co2.nodes, | ||
| suffix=" expansion", | ||
| bus0=spatial.co2.dense, | ||
| bus1=spatial.co2.nodes, | ||
| efficiency=1.0, | ||
| p_nom=1e7, | ||
| carrier="co2 expansion", | ||
| unit="t_co2", | ||
| ) |
There was a problem hiding this comment.
This introduces degeneracy/potential zero cost loops. Do you have marginal_cost and capital_cost available? Also propose to set p_nom_extendable to True and remove the arbitrary high p_nom --> let the model decide.
There was a problem hiding this comment.
Set p_nom=np.inf and p_nom_extendable=False. Small marginal cost could be added, but don't really need to.
There was a problem hiding this comment.
Looks good to me (apart from minor remarks, see dedicated comments)
One aspect I do not have an answer to yet is how we treat, e.g. how the new co2 dense carrier is shown in balance maps. co2 compression is basically equivalent with CO2 being transported through pipelines and eventually stored. Right now you would need two bus carriers to plot the whole picture:
and
|
Stream lining efficiency and capital_cost: sanity checks |
for more information, see https://pre-commit.ci
|
Thanks @toniseibold for the updates
|
fneum
left a comment
There was a problem hiding this comment.
Excellent! Couple of questions below. Main comments:
-
Inconsistent electricity consumption depending on carrier's spatial resolution -> Give all affected links electricity node resolution.
-
What fraction of change in system cost and electricity consumption is caused by dense-phase compression feature and what fraction by CC CAPEX? That would be good to understand.
-
Sources for CC capital cost scaling.
| "waste": 1.7, | ||
| "cement": 1.0, | ||
| }, | ||
| description="Size of the carbon capture unit depending on the amount of carbon dioxide in the flue gas. The more CO2, the smaller the capture unit and thus the lower the capital cost factor. The default values are based on the DEA technology-data report.", |
There was a problem hiding this comment.
Can you be more specific about the source of the default values (like you did in PR description, i.e. which figure/table/link)?
Perhaps also state explicitly that factor is relative to post-combustion capture in cement kiln.
| "gas": 2.0, | ||
| "biomass": 1.8, | ||
| "coal": 1.8, | ||
| "waste": 1.7, | ||
| "cement": 1.0, |
There was a problem hiding this comment.
How did you get to these values?
Is it Table 8 / Figure 12 in https://ens.dk/en/analyses-and-statistics/technology-data-carbon-capture-transport-and-storage?
But here it looks like biomass and waste are largely above 10% concentration with maybe 20% higher CAPEX than cement. Should't it be factors 1.15-1.2, then?
Where did you take the information for coal from?
| corine,v18_5,archive,latest supported,2026-01-13,,https://data.pypsa.org/workflows/eur/corine/v18_5/corine.zip | ||
| corine,unknown,primary,latest supported,2025-12-02,Need to register with CLMS API and create an access token. The download URL is dynamic, | ||
| costs,v0.14.0,primary,latest supported,2026-02-13,Part of the `technologydata` repository and versioned on GitHub.,https://raw.githubusercontent.com/PyPSA/technology-data/refs/tags/v0.14.0/outputs | ||
| costs,co2_management,primary,latest supported,2026-05-12,Part of the `technologydata` repository and versioned on GitHub.,https://github.com/PyPSA/technology-data/tree/co2_management/outputs |
There was a problem hiding this comment.
To be adjusted before merge following a technology-data release.
| carrier="co2 sequestered", | ||
| marginal_cost=options["co2_sequestration_cost"], | ||
| efficiency=1.0, | ||
| p_nom_extendable=True, |
There was a problem hiding this comment.
Set p_nom=np.inf (which is now possible) and p_nom_extendable=False. There should be no extendable components with zero capital cost.
| n.add( | ||
| "Link", | ||
| spatial.co2.nodes, | ||
| suffix=" expansion", | ||
| bus0=spatial.co2.dense, | ||
| bus1=spatial.co2.nodes, | ||
| efficiency=1.0, | ||
| p_nom=1e7, | ||
| carrier="co2 expansion", | ||
| unit="t_co2", | ||
| ) |
There was a problem hiding this comment.
Set p_nom=np.inf and p_nom_extendable=False. Small marginal cost could be added, but don't really need to.
| capital_cost=costs.at["CO2 dense phase compression", "capital_cost"], | ||
| efficiency=1.0, | ||
| efficiency2=-costs.at["CO2 dense phase compression", "electricity-input"], | ||
| p_nom=0, |
| marginal_cost=costs.at["CCGT", "VOM"] | ||
| * costs.at["CCGT", "efficiency"], # NB: VOM is per MWel | ||
| efficiency=costs.at["CCGT", "efficiency"], | ||
| * efficiency_cc, # NB: VOM is per MWel |
There was a problem hiding this comment.
For conversion of VOM, I would still use costs.at["CCGT", "efficiency"]. Otherwise, high electricity consumption of CC would reduce effective VOM.
| else: | ||
| bus4 = "" | ||
| efficiency4 = 1.0 |
There was a problem hiding this comment.
This neglects electricity demand if biomass is not spatially resolved. I think that would be confusing to users. I would say, let the link inherit the resolution of the highest-resolved bus - in this case bus4 with spatial.nodes. I think that would be worth the extra number of links. What do you think?
(Same for other instances below).

Changes
capital_costto the sequestration linkmarginal_costto avoid problems when optimizing the network again (since investment decisions are then forced into the system)A few comments
Carbon capture from industrial sources come from multiple sources:
Flue gas in Europe needs to meet air pollution standards. Additional investment for filters are negligible.
waiting for PyPSA/technology-data#273 to be approved since assumptions for liquefaction were currently based on shipping of CO2.
Flue Gas Properties
From the DEA technology data Table 8 and Figure 12
0.1 - 0.5 kg/tCO2 caustic soda consumption depending on flue gas quality (SO2, HCl) which is negligible compared to other VOM (400 - 600EUR/t_NaOH)
Checklist
Required:
doc/release_notes.rst.If applicable:
scripts/lib/validation.doc/*.rstfiles. not_applicable