pypsa-eur/scripts/build_central_heating_temperature_profiles/run.py
Amos Schledorn bf2d82a384
Dynamic central heating temperatures (#1206)
* feat: Add rule to build central heating temperature profiles, adjust build_cop_profiles accordingly

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

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

* style: make new config settings prettier

* docs: add file headers

* docs: update configtables and module docstring

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

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

* docs: update release notes

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

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

* chore: use smooth ambient temperature through rolling window; remove default vals in class

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

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

* Update doc/configtables/sector.csv

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Amos Schledorn <a.schledorn@tu-berlin.de>
Co-authored-by: Fabian Neumann <fabian.neumann@outlook.de>
2024-08-30 16:01:46 +02:00

148 lines
5.4 KiB
Python

# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT
"""
Approximate district heating forward and return temperature profiles based on
ambient temperature. The method is based on a reference curve from Pieper et
al. 2019, where for ambient temperatures below 0C, the highest possible forward
temperature is assumed and vice versa for temperatures above 10C. Between these
threshold levels, forward temperatures are linearly interpolated.
By default, temperature levels are increased for non-Scandinavian countries.
The default ratios between min. and max. forward temperatures is based on AGFW-Hauptbericht 2022.
Relevant Settings
-----------------
.. code:: yaml
sector:
district_heating:
max_forward_temperature:
min_forward_temperature:
return_temperature:
Inputs
------
- `resources/<run_name>/temp_air_total`: Air temperature
Outputs
-------
- `resources/<run_name>/central_heating_temperature_profiles.nc`:
References
----------
- Pieper, et al. (2019): "Assessment of a combination of three heat sources for heat pumps to supply district heating" (https://doi.org/10.1016/j.energy.2019.03.165).
- AGFW (2022): "Hauptbericht 2022" (https://www.agfw.de/zahlen-und-statistiken/agfw-hauptbericht)
"""
import sys
import geopandas as gpd
import numpy as np
import pandas as pd
import xarray as xr
from _helpers import set_scenario_config
from central_heating_temperature_approximator import (
CentralHeatingTemperatureApproximator,
)
def get_country_from_node_name(node_name: str) -> str:
return node_name[:2]
def map_temperature_dict_to_onshore_regions(
supply_temperature_by_country: dict,
regions_onshore: pd.Index,
snapshots: pd.DatetimeIndex,
) -> xr.DataArray:
"""
Map dictionary of temperatures to onshore regions.
Parameters:
----------
supply_temperature_by_country : dictionary
Dictionary with temperatures as values and country keys as keys. One key must be named "default"
regions_onshore : pd.Index
Names of onshore regions
snapshots : pd.DatetimeIndex
Time stamps
Returns:
-------
xr.DataArray
The dictionary values mapped to onshore regions with onshore regions as coordinates.
"""
return xr.DataArray(
[
[
(
supply_temperature_by_country[get_country_from_node_name(node_name)]
if get_country_from_node_name(node_name)
in supply_temperature_by_country.keys()
else supply_temperature_by_country["default"]
)
for node_name in regions_onshore.values
]
# pass both nodes and snapshots as dimensions to preserve correct data structure
for _ in snapshots
],
dims=["time", "name"],
coords={"time": snapshots, "name": regions_onshore},
)
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
snakemake = mock_snakemake(
"build_cop_profiles",
simpl="",
clusters=48,
)
set_scenario_config(snakemake)
# map forward and return temperatures specified on country-level to onshore regions
regions_onshore = gpd.read_file(snakemake.input.regions_onshore)["name"]
snapshots = pd.date_range(freq="h", **snakemake.params.snapshots)
max_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
map_temperature_dict_to_onshore_regions(
supply_temperature_by_country=snakemake.params.max_forward_temperature_central_heating,
regions_onshore=regions_onshore,
snapshots=snapshots,
)
)
min_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
map_temperature_dict_to_onshore_regions(
supply_temperature_by_country=snakemake.params.min_forward_temperature_central_heating,
regions_onshore=regions_onshore,
snapshots=snapshots,
)
)
return_temperature_central_heating_by_node_and_time: xr.DataArray = (
map_temperature_dict_to_onshore_regions(
supply_temperature_by_country=snakemake.params.return_temperature_central_heating,
regions_onshore=regions_onshore,
snapshots=snapshots,
)
)
central_heating_temperature_approximator = CentralHeatingTemperatureApproximator(
ambient_temperature=xr.open_dataarray(snakemake.input.temp_air_total),
max_forward_temperature=max_forward_temperature_central_heating_by_node_and_time,
min_forward_temperature=min_forward_temperature_central_heating_by_node_and_time,
fixed_return_temperature=return_temperature_central_heating_by_node_and_time,
lower_threshold_ambient_temperature=snakemake.params.lower_threshold_ambient_temperature,
upper_threshold_ambient_temperature=snakemake.params.upper_threshold_ambient_temperature,
rolling_window_ambient_temperature=snakemake.params.rolling_window_ambient_temperature,
)
central_heating_temperature_approximator.forward_temperature.to_netcdf(
snakemake.output.central_heating_forward_temperature_profiles
)
central_heating_temperature_approximator.return_temperature.to_netcdf(
snakemake.output.central_heating_return_temperature_profiles
)