Skip to content

Commit

Permalink
Hydrogen Gas Turbines and Retrofitting of Gas Turbines (#151)
Browse files Browse the repository at this point in the history
* first stab at enabling H2 and H2 retrofit gas plants

* forcing gas turbines from one year on

* fixing efficiency of hydrogen gas turbines

* bug fixing params

* dropping gas plants after forcing them to retrofit

* make unravelling of oil bus consistent with new refineries

I.e. separate DE oil primary from DE oil.

* update exporter

* ci: add validator

* select images and add repo owner path

* Update PULL_REQUEST_TEMPLATE.md

* Update Changelog.md

* update submodule

* Update .pre-commit-config.yaml

* remove reuse check

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Using config_provider for additional functionality exclusively (#154)

* using exclusively config_provider

* moving bc to solving config

* style changes

* minor style changes

* cosmetic changes

* add back default values of constraints

* remove unused function arguments

* small fix for exporter

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Michael Lindner <michaellindner@posteo.de>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* Create .git-blame-ignore-revs (#158)

* minor changes for running single node network (#160)

* minor changes for running single node network

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* Fix hydrogen import boundary condition (#159)

* include retrofitted and Kernnetz pipelines for hydrogen import boundary condition

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* bugfixing mock_snakemake and fullfilling prerequisites for review

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* first stab at enabling H2 and H2 retrofit gas plants

* forcing gas turbines from one year on

* fix merge bugs

* change exporter to report hydrogen plants

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* change name of retrofitted H2

* updating exporter

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix bus0 auf H2 plants

* finish rename of h2 retrofit

* default efficiency = 1

---------

Co-authored-by: Tom Brown <tom@nworbmot.org>
Co-authored-by: Michael Lindner <michaellindner@posteo.de>
Co-authored-by: lkstrp <lkstrp@pm.me>
Co-authored-by: Micha <michaellindner@pik-potsdam.de>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Julian Geis <j.geis@tu-berlin.de>
  • Loading branch information
7 people authored Aug 9, 2024
1 parent 0a060dc commit d21a5c2
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 7 deletions.
14 changes: 13 additions & 1 deletion config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
run:
prefix: 20240807unravelCH4coarse
prefix: 20240809H2_plants_retrofit
name:
# - CurrentPolicies
- KN2045_Bal_v4
Expand Down Expand Up @@ -479,6 +479,12 @@ plotting:
load: "#111100"
H2 pipeline (Kernnetz): '#6b3161'
renewable oil: '#c9c9c9'
urban central H2 retrofit CHP: '#ff0000'
H2 retrofit OCGT: '#ff0000'
H2 retrofit CCGT: '#ff0000'
H2 OCGT: '#ff0000'
H2 CCGT: '#ff0000'
urban central H2 CHP: '#ff0000'
renewable gas: '#e05b09'
countries:
- all
Expand All @@ -501,6 +507,12 @@ electricity:
custom_file: resources/german_chp.csv
estimate_renewable_capacities:
year: 2019
H2_plants_DE:
enable: true
start: 2030 # should be < force
force: 2035
cost_factor: 0.15 # repurposing cost of OCGT gas to H2 in % investment cost in EUR/MW source: Christidis et al (2023) - H2-Ready-Gaskraftwerke, Table 3 https://reiner-lemoine-institut.de/wp-content/uploads/2023/11/RLI-Studie-H2-ready_DE.pdf
efficiency_loss: 0.05

pypsa_eur:
Bus:
Expand Down
1 change: 1 addition & 0 deletions workflow/Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ rule modify_prenetwork:
transmission_costs=config_provider("costs", "transmission"),
biomass_must_run=config_provider("must_run_biomass"),
clustering=config_provider("clustering", "temporal", "resolution_sector"),
H2_plants=config_provider("electricity", "H2_plants_DE"),
land_transport_electric_share=config_provider(
"sector", "land_transport_electric_share"
),
Expand Down
51 changes: 45 additions & 6 deletions workflow/scripts/export_ariadne_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,17 @@ def _get_capacities(n, region, cap_func, cap_string="Capacity|", costs=None):
# Q: What about retrofitted gas power plants? -> Lisa
var[cap_string + "Electricity|Hydrogen"] = var[
cap_string + "Electricity|Hydrogen|FC"
] = capacities_electricity.get("H2 Fuel Cell", 0)
] = capacities_electricity.reindex(
[
"H2 Fuel Cell",
"H2 OCGT",
"H2 CCGT",
"urban central H2 CHP",
"H2 retrofit OCGT",
"H2 retrofit CCGT",
"urban central H2 retrofit CHP",
]
).sum()

var[cap_string + "Electricity|Nuclear"] = capacities_electricity.get("nuclear", 0)

Expand Down Expand Up @@ -796,6 +806,10 @@ def _get_capacities(n, region, cap_func, cap_string="Capacity|", costs=None):
}
).sum()

var[cap_string + "Heat|Hydrogen"] = capacities_central_heat.reindex(
["urban central H2 CHP", "urban central H2 retrofit CHP"]
).sum()

# !!! Missing in the Ariadne database

var[cap_string + "Heat|Gas"] = (
Expand Down Expand Up @@ -1362,9 +1376,17 @@ def get_secondary_energy(n, region, _industry_demand):
+ var["Secondary Energy|Electricity|Wind"]
)

var["Secondary Energy|Electricity|Hydrogen"] = electricity_supply.get(
"H2 Fuel Cell", 0
)
var["Secondary Energy|Electricity|Hydrogen"] = electricity_supply.reindex(
[
"H2 Fuel Cell",
"H2 OCGT",
"H2 CCGT",
"urban central H2 CHP",
"H2 retrofit OCGT",
"H2 retrofit CCGT",
"urban central H2 retrofit CHP",
]
).sum()
# ! Add H2 Turbines if they get implemented

var["Secondary Energy|Electricity|Waste"] = electricity_supply.filter(
Expand Down Expand Up @@ -1470,6 +1492,9 @@ def get_secondary_energy(n, region, _industry_demand):
# var["Secondary Energy|Heat|Nuclear"] = \
# var["Secondary Energy|Heat|Other"] = \
# ! Not implemented
var["Secondary Energy|Heat|Hydrogen"] = heat_supply.filter(
like="urban central H2"
).sum()

var["Secondary Energy|Heat|Oil"] = heat_supply.filter(
like="urban central oil"
Expand Down Expand Up @@ -1508,6 +1533,7 @@ def get_secondary_energy(n, region, _industry_demand):
+ var["Secondary Energy|Heat|Other"]
+ var["Secondary Energy|Heat|Coal"]
+ var["Secondary Energy|Heat|Waste"]
+ var["Secondary Energy|Heat|Hydrogen"]
)
assert isclose(
var["Secondary Energy|Heat"],
Expand Down Expand Up @@ -1671,10 +1697,23 @@ def get_secondary_energy(n, region, _industry_demand):
.multiply(MWh2PJ)
)

var["Secondary Energy Input|Hydrogen|Electricity"] = hydrogen_withdrawal.get(
"H2 Fuel Cell", 0
H2_CHP_E_usage, H2_CHP_H_usage = get_CHP_E_and_H_usage(n, "H2", region)

var["Secondary Energy Input|Hydrogen|Electricity"] = (
hydrogen_withdrawal.reindex(
[
"H2 Fuel Cell",
"H2 OCGT",
"H2 CCGT",
"H2 retrofit OCGT",
"H2 retrofit CCGT",
]
).sum()
+ H2_CHP_E_usage
)

var["Secondary Energy Input|Hydrogen|Heat"] = H2_CHP_H_usage

var["Secondary Energy Input|Hydrogen|Gases"] = hydrogen_withdrawal.get(
"Sabatier", 0
)
Expand Down
115 changes: 115 additions & 0 deletions workflow/scripts/modify_prenetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,111 @@ def aladin_mobility_demand(n):
n.stores.loc[dsm_i].e_nom *= pd.Series(factor.values, index=dsm_i)


def add_hydrogen_turbines(n):
"""
This adds links that instead of a gas turbine use a hydrogen turbine.
It is assumed that the efficiency stays the same. This function is
only applied to German nodes.
"""
logger.info("Adding hydrogen turbine technologies for Germany.")

gas_carrier = ["OCGT", "CCGT"]
for carrier in gas_carrier:
gas_plants = n.links[
(n.links.carrier == carrier)
& (n.links.index.str[:2] == "DE")
& (n.links.p_nom_extendable)
].index
if gas_plants.empty:
continue
h2_plants = n.links.loc[gas_plants].copy()
h2_plants.carrier = h2_plants.carrier.str.replace(carrier, "H2 " + carrier)
h2_plants.index = h2_plants.index.str.replace(carrier, "H2 " + carrier)
h2_plants.bus0 = h2_plants.bus1 + " H2"
h2_plants.bus2 = ""
h2_plants.efficiency2 = 1
# add the new links
n.import_components_from_dataframe(h2_plants, "Link")

# special handling of CHPs
gas_plants = n.links[
(n.links.carrier == "urban central gas CHP")
& (n.links.index.str[:2] == "DE")
& (n.links.p_nom_extendable)
].index
h2_plants = n.links.loc[gas_plants].copy()
h2_plants.carrier = h2_plants.carrier.str.replace("gas", "H2")
h2_plants.index = h2_plants.index.str.replace("gas", "H2")
h2_plants.bus0 = h2_plants.bus1 + " H2"
h2_plants.bus3 = ""
h2_plants.efficiency3 = 1
n.import_components_from_dataframe(h2_plants, "Link")


def force_retrofit(n, params):
"""
This function forces the retrofit of gas turbines from params["force"] on.
Extendable gas links are deleted.
"""

logger.info("Forcing retrofit of gas turbines to hydrogen turbines.")

gas_carrier = ["OCGT", "CCGT", "urban central gas CHP"]
# deleting extendable gas turbine plants
to_drop = n.links[
(n.links.carrier.isin(gas_carrier))
& (n.links.p_nom_extendable)
& (n.links.index.str[:2] == "DE")
].index
n.links.drop(to_drop, inplace=True)

# forcing retrofit
for carrier in ["OCGT", "CCGT"]:
gas_plants = n.links[
(n.links.carrier == carrier)
& (n.links.index.str[:2] == "DE")
& (n.links.build_year >= params["start"])
].index
if gas_plants.empty:
continue

h2_plants = n.links.loc[gas_plants].copy()
h2_plants.carrier = h2_plants.carrier.str.replace(
carrier, "H2 retrofit " + carrier
)
h2_plants.index = h2_plants.index.str.replace(carrier, "H2 retrofit " + carrier)
h2_plants.bus0 = h2_plants.bus1 + " H2"
h2_plants.bus2 = ""
h2_plants.efficiency -= params["efficiency_loss"]
h2_plants.efficiency2 = 1 # default value
h2_plants.capital_cost *= 1 + params["cost_factor"]
# add the new links
n.import_components_from_dataframe(h2_plants, "Link")
n.links.drop(gas_plants, inplace=True)

# special handling of CHPs
gas_plants = n.links[
(n.links.carrier == "urban central gas CHP")
& (n.links.index.str[:2] == "DE")
& (n.links.build_year >= params["start"])
].index
if gas_plants.empty:
return

h2_plants = n.links.loc[gas_plants].copy()
h2_plants.carrier = h2_plants.carrier.str.replace("gas", "H2 retrofit")
h2_plants.index = h2_plants.index.str.replace("gas", "H2 retrofit")
h2_plants.bus0 = h2_plants.bus1 + " H2"
h2_plants.bus3 = ""
h2_plants.efficiency -= params["efficiency_loss"]
h2_plants.efficiency3 = 1 # default value
h2_plants.capital_cost *= 1 + params["cost_factor"]
n.import_components_from_dataframe(h2_plants, "Link")
n.links.drop(gas_plants, inplace=True)


if __name__ == "__main__":
if "snakemake" not in globals():
import os
Expand Down Expand Up @@ -759,4 +864,14 @@ def aladin_mobility_demand(n):
snakemake.params.biomass_must_run["regions"],
)

if snakemake.params.H2_plants["enable"]:
if snakemake.params.H2_plants["start"] <= int(
snakemake.wildcards.planning_horizons
):
add_hydrogen_turbines(n)
if snakemake.params.H2_plants["force"] <= int(
snakemake.wildcards.planning_horizons
):
force_retrofit(n, snakemake.params.H2_plants)

n.export_to_netcdf(snakemake.output.network)

0 comments on commit d21a5c2

Please sign in to comment.