Skip to content

improving Carbon Manangement Modeling#2161

Open
toniseibold wants to merge 17 commits into
masterfrom
carbon_capture
Open

improving Carbon Manangement Modeling#2161
toniseibold wants to merge 17 commits into
masterfrom
carbon_capture

Conversation

@toniseibold
Copy link
Copy Markdown
Contributor

@toniseibold toniseibold commented May 7, 2026

Changes

  • Added config to include the investment and electricity demand for compressor stations for the transport of CO2 in pipelines in dense phase
  • Moved costs for sequestration from the storage sites capital_cost to the sequestration link marginal_cost to avoid problems when optimizing the network again (since investment decisions are then forced into the system)
  • Added electricity demand for the post combustion carbon capture in multiple links
  • adjusting the capital costs for post combustion capture depending on the flue gas concentration of carbon dioxide

A few comments
Carbon capture from industrial sources come from multiple sources:

  • gas for industry: dominated by HVC, cement, aluminium
  • process emissions CC: dominated by steel, cement, aluminium
  • solid biomass for industry CC: paper, pulp, cement, food, beverages, tobacco, wood, textile
    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

Flue gas source CO₂ concentration range (vol-%) relative CAPEX/t_CO2
Gas turbine 2–4 100 %
Waste-fired power plant 9–14 60 %
Biomass-fired power plant 13–17 55 %
Cement plant 20–30 50 %

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:

  • Changes are tested locally and behave as expected.
  • Code and workflow changes are documented.
  • A release note entry is added to doc/release_notes.rst.

If applicable:

  • Changes in configuration options are reflected in scripts/lib/validation.
  • For new data sources or versions, these instructions have been followed.
  • New rules are documented in the appropriate doc/*.rst files. not_applicable

@toniseibold toniseibold requested a review from bobbyxng May 7, 2026 07:38
@toniseibold toniseibold marked this pull request as ready for review May 7, 2026 07:47
Copilot AI review requested due to automatic review settings May 7, 2026 07:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_liquefaction option to model CO₂ compression/liquefaction buses and links and to route CO₂ pipelines on dense-phase buses.
  • Move sequestration cost from store capital_cost to sequestration link marginal_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 efficiency is changed to efficiency_cc, but cost scaling remains tied to costs.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, bus4 is set to "" but efficiency4 is set to 1.0, which then becomes efficiency4=-1.0. If PyPSA interprets bus4="" as “no 4th terminal”, the corresponding efficiency should be 0.0 to avoid an unintended (or invalid) extra balance term. Set efficiency4=0.0 in the non-spatial branch (and apply the same pattern anywhere else a busX is 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.

Comment thread scripts/prepare_sector_network.py
Comment thread scripts/prepare_sector_network.py Outdated
Comment thread scripts/prepare_sector_network.py Outdated
Comment thread scripts/prepare_sector_network.py
Comment thread scripts/prepare_sector_network.py Outdated
Comment thread scripts/prepare_sector_network.py
Comment thread scripts/prepare_sector_network.py
Comment thread scripts/prepare_sector_network.py
Comment thread doc/release_notes.rst Outdated
toniseibold and others added 6 commits May 7, 2026 11:46
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment thread scripts/prepare_sector_network.py
Comment thread scripts/prepare_sector_network.py
Comment on lines +845 to +855
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",
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set p_nom=np.inf and p_nom_extendable=False. Small marginal cost could be added, but don't really need to.

Copy link
Copy Markdown
Collaborator

@bobbyxng bobbyxng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Image

and

image

@toniseibold
Copy link
Copy Markdown
Contributor Author

Stream lining efficiency and capital_cost:
Changes for MeOH CCGT CC: efficiency before 60% efficiency after 57.7%
Changes for MeOH reforming CC: electricity demand 0.075 MWh/t_CO2
Changes Coal CC: efficiency before 35.6% efficiency after 32.4%
capital_costs consist of two components (coal power plant + carbon capture unit depending on coal carbon intensity)
biomass for industry CC: electricity demand 0.0341 MWh/t_co2
gas for industry CC: electricity demand 0.018414 MWh/t_co2
process emissions CC: electricity demand 0.093 MWh/t_co2

sanity checks
total system costs: + 2.29 bnEUR/yr
electricity supply: + 68.8 TWh/yr of which 33.1 TWh for co2 compression (269.3853 Mt compressed into dense phase at 0.123 MWh/Mt electricity consumption)

@bobbyxng
Copy link
Copy Markdown
Collaborator

Thanks @toniseibold for the updates
I made a proposal to update the two plot_balance_map* scripts to include the balances from the new co2 dense bus carrier, if it is enabled.

image

Copy link
Copy Markdown
Member

@fneum fneum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +761 to +765
"gas": 2.0,
"biomass": 1.8,
"coal": 1.8,
"waste": 1.7,
"cement": 1.0,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Image Image

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?

Comment thread data/versions.csv
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set p_nom=np.inf (which is now possible) and p_nom_extendable=False. There should be no extendable components with zero capital cost.

Comment on lines +845 to +855
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",
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
p_nom=0,

Comment on lines 1201 to +1202
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For conversion of VOM, I would still use costs.at["CCGT", "efficiency"]. Otherwise, high electricity consumption of CC would reduce effective VOM.

Comment on lines +4719 to +4721
else:
bus4 = ""
efficiency4 = 1.0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants