Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix myopic optimization for networks with geothermal district heating #1453

Merged
merged 4 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Release Notes
Upcoming Release
================

* Bugfix: Adjusted existing heating data in ``build_existing_heating_distribution`` and the indexing of existing heat pumps for the COP correction in ``add_brownfield`` to make the myopic code work with the geothermal district heating feature.

* Restore share policy "base" functionality to share build renewable profiles

* Feature: Introduce geothermal district heating (direct utilisation and heat pumps). Potentials are based on `Manz et al. 2024: Spatial analysis of renewable and excess heat potentials for climate-neutral district heating in Europe <https://www.sciencedirect.com/science/article/pii/S0960148124001769>`.
Expand Down
26 changes: 21 additions & 5 deletions scripts/add_brownfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,14 @@ def update_heat_pump_efficiency(n: pypsa.Network, n_p: pypsa.Network, year: int)
This function updates the efficiency in place and does not return a value.
"""

# get names of heat pumps in previous iteration
# get names of heat pumps in previous iteration that cannot be replaced by direct utilisation in this iteration
heat_pump_idx_previous_iteration = n_p.links.index[
n_p.links.index.str.contains("heat pump")
& n_p.links.index.str[:-4].isin(
n.links_t.efficiency.columns.str.rstrip( # sources that can be directly used are no longer represented by heat pumps in the dynamic efficiency dataframe
str(year)
)
)
]
# construct names of same-technology heat pumps in the current iteration
corresponding_idx_this_iteration = heat_pump_idx_previous_iteration.str[:-4] + str(
Expand All @@ -252,18 +257,29 @@ def update_heat_pump_efficiency(n: pypsa.Network, n_p: pypsa.Network, year: int)
n.links_t["efficiency"].loc[:, corresponding_idx_this_iteration].values
)

# Change efficiency2 for heat pumps that use an explicitly modelled heat source
previous_iteration_columns = heat_pump_idx_previous_iteration.intersection(
n_p.links_t["efficiency2"].columns
)
current_iteration_columns = corresponding_idx_this_iteration.intersection(
n.links_t["efficiency2"].columns
)
n_p.links_t["efficiency2"].loc[:, previous_iteration_columns] = (
n.links_t["efficiency2"].loc[:, current_iteration_columns].values
)


if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake

snakemake = mock_snakemake(
"add_brownfield",
clusters="37",
clusters="39",
opts="",
ll="v1.0",
sector_opts="168H-T-H-B-I-dist1",
planning_horizons=2030,
ll="vopt",
sector_opts="",
planning_horizons=2050,
)

configure_logging(snakemake)
Expand Down
32 changes: 23 additions & 9 deletions scripts/build_existing_heating_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,23 @@


def build_existing_heating():
# retrieve existing heating capacities

# Add existing heating capacities, data comes from the study
# "Mapping and analyses of the current and future (2020 - 2030)
# heating/cooling fuel deployment (fossil/renewables) "
# https://energy.ec.europa.eu/publications/mapping-and-analyses-current-and-future-2020-2030-heatingcooling-fuel-deployment-fossilrenewables-1_en
# file: "WP2_DataAnnex_1_BuildingTechs_ForPublication_201603.xls" -> "existing_heating_raw.csv".
# data is for buildings only (i.e. NOT district heating) and represents the year 2012
"""
Retrieve and clean existing heating capacities for the myopic code.
Data comes from the study "Mapping and analyses of the current and
future (2020 - 2030) heating/cooling fuel deployment (fossil/renewables)".

Source
------
https://energy.ec.europa.eu/publications/mapping-and-analyses-current-and-future-2020-2030-heatingcooling-fuel-deployment-fossilrenewables-1_en

File
----
"WP2_DataAnnex_1_BuildingTechs_ForPublication_201603.xls" -> "existing_heating_raw.csv".

Notes
-----
Data is for buildings only (i.e. NOT district heating) and represents the year 2012.
"""
# TODO start from original file

existing_heating = pd.read_csv(
Expand Down Expand Up @@ -143,7 +152,12 @@ def build_existing_heating():
)
nodal_heat_name_tech[(f"{sector} rural", "air heat pump")] = 0.0

nodal_heat_name_tech[("urban central", "ground heat pump")] = 0.0
# add large-scale heat pump sources as columns for district heating with 0 capacity

for heat_pump_source in snakemake.params.sector["heat_pump_sources"][
"urban central"
]:
nodal_heat_name_tech[("urban central", f"{heat_pump_source} heat pump")] = 0.0
cpschau marked this conversation as resolved.
Show resolved Hide resolved

nodal_heat_name_tech.to_csv(snakemake.output.existing_heating_distribution)

Expand Down
Loading