diff --git a/config/config.default.yaml b/config/config.default.yaml index 1cb19dbbf..a475c6fdf 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -456,7 +456,7 @@ sector: 2050: 1.0 district_heating_loss: 0.15 supply_temperature_approximation: - max_forward_temperature: + max_forward_temperature_baseyear: FR: 110 DK: 75 DE: 109 @@ -465,13 +465,14 @@ sector: PL: 130 SE: 102 IT: 90 - min_forward_temperature: + min_forward_temperature_baseyear: DE: 82 - return_temperature: + return_temperature_baseyear: DE: 58 lower_threshold_ambient_temperature: 0 upper_threshold_ambient_temperature: 10 rolling_window_ambient_temperature: 72 + relative_annual_temperature_reduction: 0.01 heat_source_cooling: 6 #K heat_pump_cop_approximation: refrigerant: ammonia diff --git a/doc/configtables/sector.csv b/doc/configtables/sector.csv index 80f8c0550..eeee192eb 100644 --- a/doc/configtables/sector.csv +++ b/doc/configtables/sector.csv @@ -10,12 +10,13 @@ district_heating,--,,`prepare_sector_network.py dict: + """ + Scale temperature for each country to investment year by constant + exponential factor. + + Parameters + ---------- + temperature_baseyear : dict + Dictionary with the current temperatures as values and country keys as keys. + relative_annual_temperature_reduction : float + The annual reduction rate of the temperature, must be between 0 and 1. + investment_year : int + The year in which the investment is planned. + current_year : int + The current year. + + Returns + ------- + dict + A dictionary with the temperature for each country in the investment year. + + Raises + ------ + ValueError + If the investment year is before the current year. + If the relative annual temperature reduction is not between 0 and 1. + """ + + if investment_year < current_year: + raise ValueError( + f"Error: Investment year {investment_year} is before current year {current_year}." + ) + if ( + relative_annual_temperature_reduction < 0 + or relative_annual_temperature_reduction > 1 + ): + raise ValueError( + f"Error: Relative annual temperature reduction must be between 0 and 1, but is {relative_annual_temperature_reduction}." + ) + + return { + key: temperature_baseyear[key] + * ( + (1 - relative_annual_temperature_reduction) + ** (investment_year - current_year) + ) + for key in temperature_baseyear.keys() + } + + if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -137,18 +192,46 @@ def map_temperature_dict_to_onshore_regions( snakemake = mock_snakemake( "build_cop_profiles", clusters=48, + planning_horizons="2050", ) 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, + # reduce temperatures to investment years by constant exponential factor + max_forward_temperature_investment_year = scale_temperature_to_investment_year( + temperature_baseyear=snakemake.params.max_forward_temperature_central_heating_baseyear, + relative_annual_temperature_reduction=snakemake.params.relative_annual_temperature_reduction, + investment_year=int(snakemake.wildcards.planning_horizons), + current_year=int(snakemake.params.energy_totals_year), + ) + + min_forward_temperature_investment_year = scale_temperature_to_investment_year( + temperature_baseyear=snakemake.params.min_forward_temperature_central_heating_baseyear, + relative_annual_temperature_reduction=snakemake.params.relative_annual_temperature_reduction, + investment_year=int(snakemake.wildcards.planning_horizons), + current_year=int(snakemake.params.energy_totals_year), ) - return_temperature = extrapolate_missing_supply_temperatures_by_country( - extrapolate_from=max_forward_temperature, - extrapolate_to=snakemake.params.return_temperature_central_heating, + + return_temperature_investment_year = scale_temperature_to_investment_year( + temperature_baseyear=snakemake.params.return_temperature_central_heating_baseyear, + relative_annual_temperature_reduction=snakemake.params.relative_annual_temperature_reduction, + investment_year=int(snakemake.wildcards.planning_horizons), + current_year=int(snakemake.params.energy_totals_year), + ) + + # min_forward_temperature and return_temperature contain only values for Germany by default + # extrapolate missing values based on ratio between max_forward_temperature and min_forward_temperature / return_temperature for Germany (or other countries provided in min_forward_temperature_baseyear and return_temperature_baseyear) + min_forward_temperature_investment_year = ( + extrapolate_missing_supply_temperatures_by_country( + extrapolate_from=max_forward_temperature_investment_year, + extrapolate_to=min_forward_temperature_investment_year, + ) + ) + return_temperature_investment_year = ( + extrapolate_missing_supply_temperatures_by_country( + extrapolate_from=max_forward_temperature_investment_year, + extrapolate_to=return_temperature_investment_year, + ) ) # map forward and return temperatures specified on country-level to onshore regions @@ -156,19 +239,19 @@ def map_temperature_dict_to_onshore_regions( 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=max_forward_temperature, + supply_temperature_by_country=max_forward_temperature_investment_year, regions_onshore=regions_onshore, ) ) min_forward_temperature_central_heating_by_node_and_time: xr.DataArray = ( map_temperature_dict_to_onshore_regions( - supply_temperature_by_country=min_forward_temperature, + supply_temperature_by_country=min_forward_temperature_investment_year, regions_onshore=regions_onshore, ) ) return_temperature_central_heating_by_node_and_time: xr.DataArray = ( map_temperature_dict_to_onshore_regions( - supply_temperature_by_country=return_temperature, + supply_temperature_by_country=return_temperature_investment_year, regions_onshore=regions_onshore, ) ) diff --git a/scripts/prepare_perfect_foresight.py b/scripts/prepare_perfect_foresight.py index f35019138..53895d0a2 100644 --- a/scripts/prepare_perfect_foresight.py +++ b/scripts/prepare_perfect_foresight.py @@ -7,6 +7,7 @@ """ import logging +from typing import List import numpy as np import pandas as pd @@ -487,6 +488,39 @@ def apply_time_segmentation_perfect( return n +def update_heat_pump_efficiency(n: pypsa.Network, years: List[int]): + """ + Update the efficiency of heat pumps from previous years to current year + (e.g. 2030 heat pumps receive 2040 heat pump COPs in 2030). + + Note: this also updates the efficiency of heat pumps in preceding years for previous years, which should have no effect (e.g. 2040 heat pumps receive 2030 COPs in 2030). + + Parameters + ---------- + n : pypsa.Network + The concatenated network. + years : List[int] + List of planning horizon years. + + Returns + ------- + None + This function updates the efficiency in place and does not return a value. + """ + + # get names of all heat pumps + heat_pump_idx = n.links.index[n.links.index.str.contains("heat pump")] + for year in years: + # for each heat pump type, correct efficiency is the efficiency of that technology built in + correct_efficiency = n.links_t["efficiency"].loc[ + (year, slice(None)), heat_pump_idx.str[:-4] + str(year) + ] + # in , set the efficiency of all heat pumps to the correct efficiency + n.links_t["efficiency"].loc[ + (year, slice(None)), heat_pump_idx + ] = correct_efficiency.values + + if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -538,5 +572,8 @@ def apply_time_segmentation_perfect( # update meta n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards))) + # update heat pump efficiency + update_heat_pump_efficiency(n=n, years=years) + # export network n.export_to_netcdf(snakemake.output[0])