Skip to content

Add biomass boiler to add_carbon_capture function and update outputs.#253

Open
jonathan-peel wants to merge 12 commits into
PyPSA:masterfrom
jonathan-peel:add-biomass-bioler-cc
Open

Add biomass boiler to add_carbon_capture function and update outputs.#253
jonathan-peel wants to merge 12 commits into
PyPSA:masterfrom
jonathan-peel:add-biomass-bioler-cc

Conversation

@jonathan-peel
Copy link
Copy Markdown

@jonathan-peel jonathan-peel commented Jan 22, 2026

Changes proposed in this Pull Request

  • following logic from @millingermarkus, I added the large biomass boiler post-combustion capture retrofit data to the existing add_carbon_capture function
  • This retrofit is larger (500 MW(th)) than the already implemented "small CHP" (100 MW(th)) retrofit, therefore it is a better approximation for full-scale thermal power plants such as CCGTs. To fit CCGTs, I will make further adjustments to the capex, efficiency and variable O&M separately in pypsa-eur.
  • I also included the variable O&M costs for all the carbon capture retrofit technologies.

Checklist

  • Code changes are sufficiently documented; i.e. new functions contain docstrings and further explanations may be given in doc.
  • Data source for new technologies is clearly stated.
  • Newly introduced dependencies are added to environment.yaml (if applicable).
  • A note for the release notes doc/release_notes.rst of the upcoming release is included.
  • I consent to the release of this PR's code under the GPLv3 license.

@lkstrp lkstrp requested a review from euronion February 9, 2026 10:38
@jonathan-peel
Copy link
Copy Markdown
Author

Hi @euronion! Just a quick ping here to ask if you could approve this - it's currently blocking a project of mine - please let me know if you have any questions. Many thanks in advance :)

Copy link
Copy Markdown
Collaborator

@euronion euronion left a comment

Choose a reason for hiding this comment

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

Thanks for the PR and sorry for not reviewing for some time in this repo.

  • Is this a retrofit option for existing boilers or additional costs for building new units with post-combustion capture?
    Or are the costs for retrofit and for new units similar?
    I'm asking because we have some carbon capture retrofit technologies already, so it would make sense to adopt a similar naming biomass boiler carbon capture retrofit.
    Although I think you tried to be consistent with the biomass CHP capture naming, right?

  • Can you regenerate the output files? We recently changed to reporting values in 2025 instead of 2020 EUR.

Comment thread docs/release_notes.rst Outdated
Comment thread outputs/US/costs_2020.csv
Comment on lines +3631 to +3632
biomass boiler capture,compression-electricity-input,0.1,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
biomass boiler capture,compression-heat-output,0.16,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
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.

The investment number contains the investment required for postprocessing (compression and dehydration). It would only be consistent to also include the electricity and heat requirements for this step as well (they are separate in the DEA data sheet) or to report it as additional rows.

Image

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hi @euronion, I'm confused about this.

I went in with the debugger, and I can confirm that the specific investment number is just the total row from the spreadsheet, which does naturally contain all the sub-costs, including CO2 comp & dehydration.

(Pdb) technology_dataframe.loc[(tech_name, "Specific investment"), :]
                                           2020 2025 2030  2035 2040 2045 2050                                             source                unit
biomass boiler capture Specific investment  2.7  2.5  2.3  2.15  2.0  1.8  1.6  Danish Energy Agency, inputs/technology_data_f...  t CO2 output/hour)

Also, given the name_list in compile_cost_assumptions.py, line 2718, we save both the rows you highlight separately too:

(Pdb) name_list
[('C2) Eletricity input ', 'electricity-input'), ('C1) Heat  input ', 'heat-input'), ('C1) Heat out ', 'heat-output'), ('CO₂ compression and dehydration - Electricity input', 'compression-electricity-input'), ('CO₂ compression and dehydration - Heat out', 'compression-heat-output')]
(Pdb) new_technology_dataframe.loc[("biomass boiler capture", "compression-electricity-input"), years]
2020      0.1
2025      0.1
2030    0.085
2035     0.08
2040    0.075
2045    0.075
2050    0.075
Name: (biomass boiler capture, compression-electricity-input), dtype: object
(Pdb) new_technology_dataframe.loc[("biomass boiler capture", "compression-heat-output"), years]
2020     0.16
2025     0.16
2030     0.14
2035    0.135
2040     0.13
2045     0.13
2050     0.13
Name: (biomass boiler capture, compression-heat-output), dtype: object

These values are confirmed in the outputs (e.g., in costs_2020.csv lines 707 and 708):

biomass boiler capture,compression-electricity-input,0.1,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0
biomass boiler capture,compression-heat-output,0.16,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0

As far as I can tell, the things you ask for above are already present - am I misunderstanding something?

Copy link
Copy Markdown
Collaborator

@euronion euronion May 13, 2026

Choose a reason for hiding this comment

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

What I mean is that right now you have:

  • investment cost (full plant incl. compression)
  • elec input and heat input (capture plant)
  • elec input and heat output (compression)

Based on past experiences, it makes sense to consistently report the numbers as either combined or separate:

  • investment cost (plant without compression)
  • investment cost (compression only)
  • elec input and heat input (capture plant)
  • elec input and heat output (compression)

OR

  • investment cost (full plant incl. compression)
  • elec input, heat input, heat output (capture plant and compression)

We've seen people in the past pick parts that were they shouldn't have picked parts, e.g. I want to prevent someone from assuming the full investment cost incl. compression, but then missing to add the electricity input/heat output for compression to their energy demand.

Comment thread outputs/US/costs_2020.csv
biomass boiler capture,electricity-input,0.03,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
biomass boiler capture,heat-input,0.833,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
biomass boiler capture,heat-output,0.833,MWh/tCO2,"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
biomass boiler capture,investment,3394803.4231,EUR/(tCO2/h),"Danish Energy Agency, inputs/technology_data_for_carbon_capture_transport_storage.xlsx",401.b Post comb - Large biomass,2020.0,,
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.

Do you know why this value does not match the value in the data sheet (2.7 MEUR/(t CO2/h))?

Image

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This happens due to the adjustment to inflation.

In compile_cost_assumptions.py line 4277, we have

        costs_tot = adjust_for_inflation(
            inflation_rate, costs_tot, techs, snakemake.config["eur_year"], "value"
        )

Before this line (from debugger):

costs_tot.loc[("biomass boiler capture", "investment"), :]
value                                                          2700000.0
unit                                                        EUR/(tCO2/h)
source                 Danish Energy Agency, inputs/technology_data_f...
further description                      401.b Post comb - Large biomass
currency_year                                                     2020.0
Name: (biomass boiler capture, investment), dtype: object

After this line (from debugger):

costs_tot.loc[("biomass boiler capture", "investment"), :]
value                                                      3394803.42308
unit                                                        EUR/(tCO2/h)
source                 Danish Energy Agency, inputs/technology_data_f...
further description                      401.b Post comb - Large biomass
currency_year                                                     2020.0
Name: (biomass boiler capture, investment), dtype: object

The value of snakemake.config["eur_year"] is 2025. This is confusing because I guess when I made the PR, this would have been 2020, therefore no inflation effects should have been observed when you reviewed my PR. I suppose when you merged in @fneum 's commit, it must have somehow retriggered the generation of results without any of us manually doing so.. This explains the above comment where my rerun of the results doesn't produce any changes according to the git diff!
All the same, it makes sense to have a 3394803/2700000=1.26=>26% inflation level over 5 years (4.7% year-on-year).

Comment thread docs/release_notes.rst Outdated
jonathan-peel and others added 2 commits May 13, 2026 10:52
Co-authored-by: Johannes HAMPP <42553970+euronion@users.noreply.github.com>
Co-authored-by: Johannes HAMPP <42553970+euronion@users.noreply.github.com>
@jonathan-peel
Copy link
Copy Markdown
Author

Thanks for the PR and sorry for not reviewing for some time in this repo.

  • Is this a retrofit option for existing boilers or additional costs for building new units with post-combustion capture?
    Or are the costs for retrofit and for new units similar?
    I'm asking because we have some carbon capture retrofit technologies already, so it would make sense to adopt a similar naming biomass boiler carbon capture retrofit.
    Although I think you tried to be consistent with the biomass CHP capture naming, right?
  • Can you regenerate the output files? We recently changed to reporting values in 2025 instead of 2020 EUR.
  1. It's for estimating the additional costs for a CCGT with post-combustion capture. This will be used similarly to coal_cc in pypsa-eur (see prepare_sector_network.py), which uses "biomass CHP capture", which I have tried to stay consistent with, as you mention. I have estimated the capex and opex based on the biomass CHP capture, since it has a capacity closer in size to a CCGT. I am happy to send you a PDF explaining my methodology for this in more detail. The changes to technology-data are only to get the processed data for the biomass boiler capture into costs.csv in pypsa-eur, so I can implement the gas CCGT + CC there. Therefore, I think it makes sense to keep the current naming. Also, all the numbers are just for the retrofit itself, not including the underlying biomass-fired boiler.
  2. I reran snakemake all, but this didn't change any of the outputs. I don't understand why! Surely after the snakemake command, I should just see a diff in the git status for my new technologies? Is there anything else I'm missing?

Thanks @euronion! Look forward to your replies :)

@euronion
Copy link
Copy Markdown
Collaborator

  1. It's for estimating the additional costs for a CCGT with post-combustion capture. This will be used similarly to coal_cc in pypsa-eur (see prepare_sector_network.py), which uses "biomass CHP capture", which I have tried to stay consistent with, as you mention. I have estimated the capex and opex based on the biomass CHP capture, since it has a capacity closer in size to a CCGT. I am happy to send you a PDF explaining my methodology for this in more detail. The changes to technology-data are only to get the processed data for the biomass boiler capture into costs.csv in pypsa-eur, so I can implement the gas CCGT + CC there. Therefore, I think it makes sense to keep the current naming. Also, all the numbers are just for the retrofit itself, not including the underlying biomass-fired boiler.

That makes sense.
The underlying assumptions might be more suitable be included in the PyPSA-Eur PR then, where you implement CCGT + CC.

If these numbers also apply to CCGT, not only to biomass boiler, would you then mind duplicating the entry and adding the same numbers for CCGT capture?

  1. I reran snakemake all, but this didn't change any of the outputs. I don't understand why! Surely after the snakemake command, I should just see a diff in the git status for my new technologies? Is there anything else I'm missing?

I mixed something up, the currency_year in the outputs won't change until #275 is merged.

There are some open questions in my comments discussions above that you would also please need to address before I can review :)

@jonathan-peel
Copy link
Copy Markdown
Author

jonathan-peel commented May 13, 2026

That makes sense. The underlying assumptions might be more suitable be included in the PyPSA-Eur PR then, where you implement CCGT + CC.

If these numbers also apply to CCGT, not only to biomass boiler, would you then mind duplicating the entry and adding the same numbers for CCGT capture?

These numbers don't also apply for CCGT, primarily because the flue gas of a CCGT has a CO2 concentration of 4% and the concentration for the boiler is 17%, and this changes the specific capital cost per ton CO2 converted. This means using the biomass boiler for a CCGT is more than just multiplying by the amount of CO2 released by a CCGT, there also needs to be an "uplift factor" of about 1.9 to model the cost-increasing effect of having a lower concentration of CO2. I do this in my pypsa-eur implementation of CCGT_gas_cc. I thought it would be best to keep the technology-data without having such complex assumptions baked in, so I could have them clearly in pypsa-eur. All I need is the values for a biomass boiler, and I can convert them to a CCGT later.

I mixed something up, the currency_year in the outputs won't change until #275 is merged.

Ah, makes sense - fantastic pull request btw, this column really threw me at first.

There are some open questions in my comments discussions above that you would also please need to address before I can review :)

Done!(?) :)

Thanks for getting back so quickly @euronion

@jonathan-peel jonathan-peel requested a review from euronion May 13, 2026 12:41
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.

2 participants