Update central heating temperatures based on Euroheat data and AGFW-Hauptbericht (#1264)
* chore: update config.default Using Euroheat market outlook 2024 and AGFW-Hauptbericht * feat: extrapolate missing values in central_heating_temperature_profile.run * update release notes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: map_temperature_dict_to_onshore regions and correct use of extrapolation function * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: extrapolation_ration in build_central_heating_temperature_profiles.run * style: remove obsolete time index in min/max fwd, return temperatures * feat: throw exception if max_fwd_temp < min_fwd_temp or min_fwd_temp < return_temp * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Amos Schledorn <a.schledorn@tu-berlin.de> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
0423366db6
commit
5cf706fe4d
@ -451,21 +451,18 @@ sector:
|
|||||||
district_heating_loss: 0.15
|
district_heating_loss: 0.15
|
||||||
supply_temperature_approximation:
|
supply_temperature_approximation:
|
||||||
max_forward_temperature:
|
max_forward_temperature:
|
||||||
default: 90
|
FR: 110
|
||||||
DK: 70
|
DK: 75
|
||||||
SE: 70
|
DE: 109
|
||||||
NO: 70
|
CZ: 130
|
||||||
|
FI: 115
|
||||||
|
PL: 130
|
||||||
|
SE: 102
|
||||||
|
IT: 90
|
||||||
min_forward_temperature:
|
min_forward_temperature:
|
||||||
default: 68
|
DE: 82
|
||||||
DK: 54
|
|
||||||
SE: 54
|
|
||||||
NO: 54
|
|
||||||
return_temperature:
|
return_temperature:
|
||||||
default: 50
|
DE: 58
|
||||||
DK: 40
|
|
||||||
SE: 40
|
|
||||||
NO: 40
|
|
||||||
FI: 40
|
|
||||||
lower_threshold_ambient_temperature: 0
|
lower_threshold_ambient_temperature: 0
|
||||||
upper_threshold_ambient_temperature: 10
|
upper_threshold_ambient_temperature: 10
|
||||||
rolling_window_ambient_temperature: 72
|
rolling_window_ambient_temperature: 72
|
||||||
|
@ -9,8 +9,8 @@ Release Notes
|
|||||||
##########################################
|
##########################################
|
||||||
|
|
||||||
.. Upcoming Release
|
.. Upcoming Release
|
||||||
.. ================
|
|
||||||
|
|
||||||
|
* Updated district heating supply temperatures based on `Euroheat's DHC Market Outlook 2024<https://api.euroheat.org/uploads/Market_Outlook_2024_beeecd62d4.pdf>`__ and `AGFW-Hauptbericht 2022 <https://www.agfw.de/securedl/sdl-eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MjU2MjI2MTUsImV4cCI6MTcyNTcxMjYxNSwidXNlciI6MCwiZ3JvdXBzIjpbMCwtMV0sImZpbGUiOiJmaWxlYWRtaW4vdXNlcl91cGxvYWQvWmFobGVuX3VuZF9TdGF0aXN0aWtlbi9IYXVwdGJlcmljaHRfMjAyMi9BR0ZXX0hhdXB0YmVyaWNodF8yMDIyLnBkZiIsInBhZ2UiOjQzNn0.Bhma3PKg9uJnC57Ixi2p9STW5-II9VXPTDXS544M208/AGFW_Hauptbericht_2022.pdf>`__. `min_forward_temperature` and `return_temperature` (not given by Euroheat) are extrapolated based on German values.
|
||||||
* Made the overdimensioning factor for heating systems specific for central/decentral heating, defaults to no overdimensionining for central heating and no changes to decentral heating compared to previous version.
|
* Made the overdimensioning factor for heating systems specific for central/decentral heating, defaults to no overdimensionining for central heating and no changes to decentral heating compared to previous version.
|
||||||
|
|
||||||
* bugfix: The carrier of stores was silently overwritten by their bus_carrier as a side effect when building the co2 constraints
|
* bugfix: The carrier of stores was silently overwritten by their bus_carrier as a side effect when building the co2 constraints
|
||||||
|
@ -58,6 +58,15 @@ class CentralHeatingTemperatureApproximator:
|
|||||||
rolling_window_ambient_temperature : int
|
rolling_window_ambient_temperature : int
|
||||||
Rolling window size for averaging ambient temperature.
|
Rolling window size for averaging ambient temperature.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if any(max_forward_temperature < min_forward_temperature):
|
||||||
|
raise ValueError(
|
||||||
|
"max_forward_temperature must be greater than min_forward_temperature"
|
||||||
|
)
|
||||||
|
if any(min_forward_temperature < fixed_return_temperature):
|
||||||
|
raise ValueError(
|
||||||
|
"min_forward_temperature must be greater than fixed_return_temperature"
|
||||||
|
)
|
||||||
self._ambient_temperature = ambient_temperature
|
self._ambient_temperature = ambient_temperature
|
||||||
self.max_forward_temperature = max_forward_temperature
|
self.max_forward_temperature = max_forward_temperature
|
||||||
self.min_forward_temperature = min_forward_temperature
|
self.min_forward_temperature = min_forward_temperature
|
||||||
|
@ -9,8 +9,8 @@ al. 2019, where for ambient temperatures below 0C, the highest possible forward
|
|||||||
temperature is assumed and vice versa for temperatures above 10C. Between these
|
temperature is assumed and vice versa for temperatures above 10C. Between these
|
||||||
threshold levels, forward temperatures are linearly interpolated.
|
threshold levels, forward temperatures are linearly interpolated.
|
||||||
|
|
||||||
By default, temperature levels are increased for non-Scandinavian countries.
|
By default, `max_forward_temperature` from Euroheat DHC Market Outlook 2024 is used; `min_forward_temperature` and `return_temperature` for Germany is used from AGFW-Hauptbericht 2022.
|
||||||
The default ratios between min. and max. forward temperatures is based on AGFW-Hauptbericht 2022.
|
`min_forward_temperature` and `return_temperature` for other countries are extrapolated based on the ratio between `max_forward_temperature` and `min_forward_temperature` and `return_temperature` for those countries not missing (by default only Germany).
|
||||||
|
|
||||||
Relevant Settings
|
Relevant Settings
|
||||||
-----------------
|
-----------------
|
||||||
@ -47,26 +47,68 @@ from central_heating_temperature_approximator import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def extrapolate_missing_supply_temperatures_by_country(
|
||||||
|
extrapolate_from: dict, extrapolate_to: dict
|
||||||
|
) -> xr.DataArray:
|
||||||
|
"""
|
||||||
|
Extrapolates missing supply temperatures by country.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
extrapolate_from (dict): A dictionary containing supply temperatures to extrapolate from. Should contain all countries.
|
||||||
|
extrapolate_to (dict): A dictionary containing supply temperatures to extrapolate to. Where `country` is present, average ratio between `extrapolate_to[country]` and `extrapolate_from[country]` is applied to all countries for which `country` is not present in `extrapolate_from.keys()` to infer ratio for extrapolation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
xr.DataArray: A DataArray containing the extrapolated supply temperatures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not all([key in extrapolate_from.keys() for key in extrapolate_to.keys()]):
|
||||||
|
raise ValueError(
|
||||||
|
"Not all countries in extrapolate_to are present in extrapolate_from."
|
||||||
|
)
|
||||||
|
# average ratio between extrapolate_from and extrapolate_to for those countries that are in both dictionaries
|
||||||
|
extrapolation_ratio = np.mean(
|
||||||
|
[extrapolate_to[key] / extrapolate_from[key] for key in extrapolate_to.keys()]
|
||||||
|
)
|
||||||
|
|
||||||
|
# apply extrapolation ratio to all keys missing in extrapolate_to
|
||||||
|
return {
|
||||||
|
key: (
|
||||||
|
extrapolate_to[key]
|
||||||
|
if key in extrapolate_to.keys()
|
||||||
|
else extrapolate_from[key] * extrapolation_ratio
|
||||||
|
)
|
||||||
|
for key in extrapolate_from.keys()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_country_from_node_name(node_name: str) -> str:
|
def get_country_from_node_name(node_name: str) -> str:
|
||||||
|
"""
|
||||||
|
Extracts the country code from a given node name.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
node_name (str): The name of the node.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The country code extracted from the node name.
|
||||||
|
"""
|
||||||
return node_name[:2]
|
return node_name[:2]
|
||||||
|
|
||||||
|
|
||||||
def map_temperature_dict_to_onshore_regions(
|
def map_temperature_dict_to_onshore_regions(
|
||||||
supply_temperature_by_country: dict,
|
supply_temperature_by_country: dict,
|
||||||
regions_onshore: pd.Index,
|
regions_onshore: pd.Index,
|
||||||
snapshots: pd.DatetimeIndex,
|
|
||||||
) -> xr.DataArray:
|
) -> xr.DataArray:
|
||||||
"""
|
"""
|
||||||
Map dictionary of temperatures to onshore regions.
|
Map dictionary of temperatures to onshore regions.
|
||||||
|
|
||||||
|
Missing values are replaced by the mean of all values.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
----------
|
----------
|
||||||
supply_temperature_by_country : dictionary
|
supply_temperature_by_country : dictionary
|
||||||
Dictionary with temperatures as values and country keys as keys. One key must be named "default"
|
Dictionary with temperatures as values and country keys as keys.
|
||||||
regions_onshore : pd.Index
|
regions_onshore : pd.Index
|
||||||
Names of onshore regions
|
Names of onshore regions
|
||||||
snapshots : pd.DatetimeIndex
|
|
||||||
Time stamps
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
-------
|
-------
|
||||||
@ -75,20 +117,16 @@ def map_temperature_dict_to_onshore_regions(
|
|||||||
"""
|
"""
|
||||||
return xr.DataArray(
|
return xr.DataArray(
|
||||||
[
|
[
|
||||||
[
|
(
|
||||||
(
|
supply_temperature_by_country[get_country_from_node_name(node_name)]
|
||||||
supply_temperature_by_country[get_country_from_node_name(node_name)]
|
if get_country_from_node_name(node_name)
|
||||||
if get_country_from_node_name(node_name)
|
in supply_temperature_by_country.keys()
|
||||||
in supply_temperature_by_country.keys()
|
else np.mean(list(supply_temperature_by_country.values()))
|
||||||
else supply_temperature_by_country["default"]
|
)
|
||||||
)
|
for node_name in regions_onshore.values
|
||||||
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"],
|
dims=["name"],
|
||||||
coords={"time": snapshots, "name": regions_onshore},
|
coords={"name": regions_onshore},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -104,28 +142,35 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
set_scenario_config(snakemake)
|
set_scenario_config(snakemake)
|
||||||
|
|
||||||
|
max_forward_temperature = snakemake.params.max_forward_temperature_central_heating
|
||||||
|
min_forward_temperature = extrapolate_missing_supply_temperatures_by_country(
|
||||||
|
extrapolate_from=max_forward_temperature,
|
||||||
|
extrapolate_to=snakemake.params.min_forward_temperature_central_heating,
|
||||||
|
)
|
||||||
|
return_temperature = extrapolate_missing_supply_temperatures_by_country(
|
||||||
|
extrapolate_from=max_forward_temperature,
|
||||||
|
extrapolate_to=snakemake.params.return_temperature_central_heating,
|
||||||
|
)
|
||||||
|
|
||||||
# map forward and return temperatures specified on country-level to onshore regions
|
# map forward and return temperatures specified on country-level to onshore regions
|
||||||
regions_onshore = gpd.read_file(snakemake.input.regions_onshore)["name"]
|
regions_onshore = gpd.read_file(snakemake.input.regions_onshore)["name"]
|
||||||
snapshots = pd.date_range(freq="h", **snakemake.params.snapshots)
|
snapshots = pd.date_range(freq="h", **snakemake.params.snapshots)
|
||||||
max_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
max_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
||||||
map_temperature_dict_to_onshore_regions(
|
map_temperature_dict_to_onshore_regions(
|
||||||
supply_temperature_by_country=snakemake.params.max_forward_temperature_central_heating,
|
supply_temperature_by_country=max_forward_temperature,
|
||||||
regions_onshore=regions_onshore,
|
regions_onshore=regions_onshore,
|
||||||
snapshots=snapshots,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
min_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
min_forward_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
||||||
map_temperature_dict_to_onshore_regions(
|
map_temperature_dict_to_onshore_regions(
|
||||||
supply_temperature_by_country=snakemake.params.min_forward_temperature_central_heating,
|
supply_temperature_by_country=min_forward_temperature,
|
||||||
regions_onshore=regions_onshore,
|
regions_onshore=regions_onshore,
|
||||||
snapshots=snapshots,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
return_temperature_central_heating_by_node_and_time: xr.DataArray = (
|
||||||
map_temperature_dict_to_onshore_regions(
|
map_temperature_dict_to_onshore_regions(
|
||||||
supply_temperature_by_country=snakemake.params.return_temperature_central_heating,
|
supply_temperature_by_country=return_temperature,
|
||||||
regions_onshore=regions_onshore,
|
regions_onshore=regions_onshore,
|
||||||
snapshots=snapshots,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user